commit
896ebda0ae
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!--
|
||||
Invoices
|
||||
-->
|
||||
|
@ -434,6 +433,7 @@
|
|||
<field name="help">Most of customer invoices are automatically generated in draft mode by OpenERP flows, following a purchase order for instance. Review, confirm or cancel, pay or refund your customers' invoices here. A manual invoice can be created here.</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_invoice_tree1_view1" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence"/>
|
||||
<field name="view_mode">tree</field>
|
||||
|
@ -446,6 +446,7 @@
|
|||
<field name="view_id" ref="invoice_form"/>
|
||||
<field name="act_window_id" ref="action_invoice_tree1"/>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_invoice_tree1" id="menu_action_invoice_tree1" parent="menu_finance_receivables"/>
|
||||
|
||||
<record id="action_invoice_tree2" model="ir.actions.act_window">
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
<action
|
||||
string="New Files"
|
||||
name="%(document.action_view_all_document_tree1)d"
|
||||
view_mode="tree"
|
||||
domain="[('name','=',time.strftime('%%Y')),('month','=',time.strftime('%%m'))]"/>
|
||||
|
||||
view_mode="tree,form"/>
|
||||
<action
|
||||
string="File Size by Month"
|
||||
name="%(document.action_view_size_month)d"
|
||||
|
@ -28,7 +26,8 @@
|
|||
<action
|
||||
string="Files by Resource Type"
|
||||
name="%(document.action_view_document_by_resourcetype_graph)d"
|
||||
view_mode="graph,tree"/>
|
||||
view_mode="graph,tree"
|
||||
/>
|
||||
|
||||
<action
|
||||
string="Files by Partner"
|
||||
|
|
|
@ -41,7 +41,7 @@ class document_file(osv.osv):
|
|||
fbrl = self.browse(cr, uid, ids, context=context)
|
||||
nctx = nodes.get_node_context(cr, uid, context={})
|
||||
# nctx will /not/ inherit the caller's context. Most of
|
||||
# it would be useless, anyway (like active_id, active_model,
|
||||
# it would be useless, anyway (like active_id, active_model,
|
||||
# bin_size etc.)
|
||||
result = {}
|
||||
bin_size = context.get('bin_size', False)
|
||||
|
@ -91,10 +91,11 @@ class document_file(osv.osv):
|
|||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'file_size': fields.integer('File Size', required=True),
|
||||
'file_type': fields.char('Content Type', size=128),
|
||||
|
||||
|
||||
# fields used for file storage
|
||||
'store_fname': fields.char('Stored Filename', size=200),
|
||||
}
|
||||
_order = "create_date desc"
|
||||
|
||||
def __get_def_directory(self, cr, uid, context=None):
|
||||
dirobj = self.pool.get('document.directory')
|
||||
|
@ -150,7 +151,7 @@ class document_file(osv.osv):
|
|||
return False
|
||||
if not self._check_duplication(cr, uid, vals, ids, 'write'):
|
||||
raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
|
||||
|
||||
|
||||
# if nodes call this write(), they must skip the code below
|
||||
from_node = context and context.get('__from_node', False)
|
||||
if (('parent_id' in vals) or ('name' in vals)) and not from_node:
|
||||
|
|
|
@ -50,7 +50,6 @@ class document_directory(osv.osv):
|
|||
],
|
||||
'Type', required=True, select=1,
|
||||
help="Each directory can either have the type Static or be linked to another resource. A static directory, as with Operating Systems, is the classic directory that can contain a set of files. The directories linked to systems resources automatically possess sub-directories for each of resource types defined in the parent directory."),
|
||||
|
||||
'ressource_type_id': fields.many2one('ir.model', 'Resource model',
|
||||
help="Select an object here and there will be one folder per record of that resource."),
|
||||
'resource_field': fields.many2one('ir.model.fields', 'Name field', help='Field to be used as name on resource directories. If empty, the "name" will be used.'),
|
||||
|
|
|
@ -292,7 +292,7 @@
|
|||
<field name="parent_id" />
|
||||
<field name="user_id">
|
||||
<filter icon="terp-personal"
|
||||
domain="[('user_id','=', False)]"
|
||||
domain="[('user_id','=',uid)]"
|
||||
help="Filter on my documents" />
|
||||
</field>
|
||||
<field name="partner_id"/>
|
||||
|
@ -334,7 +334,7 @@
|
|||
<field name="res_model">ir.attachment</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="search_view_id" ref="view_attach_filter"/>
|
||||
<field name="help">Documents give your access to all attached documents; it's a repository of all attached documents (mails, documents attached to a project, etc.)</field>
|
||||
<field name="help">The Documents repository gives you access to all attachments, such as mails, project documents, invoices etc.</field>
|
||||
</record>
|
||||
<menuitem name="Documents" id="menu_document_doc" parent="knowledge.menu_document" sequence="0"/>
|
||||
<menuitem
|
||||
|
|
|
@ -34,6 +34,7 @@ class report_document_user(osv.osv):
|
|||
'user_id':fields.integer('Owner', readonly=True),
|
||||
'user':fields.char('User',size=64,readonly=True),
|
||||
'directory': fields.char('Directory',size=64,readonly=True),
|
||||
'datas_fname': fields.char('File Name',size=64,readonly=True),
|
||||
'create_date': fields.datetime('Date Created', readonly=True),
|
||||
'change_date': fields.datetime('Modified Date', readonly=True),
|
||||
'file_size': fields.integer('File Size', readonly=True),
|
||||
|
@ -52,6 +53,7 @@ class report_document_user(osv.osv):
|
|||
u.name as user,
|
||||
count(*) as nbr,
|
||||
d.name as directory,
|
||||
f.datas_fname as datas_fname,
|
||||
f.create_date as create_date,
|
||||
f.file_size as file_size,
|
||||
min(d.type) as type,
|
||||
|
@ -59,11 +61,13 @@ class report_document_user(osv.osv):
|
|||
FROM ir_attachment f
|
||||
left join document_directory d on (f.parent_id=d.id and d.name<>'')
|
||||
inner join res_users u on (f.user_id=u.id)
|
||||
group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,u.name,d.type,f.write_date
|
||||
group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,u.name,d.type,f.write_date,f.datas_fname
|
||||
)
|
||||
""")
|
||||
report_document_user()
|
||||
|
||||
|
||||
|
||||
class report_files_partner(osv.osv):
|
||||
_name = "report.files.partner"
|
||||
_description = "Files details by Partners"
|
||||
|
@ -86,7 +90,7 @@ class report_files_partner(osv.osv):
|
|||
to_char(date_trunc('month', f.create_date),'MM') AS month,
|
||||
SUM(f.file_size) AS file_size,
|
||||
p.name AS partner
|
||||
|
||||
|
||||
FROM ir_attachment f
|
||||
LEFT JOIN res_partner p ON (f.partner_id=p.id)
|
||||
WHERE f.datas_fname IS NOT NULL
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<field name="name" select="1"/>
|
||||
<field name="user" select="1"/>
|
||||
<field name="directory" select="1"/>
|
||||
<field name="datas_fname" select="1"/>
|
||||
<field name="file_size"/>
|
||||
<field name="create_date"/>
|
||||
</form>
|
||||
|
@ -25,10 +26,11 @@
|
|||
<tree string="Files">
|
||||
<field name="name" select="1"/>
|
||||
<field name="month" select="1"/>
|
||||
<field name="user" select="1"/>
|
||||
<field name="directory" select="1"/>
|
||||
<field name="file_size"/>
|
||||
<field name="create_date"/>
|
||||
<field name="user" select="1" invisible="1"/>
|
||||
<field name="directory" select="1" invisible="1"/>
|
||||
<field name="file_size" invisible="1"/>
|
||||
<field name="create_date" invisible="1"/>
|
||||
<field name="nbr"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -60,8 +62,8 @@
|
|||
<field name="name">All Users files</field>
|
||||
<field name="res_model">report.document.user</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="context">{'search_default_user': 'user_id'}</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'group_by': ['name','month']}</field>
|
||||
<field name="search_view_id" ref="view_report_document_user_search"/>
|
||||
</record>
|
||||
|
||||
|
@ -112,30 +114,18 @@
|
|||
<field name="arch" type="xml">
|
||||
<graph string="Files by Resource Type" type="pie">
|
||||
<field name="type" />
|
||||
<!-- <field name="file_size" operator="+"/>-->
|
||||
<field name="nbr" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="ir.ui.view" id="view_document_by_resourcetype_tree">-->
|
||||
<!-- <field name="name">report.document.resource.tree.view</field>-->
|
||||
<!-- <field name="model">report.document.user</field>-->
|
||||
<!-- <field name="type">tree</field>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <tree string="Files by Resource Type">-->
|
||||
<!-- <field name="type" />-->
|
||||
<!-- <field name="nbr"/>-->
|
||||
<!-- </tree>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<record model="ir.actions.act_window" id="action_view_document_by_resourcetype_graph">
|
||||
<field name="name">Files by Resource Type</field>
|
||||
<field name="res_model">report.document.user</field>
|
||||
<field name="view_id" ref="view_document_by_resourcetype_graph"></field>
|
||||
<field name="view_id" ref="view_document_by_resourcetype_graph"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
</record>
|
||||
|
||||
<!--***************************************************************************************-->
|
||||
|
@ -150,7 +140,7 @@
|
|||
<field name="file_size" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_size_month_tree">
|
||||
<field name="name">report.document.user.tree</field>
|
||||
|
|
|
@ -196,7 +196,7 @@
|
|||
!python {model: ir.attachment}: |
|
||||
from document_ftp import test_easyftp as te
|
||||
ftp = te.get_ftp_folder(cr, uid, self, 'Documents')
|
||||
ftp.mkd("Test-Folder2")
|
||||
ftp.mkd("Test-Folder3")
|
||||
# TODO move
|
||||
-
|
||||
I remove the 'Test-Folder3'
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Browse Document">
|
||||
<separator string="Browse Document" colspan="4"/>
|
||||
<field name="url" widget="url" colspan="4"/>
|
||||
<field name="url" widget="url" colspan="4" width="250"/>
|
||||
<separator colspan="4"/>
|
||||
<group col="4" colspan="4">
|
||||
<label string="" colspan="2"/>
|
||||
|
|
|
@ -30,7 +30,7 @@ class document_ftp_configuration(osv.osv_memory):
|
|||
_rec_name = 'host'
|
||||
_columns = {
|
||||
'host': fields.char('Address', size=64,
|
||||
help="Server address or IP and port to which users should connect to for DMS access",
|
||||
help="Server address or IP and port to which users should connect to for DMS access",
|
||||
required=True),
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
|
||||
<menuitem id="menu_project_working_hours" parent="base.menu_project_management_time_tracking" action="act_hr_timesheet_line_evry1_all_form"/>
|
||||
<menuitem id="menu_hr_working_hours" parent="hr_attendance.menu_hr_time_tracking" action="act_hr_timesheet_line_evry1_all_form"/>
|
||||
<menuitem id="menu_partner_invc" parent="base.menu_project_management_time_tracking" action="account.action_invoice_tree1"/>
|
||||
|
||||
<record id="hr_timesheet_employee_extd_form" model="ir.ui.view">
|
||||
<field name="name">hr.timesheet.employee.extd_form</field>
|
||||
|
|
|
@ -637,6 +637,7 @@ class task(osv.osv):
|
|||
if context is None:
|
||||
context = {}
|
||||
request = self.pool.get('res.request')
|
||||
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
project = task.project_id
|
||||
if project and project.warn_manager and project.user_id.id and (project.user_id.id != uid):
|
||||
|
@ -651,6 +652,7 @@ class task(osv.osv):
|
|||
})
|
||||
|
||||
self.write(cr, uid, [task.id], {'state': 'open'})
|
||||
|
||||
return True
|
||||
|
||||
def do_cancel(self, cr, uid, ids, *args):
|
||||
|
|
|
@ -89,7 +89,7 @@ class report_project_task_user(osv.osv):
|
|||
planned_hours as hours_planned,
|
||||
(extract('epoch' from (t.date_end-t.create_date)))/(3600*24) as closing_days,
|
||||
(extract('epoch' from (t.date_start-t.create_date)))/(3600*24) as opening_days,
|
||||
(extract('epoch' from (t.date_deadline-t.date_end)))/(3600*24) as delay_endings_days
|
||||
abs((extract('epoch' from (t.date_deadline-t.date_end)))/(3600*24)) as delay_endings_days
|
||||
FROM project_task t
|
||||
|
||||
GROUP BY
|
||||
|
|
|
@ -254,6 +254,7 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
data_obj = self.pool.get('ir.model.data')
|
||||
task_obj = self.pool.get('project.task')
|
||||
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
|
@ -297,6 +298,7 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
'nodestroy': True
|
||||
}
|
||||
|
||||
|
||||
def _convert(self, cr, uid, ids, xml_id, context=None):
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
id2 = data_obj._get_id(cr, uid, 'project_issue', xml_id)
|
||||
|
@ -335,6 +337,7 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
self.write(cr, uid, task.id, {'type_id': index and types[index-1] or False})
|
||||
return True
|
||||
|
||||
|
||||
def onchange_task_id(self, cr, uid, ids, task_id, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
|
|
@ -326,6 +326,19 @@
|
|||
# Project
|
||||
# ------------------------------------------------------
|
||||
|
||||
<record id="project.view_project_resource_form1" model="ir.ui.view">
|
||||
<field name="name">Project Resource Calendar View</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="priority" position="before">
|
||||
<field name="resource_calendar_id"/>
|
||||
</field>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_form_inherited" model="ir.ui.view">
|
||||
<field name="name">project.project.form.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
|
@ -333,7 +346,6 @@
|
|||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="priority" position="before">
|
||||
<field name="resource_calendar_id"/>
|
||||
<field name="project_escalation_id"/>
|
||||
<field name="reply_to"/>
|
||||
</field>
|
||||
|
|
|
@ -91,8 +91,8 @@ class project_phase(osv.osv):
|
|||
model_data_obj = self.pool.get('ir.model.data')
|
||||
model_data_id = model_data_obj._get_id(cr, uid, 'product', 'uom_hour')
|
||||
return model_data_obj.read(cr, uid, [model_data_id], ['res_id'])[0]['res_id']
|
||||
|
||||
def _compute(self, cr, uid, ids,field_name, arg, context=None):
|
||||
|
||||
def _compute(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
if not ids:
|
||||
return res
|
||||
|
@ -143,7 +143,7 @@ class project_phase(osv.osv):
|
|||
project_id = project_obj.browse(cr, uid, project, context=context)
|
||||
result['date_start'] = project_id.date_start
|
||||
return {'value': result}
|
||||
|
||||
|
||||
def onchange_days(self, cr, uid, ids, project, context=None):
|
||||
result = {}
|
||||
for id in ids:
|
||||
|
@ -219,7 +219,7 @@ class project_phase(osv.osv):
|
|||
cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
|
||||
if cal_id:
|
||||
calendar_id = cal_id
|
||||
|
||||
|
||||
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
|
||||
# Change the date_start and date_end
|
||||
# for previous and next phases respectively based on valid condition
|
||||
|
@ -232,7 +232,7 @@ class project_phase(osv.osv):
|
|||
if prv_phase.id == phase.id:
|
||||
continue
|
||||
self._check_date_start(cr, uid, prv_phase, dt_start, context=context)
|
||||
|
||||
|
||||
if vals.get('date_end', False) and vals['date_end'] > phase.date_end:
|
||||
dt_end = datetime.strptime(vals['date_end'], '%Y-%m-%d')
|
||||
work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id, dt_end, avg_hours or 0.0, resource_id and resource_id[0] or False)
|
||||
|
@ -242,7 +242,7 @@ class project_phase(osv.osv):
|
|||
if next_phase.id == phase.id:
|
||||
continue
|
||||
self._check_date_end(cr, uid, next_phase, dt_end, context=context)
|
||||
|
||||
|
||||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
|
@ -293,7 +293,7 @@ class project_phase(osv.osv):
|
|||
Schedule phase with the start date till all the next phases are completed.
|
||||
@param: start_dsate : start date for the phase
|
||||
@param: calendar_id : working calendar of the project
|
||||
"""
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
|
@ -304,7 +304,7 @@ class project_phase(osv.osv):
|
|||
for phase in self.browse(cr, uid, ids, context=context):
|
||||
if not phase.responsible_id:
|
||||
raise osv.except_osv(_('No responsible person assigned !'),_("You must assign a responsible person for phase '%s' !") % (phase.name,))
|
||||
|
||||
|
||||
phase_resource_obj = resource_pool.generate_resources(cr, uid, [phase.responsible_id.id], calendar_id, context=context)
|
||||
avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
|
||||
duration = str(avg_hours) + 'H'
|
||||
|
@ -369,7 +369,7 @@ class project_phase(osv.osv):
|
|||
if not start_date and phase.project_id.date_start:
|
||||
start_date = phase.project_id.date_start
|
||||
if not start_date:
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
resources = resources_list.get(phase.id, [])
|
||||
calendar_id = phase.project_id.resource_calendar_id.id
|
||||
task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
|
||||
|
@ -396,7 +396,7 @@ class project_resource_allocation(osv.osv):
|
|||
'user_id': fields.related('resource_id', 'user_id', type='many2one', relation="res.users", string='User'),
|
||||
'date_start': fields.date('Start Date', help="Starting Date"),
|
||||
'date_end': fields.date('End Date', help="Ending Date"),
|
||||
'useability': fields.float('Usability', help="Usability of this resource for this project phase in percentage (=50%)"),
|
||||
'useability': fields.float('Availability', help="Usability of this resource for this project phase in percentage (=50%)"),
|
||||
}
|
||||
_defaults = {
|
||||
'useability': 100,
|
||||
|
@ -458,19 +458,19 @@ class project(osv.osv):
|
|||
resource_pool = self.pool.get('resource.resource')
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
|
||||
resources_list = self.generate_members(cr, uid, ids, context=context)
|
||||
return_msg = {}
|
||||
for project in self.browse(cr, uid, ids, context=context):
|
||||
start_date = project.date_start
|
||||
if not start_date:
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
resources = resources_list.get(project.id, [])
|
||||
calendar_id = project.resource_calendar_id.id
|
||||
task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
|
||||
('state', 'in', ['draft', 'open', 'pending'])
|
||||
])
|
||||
|
||||
|
||||
|
||||
if task_ids:
|
||||
task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
|
||||
|
@ -481,7 +481,7 @@ class project(osv.osv):
|
|||
else:
|
||||
return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
|
||||
|
||||
return return_msg
|
||||
return return_msg
|
||||
|
||||
project()
|
||||
|
||||
|
@ -504,7 +504,7 @@ class project_task(osv.osv):
|
|||
_columns = {
|
||||
'phase_id': fields.many2one('project.phase', 'Project Phase'),
|
||||
}
|
||||
|
||||
|
||||
def generate_schedule(self, cr, uid, ids, resources, calendar_id, start_date, context=None):
|
||||
"""
|
||||
Schedule the tasks according to resource available and priority.
|
||||
|
@ -554,10 +554,10 @@ class project_task(osv.osv):
|
|||
if task_resource.__name__ == task_resource:
|
||||
real_resource = task_resource
|
||||
break
|
||||
|
||||
|
||||
task = create_tasks(task_number, hours, priorty, real_resource)
|
||||
task_number += 1
|
||||
|
||||
|
||||
|
||||
face_projects = Task.BalancedProject(Project)
|
||||
loop_no = 0
|
||||
|
|
|
@ -81,9 +81,9 @@
|
|||
</group>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By..." colspan="4" col="20">
|
||||
<filter name="resource" string="Resource" icon="terp-folder-blue" domain="[]" context="{'group_by':'resource_id'}"/>
|
||||
<filter name="resource" string="Resource" icon="terp-personal" domain="[]" context="{'group_by':'resource_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Project" icon="terp-project" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Project" icon="terp-folder-blue" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Phase" icon="terp-project" domain="[]" context="{'group_by':'phase_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
|
@ -110,22 +110,18 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project Phase">
|
||||
<group colspan="8" col="7">
|
||||
<group colspan="8">
|
||||
<field name="name" select="1"/>
|
||||
<field name="total_hours"/>
|
||||
<field name="project_id" on_change="onchange_project(project_id)" colspan="2"/>
|
||||
<field name="responsible_id" colspan="2"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group colspan="2">
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<group colspan="6" col="6">
|
||||
<group colspan="6" col="6" >
|
||||
<field name="name" select="1"/>
|
||||
<field name="project_id" on_change="onchange_project(project_id)"/>
|
||||
<field name="responsible_id"/>
|
||||
</group>
|
||||
<group colspan="6" col="6">
|
||||
<field name="date_start"/>
|
||||
<field name="duration" on_change="onchange_days(project_id)" />
|
||||
<field name="product_uom" nolabel="1" domain="[('category_id.name', '=', 'Working Time')]"/>
|
||||
<field name="date_end"/>
|
||||
</group>
|
||||
<group colspan="2">
|
||||
<field name="duration" on_change="onchange_days(project_id)"/>
|
||||
<field name="product_uom" nolabel="1" domain="[('category_id.name', '=', 'Working Time')]"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Resource Allocation">
|
||||
|
@ -275,7 +271,7 @@
|
|||
</group>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By..." colspan="4" col="20" groups="base.group_extended">
|
||||
<filter string="User" icon="terp-personal" domain="[]" context="{'group_by':'responsible_id'}"/>
|
||||
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'responsible_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Project" icon="terp-folder-blue" domain="[]" context="{'group_by':'project_id'}" name="project"/>
|
||||
<separator orientation="vertical"/>
|
||||
|
@ -292,7 +288,7 @@
|
|||
<field name="res_model">project.phase</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">gantt,tree,form,calendar</field>
|
||||
<field name="context">{'search_default_responsible_id':uid}</field>
|
||||
<field name="context">{'search_default_responsible_id':uid,'group_by':'project_id'}</field>
|
||||
<field name="search_view_id" ref="view_project_phase_search"/>
|
||||
<field name="help">You can subdivide your larger projects into several phases. For each phase, you can define your resources allocation (humans or engine), describe de differend task and link your phase with previous and next one, add constraints date and scheduling. A gantt view of your project phase is also available from this menu. Gantt view is a graphically draw of the project plan; it includes any task dependencies by visually adjusting task durations and priorities, and by linking tasks to each other.</field>
|
||||
</record>
|
||||
|
@ -302,7 +298,7 @@
|
|||
<field name="res_model">project.phase</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,calendar</field>
|
||||
<field name="context">{'search_default_responsible_id':uid}</field>
|
||||
<field name="context">{'search_default_responsible_id':uid,'group_by':'project_id'}</field>
|
||||
<field name="search_view_id" ref="view_project_phase_search"/>
|
||||
</record>
|
||||
|
||||
|
@ -311,8 +307,8 @@
|
|||
# Project
|
||||
# ------------------------------------------------------
|
||||
|
||||
<record id="view_phase_project_form1" model="ir.ui.view">
|
||||
<field name="name">phase.project.form1</field>
|
||||
<record id="project.view_project_resource_form1" model="ir.ui.view">
|
||||
<field name="name">Project Resource Calendar View</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
|
@ -327,7 +323,7 @@
|
|||
# ------------------------------------------------------
|
||||
# Project Task
|
||||
# ------------------------------------------------------
|
||||
|
||||
|
||||
<record id="view_phase_task_form2" model="ir.ui.view">
|
||||
<field name="name">phase.task.form2</field>
|
||||
<field name="model">project.task</field>
|
||||
|
@ -349,8 +345,8 @@
|
|||
<field name="phase_id" select="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</record>
|
||||
|
||||
<act_window
|
||||
id="project_phase_task_list"
|
||||
name="Related Tasks"
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
'wizard/project_scrum_backlog_create_task_view.xml',
|
||||
'wizard/project_scrum_backlog_merger_view.xml',
|
||||
'wizard/project_scrum_postpone_view.xml',
|
||||
"wizard/project_scrum_email_view.xml",
|
||||
'project_scrum_view.xml',
|
||||
'wizard/project_scrum_backlog_sprint_view.xml',
|
||||
'process/project_scrum_process.xml',
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
<record id="scrum_sprint_0" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 1</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-01-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-01-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-06-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-06-15')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','admin')]"/>
|
||||
|
@ -15,8 +15,8 @@
|
|||
|
||||
<record id="scrum_sprint_1" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 2</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-01-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-01-31')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-06-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-06-30')"></field>
|
||||
<field name="expected_hours">100.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -26,8 +26,8 @@
|
|||
|
||||
<record id="scrum_sprint_2" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 3</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-02-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-02-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-07-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-07-15')"></field>
|
||||
<field name="expected_hours">89.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -37,8 +37,8 @@
|
|||
|
||||
<record id="scrum_sprint_3" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 4</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-02-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-02-28')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-07-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-07-31')"></field>
|
||||
<field name="expected_hours">125.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -48,8 +48,8 @@
|
|||
|
||||
<record id="scrum_sprint_4" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 5</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-03-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-03-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-08-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-08-15')"></field>
|
||||
<field name="expected_hours">178.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -59,8 +59,8 @@
|
|||
|
||||
<record id="scrum_sprint_5" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 6</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-03-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-03-30')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-08-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-08-31')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="expected_hours">200.0</field>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -70,8 +70,8 @@
|
|||
|
||||
<record id="scrum_sprint_6" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 7</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-04-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-04-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-09-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-09-15')"></field>
|
||||
<field name="expected_hours">175.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -81,8 +81,8 @@
|
|||
|
||||
<record id="scrum_sprint_7" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 8</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-04-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-04-30')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-09-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-09-30')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field name="expected_hours">122.0</field>
|
||||
|
@ -92,8 +92,8 @@
|
|||
|
||||
<record id="scrum_sprint_8" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 9</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-05-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-05-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-10-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-10-15')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','demo')]"/>
|
||||
|
@ -102,8 +102,8 @@
|
|||
|
||||
<record id="scrum_sprint_9" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 10</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-05-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-05-30')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-10-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-10-31')"></field>
|
||||
<field name="expected_hours">78.0</field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
|
@ -113,8 +113,8 @@
|
|||
|
||||
<record id="scrum_sprint_10" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 11</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-06-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-06-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-11-01')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-11-15')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','demo')]"/>
|
||||
|
@ -123,8 +123,8 @@
|
|||
|
||||
<record id="scrum_sprint_11" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 12</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-06-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-06-30')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-11-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-11-30')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','admin')]"/>
|
||||
|
@ -133,8 +133,18 @@
|
|||
|
||||
<record id="scrum_sprint_12" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 13</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-07-1')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-07-15')"></field>
|
||||
<field name="date_start" eval="time.strftime('%Y-12-1')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-12-15')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','admin')]"/>
|
||||
<field name="state">open</field>
|
||||
</record>
|
||||
|
||||
<record id="scrum_sprint_13" model="project.scrum.sprint">
|
||||
<field name="name">Sprint 14</field>
|
||||
<field name="date_start" eval="time.strftime('%Y-12-16')"></field>
|
||||
<field name="date_stop" eval="time.strftime('%Y-12-31')"></field>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="product_owner_id" ref="base.user_root"/>
|
||||
<field model="res.users" name="scrum_master_id" search="[('login','=','admin')]"/>
|
||||
|
@ -391,7 +401,7 @@ Demo: Work on Editable trees</field>
|
|||
<field name="question_blocks">
|
||||
Demo :Bugfix - memory leak
|
||||
</field>
|
||||
<field name="sprint_id" ref="scrum_sprint_0"/>
|
||||
<field name="sprint_id" ref="scrum_sprint_8"/>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date"/>
|
||||
</record>
|
||||
<record id="project_task_work_scrum_task1" model="project.task.work" context="{'withoutemployee': True }">
|
||||
|
|
|
@ -390,10 +390,11 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Scrum Meeting">
|
||||
<group colspan="4" col="6">
|
||||
<group colspan="4" col="8">
|
||||
<field name="date"/>
|
||||
<field name="sprint_id" domain="[('state', '=', 'open')]"/>
|
||||
<field name="user_id"/>
|
||||
<button name="%(action_project_scrum_email)d" string="Send Email" type="action" icon="terp-mail-message-new" />
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Scrum Meeting">
|
||||
|
@ -404,8 +405,6 @@
|
|||
<separator colspan="4" string="Are there anything blocking you?"/>
|
||||
<field colspan="4" name="question_blocks" nolabel="1"/>
|
||||
<separator colspan="4" string=""/>
|
||||
<button name="button_send_to_master" type="object" string="Send to Scrum Master" icon="gtk-ok"/>
|
||||
<button name="button_send_product_owner" type="object" string="Send to Product Owner" icon="gtk-ok"/>
|
||||
</page>
|
||||
<page string="Optional Info">
|
||||
<separator colspan="4" string="Are your Sprint Backlog estimate accurate ?"/>
|
||||
|
|
|
@ -23,6 +23,7 @@ import project_scrum_backlog_create_task
|
|||
import project_scrum_backlog_sprint
|
||||
import project_scrum_backlog_merger
|
||||
import project_scrum_postpone
|
||||
import project_scrum_email
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# -*- 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 tools.translate import _
|
||||
from datetime import datetime
|
||||
import tools
|
||||
|
||||
class project_scrum_email(osv.osv_memory):
|
||||
_name = 'project.scrum.email'
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param fields: List of fields for default value
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
meeting_pool = self.pool.get('project.scrum.meeting')
|
||||
record_ids = context and context.get('active_ids', []) or []
|
||||
res = super(project_scrum_email, self).default_get(cr, uid, fields, context=context)
|
||||
for meeting in meeting_pool.browse(cr, uid, record_ids, context=context):
|
||||
sprint = meeting.sprint_id
|
||||
if 'scrum_master_email' in fields:
|
||||
res.update({'scrum_master_email': sprint.scrum_master_id and sprint.scrum_master_id.user_email or False})
|
||||
if 'product_owner_email' in fields:
|
||||
res.update({'product_owner_email': sprint.product_owner_id and sprint.product_owner_id.user_email or False})
|
||||
if 'subject' in fields:
|
||||
subject = _("Scrum Meeting : %s") %(meeting.date)
|
||||
res.update({'subject': subject})
|
||||
if 'message' in fields:
|
||||
message = _("Hello , \nI am sending you Scrum Meeting : %s for the Sprint '%s' of Project '%s'") %(meeting.date, sprint.name, sprint.project_id.name)
|
||||
res.update({'message': message})
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'scrum_master_email': fields.char('Scrum Master Email', size=64, help="Email Id of Scrum Master"),
|
||||
'product_owner_email': fields.char('Product Owner Email', size=64, help="Email Id of Product Owner"),
|
||||
'subject':fields.char('Subject', size=64),
|
||||
'message':fields.text('Message'),
|
||||
|
||||
}
|
||||
|
||||
def button_send_scrum_email(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context={}
|
||||
|
||||
active_id = context.get('active_id', False)
|
||||
scrum_meeting_pool = self.pool.get('project.scrum.meeting')
|
||||
user_pool = self.pool.get('res.users')
|
||||
meeting = scrum_meeting_pool.browse(cr, uid, active_id, context=context)
|
||||
|
||||
# wizard data
|
||||
data_id = ids and ids[0] or False
|
||||
if not data_id or not active_id:
|
||||
return False
|
||||
data = self.browse(cr, uid, data_id, context=context)
|
||||
|
||||
email_from = tools.config.get('email_from', False)
|
||||
user = user_pool.browse(cr, uid, uid, context=context)
|
||||
user_email = email_from or user.address_id.email
|
||||
|
||||
body = "%s\n" %(data.message)
|
||||
body += "\n%s\n" %_('Tasks since yesterday')
|
||||
body += "_______________________\n"
|
||||
body += "\n%s\n" %(meeting.question_yesterday or _('None'))
|
||||
body += "\n%s\n" %_("Task for Today")
|
||||
body += "_______________________ \n"
|
||||
body += "\n%s\n" %(meeting.question_today or _('None'))
|
||||
body += "\n%s\n" % _('Blocking points encountered:')
|
||||
body += "_______________________ \n"
|
||||
body += "\n%s\n" %(meeting.question_blocks or _('None'))
|
||||
body += "\n%s\n%s" %(_('Thank you,'), user.name)
|
||||
if user.signature:
|
||||
body += "\n%s" %(user.signature)
|
||||
if data.scrum_master_email == data.product_owner_email:
|
||||
data.product_owner_email = False
|
||||
if data.scrum_master_email:
|
||||
tools.email_send(user_email, [data.scrum_master_email], data.subject, body, reply_to=user_email)
|
||||
if data.product_owner_email:
|
||||
tools.email_send(user_email, [data.product_owner_email], data.subject, body, reply_to=user_email)
|
||||
return {}
|
||||
project_scrum_email()
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_project_scrum_email" model="ir.ui.view">
|
||||
<field name="name">Scrum Meeting</field>
|
||||
<field name="model">project.scrum.email</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Scrum Meeting">
|
||||
<separator colspan="4" string="Send Email for Scrum Meeting Details"/>
|
||||
<field name="scrum_master_email" width="64"/>
|
||||
<field name="product_owner_email" width="64"/>
|
||||
<field name="subject" colspan="4"/>
|
||||
<separator string="Message" colspan="4"/>
|
||||
<field name="message" nolabel="1" colspan="4"/>
|
||||
|
||||
<separator string="" colspan="4"/>
|
||||
<group colspan="2" col="2">
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
|
||||
<button icon="gtk-go-forward" name="button_send_scrum_email" string="_Send" type="object" default_focus="1" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_scrum_email" model="ir.actions.act_window">
|
||||
<field name="name">Scrum Meeting</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">project.scrum.email</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
Loading…
Reference in New Issue