rename report_analytic_planing to project_planing and removed dependancy of account from project and add analytic module + improvement in account_anglo_saxon
bzr revid: hda@tinyerp.com-20100205150927-ztj0oaw3d3mv4f34
This commit is contained in:
parent
4261bf5960
commit
904de67cf5
|
@ -23,7 +23,7 @@
|
|||
{
|
||||
"name" : "Accounting and Financial Management",
|
||||
"version" : "1.1",
|
||||
"depends" : ["product", "base", "process"],
|
||||
"depends" : ["product", "analytic", "process"],
|
||||
"author" : "Tiny",
|
||||
"description": """Financial and accounting module that covers:
|
||||
General accounting
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<record id="process_node_analytic0" model="process.node">
|
||||
<field name="menu_id" ref="account.account_analytic_def_account"/>
|
||||
<field name="model_id" ref="account.model_account_analytic_account"/>
|
||||
<field name="model_id" ref="analytic.model_account_analytic_account"/>
|
||||
<field eval=""""state"""" name="kind"/>
|
||||
<field eval=""""Analytic Costs"""" name="name"/>
|
||||
<field eval=""""Analytic costs to invoice"""" name="note"/>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<record id="process_node_analyticcost0" model="process.node">
|
||||
<field name="menu_id" ref="account.account_analytic_def_account"/>
|
||||
<field name="model_id" ref="account.model_account_analytic_account"/>
|
||||
<field name="model_id" ref="analytic.model_account_analytic_account"/>
|
||||
<field eval=""""state"""" name="kind"/>
|
||||
<field eval=""""Analytic Costs"""" name="name"/>
|
||||
<field eval=""""Analytic costs to invoice"""" name="note"/>
|
||||
|
|
|
@ -29,239 +29,6 @@ from osv import osv
|
|||
# Object definition
|
||||
#
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
_name = 'account.analytic.account'
|
||||
_description = 'Analytic Accounts'
|
||||
|
||||
def _credit_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount<0 and a.id =ANY(%s) GROUP BY a.id",(ids,))
|
||||
r = dict(cr.fetchall())
|
||||
for i in ids:
|
||||
r.setdefault(i,0.0)
|
||||
return r
|
||||
|
||||
def _debit_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids,))
|
||||
r= dict(cr.fetchall())
|
||||
for i in ids:
|
||||
r.setdefault(i,0.0)
|
||||
return r
|
||||
|
||||
def _balance_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
res = {}
|
||||
ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
|
||||
for i in ids:
|
||||
res.setdefault(i,0.0)
|
||||
if not ids2:
|
||||
return res
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,))
|
||||
|
||||
for account_id, sum in cr.fetchall():
|
||||
res[account_id] = sum
|
||||
|
||||
cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id =ANY(%s)",(ids2,))
|
||||
|
||||
currency= dict(cr.fetchall())
|
||||
|
||||
res_currency= self.pool.get('res.currency')
|
||||
for id in ids:
|
||||
if id not in ids2:
|
||||
continue
|
||||
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
|
||||
if child <> id:
|
||||
res.setdefault(id, 0.0)
|
||||
if currency[child]<>currency[id]:
|
||||
res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context)
|
||||
else:
|
||||
res[id] += res.get(child, 0.0)
|
||||
|
||||
cur_obj = res_currency.browse(cr,uid,currency.values(),context)
|
||||
cur_obj = dict([(o.id, o) for o in cur_obj])
|
||||
for id in ids:
|
||||
if id in ids2:
|
||||
res[id] = res_currency.round(cr,uid,cur_obj[currency[id]],res.get(id,0.0))
|
||||
|
||||
return dict([(i, res[i]) for i in ids ])
|
||||
|
||||
def _quantity_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
#XXX must convert into one uom
|
||||
res = {}
|
||||
ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
|
||||
acc_set = ",".join(map(str, ids2))
|
||||
|
||||
for i in ids:
|
||||
res.setdefault(i,0.0)
|
||||
|
||||
if not acc_set:
|
||||
return res
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \
|
||||
FROM account_analytic_account a \
|
||||
LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \
|
||||
WHERE a.id =ANY(%s) GROUP BY a.id',(ids2,))
|
||||
|
||||
for account_id, sum in cr.fetchall():
|
||||
res[account_id] = sum
|
||||
|
||||
for id in ids:
|
||||
if id not in ids2:
|
||||
continue
|
||||
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
|
||||
if child <> id:
|
||||
res.setdefault(id, 0.0)
|
||||
res[id] += res.get(child, 0.0)
|
||||
return dict([(i, res[i]) for i in ids])
|
||||
|
||||
def name_get(self, cr, uid, ids, context={}):
|
||||
if not len(ids):
|
||||
return []
|
||||
reads = self.read(cr, uid, ids, ['name','parent_id'], context)
|
||||
res = []
|
||||
for record in reads:
|
||||
name = record['name']
|
||||
if record['parent_id']:
|
||||
name = record['parent_id'][1]+' / '+name
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def _complete_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
|
||||
res = self.name_get(cr, uid, ids)
|
||||
return dict(res)
|
||||
|
||||
def _get_company_currency(self, cr, uid, ids, field_name, arg, context={}):
|
||||
result = {}
|
||||
for rec in self.browse(cr, uid, ids, context):
|
||||
result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Account Name', size=128, required=True),
|
||||
'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'),
|
||||
'code' : fields.char('Account Code', size=24),
|
||||
# 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."),
|
||||
'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'),
|
||||
'description' : fields.text('Description'),
|
||||
'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
|
||||
'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts'),
|
||||
'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'),
|
||||
'balance' : fields.function(_balance_calc, method=True, type='float', string='Balance'),
|
||||
'debit' : fields.function(_debit_calc, method=True, type='float', string='Debit'),
|
||||
'credit' : fields.function(_credit_calc, method=True, type='float', string='Credit'),
|
||||
'quantity': fields.function(_quantity_calc, method=True, type='float', string='Quantity'),
|
||||
'quantity_max': fields.float('Maximum Quantity', help='Sets the higher limit of quantity of hours.'),
|
||||
'partner_id' : fields.many2one('res.partner', 'Associated Partner'),
|
||||
'contact_id' : fields.many2one('res.partner.address', 'Contact'),
|
||||
'user_id' : fields.many2one('res.users', 'Account Manager'),
|
||||
'date_start': fields.date('Date Start'),
|
||||
'date': fields.date('Date End'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'company_currency_id': fields.function(_get_company_currency, method=True, type='many2one', relation='res.currency', string='Currency'),
|
||||
'state': fields.selection([('draft','Draft'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Close'),('template', 'Template')], 'State', required=True,readonly=True,
|
||||
help='* When an account is created its in \'Draft\' state.\
|
||||
\n* If any associated partner is there, it can be in \'Open\' state.\
|
||||
\n* If any pending balance is there it can be in \'Pending\'. \
|
||||
\n* And finally when all the transactions are over, it can be in \'Close\' state. \
|
||||
\n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\
|
||||
\n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'),
|
||||
}
|
||||
|
||||
def _default_company(self, cr, uid, context={}):
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if user.company_id:
|
||||
return user.company_id.id
|
||||
return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
|
||||
_defaults = {
|
||||
# 'active' : lambda *a : True,
|
||||
'type' : lambda *a : 'normal',
|
||||
'company_id': _default_company,
|
||||
'state' : lambda *a : 'open',
|
||||
'user_id' : lambda self,cr,uid,ctx : uid,
|
||||
'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False),
|
||||
'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False),
|
||||
'date_start': lambda *a: time.strftime('%Y-%m-%d')
|
||||
}
|
||||
|
||||
def check_recursion(self, cr, uid, ids, parent=None):
|
||||
return super(account_analytic_account, self).check_recursion(cr, uid, ids, parent=parent)
|
||||
|
||||
_order = 'parent_id desc,code'
|
||||
_constraints = [
|
||||
(check_recursion, 'Error! You can not create recursive analytic accounts.', ['parent_id'])
|
||||
]
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
parent_id = vals.get('parent_id', 0)
|
||||
if ('code' not in vals or not vals['code']) and not parent_id:
|
||||
vals['code'] = self.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account')
|
||||
return super(account_analytic_account, self).create(cr, uid, vals, context=context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context={}):
|
||||
if not default:
|
||||
default = {}
|
||||
default['code'] = False
|
||||
default['line_ids'] = []
|
||||
return super(account_analytic_account, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
|
||||
def on_change_parent(self, cr, uid, id, parent_id):
|
||||
if not parent_id:
|
||||
return {}
|
||||
parent = self.read(cr, uid, [parent_id], ['partner_id','code'])[0]
|
||||
childs = self.search(cr, uid, [('parent_id', '=', parent_id), ('active', 'in', [True, False])])
|
||||
numchild = len(childs)
|
||||
if parent['partner_id']:
|
||||
partner = parent['partner_id'][0]
|
||||
else:
|
||||
partner = False
|
||||
res = {'value' : {'code' : '%s - %03d' % (parent['code'] or '', numchild + 1),}}
|
||||
if partner:
|
||||
res['value']['partner_id'] = partner
|
||||
return res
|
||||
|
||||
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
|
||||
if not args:
|
||||
args=[]
|
||||
if not context:
|
||||
context={}
|
||||
account = self.search(cr, uid, [('code', '=', name)]+args, limit=limit, context=context)
|
||||
if not account:
|
||||
account = self.search(cr, uid, [('name', 'ilike', '%%%s%%' % name)]+args, limit=limit, context=context)
|
||||
newacc = account
|
||||
while newacc:
|
||||
newacc = self.search(cr, uid, [('parent_id', 'in', newacc)]+args, limit=limit, context=context)
|
||||
account+=newacc
|
||||
return self.name_get(cr, uid, account, context=context)
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
|
||||
class account_analytic_journal(osv.osv):
|
||||
_name = 'account.analytic.journal'
|
||||
_columns = {
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"access_account_bank_statement_line","account.bank.statement.line","model_account_bank_statement_line","account.group_account_user",1,1,1,1
|
||||
"access_account_analytic_line","account.analytic.line","model_account_analytic_line","account.group_account_user",1,1,1,1
|
||||
"access_report_hr_timesheet_invoice_journal","report.hr.timesheet.invoice.journal","model_report_hr_timesheet_invoice_journal","account.group_account_manager",1,0,0,0
|
||||
"access_account_analytic_account","account.analytic.account","model_account_analytic_account","base.group_user",1,0,0,0
|
||||
"access_account_analytic_account","account.analytic.account","analytic.model_account_analytic_account","base.group_user",1,0,0,0
|
||||
"access_account_analytic_journal","account.analytic.journal","model_account_analytic_journal","account.group_account_user",1,0,0,0
|
||||
"access_account_invoice_uinvoice","account.invoice","model_account_invoice","account.group_account_invoice",1,1,1,1
|
||||
"access_account_invoice_line_uinvoice","account.invoice.line","model_account_invoice_line","account.group_account_invoice",1,1,1,1
|
||||
|
@ -58,7 +58,7 @@
|
|||
"access_account_tax_code_manager","account.tax.code","model_account_tax_code","account.group_account_manager",1,1,1,1
|
||||
"access_account_tax_manager","account.tax","model_account_tax","account.group_account_manager",1,1,1,1
|
||||
"access_account_invoice_group_invoice","account.invoice group invoice","model_account_invoice","account.group_account_invoice",1,1,1,1
|
||||
"access_account_analytic_account_manager","account.analytic.account","model_account_analytic_account","account.group_account_manager",1,1,1,1
|
||||
"access_account_analytic_account_manager","account.analytic.account","analytic.model_account_analytic_account","account.group_account_manager",1,1,1,1
|
||||
"access_account_analytic_journal_manager","account.analytic.journal","model_account_analytic_journal","account.group_account_manager",1,1,1,1
|
||||
"access_account_fiscalyear","account.fiscalyear","model_account_fiscalyear","account.group_account_manager",1,1,1,1
|
||||
"access_account_fiscalyear_user","account.fiscalyear.user","model_account_fiscalyear","account.group_account_user",1,0,0,0
|
||||
|
|
|
|
@ -18,17 +18,18 @@
|
|||
#
|
||||
##############################################################################
|
||||
{
|
||||
"name" : "Stock Account",
|
||||
"version" : "1.1",
|
||||
"author" : "Tiny",
|
||||
"website" : "http://tinyerp.com",
|
||||
"name" : "Stock Accounting for Anglo Saxon countries",
|
||||
"version" : "1.2",
|
||||
"author" : "Tiny, Veritos",
|
||||
"website" : "http://tinyerp.com - http://veritos.nl",
|
||||
"description" : """This module will support the Anglo-Saxons accounting methodology by
|
||||
changing the accounting logic with stock transactions. The difference between the Anglo-Saxon accounting countries
|
||||
and the Rhine or also called Continental accounting countries is the moment of taking the Cost of Goods Sold versus Cost of Sales.
|
||||
Anglo-Saxons accounting does take the cost when sales invoice is created, Continental accounting will take the cost at he moment the goods are shipped.
|
||||
This module will add this functionality by using a interim account, to store the value of shipped goods and will contra book this interim account
|
||||
when the invoice is created to transfer this amount to the debtor or creditor account.""",
|
||||
"depends" : ["product", "account", "sale", "purchase"],
|
||||
when the invoice is created to transfer this amount to the debtor or creditor account.
|
||||
Secondly, price differences between actual purchase price and fixed product standard price are booked on a seperate account""",
|
||||
"depends" : ["product", "account", "sale", "purchase", "stock"],
|
||||
"category" : "Generic Modules/Inventory Control",
|
||||
"init_xml" : [],
|
||||
"demo_xml" : [],
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C)
|
||||
# 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# 2009-2010 Veritos (http://veritos.nl).
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -30,14 +33,20 @@ class account_invoice_line(osv.osv):
|
|||
for i_line in inv.invoice_line:
|
||||
if i_line.product_id:
|
||||
if inv.type == 'out_invoice':
|
||||
# debit account dacc will be the output account
|
||||
# first check the product, if empty check the category
|
||||
dacc = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id
|
||||
if not dacc:
|
||||
dacc = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id
|
||||
else:
|
||||
# = out_refund
|
||||
# debit account dacc will be the input account
|
||||
# first check the product, if empty check the category
|
||||
dacc = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id
|
||||
if not dacc:
|
||||
dacc = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id
|
||||
|
||||
# in both cases the credit account cacc will be the expense account
|
||||
# first check the product, if empty check the category
|
||||
cacc = i_line.product_id.product_tmpl_id.property_account_expense and i_line.product_id.product_tmpl_id.property_account_expense.id
|
||||
if not cacc:
|
||||
cacc = i_line.product_id.categ_id.property_account_expense_categ and i_line.product_id.categ_id.property_account_expense_categ.id
|
||||
|
@ -71,27 +80,36 @@ class account_invoice_line(osv.osv):
|
|||
for i_line in inv.invoice_line:
|
||||
if i_line.product_id:
|
||||
if i_line.product_id.product_tmpl_id.type != 'service':
|
||||
# get the price difference account at the product
|
||||
acc = i_line.product_id.product_tmpl_id.property_account_creditor_price_difference and i_line.product_id.product_tmpl_id.property_account_creditor_price_difference.id
|
||||
if not acc:
|
||||
# if not found on the product get the price difference account at the category
|
||||
acc = i_line.product_id.categ_id.property_account_creditor_price_difference_categ and i_line.product_id.categ_id.property_account_creditor_price_difference_categ.id
|
||||
a = None
|
||||
if inv.type == 'in_invoice':
|
||||
# oa will be the stock input account
|
||||
# first check the product, if empty check the category
|
||||
oa = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id
|
||||
if not oa:
|
||||
oa = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id
|
||||
else:
|
||||
# = in_refund
|
||||
# oa will be the stock output account
|
||||
# first check the product, if empty check the category
|
||||
oa = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id
|
||||
if not oa:
|
||||
oa = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id
|
||||
if oa:
|
||||
# get the fiscal position
|
||||
fpos = i_line.invoice_id.fiscal_position or False
|
||||
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
|
||||
diff_res = []
|
||||
# calculate and write down the possible price difference between invoice price and product price
|
||||
for line in res:
|
||||
if a == line['account_id'] and i_line.product_id.id == line['product_id']:
|
||||
uom = i_line.product_id.uos_id or i_line.product_id.uom_id
|
||||
standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.product_tmpl_id.standard_price, i_line.uos_id.id)
|
||||
if standard_price != i_line.price_unit and line['price'] == i_line.price_unit and acc:
|
||||
if standard_price != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
||||
price_diff = i_line.price_unit - standard_price
|
||||
line.update({'price':standard_price * line['quantity']})
|
||||
diff_res.append({
|
||||
|
|
|
@ -43,6 +43,18 @@ class stock_picking(osv.osv):
|
|||
fpos = ol.invoice_id.fiscal_position or False
|
||||
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
|
||||
self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a})
|
||||
|
||||
elif type == 'in_invoice':
|
||||
for inv in self.pool.get('account.invoice').browse(cr, uid, res.values(), context=context):
|
||||
for ol in inv.invoice_line:
|
||||
if ol.product_id:
|
||||
oa = ol.product_id.product_tmpl_id.property_stock_account_input and ol.product_id.product_tmpl_id.property_stock_account_input.id
|
||||
if not oa:
|
||||
oa = ol.product_id.categ_id.property_stock_account_input_categ and ol.product_id.categ_id.property_stock_account_input_categ.id
|
||||
if oa:
|
||||
fpos = ol.invoice_id.fiscal_position or False
|
||||
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
|
||||
self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a})
|
||||
return res
|
||||
|
||||
stock_picking()
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import project
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# -*- 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" : "Analytic Account",
|
||||
"version": "1.1",
|
||||
"author" : "Tiny",
|
||||
"website" : "http://www.openerp.com",
|
||||
"category" : "Generic Modules/Projects & Services",
|
||||
"depends" : ["base"],
|
||||
"description": """Module for defining analytic accounting object.
|
||||
""",
|
||||
"init_xml" : [],
|
||||
"update_xml": ["security/ir.model.access.csv",
|
||||
],
|
||||
'demo_xml': [
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate': '',
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,262 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import operator
|
||||
|
||||
from osv import fields
|
||||
from osv import osv
|
||||
|
||||
#
|
||||
# Object definition
|
||||
#
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
_name = 'account.analytic.account'
|
||||
_description = 'Analytic Accounts'
|
||||
|
||||
def _credit_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount<0 and a.id =ANY(%s) GROUP BY a.id",(ids,))
|
||||
r = dict(cr.fetchall())
|
||||
for i in ids:
|
||||
r.setdefault(i,0.0)
|
||||
return r
|
||||
|
||||
def _debit_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids,))
|
||||
r= dict(cr.fetchall())
|
||||
for i in ids:
|
||||
r.setdefault(i,0.0)
|
||||
return r
|
||||
|
||||
def _balance_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
res = {}
|
||||
ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
|
||||
for i in ids:
|
||||
res.setdefault(i,0.0)
|
||||
if not ids2:
|
||||
return res
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,))
|
||||
|
||||
for account_id, sum in cr.fetchall():
|
||||
res[account_id] = sum
|
||||
|
||||
cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id =ANY(%s)",(ids2,))
|
||||
|
||||
currency= dict(cr.fetchall())
|
||||
|
||||
res_currency= self.pool.get('res.currency')
|
||||
for id in ids:
|
||||
if id not in ids2:
|
||||
continue
|
||||
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
|
||||
if child <> id:
|
||||
res.setdefault(id, 0.0)
|
||||
if currency[child]<>currency[id]:
|
||||
res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context)
|
||||
else:
|
||||
res[id] += res.get(child, 0.0)
|
||||
|
||||
cur_obj = res_currency.browse(cr,uid,currency.values(),context)
|
||||
cur_obj = dict([(o.id, o) for o in cur_obj])
|
||||
for id in ids:
|
||||
if id in ids2:
|
||||
res[id] = res_currency.round(cr,uid,cur_obj[currency[id]],res.get(id,0.0))
|
||||
|
||||
return dict([(i, res[i]) for i in ids ])
|
||||
|
||||
def _quantity_calc(self, cr, uid, ids, name, arg, context={}):
|
||||
#XXX must convert into one uom
|
||||
res = {}
|
||||
ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
|
||||
acc_set = ",".join(map(str, ids2))
|
||||
|
||||
for i in ids:
|
||||
res.setdefault(i,0.0)
|
||||
|
||||
if not acc_set:
|
||||
return res
|
||||
|
||||
where_date = ''
|
||||
if context.get('from_date',False):
|
||||
where_date += " AND l.date >= '" + context['from_date'] + "'"
|
||||
if context.get('to_date',False):
|
||||
where_date += " AND l.date <= '" + context['to_date'] + "'"
|
||||
|
||||
cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \
|
||||
FROM account_analytic_account a \
|
||||
LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \
|
||||
WHERE a.id =ANY(%s) GROUP BY a.id',(ids2,))
|
||||
|
||||
for account_id, sum in cr.fetchall():
|
||||
res[account_id] = sum
|
||||
|
||||
for id in ids:
|
||||
if id not in ids2:
|
||||
continue
|
||||
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
|
||||
if child <> id:
|
||||
res.setdefault(id, 0.0)
|
||||
res[id] += res.get(child, 0.0)
|
||||
return dict([(i, res[i]) for i in ids])
|
||||
|
||||
def name_get(self, cr, uid, ids, context={}):
|
||||
if not len(ids):
|
||||
return []
|
||||
reads = self.read(cr, uid, ids, ['name','parent_id'], context)
|
||||
res = []
|
||||
for record in reads:
|
||||
name = record['name']
|
||||
if record['parent_id']:
|
||||
name = record['parent_id'][1]+' / '+name
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def _complete_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict):
|
||||
res = self.name_get(cr, uid, ids)
|
||||
return dict(res)
|
||||
|
||||
def _get_company_currency(self, cr, uid, ids, field_name, arg, context={}):
|
||||
result = {}
|
||||
for rec in self.browse(cr, uid, ids, context):
|
||||
result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Account Name', size=128, required=True),
|
||||
'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'),
|
||||
'code' : fields.char('Account Code', size=24),
|
||||
# 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."),
|
||||
'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'),
|
||||
'description' : fields.text('Description'),
|
||||
'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
|
||||
'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts'),
|
||||
'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'),
|
||||
'balance' : fields.function(_balance_calc, method=True, type='float', string='Balance'),
|
||||
'debit' : fields.function(_debit_calc, method=True, type='float', string='Debit'),
|
||||
'credit' : fields.function(_credit_calc, method=True, type='float', string='Credit'),
|
||||
'quantity': fields.function(_quantity_calc, method=True, type='float', string='Quantity'),
|
||||
'quantity_max': fields.float('Maximum Quantity', help='Sets the higher limit of quantity of hours.'),
|
||||
'partner_id' : fields.many2one('res.partner', 'Associated Partner'),
|
||||
'contact_id' : fields.many2one('res.partner.address', 'Contact'),
|
||||
'user_id' : fields.many2one('res.users', 'Account Manager'),
|
||||
'date_start': fields.date('Date Start'),
|
||||
'date': fields.date('Date End'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'company_currency_id': fields.function(_get_company_currency, method=True, type='many2one', relation='res.currency', string='Currency'),
|
||||
'state': fields.selection([('draft','Draft'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Close'),('template', 'Template')], 'State', required=True,readonly=True,
|
||||
help='* When an account is created its in \'Draft\' state.\
|
||||
\n* If any associated partner is there, it can be in \'Open\' state.\
|
||||
\n* If any pending balance is there it can be in \'Pending\'. \
|
||||
\n* And finally when all the transactions are over, it can be in \'Close\' state. \
|
||||
\n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\
|
||||
\n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'),
|
||||
}
|
||||
|
||||
def _default_company(self, cr, uid, context={}):
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if user.company_id:
|
||||
return user.company_id.id
|
||||
return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
|
||||
_defaults = {
|
||||
# 'active' : lambda *a : True,
|
||||
'type' : lambda *a : 'normal',
|
||||
'company_id': _default_company,
|
||||
'state' : lambda *a : 'open',
|
||||
'user_id' : lambda self,cr,uid,ctx : uid,
|
||||
'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False),
|
||||
'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False),
|
||||
'date_start': lambda *a: time.strftime('%Y-%m-%d')
|
||||
}
|
||||
|
||||
def check_recursion(self, cr, uid, ids, parent=None):
|
||||
return super(account_analytic_account, self).check_recursion(cr, uid, ids, parent=parent)
|
||||
|
||||
_order = 'parent_id desc,code'
|
||||
_constraints = [
|
||||
(check_recursion, 'Error! You can not create recursive analytic accounts.', ['parent_id'])
|
||||
]
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
parent_id = vals.get('parent_id', 0)
|
||||
if ('code' not in vals or not vals['code']) and not parent_id:
|
||||
vals['code'] = self.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account')
|
||||
return super(account_analytic_account, self).create(cr, uid, vals, context=context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context={}):
|
||||
if not default:
|
||||
default = {}
|
||||
default['code'] = False
|
||||
default['line_ids'] = []
|
||||
return super(account_analytic_account, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
|
||||
def on_change_parent(self, cr, uid, id, parent_id):
|
||||
if not parent_id:
|
||||
return {}
|
||||
parent = self.read(cr, uid, [parent_id], ['partner_id','code'])[0]
|
||||
childs = self.search(cr, uid, [('parent_id', '=', parent_id), ('active', 'in', [True, False])])
|
||||
numchild = len(childs)
|
||||
if parent['partner_id']:
|
||||
partner = parent['partner_id'][0]
|
||||
else:
|
||||
partner = False
|
||||
res = {'value' : {'code' : '%s - %03d' % (parent['code'] or '', numchild + 1),}}
|
||||
if partner:
|
||||
res['value']['partner_id'] = partner
|
||||
return res
|
||||
|
||||
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
|
||||
if not args:
|
||||
args=[]
|
||||
if not context:
|
||||
context={}
|
||||
account = self.search(cr, uid, [('code', '=', name)]+args, limit=limit, context=context)
|
||||
if not account:
|
||||
account = self.search(cr, uid, [('name', 'ilike', '%%%s%%' % name)]+args, limit=limit, context=context)
|
||||
newacc = account
|
||||
while newacc:
|
||||
newacc = self.search(cr, uid, [('parent_id', 'in', newacc)]+args, limit=limit, context=context)
|
||||
account+=newacc
|
||||
return self.name_get(cr, uid, account, context=context)
|
||||
|
||||
account_analytic_account()
|
|
@ -0,0 +1,3 @@
|
|||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_account_analytic_account_manager","account.analytic.account","model_account_analytic_account","project.group_project_user",1,1,1,1
|
||||
"access_account_analytic_account","account.analytic.account","model_account_analytic_account","project.group_project_user",1,0,0,0
|
|
|
@ -36,7 +36,7 @@ This module implements a dashboard for project member that includes:
|
|||
'project',
|
||||
'report_timesheet',
|
||||
'board',
|
||||
'report_analytic_planning',
|
||||
'project_planning',
|
||||
'report_analytic_line',
|
||||
'report_task',
|
||||
'hr_timesheet_sheet',
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
<button colspan="4" icon="terp-partner" name="%(open_board_project)d" string="My tasks board" type="action"/>
|
||||
|
||||
|
||||
<action colspan="4" name="%(report_analytic_planning.action_account_analytic_planning_stat_form)d" string="My Project's planning" domain="[('manager_id','=',uid),('planning_id.state','<>','cancel')]"/>
|
||||
<action colspan="4" name="%(project_planning.action_account_analytic_planning_stat_form)d" string="My Project's planning" domain="[('manager_id','=',uid),('planning_id.state','<>','cancel')]"/>
|
||||
|
||||
<action colspan="4" name="%(action_project_pipeline_user)d" string="My user's pipeline"/>
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"author" : "Tiny",
|
||||
"website" : "http://www.openerp.com",
|
||||
"category" : "Generic Modules/Projects & Services",
|
||||
"depends" : ["product", "account", "hr", "process", "mail_gateway"],
|
||||
"depends" : ["product", "analytic", "hr", "process", "mail_gateway"],
|
||||
"description": """Project management module that track multi-level projects, tasks,
|
||||
works done on tasks, eso. It is able to render planning, order tasks, eso.
|
||||
""",
|
||||
|
|
|
@ -60,18 +60,6 @@
|
|||
<field eval="0" name="flow_start"/>
|
||||
</record>
|
||||
|
||||
<record id="process_node_triggerinvoice0" model="process.node">
|
||||
<field name="menu_id" ref="account.menu_finance_invoice"/>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field eval=""""subflow"""" name="kind"/>
|
||||
<field eval=""""Trigger Invoice"""" name="name"/>
|
||||
<field name="subflow_id" ref="account.process_process_invoiceprocess0"/>
|
||||
<field eval=""""Trigger invoices from sale order lines"""" name="note"/>
|
||||
<field name="process_id" ref="process_process_tasksprocess0"/>
|
||||
<field eval=""""object.state=='paid'"""" name="model_states"/>
|
||||
<field eval="0" name="flow_start"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Process Transition
|
||||
-->
|
||||
|
@ -103,14 +91,6 @@
|
|||
<field model="process.node" name="source_node_id" ref="process_node_opentask0"/>
|
||||
</record>
|
||||
|
||||
<record id="process_transition_taskinvoice0" model="process.transition">
|
||||
<field eval="[(6,0,[])]" name="role_ids"/>
|
||||
<field eval="[(6,0,[])]" name="transition_ids"/>
|
||||
<field eval=""""Task invoice"""" name="name"/>
|
||||
<field eval=""""After task is completed, Create its invoice."""" name="note"/>
|
||||
<field model="process.node" name="target_node_id" ref="process_node_triggerinvoice0"/>
|
||||
<field model="process.node" name="source_node_id" ref="process_node_donetask0"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Process Action
|
||||
|
|
|
@ -546,10 +546,9 @@ def _project_get(self, cr, uid, context={}):
|
|||
else:
|
||||
cr.execute("""SELECT project.id,account.name FROM project_project project
|
||||
LEFT JOIN account_analytic_account account ON account.id = project.category_id
|
||||
WHERE (account.user_id = %s) OR project.id IN (SELECT project_id FROM project_resource_rel
|
||||
WHERE resource_id IN (SELECT id FROM resource_resource
|
||||
WHERE (user_id= %s)))"""%(uid, uid))
|
||||
WHERE (account.user_id = %s)"""%(uid))
|
||||
res = cr.fetchall()
|
||||
print res
|
||||
res = [(str(r[0]),r[1]) for r in res]
|
||||
return res
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_project_project_manager","project.project manager","model_project_project","project.group_project_manager",1,1,1,1
|
||||
"access_account_analytic_account_manager","account.analytic.account","account.model_account_analytic_account","project.group_project_user",1,1,1,1
|
||||
"access_account_analytic_account_manager","account.analytic.account","analytic.model_account_analytic_account","project.group_project_user",1,1,1,1
|
||||
"access_project_project","project.project","model_project_project","project.group_project_user",1,0,0,0
|
||||
"access_account_analytic_account","account.analytic.account","account.model_account_analytic_account","project.group_project_user",1,0,0,0
|
||||
"access_account_analytic_account","account.analytic.account","analytic.model_account_analytic_account","project.group_project_user",1,0,0,0
|
||||
"access_project_task_type_user","project.task.type user","model_project_task_type","project.group_project_user",1,0,0,1
|
||||
"access_project_task_type","project.task.type","model_project_task_type","project.group_project_manager",1,1,1,1
|
||||
"access_project_task_manager","project.task manager","model_project_task","project.group_project_manager",1,1,1,1
|
||||
|
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import report_analytic_planning
|
||||
import project_planning
|
||||
import report
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -46,12 +46,12 @@ At the end of the month, the planning manager can also check if the encoded time
|
|||
'init_xml': [],
|
||||
'update_xml': [
|
||||
'security/ir.model.access.csv',
|
||||
'report_analytic_planning_view.xml',
|
||||
'report_analytic_planning_report.xml'
|
||||
'project_planning_view.xml',
|
||||
'project_planning_report.xml'
|
||||
],
|
||||
'demo_xml': [
|
||||
#'report_account_analytic.planning.csv',
|
||||
'report_analytic_planning_demo.xml',
|
||||
'project_planning_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<report id="report_planning" model="report_account_analytic.planning" name="report_account_analytic.planning.print" rml="report_analytic_planning/report/report_planning.rml" string="Planning"/>
|
||||
<report id="report_planning" model="report_account_analytic.planning" name="report_account_analytic.planning.print" rml="project_planning/report/report_planning.rml" string="Planning"/>
|
||||
</data>
|
||||
</openerp>
|
|
@ -27,6 +27,19 @@
|
|||
<field eval="1" name="flow_start"/>
|
||||
</record>
|
||||
|
||||
<record id="process_node_triggerinvoice0" model="process.node">
|
||||
<field name="menu_id" ref="account.menu_finance_invoice"/>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field eval=""""subflow"""" name="kind"/>
|
||||
<field eval=""""Trigger Invoice"""" name="name"/>
|
||||
<field name="subflow_id" ref="account.process_process_invoiceprocess0"/>
|
||||
<field eval=""""Trigger invoices from sale order lines"""" name="note"/>
|
||||
<field name="process_id" ref="process_process_tasksprocess0"/>
|
||||
<field eval=""""object.state=='paid'"""" name="model_states"/>
|
||||
<field eval="0" name="flow_start"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
Process Transition
|
||||
-->
|
||||
|
@ -49,5 +62,16 @@
|
|||
<field model="process.node" name="source_node_id" ref="process_node_taskwork0"/>
|
||||
</record>
|
||||
|
||||
<record id="process_transition_taskinvoice0" model="process.transition">
|
||||
<field eval="[(6,0,[])]" name="role_ids"/>
|
||||
<field eval="[(6,0,[])]" name="transition_ids"/>
|
||||
<field eval=""""Task invoice"""" name="name"/>
|
||||
<field eval=""""After task is completed, Create its invoice."""" name="note"/>
|
||||
<field model="process.node" name="target_node_id" ref="process_node_triggerinvoice0"/>
|
||||
<field model="process.node" name="source_node_id" ref="project.process_node_donetask0"/>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
Loading…
Reference in New Issue