[MERGE] merge with dev addons3 branch

bzr revid: psi@tinyerp.co.in-20100610094230-fs2zdfmy7m7ffsej
This commit is contained in:
psi (Open ERP) 2010-06-10 15:12:30 +05:30
commit 5bf5f81b7a
29 changed files with 1088 additions and 287 deletions

View File

@ -562,39 +562,35 @@ class account_journal(osv.osv):
_name = "account.journal"
_description = "Journal"
_columns = {
'name': fields.char('Journal Name', size=64, required=True, translate=True),
'code': fields.char('Code', size=16),
'type': fields.selection([('sale', 'Sale'), ('purchase', 'Purchase'), ('expense', 'Expense'), ('cash', 'Cash'), ('bank', 'Bank'), ('general', 'General'), ('situation', 'Situation')], 'Type', size=32, required=True,
'name': fields.char('Journal Name', size=64, required=True, translate=True,help="Name of the journal"),
'code': fields.char('Code', size=16,required=True,help="Code of the journal"),
'type': fields.selection([('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'),('expense', 'Expense'), ('cash', 'Cash'), ('bank', 'Bank'), ('general', 'General'), ('situation', 'Situation')], 'Type', size=32, required=True,
help="Select 'Sale' for Sale journal to be used at the time of making invoice."\
" Select 'Purchase' for Purchase Journal to be used at the time of approving purchase order."\
" Select 'Cash' to be used at the time of making payment."\
" Select 'General' to be used at the time of stock input/output."\
" Select 'Situation' to be used at the time of making vouchers."),
'refund_journal': fields.boolean('Refund Journal', help='Fill this if the journal is to be used for refunds of invoices.'),
'type_control_ids': fields.many2many('account.account.type', 'account_journal_type_rel', 'journal_id','type_id', 'Type Controls', domain=[('code','<>','view'), ('code', '<>', 'closed')]),
'account_control_ids': fields.many2many('account.account', 'account_account_type_rel', 'journal_id','account_id', 'Account', domain=[('type','<>','view'), ('type', '<>', 'closed')]),
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the journal without removing it."),
'view_id': fields.many2one('account.journal.view', 'View', required=True, help="Gives the view used when writing or browsing entries in this journal. The view tells Open ERP which fields should be visible, required or readonly and in which order. You can create your own view for a faster encoding in each journal."),
'default_credit_account_id': fields.many2one('account.account', 'Default Credit Account', domain="[('type','!=','view')]"),
'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account', domain="[('type','!=','view')]"),
'view_id': fields.many2one('account.journal.view', 'Display Mode', required=True, help="Gives the view used when writing or browsing entries in this journal. The view tells Open ERP which fields should be visible, required or readonly and in which order. You can create your own view for a faster encoding in each journal."),
'default_credit_account_id': fields.many2one('account.account', 'Default Credit Account', domain="[('type','!=','view')]",help="This will act as a default account for credit amount"),
'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account', domain="[('type','!=','view')]",help="This will act as a default account for debit amount"),
'centralisation': fields.boolean('Centralised counterpart', help="Check this box to determine that each entry of this journal won't create a new counterpart but will share the same counterpart. This is used in fiscal year closing."),
'update_posted': fields.boolean('Allow Cancelling Entries'),
'update_posted': fields.boolean('Allow Cancelling Entries',help="Check this box if you want to cancel the entries related to this journal or want to cancel the invoice related to this journal"),
'group_invoice_lines': fields.boolean('Group invoice lines', help="If this box is checked, the system will try to group the accounting lines when generating them from invoices."),
'sequence_id': fields.many2one('ir.sequence', 'Entry Sequence', help="The sequence gives the display order for a list of journals", required=True),
'user_id': fields.many2one('res.users', 'User', help="The user responsible for this journal"),
'groups_id': fields.many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', 'Groups'),
'currency': fields.many2one('res.currency', 'Currency', help='The currency used to enter statement'),
'entry_posted': fields.boolean('Skip \'Draft\' State for Created Entries', help='Check this box if you don\'t want new account moves to pass through the \'draft\' state and instead goes directly to the \'posted state\' without any manual validation.'),
'company_id': fields.many2one('res.company', 'Company', required=True,select=1),
'company_id': fields.many2one('res.company', 'Company', required=True,select=1,help="Company related to a journal"),
'invoice_sequence_id': fields.many2one('ir.sequence', 'Invoice Sequence', \
help="The sequence used for invoice numbers in this journal."),
'allow_date':fields.boolean('Check Date not in the Period', help= 'If set to True then do not accept the entry if the entry date is not into the period dates'),
}
_defaults = {
'active': lambda *a: 1,
'user_id': lambda self,cr,uid,context: uid,
'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
}
@ -604,7 +600,7 @@ class account_journal(osv.osv):
move_lines = self.pool.get('account.move.line').search(cr, uid, [('journal_id', 'in', ids)])
if move_lines:
raise osv.except_osv(_('Warning !'), _('You cannot modify company of this journal as its related record exist in Entry Lines'))
return super(account_period, self).write(cr, uid, ids, vals, context=context)
return super(account_journal, self).write(cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context={}):
journal_id = super(account_journal, self).create(cr, uid, vals, context)
@ -631,6 +627,16 @@ class account_journal(osv.osv):
ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit, context=context)
return self.name_get(cr, user, ids, context=context)
def onchange_type(self, cr, uid, ids, type):
res={}
for line in self.browse(cr, uid, ids):
if type == 'situation':
res= {'value':{'centralisation': True}}
else:
res= {'value':{'centralisation': False}}
return res
account_journal()
class account_fiscalyear(osv.osv):

View File

@ -272,22 +272,19 @@
<group colspan="4" col="6">
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="active" select="1"/>
<field name="type"/>
<field name="type" on_change="onchange_type(type)"/>
<field name="refund_journal" attrs="{'readonly':[('type','=','general'),('type','=','cash'),('type','=','situation')]}"/>
</group>
<notebook colspan="4">
<notebook colspan="4">
<page string="General Information">
<group colspan="2" col="2">
<separator string="Journal View" colspan="4"/>
<field name="view_id"/>
<field name="view_id" widget="selection"/>
</group>
<group colspan="2" col="2">
<separator string="Sequence" colspan="4"/>
<field name="sequence_id"/>
<field name="invoice_sequence_id"/>
</group>
<group colspan="2" col="2">
@ -296,7 +293,7 @@
<field name="default_credit_account_id" attrs="{'required':[('type','=','cash')]}" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]"/>
</group>
<group colspan="2" col="2">
<group colspan="2" col="2">
<separator string="Validations" colspan="4"/>
<field name="allow_date" groups="base.group_extended"/>
</group>
@ -307,15 +304,19 @@
<field name="user_id" groups="base.group_extended"/>
<field name="currency"/>
</group>
<group colspan="2" col="2">
<separator string="Other Configuration" colspan="4"/>
<field name="centralisation"/>
<field name="group_invoice_lines"/>
<field name="update_posted"/>
<field name="centralisation" groups="base.group_extended"/>
<field name="entry_posted"/>
<group colspan="2" col="2">
<separator string="Invoicing Data" colspan="4"/>
<field name="invoice_sequence_id"/>
<field name="group_invoice_lines"/>
</group>
</group>
</page>
<page string="Entry Controls">
<page string="Entry Controls" groups="base.group_extended">
<separator colspan="4" string="Accounts Type Allowed (empty for no control)"/>
<field colspan="4" name="type_control_ids" nolabel="1"/>
<separator colspan="4" string="Accounts Allowed (empty for no control)"/>
@ -957,7 +958,6 @@
<field name="state" select="1"/>
<group col="2" colspan="2">
<button name="button_validate" states="draft" string="Validate" type="object" icon="gtk-execute"/>
<button name="button_cancel" states="posted" string="Cancel" type="object" icon="gtk-cancel"/>
</group>
</page>
<page string="Other Information">

View File

@ -923,13 +923,13 @@ class account_invoice(osv.osv):
account_move_obj = self.pool.get('account.move')
invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids'])
for i in invoices:
if i['move_id']:
if i['move_id']:
account_move_obj.button_cancel(cr, uid, [i['move_id'][0]])
# delete the move this invoice was pointing to
# Note that the corresponding move_lines and move_reconciles
# will be automatically deleted too
account_move_obj.unlink(cr, uid, [i['move_id'][0]])
if i['payment_ids']:
if i['payment_ids']:
account_move_line_obj = self.pool.get('account.move.line')
pay_ids = account_move_line_obj.browse(cr, uid , i['payment_ids'])
for move_line in pay_ids:

View File

@ -0,0 +1,23 @@
# -*- 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/>.
#
##############################################################################
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,40 @@
# -*- 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" : "Account Cancel",
"version" : "1.1",
"depends" : ["account"],
"author" : "Tiny",
"category": 'Generic Modules/Accounting',
"description": """
Module Add Allow cancelling entries field on form view of account journal if it set to true it allows user to cancel entries & invoices.
""",
'website': 'http://www.openerp.com',
'init_xml': [],
'update_xml': ['account_cancel_view.xml' ],
'demo_xml': [],
'installable': True,
'active': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="view_account_journal_form_inherit" model="ir.ui.view">
<field name="name">account.journal.form</field>
<field name="model">account.journal</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="arch" type="xml">
<xpath expr="/form/notebook/page[@string='General Information']/group/field[@name='centralisation']" position="after">
<field name="update_posted"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -35,6 +35,7 @@ This module implement the modification on the invoice form.
'init_xml': [],
'update_xml': ['account_tax_include_view.xml'],
'demo_xml': [],
'test': ['test/account_tax_include.yml'],
'installable': True,
'active': False,
'certificate': '0070514190381',

