Kirti Savalia(OpenERP) has proposed merging lp:~openerp-dev/openobject-addons/trunk-temporal-db-fuctionality-branch-ksa into lp:~openerp-dev/openobject-addons/trunk-temporal-db-intermediate-branch-rpa-ksa.
Requested reviews: Rucha (Open ERP) (rpa-openerp) For more details, see: https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-temporal-db-fuctionality-branch-ksa/+merge/65305 [1]create method [2]temporal_date_to: fields.function with store = {} -> we should compute the temporal_date_to only if we modify the temporal_date_from of the next record in timeline. [3]write method: -> if 'temporal_date_from' in args just call super -> if 'temporal_mode' true avoid creating duplication of record for each modification -> solve the problem of one2many field for temporal object -> store timenow on the cursor -> copy only that fields located on the object [4]unlink method: -> Delete all the History Related with the temporal parent ID [5]search method: ->temporal_date BETWEEN temporal_date_from and temporal_date_to ->pass a search criteria on the field 'id' then replace it with the same search criteria on the field 'temporal_parent_id' [6]Read method: ->if 'temporal_date not in context just call super() ->passed the ID of the original record or of an historized record with valid date -- https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-temporal-db-fuctionality-branch-ksa/+merge/65305 Your team OpenERP R&D Team is subscribed to branch lp:~openerp-dev/openobject-addons/trunk-temporal-db-intermediate-branch-rpa-ksa.
=== added directory 'base_temporal' === added file 'base_temporal/__init__.py' --- base_temporal/__init__.py 1970-01-01 00:00:00 +0000 +++ base_temporal/__init__.py 2011-06-21 07:04:54 +0000 @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +import base_temporal +import base_temporal_test + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: === added file 'base_temporal/__openerp__.py' --- base_temporal/__openerp__.py 1970-01-01 00:00:00 +0000 +++ base_temporal/__openerp__.py 2011-06-21 07:04:54 +0000 @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +{ + 'name': 'Base Temporal', + 'version': '1.0', + 'category': 'Generic Modules/Base', + 'description': """ + More specifically the temporal aspects usually include valid-time and transaction-time + -> Valid time denotes the time period during which a fact is true with respect to the real world. + -> Transaction time is the time period during which a fact is stored in the database. + Provides to be able to find the original record of an historization record. + Already a history record for that we can not change any thing. + IF temporal_mode set true avoid creating duplication of the record for every modification. + Store validate date for the records and returns ids of the origional record with all the history records. + """, + 'author': 'OpenERP SA', + 'website': 'http://openerp.com', + 'depends': ['base'], + 'init_xml': [], + 'update_xml': [ + 'base_temporal_test_view.xml' + ,'security/ir.model.access.csv' + ], + 'test': [], + 'installable': True, + 'active': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: === added file 'base_temporal/base_temporal.py' --- base_temporal/base_temporal.py 1970-01-01 00:00:00 +0000 +++ base_temporal/base_temporal.py 2011-06-21 07:04:54 +0000 @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +from osv import fields, osv +from osv import orm +import time + +class orm_temporal(orm.orm): + def set_date(self, obj, cr, uid, ids, name, args, context=None): + res = {} + for id in ids: + context.update({'temporal_mode': False}) + next_id = self.get_next_id_in_timeline(obj, cr, uid, [id], context=context) + res[id] = next_id and obj.read(cr, uid, next_id, ['temporal_date_from'])[0]['temporal_date_from'] or False + return res + + def get_ids_of_same_group(self, cr, uid, ids, context=None): + res = {} + for record in self.browse(cr, uid, ids, context=context): + context.update({'temporal_mode': False}) + res[record.id] = self.search(cr, uid, [('temporal_parent_id','=',record.temporal_parent_id)], context=context) + return res + + def get_next_id_in_timeline(self, obj, cr, uid, ids, context=None): + res = obj.get_ids_of_same_group(cr, uid, ids, context) + for record in obj.browse(cr, uid, ids, context=context): + context.update({'temporal_mode': False}) + search_id = obj.search(cr, uid, [('id', 'in', res[record.id]), ('temporal_date_from', '>', record.temporal_date_from)], order='temporal_date_from asc', limit=1, context=context) + return search_id + + def get_previous_id_in_timeline(self, obj, cr, uid, ids, context=None): + res = obj.get_ids_of_same_group(cr, uid, ids, context=context) + for record in obj.browse(cr, uid, ids, context=context): + context.update({'temporal_mode': False}) + search_id = obj.search(cr, uid, [('id', 'in', res[record.id]), ('temporal_date_from', '<', record.temporal_date_from)], order='temporal_date_from desc', limit=1, context=context) + return search_id + ids + + def __init__(self, cr): + self._columns.update({ + 'temporal_date_from': fields.datetime('Temporal From Date', select=True), + 'temporal_date_to': fields.function(self.set_date, method=True, select=True, string='Temporal To Date', type='datetime', + store = { + self._name: (self.get_previous_id_in_timeline , ['temporal_date_from'], 10), + }), + 'temporal_parent_id': fields.integer('Temporal Parent ID', select=True,) + }) + return super(orm_temporal, self).__init__(cr) + + def create(self, cr, uid, vals, context=None): + """on creation, fill the temporal_date_from and the temporal_parent_id""" + if not vals.get('temporal_date_from'): + vals.update({'temporal_date_from': time.strftime('%Y-%m-%d %H:%M:%S')}) + res_id = super(orm_temporal, self).create(cr, uid, vals, context=context) + if not vals.get('temporal_parent_id'): + self.write(cr, uid, res_id, {'temporal_parent_id': res_id}, context={'temporal_mode': False}) + return res_id + + def unlink(self, cr, uid, ids, context=None): + if isinstance(ids, (int, long)): + ids = list(ids) + if context.get('temporal_mode',True): + ctx=context.copy() + ctx.update({'temporal_mode':False}) + temporal_parent_ids = self.search(cr, uid, [('temporal_parent_id','in', ids)], context=ctx) + ids += temporal_parent_ids + return super(orm_temporal, self).unlink(cr, uid, ids, context) + + def write(self, cr, uid, ids, vals, context=None): + if context is None: + context = {} + if isinstance(ids, (int, long)): + ids = [ids] + # if temporal_date_from pass in vals just call super without any copy + def _test_vals(vals): + for key, value in vals.items(): + if self._columns[key]._type not in ('one2many','many2many'): + return True + return False + # if there is no fields written that are located on the temporal model, just call super + if not _test_vals(vals): + return super(orm_temporal, self).write(cr, uid, ids, vals, context=context) + + if vals.get('temporal_date_from'): + return super(orm_temporal, self).write(cr, uid, ids, vals, context=context) + + cr.timenow = time.strftime('%Y-%m-%d %H:%M:%S') + + if context.get('temporal_mode', True): + for record in self.browse(cr, uid, ids, context=context): + # get current time when make new copy of the current record + vals.update({'temporal_date_from': cr.timenow}) + self.shallow_copy(cr, uid, record.id, {}, context) + return super(orm_temporal, self).write(cr, uid, ids, vals, context=context) + + def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False): + if context is None: + context = {} + #if the key 'temporal_mode' is in the context with False, just make a normal read by calling super() + if not context.get('temporal_mode', True): + return super(orm_temporal,self).search(cr, user, args, offset, limit, order, context, count) + #if present in the args, replace the clause with field 'id' + new_args = [] + for item in args: + if isinstance(item, tuple): + a, b, c = item + if a == 'id': + new_args += ['|', ('temporal_parent_id', b, c)] + new_args.append(item) + + #add the time constraint + cr.timenow = time.strftime('%Y-%m-%d %H:%M:%S') + temporal_date = context.get("temporal_date", cr.timenow) + new_args += ['&','|',('temporal_date_from','=',False),('temporal_date_from', '<=', temporal_date), '|', ('temporal_date_to', '=', False), ('temporal_date_to', '>', temporal_date)] + return super(orm_temporal, self).search(cr, user, new_args, offset, limit, order, context, count) + + def read(self, cr, uid, ids_orig, fields=None, context=None, load='_classic_read'): + ids = isinstance(ids_orig, (int, long)) and [ids_orig] or ids_orig + if context is None: + context = {} + #if the context doesn't contain the key 'temporal_date', just call super() and make a normal read + if not context.get('temporal_date'): + result = super(orm_temporal, self).read(cr, uid, ids, fields=fields, context=context, load=load) + else: + #get the temporal_parent_id of given ids + temporal_parent_ids = super(orm_temporal, self).read(cr, uid, ids, fields=['temporal_parent_id'], context=context, load=load) + #search for real ids to read + ids2 = [] + for id in ids: + cr.timenow = time.strftime('%Y-%m-%d %H:%M:%S') + temporal_date = context.get("temporal_date", cr.timenow) + search_criteria = [('temporal_parent_id','=', temporal_parent_ids[0]['temporal_parent_id']), '&','|',('temporal_date_from','=',False),('temporal_date_from', '<=', temporal_date), '|', ('temporal_date_to', '=', False), ('temporal_date_to', '>', temporal_date)] + ids2 += self.search(cr, uid, search_criteria, context=context) + result = super(orm_temporal, self).read(cr, uid, ids2, fields=fields, context=context, load=load) + if isinstance(ids_orig, (int, long)): + return result[0] + return result + +class osv_temporal(osv.osv, orm_temporal): + pass + +setattr(osv, 'osv_temporal', osv_temporal) + +class test_temporal(osv.osv_temporal): + _inherit='res.partner' +test_temporal() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: === added file 'base_temporal/base_temporal_test.py' --- base_temporal/base_temporal_test.py 1970-01-01 00:00:00 +0000 +++ base_temporal/base_temporal_test.py 2011-06-21 07:04:54 +0000 @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +from osv import fields, osv +import time + +class base_temporal_test(osv.osv_temporal): + _name = "base.temporal.test" + _description = "Base Temporal" + + _columns = { + 'name': fields.char('Temporal Name', size=64), + 'line_ids': fields.one2many('base.temporal.test.line', 'test_id', 'Line IdS'), + } + + +base_temporal_test() + +class base_temporal_test_line(osv.osv_temporal): + _name = "base.temporal.test.line" + _description = "Base Temporal Line" + _columns = { + 'name': fields.char('Temporal Name', size=64), + 'test_id': fields.many2one('base.temporal.test','Test ID'), + } + +base_temporal_test_line() + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: === added file 'base_temporal/base_temporal_test_view.xml' --- base_temporal/base_temporal_test_view.xml 1970-01-01 00:00:00 +0000 +++ base_temporal/base_temporal_test_view.xml 2011-06-21 07:04:54 +0000 @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + <record model="ir.ui.view" id="view_base_temporal_test_form"> + <field name="name">base.temporal.test.form</field> + <field name="model">base.temporal.test</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Base Temporal Test"> + <field name="name"/> + <field name="temporal_date_from"/> + <field name="temporal_date_to"/> + <field name="temporal_parent_id"/> + <field colspan="4" name="line_ids" nolabel="1" mode="tree,form"> + <tree string="Base Temporal Test Lines"> + <field name="name"/> + <field name="test_id"/> + </tree> + <form string="Base Temporal Test Lines"> + <field name="name"/> + <field name="test_id"/> + </form> + </field> + </form> + </field> + </record> + + <record model="ir.ui.view" id="view_base_temporal_test_tree"> + <field name="name">base.temporal.test.tree</field> + <field name="model">base.temporal.test</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Base Temporal Test"> + <field name="name"/> + <field name="temporal_date_from"/> + <field name="temporal_date_to"/> + <field name="temporal_parent_id"/> + </tree> + </field> + </record> + + <record model="ir.actions.act_window" id="action_base_temporal_test_tree"> + <field name="name">Base Temporal Test</field> + <field name="res_model">base.temporal.test</field> + <field name="type">ir.actions.act_window</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="context">{'temporal_mode': True}</field> + <field name="search_view_id" ref="view_base_temporal_test_tree"/> + </record> + + <menuitem action="action_base_temporal_test_tree" + id="menu_partner_temporal_tree" + parent="base.menu_base_partner" sequence="50"/> + + <record model="ir.actions.act_window" id="action_base_temporal_test_1"> + <field name="name">Base Temporal Test All</field> + <field name="res_model">base.temporal.test</field> + <field name="type">ir.actions.act_window</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="context">{'temporal_mode': False}</field> + <field name="search_view_id" ref="view_base_temporal_test_tree"/> + </record> + + <menuitem action="action_base_temporal_test_1" + id="menu_partner_temporal_tree1" + parent="base.menu_base_partner" sequence="50"/> + </data> +</openerp> + === added directory 'base_temporal/security' === added file 'base_temporal/security/ir.model.access.csv' --- base_temporal/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 +++ base_temporal/security/ir.model.access.csv 2011-06-21 07:04:54 +0000 @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_base_temporal_test","base.temporal.test","model_base_temporal_test","base.group_user",1,1,0,0 +"access_base_temporal_test_line","base.temporal.test.line","model_base_temporal_test_line","base.group_user",1,1,0,0
_______________________________________________ Mailing list: https://launchpad.net/~openerp-dev-gtk Post to : [email protected] Unsubscribe : https://launchpad.net/~openerp-dev-gtk More help : https://help.launchpad.net/ListHelp