View File

@ -0,0 +1,93 @@
-
Creating a tax record
-
!record {model: account.tax, id: account_tax_a0}:
amount: 0.10000000000000001
applicable_type: 'true'
company_id: base.main_company
description: a
name: a
sequence: 1
type: percent
type_tax_use: all
-
Creating a account invoice record with tax excluded
-
!record {model: account.invoice, id: account_invoice_tax_exclude}:
account_id: account.a_recv
address_contact_id: base.res_partner_address_3000
address_invoice_id: base.res_partner_address_3000
company_id: base.main_company
currency_id: base.EUR
invoice_line:
- account_id: account.a_sale
name: '[PC1] Basic PC'
price_unit: 100.0
quantity: 1.0
invoice_line_tax_id:
- account_tax_a0
product_id: product.product_product_pc1
uos_id: product.product_uom_unit
journal_id: account.sales_journal
partner_id: base.res_partner_desertic_hispafuentes
price_type: tax_excluded
reference_type: none
-
Performing an osv_memory action button_reset_taxes on module account.invoice
-
!python {model: account.invoice}: |
self.button_reset_taxes(cr, uid, [ref("account_invoice_tax_exclude")], {"lang": "en_US", "tz": False,
"active_model": "ir.ui.menu", "active_ids": [ref("account.menu_action_invoice_tree1")],
"type": "out_invoice", "active_id": ref("account.menu_action_invoice_tree1"),
})
-
Check if tax is excluded in invoice
-
!assert {model: account.invoice, id: account_invoice_tax_exclude, severity: error, string: price type is tax excluded}:
- state == "draft"
- amount_untaxed == 100.0
- amount_tax == 10.0
- amount_total == 110.0
-
Creating a account invoice record with tax include
-
!record {model: account.invoice, id: account_invoice_tax_include}:
account_id: account.a_recv
address_contact_id: base.res_partner_address_3000
address_invoice_id: base.res_partner_address_3000
company_id: base.main_company
currency_id: base.EUR
invoice_line:
- account_id: account.a_sale
name: '[PC1] Basic PC'
price_unit: 100.0
quantity: 1.0
invoice_line_tax_id:
- account_tax_a0
product_id: product.product_product_pc1
uos_id: product.product_uom_unit
journal_id: account.sales_journal
partner_id: base.res_partner_desertic_hispafuentes
price_type: tax_included
reference_type: none
-
Performing an osv_memory action button_reset_taxes on module account.invoice
-
!python {model: account.invoice}: |
self.button_reset_taxes(cr, uid, [ref("account_invoice_tax_include")], {"lang": "en_US", "tz": False,
"active_model": "ir.ui.menu", "active_ids": [ref("account.menu_action_invoice_tree1")],
"type": "out_invoice", "active_id": ref("account.menu_action_invoice_tree1"),
})
-
Check if tax is included in invoice
-
!assert {model: account.invoice, id: account_invoice_tax_include, severity: error, string: price type is tax included}:
- state == "draft"
- amount_untaxed == 90.91
- amount_tax == 9.09
- amount_total == 100.00

View File

@ -1,15 +1,15 @@
- |
In order to test the hr module in OpenERP, I will create new Employee , Department and Job Position.
In order to test hr module in OpenERP, I will create new Employee , Department and Job Position.
-
|
First I create Department "R & D" in Department form.
I create "R & D" Department in Department form.
-
!record {model: hr.department, id: hr_department_rd0}:
manager_id: base.user_root
name: 'R & D '
-
|
Now, I create a new employee “employee1”.
Now, I create a new employee “Mark Johnson”.
select "R & D" Department which I had created.
-
!record {model: hr.employee, id: hr_employee_employee0}:
@ -22,7 +22,7 @@
department_id: 'hr_department_rd0'
- |
In order to check the wizard “Employee Hierarchy” I will create new employee “employee2” and select "employee1" as
In order to check the wizard “Employee Hierarchy” , I will create new employee “Phil Graves ” and select "Mark Johnson" as
Manager.
-
!record {model: hr.employee, id: hr_employee_employee1}:
@ -33,11 +33,11 @@
user_id: base.user_demo
parent_id: 'hr_employee_employee0'
- |
Now I will open up form view of “employee1” and test the wizard “Employee Hierarchy” so it display the employee
hierarchy starting from “employee1”.
I will open up form view of “Mark Johnson” and test the wizard “Employee Hierarchy” so it display the employee
hierarchy starting from “Mark Johnson”.
- |
Now I will create new Job Position. I will check successfull creation of new Job Position by adding the information.
I will create new Job Position. I will check successfull creation of new Job Position by adding the information.
-
!record {model: hr.job, id: hr_job_jea0}:
department_id: 'hr_department_rd0'
@ -51,17 +51,17 @@
- state == 'open'
- |
I create Employee for this position in this Job Position form.
I create Employee for job position.
-
!record {model: hr.job, id: hr_job_jea0}:
employee_ids:
- address_home_id: base.res_partner_address_1
name: employee3
name: Manuel Lehba
department_id: 'hr_department_rd0'
gender: male
parent_id: 'hr_employee_employee0'
-
I check that "NO of Employee" is "1"
- |
I check that "Number of Employees" field have some value.
-
!assert {model: hr.job, id: hr_job_jea0}:
- no_of_employee != False

View File

@ -44,6 +44,7 @@
'wizard/hr_attendance_sign_in_out_view.xml',
],
'demo_xml': ['hr_attendance_demo.xml'],
'test': ['test/test_hr_attendance.yml'],
'installable': True,
'active': False,
'certificate': '0063495605613',

View File

@ -0,0 +1,109 @@
- |
In order to test hr_attendance module in OpenERP, I create new attendance and perform Sign In/Sign Out operation.
- |
First I create Employee "Mark Johnson".
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
company_id: base.main_company
gender: male
name: Mark Johnson
user_id: base.user_root
- |
Given that I have Attendance Reason "Good Morning" for Sign In.
-
!record {model: hr.action.reason, id: hr_action_reason_goodmorning0}:
name: Good Morning
action_type: sign_in
- |
I also create another Attendance Reason for Sign Out.
-
!record {model: hr.action.reason, id: hr_action_reason_goodnight0}:
name: Good Night
action_type: sign_out
- |
Now , When I came in office , I create Atendances and perform "Sign In" action with proper reason.
-
!record {model: hr.attendance, id: hr_attendance_0}:
action: sign_in
action_desc: 'hr_action_reason_goodmorning0'
employee_id: 'hr_employee_employee0'
name: '2010-05-18 19:08:08'
- |
I check that Employee is in "Present" state.
-
!assert {model: hr.employee, id: hr_employee_employee0}:
- state == 'present'
- |
When I left office , I create attendance and perform "Sign Out".
-
!record {model: hr.attendance, id: hr_attendance_1}:
action: sign_out
employee_id: 'hr_employee_employee0'
name: '2010-05-18 19:10:55'
- |
I check that Employee is in "Absent" state.
-
!assert {model: hr.employee, id: hr_employee_employee0}:
- state == 'absent'
- |
I can also fill my attendance using "Sign In/Sign Out" wizard.
-
!record {model: hr.sign.in.out, id: hr_sign_in_out_markjohnson0}:
name: Mark Johnson
state: absent
- |
I click on "Sign In" button of this wizard to perform present action.
-
!python {model: hr.sign.in.out}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
if emp_id:
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_sign_in_out_markjohnson0')], {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]})
self.si_check(cr, uid, [ref("hr_sign_in_out_markjohnson0")], {"active_id": ref("hr_employee_employee0")})
- |
I check that Employee is in "Present" state.
-
!assert {model: hr.employee, id: hr_employee_employee0}:
- state == 'present'
- |
I forgot to "Sign Out" in Yesterday and want to sign in Today using This wizard.
-
!record {model: hr.sign.in.out, id: hr_sign_in_out_markjohnson0}:
name: Mark Johnson
state: present
- |
I click on "Sign In" button of this wizard. that will Open new form which ask for Last Sign Out date.
-
!python {model: hr.sign.in.out}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
if emp_id:
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_sign_in_out_markjohnson0')], {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]})
self.si_check(cr, uid, [ref("hr_sign_in_out_markjohnson0")])
- |
I select Last Sign Out date in "hr sign out ask" wizard.
-
!record {model: hr.sign.in.out.ask, id: hr_sign_in_out_ask_markjohnson0}:
last_time: !eval time.strftime('%Y-%m-%d %H:%M:%S')
name: Mark Johnson
- |
Now I click on "Sign In" button of this wizard.
-
!python {model: hr.sign.in.out.ask}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "Mark Johnson")])
if emp_id:
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_sign_in_out_ask_markjohnson0')], {'emp_id': emp_id[0]})
#self.sign_in(cr, uid, [ref("hr_sign_in_out_ask_markjohnson0")], {"active_ids": [ref("hr_attendance.menu_hr_attendance_sigh_in_out")]})

View File

@ -33,16 +33,16 @@ class hr_si_so_ask(osv.osv_memory):
'emp_id': fields.char('Empoyee ID', size=32, required=True, readonly=True),
}
def _get_empname(self, cr, uid, context=None):
service = netsvc.LocalService('object_proxy')
emp_id = service.execute(cr.dbname, uid, 'hr.employee', 'search', [('user_id', '=', uid)])
emp_obj = self.pool.get('hr.employee')
emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid)])
if emp_id:
employee = service.execute(cr.dbname, uid, 'hr.employee', 'read', emp_id)[0]
employee = emp_obj.read(cr, uid, emp_id)[0]
return employee['name']
return ''
def _get_empid(self, cr, uid, context=None):
service = netsvc.LocalService('object_proxy')
emp_id = service.execute(cr.dbname, uid, 'hr.employee', 'search', [('user_id', '=', uid)])
emp_obj = self.pool.get('hr.employee')
emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid)])
if emp_id:
return emp_id[0]
return False
@ -74,10 +74,10 @@ class hr_sign_in_out(osv.osv_memory):
}
def _get_empid(self, cr, uid, context=None):
service = netsvc.LocalService('object_proxy')
emp_id = service.execute(cr.dbname, uid, 'hr.employee', 'search', [('user_id', '=', uid)])
emp_obj = self.pool.get('hr.employee')
emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid)])
if emp_id:
employee = service.execute(cr.dbname, uid, 'hr.employee', 'read', emp_id)[0]
employee = emp_obj.read(cr, uid, emp_id)[0]
return {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]}
return {}
@ -88,12 +88,13 @@ class hr_sign_in_out(osv.osv_memory):
return res
def si_check(self, cr, uid, ids, context=None):
service = netsvc.LocalService('object_proxy')
att_obj = self.pool.get('hr.attendance')
obj_model = self.pool.get('ir.model.data')
data = self.read(cr, uid, ids, [])[0]
emp_id = data['emp_id']
att_id = service.execute(cr.dbname, uid, 'hr.attendance', 'search', [('employee_id', '=', emp_id)], limit=1, order='name desc')
last_att = service.execute(cr.dbname, uid, 'hr.attendance', 'read', att_id)
att_id = att_obj.search(cr, uid, [('employee_id', '=', emp_id)], limit=1, order='name desc')
last_att = att_obj.read(cr, uid, att_id)
if last_att:
last_att = last_att[0]
cond = not last_att or last_att['action'] == 'sign_out'
@ -113,12 +114,13 @@ class hr_sign_in_out(osv.osv_memory):
}
def so_check(self, cr, uid, ids, context=None):
service = netsvc.LocalService('object_proxy')
att_obj = self.pool.get('hr.attendance')
obj_model = self.pool.get('ir.model.data')
data = self.read(cr, uid, ids, [])[0]
emp_id = data['emp_id']
att_id = service.execute(cr.dbname, uid, 'hr.attendance', 'search', [('employee_id', '=', emp_id),('action','!=','action')], limit=1, order='name desc')
last_att = service.execute(cr.dbname, uid, 'hr.attendance', 'read', att_id)
att_id = att_obj.search(cr, uid, [('employee_id', '=', emp_id),('action','!=','action')], limit=1, order='name desc')
last_att = att_obj.read(cr, uid, att_id)
if last_att:
last_att = last_att[0]
if not att_id and not last_att:
@ -151,31 +153,31 @@ class hr_sign_in_out(osv.osv_memory):
}
def sign_in(self, cr, uid, data, context=None):
service = netsvc.LocalService('object_proxy')
att_obj = self.pool.get('hr.attendance')
emp_id = data['emp_id']
if 'last_time' in data:
if data['last_time'] > time.strftime('%Y-%m-%d %H:%M:%S'):
raise osv.except_osv(_('UserError'), _('The sign-out date must be in the past'))
service.execute(cr.dbname, uid, 'hr.attendance', 'create', {
att_obj.create(cr, uid, {
'name': data['last_time'],
'action': 'sign_out',
'employee_id': emp_id
})
try:
success = service.execute(cr.dbname, uid, 'hr.employee', 'attendance_action_change', [emp_id], 'sign_in')
success = self.pool.get('hr.employee').attendance_action_change(cr, uid, [emp_id], 'sign_in')
except:
raise osv.except_osv(_('UserError'), _('A sign-in must be right after a sign-out !'))
return {} # To do: Return Success message
def sign_out(self, cr, uid, data, context=None):
service = netsvc.LocalService('object_proxy')
att_obj = self.pool.get('hr_attendance')
emp_id = data['emp_id']
if 'last_time' in data:
if data['last_time'] > time.strftime('%Y-%m-%d %H:%M:%S'):
raise osv.except_osv(_('UserError'), _('The Sign-in date must be in the past'))
service.execute(cr.dbname, uid, 'hr.attendance', 'create', {'name':data['last_time'], 'action':'sign_in', 'employee_id':emp_id})
att_obj.create(cr, uid, {'name':data['last_time'], 'action':'sign_in', 'employee_id':emp_id})
try:
success = service.execute(cr.dbname, uid, 'hr.employee', 'attendance_action_change', [emp_id], 'sign_out')
success = self.pool.get('hr.employee').attendance_action_change(cr, uid, [emp_id], 'sign_out')
except:
raise osv.except_osv(_('UserError'), _('A sign-out must be right after a sign-in !'))
return {} # To do: Return Success message

View File

@ -3,7 +3,7 @@
I will create contract for "Mark Johnson" employee.
- |
First I create Employee "Mark Johnson"
I create Employee "Mark Johnson" to assign contract.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
@ -30,9 +30,9 @@
type: gross
- |
Now I start by create contract for "Mark Johnson".
Now I start by creating contract for "Mark Johnson".
Select wage type "Monthly Gross Wage" and Wage period "monthly"
which I have given.
which I had given.
-
!record {model: hr.contract, id: hr_contract_contract0}:
advantages_gross: 0.0

View File

@ -35,13 +35,14 @@
is done by the manager.Every evaluation filled by the employees can be viewed
in the form of.Implements a dashboard for My Current Evaluations """,
"init_xml" : [],
"demo_xml" : ["hr_evaluation_demo.xml"],
"demo_xml" : ["hr_evaluation_demo.xml",
],
"update_xml" : [
"security/ir.model.access.csv",
"wizard/hr_evaluation_mail_view.xml",
"hr_evaluation_view.xml",
"report/hr_evaluation_report_view.xml",
'board_hr_evaluation_view.xml',],
"report/hr_evaluation_report_view.xml"],
"test": ["test/test_hr_evaluation.yml"],
"active": False,
"installable": True
}

View File

@ -0,0 +1,152 @@
- |
In order to test hr_evaluation module for OpenERP, I will create plan then create evaluation under that plan.
-
|
Given that I have "R & D" Department for employee.
-
!record {model: hr.department, id: hr_department_rd0}:
manager_id: base.user_root
name: 'R & D '
-
|
Given that I have Employee “Mark Johnson” which take Interview.
select "R & D" Department.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
company_id: base.main_company
gender: male
marital: hr.hr_employee_marital_status_single
name: Mark Johnson
user_id: base.user_root
department_id: 'hr_department_rd0'
- |
I create new employee “Phil Graves ” and select "Mark Johnson" as
Manager.
-
!record {model: hr.employee, id: hr_employee_employee1}:
address_home_id: base.res_partner_address_3000
company_id: base.main_company
gender: male
name: Phil Graves
user_id: base.user_demo
parent_id: 'hr_employee_employee0'
- |
I Create "Employee Evaluation" survey for Manager's Evaluation Plan.
-
!record {model: 'survey', id: survey_0}:
title: 'Employee Evaluation'
max_response_limit: 20
response_user: 2
- |
I Create "Employee Evaluation" page in "Employee Evaluation" survey.
-
!record {model: 'survey.page', id: survey_employee_page_0}:
title: 'Employee Evaluation'
survey_id: survey_0
- |
I Create "What is your Name" question in "Employee Evaluation" survey page.
-
!record {model: 'survey.question', id: survey_p_question_0}:
question: 'What is your Name?'
type: 'single_textbox'
sequence: 1
page_id: survey_employee_page_0
- |
I Create "What is your gender" Question in "Employee Evaluation" survey page.
-
!record {model: 'survey.question', id: survey_p_question_1}:
question: 'What is your gender?'
type: multiple_choice_only_one_ans
sequence: 2
is_require_answer: true
page_id: survey_employee_page_0
- |
I Create "Male" answer in question "What is your gender?"
-
!record {model: 'survey.answer', id: survey_p_1_1}:
answer: 'Male'
sequence: 1
question_id : survey_p_question_1
- |
I Create "Female" answer in question "What is your gender?"
-
!record {model: 'survey.answer', id: survey_p_1_2}:
answer: 'Female'
sequence: 2
question_id : survey_p_question_1
- |
Now Survey set in open state.
-
!python {model: survey}: |
self.survey_open(cr, uid, [ref("survey_0")], context)
- |
I creating a Evaluation plan and select "Employee Evaluation" survey for "Send to Subordinates" and "Final interview with Manager" Phase.
-
!record {model: hr_evaluation.plan, id: hr_evaluation_plan_managersplan0}:
company_id: base.main_company
month_first: 3
month_next: 6
name: Manager's Plan
phase_ids:
- action: bottom-up
name: Send to Subordinates
survey_id: 'survey_0'
- action: top-down
name: Final Interview with manager
sequence: 2
survey_id: 'survey_0'
- |
Now I create Evaluation for "Phil Graves" Employee under "Manager Evaluation Plan".
-
!record {model: hr_evaluation.evaluation, id: hr_evaluation_evaluation_0}:
date: '2010-06-28'
employee_id: 'hr_employee_employee1'
plan_id: 'hr_evaluation_plan_managersplan0'
progress: 0.0
state: draft
- |
I check that Evaluation is in "Draft" state.
-
!assert {model: hr_evaluation.evaluation, id: hr_evaluation_evaluation_0}:
- state == 'draft'
- |
I start Evaluation process by click on "Start Evaluation" button.
-
!python {model: hr_evaluation.evaluation}: |
self.button_plan_in_progress(cr, uid, [ref('hr_evaluation_evaluation_0')])
- |
After that Manager Evaluation plan is In Progress.
I close this servey request by giving answer of survey question.
-
!python {model: hr.evaluation.interview}: |
self.survey_req_done(cr, uid, [ref('hr_evaluation_evaluation_0')])
- |
I click on "Final Validation" button to finalize Evaluation.
-
!python {model: hr_evaluation.evaluation}: |
self.button_final_validation(cr, uid, [ref("hr_evaluation.hr_evaluation_evaluation_0")],
{"active_ids": [ref("hr_evaluation.menu_open_view_hr_evaluation_tree")]})
- |
I check that state is "Final Validation".
-
!assert {model: hr_evaluation.evaluation, id: hr_evaluation_evaluation_0}:
- state == 'progress'
- |
Give Rating "Meet expectations" by selecting overall Rating.
-
!record {model: hr_evaluation.evaluation, id: hr_evaluation.hr_evaluation_evaluation_0}:
rating: '2'
- |
I close this Evaluation by click on "Done" button of this wizard.
-
!python {model: hr_evaluation.evaluation}: |
self.button_done(cr, uid, [ref("hr_evaluation.hr_evaluation_evaluation_0")], {"active_ids": [ref("hr_evaluation.menu_open_view_hr_evaluation_tree")]})

View File

@ -1,6 +1,5 @@
- |
In order to test the hr_holiday in OpenERP, I will Manage leaves for employee,
Leave requests.
In order to test the hr_holiday in OpenERP, I will Allocate leaves for Employee and manage leaves and leaves requests.
- |
For that First I create new user "user1" to make leave request.
-
@ -15,7 +14,7 @@
name: user1
password: user1
- |
Now, I create a new employee “Mark Johnshon” as Manager to validate employee leave.
I create a new employee “Mark Johnshon” as Manager to validate employee leave.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
@ -24,11 +23,11 @@
name: Mark Johnson
user_id: base.user_root
- |
create another employee "Brijesh Patel" as "user1" who make leave request.
Create another employee "Phil Graves" as "user1" who make leave request.
-
!record {model: hr.employee, id: hr_employee_brijeshpatel0}:
!record {model: hr.employee, id: hr_employee_philgraves0}:
address_home_id: base.res_partner_address_8
name: Brijesh Patel
name: Phil Graves
parent_id: 'hr_employee_employee0'
user_id: 'res_users_user0'
- |
@ -40,11 +39,11 @@
limit: 1
- |
After that I allocate leave request for employee "Brijesh Patel".
After that I allocate leave request for employee "Phil Graves".
-
!record {model: hr.holidays, id: hr_holidays_allocateleaveforuser0}:
allocation_type: employee
employee_id: 'hr_employee_brijeshpatel0'
employee_id: 'hr_employee_philgraves0'
holiday_status_id: hr_holidays_status_fullleave0
name: Allocate leave for user1
number_of_days_temp: 12.0
@ -62,13 +61,13 @@
!workflow {model: hr.holidays, action: validate, ref: hr_holidays_allocateleaveforuser0}
- |
Now employee "Brijesh Patel" want to leave. so, I connect as user1 which is username of this employee and want to make leave request.
Now employee "Phil Graves" want to leave. so, I connect as user1 which is username of this employee and want to make leave request.
-
!record {model: hr.holidays, id: hr_holidays_iwanttoleaveforgotohospital0}:
allocation_type: employee
date_from: '2010-05-20 11:48:00'
date_to: '2010-05-21 11:48:00'
employee_id: 'hr_employee_brijeshpatel0'
employee_id: 'hr_employee_philgraves0'
holiday_status_id: 'hr_holidays_status_fullleave0'
name: I want to leave for go to hospital
notes: I want to leave for go to hospital. so please accept my leave.
@ -82,12 +81,12 @@
- state == 'draft'
- |
Now I confirm my leave Request by click on "Confirm" button.
I confirm my leave Request by click on "Confirm" button.
-
!workflow {model: hr.holidays, action: confirm, ref: hr_holidays_iwanttoleaveforgotohospital0}
- |
Now I connect as Admin user and Open Leave request of "Brijesh Patel".
I connect as Admin user and Open Leave request of "Phil Graves".
and "validate" it by click on "validate" button.
-
!workflow {model: hr.holidays, action: validate, ref: hr_holidays_iwanttoleaveforgotohospital0}

View File

@ -1,10 +1,10 @@
- |
In order to test hr_recruitment module for OpenERP object, I create applicants form and Manages job positions and the recruitement process.
In order to test hr_recruitment module for OpenERP, I will create applicants form, Manages job positions and the recruitement process.
- |
I create job possition for employee to manage job position.
I create job position for employee to manage job position.
-
|
First I create Department "R & D" in Department form for which I make recruitment.
For that First I create Department "R & D" in Department form for which I make recruitment.
-
!record {model: hr.department, id: hr_department_rd0}:
manager_id: base.user_root

View File

@ -51,6 +51,7 @@ to set up a management by affair.
],
'demo_xml': ['hr_timesheet_demo.xml'],
'test': ['test/test_hr_timesheet.yml'],
'installable': True,
'active': False,
'certificate': '0071405533469',

View File

@ -0,0 +1,96 @@
- |
In order to test hr_timesheet Module in OpenERP, I make "Sign In or Sign Out for Project" to encode and
track time spent on the different projects.
- |
Now, I create a new employee “Mark Johnson” to test Timesheet.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
company_id: base.main_company
gender: male
marital: hr.hr_employee_marital_status_single
name: Mark Johnson
user_id: base.user_root
- |
I start by "Sign In/Sign Out by Project" wizard and click on "Sign In/Sign Out" button of this wizard.
-
!python {model: hr.sign.in.project}: |
self.check_state(cr, uid, [ref("hr_employee_employee0")])
- |
I select start date and Perform start work on project.
-
!record {model: hr.sign.in.project, id: hr_employee_employee0}:
name: employee1
server_date: '2010-05-20 16:10:59'
state: absent
- |
I click on "Start Working" button of this wizard to start work on Project.
-
!python {model: hr.sign.in.project}: |
self.sign_in_result(cr, uid, [ref("hr_employee_employee0")], context)
- |
My work is done and I want to stop work.for that I click on "Sign In/Sign Out" button of "Sign In/Sign Out by Project" wizard.
Which check state in hr attendace form for user.
-
!python {model: hr.sign.in.project}: |
obj_attendance = self.pool.get('hr.employee')
emp_id = obj_attendance.search(cr, uid, [('user_id', '=', uid), ('name', '=', "employee1")])
if emp_id:
employee = obj_attendance.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_employee_employee0')], {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]})
self.check_state(cr, uid, [ref("hr_employee_employee0")], {"active_ids": [ref("hr_timesheet.menu_hr_timesheet_sign_in")]
})
- |
Given that I have product for "Consultancy - Senior Developer".
-
!record {model: product.product, id: product_consultant}:
categ_id: product.product_category_10
default_code: DEV
list_price: 75.0
name: Consultancy - Senior Developer
procure_method: make_to_order
purchase_ok: False
standard_price: 30.0
supply_method: produce
type: service
uom_id: product.uom_hour
uom_po_id: product.uom_hour
- |
I assing product and journal to "Mark Johnson"
-
!record {model: hr.employee, id: hr_employee_employee0}:
journal_id: analytic_journal
product_id: product_consultant
- |
This will Open "hr sign out project" form. I select analytical project2 development account.
-
!record {model: hr.sign.out.project, id: hr_employee_employee0}:
account_id: account.analytic_project_2_development
analytic_amount: 7.0
date: '2010-05-21 16:40:00'
date_start: '2010-05-19 16:37:00'
info: Create Yaml for hr module
name: Mark Johnson
server_date: '2010-05-19 16:40:15'
state: present
- |
My work for this project is over and I stop work by click on "Stop Work" button of this wizard.
-
!python {model: hr.sign.out.project}: |
emp_obj = self.pool.get('hr.employee')
emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid), ('name', '=', 'employee1')])
if emp_id:
employee = emp_obj.read(cr, uid, emp_id)[0]
self.write(cr, uid, [ref('hr_employee_employee0')], {'emp_id': emp_id[0] })
#self.sign_out_result(cr, uid, [ref('hr_employee_employee0')])
- |
I can see employee timesheet for particular month using "Employee Timesheet" report.

View File

@ -45,7 +45,9 @@ reports, eso.""",
'wizard/hr_timesheet_invoice_create_final_view.xml',
'board_hr_timesheet_invoice.xml',
],
'demo_xml': ['hr_timesheet_invoice_demo.xml'],
'demo_xml': ['hr_timesheet_invoice_demo.xml',
],
'test': ['test/test_hr_timesheet_invoice.yml'],
'installable': True,
'active': False,
'certificate': '0056091842381',

View File

@ -0,0 +1,89 @@
- |
In order to test hr_timesheet_invoice in OpenERP, I create account line to manage invoice based on costs.
- |
In order to test flow, I create analytic line for sednacom analytic account.
-
!record {model: account.analytic.line, id: account_analytic_line_developyamlforhrmodule0}:
account_id: account.analytic_sednacom
amount: -1.0
company_id: base.main_company
date: '2010-05-30'
general_account_id: account.a_expense
journal_id: hr_timesheet.analytic_journal
name: develop yaml for hr module
product_id: hr_timesheet.product_consultant
product_uom_id: product.uom_hour
to_invoice: hr_timesheet_invoice.timesheet_invoice_factor2
unit_amount: 5.00
user_id: base.user_root
- |
Give partner name and price list in analytic account.
-
!record {model: account.analytic.account, id: account.analytic_sednacom}:
partner_id: base.res_partner_9
pricelist_id: product.list0
- |
I create invoice on analytic Line using "Invoice analytic Line" wizard.
Give date , detail of each work , time spend on that work on this wizard.
-
!record {model: hr.timesheet.invoice.create, id: hr_timesheet_invoice_create_0}:
accounts:
- account.analytic_sednacom
date: 1
name: 1
price: 1
product: hr_timesheet.product_consultant
time: 1
- |
I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice.
-
!python {model: hr.timesheet.invoice.create}: |
self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], {"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0")]})
- |
I check that Invoice is create for this timesheet.
-
!python {model: account.analytic.line}: |
exp = self.browse(cr, uid, [ref('account_analytic_line_developyamlforhrmodule0')])[0]
analytic_account_obj = self.pool.get('account.analytic.account')
data = self.pool.get('hr.timesheet.invoice.create').read(cr, uid, [ref("hr_timesheet_invoice_create_0")], [], context)[0]
account_ids = data['accounts']
for account in analytic_account_obj.browse(cr, uid, account_ids, context):
partner = account.partner_id.id
invoice_obj = self.pool.get('account.invoice')
invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner)])
invoice_id = invoice_obj.browse(cr, uid, invoice_ids)[0]
for invoice in invoice_id.invoice_line:
product = invoice.product_id.id
product_exp = data['product']
assert product == product_exp
- |
I creating a final invoice for "Sednacom" analytic account.
-
!record {model: hr.timesheet.invoice.create.final, id: hr_timesheet_invoice_create_final_0}:
balance_product: hr_timesheet.product_consultant
date: 1
name: 1
price: 1
time: 1
- |
I click on "Create Invoice" button to create Invoice.
-
!python {model: hr.timesheet.invoice.create.final}: |
self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_final_0")], {"active_ids": [ref("account.analytic_sednacom")]})
- |
I can also make some theoretical revenue reports.
- |
I can also see timesheet profit using Timesheet profit report.

View File

@ -71,8 +71,8 @@ class hr_timesheet_invoice_create(osv.osv_memory):
result = mod_obj._get_id(cr, uid, 'account', 'view_account_invoice_filter')
res = mod_obj.read(cr, uid, result, ['res_id'])
data = self.read(cr, uid, ids, [], context)[0]
account_ids = data['accounts']
for account in analytic_account_obj.browse(cr, uid, account_ids, context):
partner = account.partner_id
@ -119,11 +119,11 @@ class hr_timesheet_invoice_create(osv.osv_memory):
"GROUP BY product_id,to_invoice", (account.id,context['active_ids'],))
for product_id,factor_id,qty in cr.fetchall():
product = pool.get('product.product').browse(cr, uid, product_id, context2)
product = self.pool.get('product.product').browse(cr, uid, product_id, context2)
if not product:
raise osv.except_osv(_('Error'), _('At least one line has no product !'))
factor_name = ''
factor = pool.get('hr_timesheet_invoice.factor').browse(cr, uid, factor_id, context2)
factor = self.pool.get('hr_timesheet_invoice.factor').browse(cr, uid, factor_id, context2)
if not data['product']:
if factor.customer_name:
@ -131,16 +131,16 @@ class hr_timesheet_invoice_create(osv.osv_memory):
else:
factor_name = product.name
else:
factor_name = pool.get('product.product').name_get(cr, uid, [data['product']], context=context)[0][1]
factor_name = self.pool.get('product.product').name_get(cr, uid, [data['product']], context=context)[0][1]
if account.pricelist_id:
pl = account.pricelist_id.id
price = pool.get('product.pricelist').price_get(cr,uid,[pl], data['product'] or product_id, qty or 1.0, account.partner_id.id)[pl]
price = self.pool.get('product.pricelist').price_get(cr,uid,[pl], data['product'] or product_id, qty or 1.0, account.partner_id.id)[pl]
else:
price = 0.0
taxes = product.taxes_id
tax = pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id.property_account_position, taxes)
tax = self.pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id.property_account_position, taxes)
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
curr_line = {
'price_unit': price,
@ -159,7 +159,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
#
# Compute for lines
#
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id = ANY (%s) AND product_id=%s and to_invoice=%s", (account.id, data['ids'], product_id, factor_id))
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id = %s AND product_id=%s and to_invoice=%s", (account.id, data['id'], product_id, factor_id))
line_ids = cr.dictfetchall()
note = []
@ -170,7 +170,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
details.append(line['date'])
if data['time']:
if line['product_uom_id']:
details.append("%s %s" % (line['unit_amount'], pool.get('product.uom').browse(cr, uid, [line['product_uom_id']])[0].name))
details.append("%s %s" % (line['unit_amount'], self.pool.get('product.uom').browse(cr, uid, [line['product_uom_id']])[0].name))
else:
details.append("%s" % (line['unit_amount'], ))
if data['name']:
@ -180,8 +180,8 @@ class hr_timesheet_invoice_create(osv.osv_memory):
note.append(u' - '.join(map(lambda x: unicode(x) or '',details)))
curr_line['note'] = "\n".join(map(lambda x: unicode(x) or '',note))
pool.get('account.invoice.line').create(cr, uid, curr_line)
cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id =ANY(%s)" ,(last_invoice, account.id,data['ids']))
self.pool.get('account.invoice.line').create(cr, uid, curr_line)
cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id =%s" ,(last_invoice, account.id,data['id']))
self.pool.get('account.invoice').button_reset_taxes(cr, uid, [last_invoice], context)

View File

@ -56,7 +56,10 @@ The validation can be configured in the company:
'report/timesheet_report_view.xml',
'board_hr_timesheet_view.xml',
],
'demo_xml': ['hr_timesheet_sheet_demo.xml'],
'demo_xml': ['hr_timesheet_sheet_demo.xml',
],
'test':['test/test_hr_timesheet_sheet.yml'],
'installable': True,
'active': False,
'certificate': '0073297700829',

View File

@ -151,13 +151,16 @@ class hr_timesheet_sheet(osv.osv):
raise osv.except_osv(_('Error !'), _('You can not duplicate a timesheet !'))
def button_confirm(self, cr, uid, ids, context=None):
if context is None:
context = {}
for sheet in self.browse(cr, uid, ids, context=context):
di = sheet.user_id.company_id.timesheet_max_difference
if (abs(sheet.total_difference) < di) or not di:
wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'hr_timesheet_sheet.sheet', sheet.id, 'confirm', cr)
else:
raise osv.except_osv(_('Warning !'), _('Please verify that the total difference of the sheet is lower than %.2f !') %(di,))
return True

View File

@ -0,0 +1,139 @@
- |
In order, to test hr_timesheet_sheet module in OpenERP, I create timesheet and check validation process done by
manager.
- |
Now, I create a new employee “Mark Johnson” to test Timesheet.
-
!record {model: hr.employee, id: hr_employee_employee0}:
address_home_id: base.res_partner_address_1
company_id: base.main_company
gender: male
marital: hr.hr_employee_marital_status_single
name: Mark Johnson
user_id: base.user_root
- |
I create new user "user1".
-
!record {model: res.users, id: res_users_user0}:
company_id: base.main_company
context_lang: en_US
groups_id:
- hr.group_hr_user
- hr_attendance.group_hr_attendance
- base.group_user
- base.group_extended
- hr.group_hr_manager
login: user1
name: user1
password: user1
- |
create another employee "Francline" as "user1".
-
!record {model: hr.employee, id: hr_employee_fracline0}:
address_home_id: base.res_partner_address_8
name: Francline
parent_id: 'hr_employee_employee0'
user_id: 'res_users_user0'
- |
Given that I have Timesheet journal for employee.
-
!record {model: account.analytic.journal, id: analytic_journal}:
code: TS
name: Timesheet Journal
type: general
- |
Given that I have product for "Consultancy - Senior Developer".
-
!record {model: product.product, id: product_consultant}:
categ_id: product.product_category_10
default_code: DEV
list_price: 75.0
name: Consultancy - Senior Developer
procure_method: make_to_order
purchase_ok: False
standard_price: 30.0
supply_method: produce
type: service
uom_id: product.uom_hour
uom_po_id: product.uom_hour
- |
I assing product and journal to "Mark Johnson"
-
!record {model: hr.employee, id: hr_employee_employee0}:
product_id: product_consultant
journal_id: analytic_journal
- |
And also assing product and journal to "francline" employee.
-
!record {model: hr.employee, id: hr_employee_fracline0}:
product_id: product_consultant
journal_id: analytic_journal
- |
I connect as "francline" and create my current timesheet.
-
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
date_current: '2010-05-26'
date_from: '2010-05-01'
date_to: '2010-05-31'
name: Week-22(2010)
state: new
user_id: 'res_users_user0'
- |
Now , When I came in office , I create Attendances and perform "Sign In" action with proper reason.
-
!record {model: hr.attendance, id: hr_attendance_0}:
action: sign_in
employee_id: 'hr_employee_fracline0'
name: '2010-05-26 10:08:08'
- |
When I left office , I create attendance and perform "Sign Out".
-
!record {model: hr.attendance, id: hr_attendance_1}:
action: sign_out
employee_id: 'hr_employee_fracline0'
name: '2010-05-26 15:10:55'
-
I create Timesheet Entry for time spend on today work.
-
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet.sheet1}:
timesheet_ids:
- account_id: account.analytic_sednacom
date: '05/26/2010'
name: 'Develop yaml for hr module'
unit_amount: 5.00
amount: -90.00
product_id: hr_timesheet.product_consultant
general_account_id: account.a_expense
user_id: res_users_user0
journal_id: hr_timesheet.analytic_journal
- |
I confirm my timesheet at end of period by click on "Confirm" button which is signal of workflow.
-
!python {model: hr_timesheet_sheet.sheet}: |
uid = ref('res_users_user0')
self.button_confirm(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')])
- |
I check that state is "Confirmed".
-
!assert {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
- state == 'confirm'
- |
"Mark Johnson" check timesheet and time spend on project by "francline" employee.
And then accept it request by click on "Accept" button.
If "Maximal difference between timesheet and attendances" is more than 1 then manage can "Refuse" his request.
-
!python {model: hr_timesheet_sheet.sheet}: |
#self.write(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], {'state': 'done'})

View File

@ -31,6 +31,7 @@
<group colspan="8">
<field name="marketing_campaign" />
<field name="crm_profiling" />
<field name="marketing_campaign_mailchimp" />
</group>
</data>
</field>

View File

@ -28,6 +28,8 @@ class marketing_installer(osv.osv_memory):
# Generic modules
'marketing_campaign':fields.boolean('Marketing Campaigns',
help="Helps you to manage marketing campaigns and automate actions and communication steps."),
'marketing_campaign_mailchimp':fields.boolean('Mailchimp Integration',
help="This modules integrate mailchimp.com's service with OpenERP to automate mass mailings."),
'crm_profiling':fields.boolean('Profiling Tools',
help="Helps you to perform segmentation within partners and design questionaires.")
}

View File

@ -25,7 +25,7 @@ from dateutil.relativedelta import relativedelta
from osv import fields, osv
import netsvc
import tools
import tools
_intervalTypes = {
'hours': lambda interval: relativedelta(hours=interval),
@ -37,10 +37,10 @@ _intervalTypes = {
class marketing_campaign(osv.osv): #{{{
_name = "marketing.campaign"
_description = "Marketing Campaign"
_columns = {
'name': fields.char('Name', size=64, required=True),
'object_id': fields.many2one('ir.model', 'Objects', required=True,
'object_id': fields.many2one('ir.model', 'Object', required=True,
help="Choose the Object on which you want \
this campaign to be run"),
'mode':fields.selection([('test', 'Test'),
@ -52,17 +52,15 @@ class marketing_campaign(osv.osv): #{{{
('running', 'Running'),
('done', 'Done'),
('cancelled', 'Cancelled'),],
'State',),
'activity_ids': fields.one2many('marketing.campaign.activity',
'State',),
'activity_ids': fields.one2many('marketing.campaign.activity',
'campaign_id', 'Activities'),
'fixed_cost': fields.float('Fixed Cost', help="The fixed cost is cost\
you required for the campaign"),
you required for the campaign"),
}
_defaults = {
'state': lambda *a: 'draft',
'mode': lambda *a: 'test',
'mode': lambda *a: 'test',
}
def state_running_set(self, cr, uid, ids, *args):
@ -79,16 +77,16 @@ class marketing_campaign(osv.osv): #{{{
('state', '=', 'draft')])
self.write(cr, uid, ids, {'state': 'running'})
return True
def state_done_set(self, cr, uid, ids, *args):
segment_ids = self.pool.get('marketing.campaign.segment').search(cr, uid,
[('campaign_id', 'in', ids),
('state', '=', 'running')])
if segment_ids :
raise osv.except_osv("Error", "Camapign cannot be done before all segments are done")
raise osv.except_osv("Error", "Camapign cannot be done before all segments are done")
self.write(cr, uid, ids, {'state': 'done'})
return True
def state_cancel_set(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'cancelled'})
return True
@ -100,7 +98,7 @@ class marketing_campaign_segment(osv.osv): #{{{
_columns = {
'name': fields.char('Name', size=64,required=True),
'campaign_id': fields.many2one('marketing.campaign', 'Campaign',
'campaign_id': fields.many2one('marketing.campaign', 'Campaign',
required=True),
'object_id': fields.related('campaign_id','object_id',
type='many2one', relation='ir.model',
@ -114,22 +112,22 @@ class marketing_campaign_segment(osv.osv): #{{{
('running', 'Running'),
('done', 'Done'),
('cancelled', 'Cancelled')],
'State',),
'State',),
'date_run': fields.datetime('Running'),
'date_done': fields.datetime('Done'),
}
_defaults = {
'state': lambda *a: 'draft',
'sync_mode': lambda *a: 'create_date',
}
def state_running_set(self, cr, uid, ids, *args):
segment = self.browse(cr, uid, ids[0])
curr_date = time.strftime('%Y-%m-%d %H:%M:%S')
vals = {'state': 'running'}
if not segment.date_run:
vals['date_run'] = time.strftime('%Y-%m-%d %H:%M:%S')
vals['date_run'] = time.strftime('%Y-%m-%d %H:%M:%S')
if not segment.sync_last_date:
vals['sync_last_date']=curr_date
if not segment.date_done:
@ -137,9 +135,9 @@ class marketing_campaign_segment(osv.osv): #{{{
).strftime('%Y-%m-%d %H:%M:%S')
self.write(cr, uid, ids, vals)
return True
def state_done_set(self, cr, uid, ids, *args):
date_done = self.browse(cr, uid, ids[0]).date_done
date_done = self.browse(cr, uid, ids[0]).date_done
if (date_done > time.strftime('%Y-%m-%d %H:%M:%S')):
raise osv.except_osv("Error", "Segment cannot be closed before end date")
@ -147,21 +145,21 @@ class marketing_campaign_segment(osv.osv): #{{{
[('state', 'in', ['inprogress', 'todo']),
('segment_id', '=', ids[0])])
if wi_ids :
raise osv.except_osv("Error", "Segment cannot be done before all workitems are processed")
raise osv.except_osv("Error", "Segment cannot be done before all workitems are processed")
self.write(cr, uid, ids, {'state': 'done'})
return True
def state_cancel_set(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'cancelled'})
return True
def process_segment(self, cr, uid, context={}):
segment_ids = self.search(cr, uid, [('state', '=', 'running')])
action_date = time.strftime('%Y-%m-%d %H:%M:%S')
last_action_date = (datetime.now() + _intervalTypes['days'](-1) \
).strftime('%Y-%m-%d %H:%M:%S')
for segment in self.browse(cr, uid, segment_ids):
act_ids = self.pool.get('marketing.campaign.activity').search(cr,
act_ids = self.pool.get('marketing.campaign.activity').search(cr,
uid, [('start', '=', True),
('campaign_id', '=', segment.campaign_id.id)])
if (segment.sync_last_date and \
@ -195,23 +193,23 @@ class marketing_campaign_activity(osv.osv): #{{{
_columns = {
'name': fields.char('Name', size=128, required=True),
'campaign_id': fields.many2one('marketing.campaign', 'Campaign',
'campaign_id': fields.many2one('marketing.campaign', 'Campaign',
required = True, ondelete='cascade'),
'object_id': fields.related('campaign_id','object_id',
type='many2one', relation='ir.model',
string='Object'),
'start': fields.boolean('Start',help= "Its necessary to start activity \
before running campaign"),
'condition': fields.char('Condition', size=256, required=True,
'condition': fields.char('Condition', size=256, required=True,
help="Condition that is to be tested before \
action is executed"),
action is executed"),
'type': fields.selection([('email', 'E-mail'),
('paper', 'Paper'),
('action', 'Action'),
('subcampaign', 'Sub-Campaign')],
'Type', required=True),
'email_template_id': fields.many2one('email.template','Email Template'),
'report_id': fields.many2one('ir.actions.report.xml', 'Reports', ),
'report_id': fields.many2one('ir.actions.report.xml', 'Reports', ),
'report_directory_id': fields.many2one('document.directory','Directory',
help="Folder is used to store the generated reports"),
'server_action_id': fields.many2one('ir.actions.server', string='Action',
@ -222,7 +220,7 @@ class marketing_campaign_activity(osv.osv): #{{{
'Next Activities'),
'from_ids': fields.one2many('marketing.campaign.transition',
'activity_to_id',
'Previous Activities'),
'Previous Activities'),
'subcampaign_id': fields.many2one('marketing.campaign', 'Sub-Campaign'),
'subcampaign_segment_id': fields.many2one('marketing.campaign.segment',
'Sub Campaign Segment'),
@ -236,7 +234,7 @@ class marketing_campaign_activity(osv.osv): #{{{
'object_id' : lambda obj, cr, uid, context : context.get('object_id',False),
}
def search(self, cr, uid, args, offset=0, limit=None, order=None,
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
if context == None:
context = {}
@ -247,14 +245,14 @@ class marketing_campaign_activity(osv.osv): #{{{
for activity in segment_obj.campaign_id.activity_ids:
act_ids.append(activity.id)
return act_ids
return super(marketing_campaign_activity, self).search(cr, uid, args,
return super(marketing_campaign_activity, self).search(cr, uid, args,
offset, limit, order, context, count)
def process(self, cr, uid, act_id, wi_id, context={}):
activity = self.browse(cr, uid, act_id)
workitem_obj = self.pool.get('marketing.campaign.workitem')
workitem = workitem_obj.browse(cr, uid, wi_id)
if activity.type == 'paper' :
service = netsvc.LocalService('report.%s'%activity.report_id.report_name)
(report_data, format) = service.create(cr, uid, [], {}, {})
@ -298,7 +296,7 @@ class marketing_campaign_activity(osv.osv): #{{{
server_obj = self.pool.get('ir.actions.server')
server_obj.run(cr, uid, [activity.server_action_id.id], context)
#???
return True
return True
marketing_campaign_activity()#}}}
class marketing_campaign_transition(osv.osv): #{{{
@ -309,10 +307,10 @@ class marketing_campaign_transition(osv.osv): #{{{
_columns = {
'activity_from_id': fields.many2one('marketing.campaign.activity',
'Source Activity'),
'activity_to_id': fields.many2one('marketing.campaign.activity',
'activity_to_id': fields.many2one('marketing.campaign.activity',
'Destination Activity'),
'interval_nbr': fields.integer('Interval No.'),
'interval_type': fields.selection([('hours', 'Hours'), ('days', 'Days'),
'interval_type': fields.selection([('hours', 'Hours'), ('days', 'Days'),
('months', 'Months'),
('years','Years')],'Interval Type')
}
@ -323,32 +321,46 @@ class marketing_campaign_transition(osv.osv): #{{{
if context.has_key('type_id'):
value[context['type_id']] = context['activity_id']
return value
marketing_campaign_transition() #}}}
class marketing_campaign_workitem(osv.osv): #{{{
_name = "marketing.campaign.workitem"
_description = "Campaign Workitem"
def _res_name_get(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for obj in self.browse(cr, uid, ids, context=context):
if obj.res_id:
try:
res[obj.id] = self.pool.get(obj.object_id.model).name_get(cr, uid, [obj.res_id], context=context)[0][1]
except:
res[obj.id] = '/'
else:
res[obj.id] = '/'
return res
_columns = {
'segment_id': fields.many2one('marketing.campaign.segment', 'Segment',
required=True),
required=True),
'activity_id': fields.many2one('marketing.campaign.activity','Activity',
required=True),
'object_id': fields.related('segment_id', 'campaign_id', 'object_id',
type='many2one', relation='ir.model',
string='Object'),
'res_id': fields.integer('Results'),
required=True),
'campaign_id': fields.related('segment_id', 'campaign_id',
type='many2one', relation='marketing.campaign', string='Campaign', readonly=True),
'object_id': fields.related('segment_id', 'campaign_id', 'object_id',
type='many2one', relation='ir.model', string='Object'),
'res_id': fields.integer('Resource ID'),
'res_name': fields.function(_res_name_get, method=True, string='Resource Name', type="char", size=64),
'date': fields.datetime('Execution Date'),
'partner_id': fields.many2one('res.partner', 'Partner',required=True),
'state': fields.selection([('todo', 'ToDo'), ('inprogress', 'In Progress'),
'state': fields.selection([('todo', 'ToDo'), ('inprogress', 'In Progress'),
('exception', 'Exception'), ('done', 'Done'),
('cancelled', 'Cancelled')], 'State'),
'error_msg' : fields.text('Error Message')
}
}
_defaults = {
'state': lambda *a: 'draft',
'state': lambda *a: 'todo',
}
def process_chain(self, cr, uid, workitem_id, context={}):
@ -369,11 +381,17 @@ class marketing_campaign_workitem(osv.osv): #{{{
'state': 'todo',
}
self.create(cr, uid, workitem_vals)
def button_cancel(self, cr, uid, workitem_ids, context={}):
for wi in self.browse(cr, uid, workitem_ids):
if wi.state in ('todo','exception'):
self.write(cr, uid, [wi.id], {'state':'cancelled'}, context=context)
return True
def process(self, cr, uid, workitem_ids, context={}):
for wi in self.browse(cr, uid, workitem_ids):
if wi.state == 'todo':# we searched the wi which are in todo state
#then y v keep this filter again
if wi.state == 'todo':# we searched the wi which are in todo state
#then y v keep this filter again
eval_context = {
'pool': self.pool,
'cr': cr,
@ -390,45 +408,44 @@ class marketing_campaign_workitem(osv.osv): #{{{
if res :
self.write(cr, uid, wi.id, {'state': 'done'})
self.process_chain(cr, uid, wi.id, context)
else :
else :
self.write(cr, uid, wi.id, {'state': 'exception',
'error_msg': res['error_msg']})
except Exception,e:
self.write(cr, uid, wi.id, {'state': 'exception'})
else :
self.write(cr, uid, wi.id, {'state': 'cancelled'})
return True
def process_all(self, cr, uid, context={}):
workitem_ids = self.search(cr, uid, [('state', '=', 'todo'),
('date','<=', time.strftime('%Y-%m-%d %H:%M:%S'))])
if workitem_ids:
self.process(cr, uid, workitem_ids, context)
marketing_campaign_workitem() #}}}
marketing_campaign_workitem() #}}}
class email_template(osv.osv):
_inherit = "email.template"
_defaults = {
'object_name': lambda obj, cr, uid, context: context.get('object_id',False),
}
email_template()
email_template()
class report_xml(osv.osv):
_inherit = 'ir.actions.report.xml'
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if not context:
context = {}
if context and 'object_id' in context and context['object_id']:
model = self.pool.get('ir.model').browse(cr, uid,
model = self.pool.get('ir.model').browse(cr, uid,
context['object_id']).model
args.append(('model', '=', model))
return super(report_xml, self).search(cr, uid, args, offset, limit, order, context, count)
report_xml()
report_xml()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -14,75 +14,67 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Campaign">
<group colspan="4">
<group colspan="4" col="6">
<field name="name" select="1"/>
<field name="object_id" select="1"/>
<field name="mode"/>
<field name="fixed_cost"/>
</group>
<field name="activity_ids" nolabel = "1" colspan="4" default_get="{'object_id':object_id}">
<form string="Activities">
<field name="name" select="1" />
<field name="object_id" readonly="True"/>
<field name="variable_cost" select="1"/>
<field name="start"/>
<field name="condition" colspan="4"/>
<form string="Activities">
<group colspan="4" col="6">
<separator string="Activity Definition" colspan="4"/>
<separator string="Cost Control" colspan="2"/>
<field name="name" select="1" />
<field name="start"/>
<field name="variable_cost" select="1"/>
</group>
<group colspan="2" col="2">
<separator string="Condition" colspan="2"/>
<field name="condition"/>
</group>
<group colspan="2" col="2">
<separator string="Action" colspan="2"/>
<field name="type" colspan="4"/>
<group colspan="4" attrs="{'invisible':[('type','!=','email')]}" >
<field name="email_template_id" attrs="{'required':[('type','=','email')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','paper')]}" >
<field name="report_id" attrs="{'required':[('type','=','paper')]}"/>
<field name="report_directory_id" attrs="{'required':[('type','=','paper')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','action')]}" >
<field name="server_action_id" attrs="{'required':[('type','=','action')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','subcampaign')]}" >
<field name="subcampaign_id" attrs="{'required':[('type','=','subcampaign')]}" />
<field name="subcampaign_segment_id" attrs="{'required':[('type','=','subcampaign')]}" />
</group>
</group>
<newline/>
<field name="type" colspan="4"/>
<group colspan="4" attrs="{'invisible':[('type','!=','email')]}" >
<field name="email_template_id" attrs="{'required':[('type','=','email')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','paper')]}" >
<field name="report_id" attrs="{'required':[('type','=','paper')]}"/>
<field name="report_directory_id" attrs="{'required':[('type','=','paper')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','action')]}" >
<field name="server_action_id" attrs="{'required':[('type','=','action')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','subcampaign')]}" >
<field name="subcampaign_id" attrs="{'required':[('type','=','subcampaign')]}" />
<field name="subcampaign_segment_id" attrs="{'required':[('type','=','subcampaign')]}" />
</group>
<field name="to_ids" nolabel="1" colspan="4" mode="tree" default_get="{'type_id':'activity_from_id','activity_id':active_id or False}">
<form string="Out Transitions" >
<field name="activity_from_id" readonly="True"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</form>
<tree string="Out Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
<field name="from_ids" nolabel="1" colspan="4" mode="tree" default_get="{'type_id':'activity_to_id','activity_id':active_id or False}">
<form string="In Transitions" >
<field name="activity_from_id"/>
<field name="activity_to_id" readonly="True"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</form>
<tree string="In Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
<group colspan="4" col="4">
<separator string="Transitions" colspan="4"/>
<field name="to_ids" nolabel="1" colspan="2" mode="tree" default_get="{'type_id':'activity_from_id','activity_id':active_id or False}">
<tree string="Outgoing Transitions" editable="bottom">
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
<field name="from_ids" nolabel="1" colspan="2" mode="tree" default_get="{'type_id':'activity_to_id','activity_id':active_id or False}">
<tree string="Incoming Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
</group>
</form>
<tree string="Activities">
<field name="name" select="1"/>
<field name="object_id"/>
<field name="name"/>
<field name="start"/>
<field name="condition"/>
<field name="variable_cost" select="1"/>
<field name="type"/>
<field name="report_id"/>
<field name="to_ids"/>
<field name="subcampaign_id"/>
<field name="subcampaign_segment_id"/>
</tree>
</field>
<separator string="Status" colspan="4" />
@ -105,7 +97,6 @@
<field name="name" select="1"/>
<field name="object_id" select="1"/>
<field name="mode"/>
<field name="fixed_cost"/>
<field name="state"/>
</tree>
</field>
@ -122,13 +113,13 @@
<field name="type"/>
<field name="start" invisible="1"/>
<field name="condition"/>
</node>
<arrow object="marketing.campaign.transition" source="activity_from_id" destination="activity_to_id" label="['interval_type']">
</node>
<arrow object="marketing.campaign.transition" source="activity_from_id" destination="activity_to_id" label="['interval_type']">
<field name="activity_from_id"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</arrow>
<field name="interval_type"/>
</arrow>
</diagram>
</field>
</record>
@ -183,21 +174,23 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Segments">
<group colspan="4">
<field name="name" select="1" colspan="4"/>
<newline/>
<group colspan="4" col="6">
<field name="name"/>
<field name="campaign_id" select="1"/>
<field name="object_id" select="1" readonly="True"/>
<newline/>
<field name="ir_filter_id" select="1"/>
<newline/>
<field name="object_id" invisible="1" readonly="True"/>
</group>
<group colspan="2" col="2">
<separator string="Synchronization" colspan="2"/>
<field name="sync_last_date"/>
<field name="sync_mode" required="True"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<field name="date_run" attrs="{'readonly':[('date_run','!=',False),('state','=','running')]}"/>
<field name="date_done"/>
<separator string="Synchronization" colspan="4" />
<field name="sync_last_date"/>
<field name="sync_mode" required="True"/>
</group>
<separator string="Status" colspan="4" />
<separator string="Status" colspan="4"/>
<group col="10" colspan="4">
<field name="state" readonly="1" select="2" nolabel="1"/>
<button name="state_running_set" string="Run" states="draft" icon="gtk-apply"/>
@ -214,13 +207,11 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Segments">
<field name="name" select="1"/>
<field name="campaign_id" select="1"/>
<field name="object_id" select="1" />
<field name="name"/>
<field name="campaign_id"/>
<field name="object_id"/>
<field name="date_run"/>
<field name="date_done"/>
<field name="sync_last_date" string="Sync Date"/>
<field name="sync_mode" string="Sync Mode"/>
<field name="state" />
</tree>
</field>
@ -277,54 +268,55 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Activities">
<field name="name" select="1" />
<field name="start"/>
<field name="campaign_id" select="1"/>
<field name="object_id" readonly="True"/>
<group colspan="4" col="6">
<separator string="Activity Definition" colspan="4"/>
<separator string="Cost Control" colspan="2"/>
<field name="name" select="1" />
<field name="start"/>
<field name="variable_cost" select="1"/>
<field name="object_id" invisible="1"/>
</group>
<group colspan="2" col="2">
<separator string="Condition" colspan="2"/>
<field name="condition"/>
</group>
<group colspan="2" col="2">
<separator string="Action"/>
<field name="type" colspan="4"/>
<group colspan="4" attrs="{'invisible':[('type','!=','email')]}" >
<field name="email_template_id" attrs="{'required':[('type','=','email')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','paper')]}" >
<field name="report_id" attrs="{'required':[('type','=','paper')]}"/>
<field name="report_directory_id" attrs="{'required':[('type','=','paper')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','action')]}" >
<field name="server_action_id" attrs="{'required':[('type','=','action')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','subcampaign')]}" >
<field name="subcampaign_id" attrs="{'required':[('type','=','subcampaign')]}" />
<field name="subcampaign_segment_id" attrs="{'required':[('type','=','subcampaign')]}" />
</group>
</group>
<newline/>
<field name="type"/>
<group colspan="4" attrs="{'invisible':[('type','!=','email')]}" >
<field name="email_template_id" attrs="{'required':[('type','=','email')]}" />
<group colspan="4" col="4">
<separator string="Transitions" colspan="4"/>
<field name="to_ids" nolabel="1" colspan="2" mode="tree" default_get="{'type_id':'activity_from_id','activity_id':active_id or False}">
<tree string="Outgoing Transitions" editable="bottom">
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
<field name="from_ids" nolabel="1" colspan="2" mode="tree" default_get="{'type_id':'activity_to_id','activity_id':active_id or False}">
<tree string="Incoming Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','paper')]}" >
<field name="report_id" attrs="{'required':[('type','=','paper')]}" />
<field name="report_directory_id" attrs="{'required':[('type','=','paper')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','action')]}" >
<field name="server_action_id" attrs="{'required':[('type','=','action')]}" />
</group>
<group colspan="4" attrs="{'invisible':[('type','!=','subcampaign')]}" >
<field name="subcampaign_id" attrs="{'required':[('type','=','subcampaign')]}" />
<field name="subcampaign_segment_id" attrs="{'required':[('type','=','subcampaign')]}" />
</group>
<field name="to_ids" nolabel="1" colspan="4" mode="tree" default_get="{'type_id':'activity_from_id','activity_id':active_id or False}">
<form string="Out Transitions" >
<field name="activity_from_id" readonly="True"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</form>
<tree string="Out Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
<field name="from_ids" nolabel="1" colspan="4" mode="tree" default_get="{'type_id':'activity_to_id','activity_id':active_id or False}">
<form string="In Transitions" >
<field name="activity_from_id"/>
<field name="activity_to_id" readonly="True"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</form>
<tree string="In Transitions" editable="bottom">
<field name="activity_from_id"/>
<field name="activity_to_id"/>
<field name="interval_nbr"/>
<field name="interval_type"/>
</tree>
</field>
</form>
</field>
</record>
@ -338,13 +330,8 @@
<field name="name" select="1"/>
<field name="campaign_id" select="1"/>
<field name="start"/>
<field name="object_id"/>
<field name="condition"/>
<field name="type"/>
<field name="report_id"/>
<field name="to_ids" />
<field name="subcampaign_id"/>
<field name="subcampaign_segment_id"/>
</tree>
</field>
</record>
@ -374,11 +361,12 @@
<tree string="Workitems">
<field name="segment_id"/>
<field name="activity_id" />
<field name="object_id"/>
<field name="partner_id" select="1"/>
<field name="res_id" />
<field name="res_name" />
<field name="partner_id"/>
<field name="date"/>
<field name="state"/>
<button string="Process" states="todo" name="process" type="object" icon="gtk-ok"/>
<button string="Cancel" states="todo" name="button_cancel" type="object" icon="gtk-cancel"/>
</tree>
</field>
</record>
@ -389,14 +377,31 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Workitem">
<field name="segment_id" select="1"/>
<field name="activity_id" context="{'segment_id':segment_id}" select="1"/>
<field name="object_id" readonly="True"/>
<field name="partner_id" select="1"/>
<field name="res_id"/>
<field name="date" select="1"/>
<group colspan="4" col="6">
<group colspan="2" col="2">
<separator string="Campaign Step" colspan="2"/>
<field name="campaign_id" select="1"/>
<field name="segment_id" select="1"/>
<field name="activity_id" context="{'segment_id':segment_id}" select="1"/>
</group><group colspan="2" col="2">
<separator string="Related Resource" colspan="2"/>
<field name="object_id" readonly="True"/>
<field name="res_name"/>
<field name="res_id"/>
<field name="partner_id" select="1"/>
</group><group colspan="2" col="2">
<separator string="Date" colspan="2"/>
<field name="date"/>
<label string="" colspan="1"/>
<button string="Preview" states="todo" name="preview" icon="gtk-apply"/>
</group>
</group>
<separator string="Status" colspan="4"/>
<field name="state" nolabel="1" colspan="4" readonly="True" select="1"/>
<group colspan="4" col="11">
<field name="state" nolabel="1" readonly="True" select="1"/>
<button string="Process" states="todo" name="process" type="object" icon="gtk-ok"/>
<button string="Cancel" states="todo" name="button_cancel" type="object" icon="gtk-cancel"/>
</group>
</form>
</field>
</record>