@@ -202,19 +214,6 @@
-
-
-
-
- Description |
- Taxes |
- Quantity |
- Unit Price |
- Disc.(%) |
- Price |
-
-
-
@@ -262,7 +261,6 @@
|
-
@@ -297,7 +295,7 @@
|
- Total:
+ Total:
|
[[ formatLang(o.amount_total, digits=get_digits(dp='Account'), currency_obj=o.currency_id) ]]
@@ -370,5 +368,6 @@
+
diff --git a/addons/account/report/account_print_overdue.py b/addons/account/report/account_print_overdue.py
index 68c1c35ef5323..cd3c39b964722 100644
--- a/addons/account/report/account_print_overdue.py
+++ b/addons/account/report/account_print_overdue.py
@@ -1,70 +1,63 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-
-from openerp.report import report_sxw
-from openerp import pooler
-
-class Overdue(report_sxw.rml_parse):
- def __init__(self, cr, uid, name, context):
- super(Overdue, self).__init__(cr, uid, name, context=context)
- self.localcontext.update( {
- 'time': time,
- 'getLines': self._lines_get,
- 'tel_get': self._tel_get,
- 'message': self._message,
- })
- self.context = context
-
- def _tel_get(self,partner):
- if not partner:
- return False
- res_partner = pooler.get_pool(self.cr.dbname).get('res.partner')
- addresses = res_partner.address_get(self.cr, self.uid, [partner.id], ['invoice'])
- adr_id = addresses and addresses['invoice'] or False
- if adr_id:
- adr=res_partner_address.read(self.cr, self.uid, [adr_id])[0]
- return adr['phone']
- else:
- return partner.phone or False
- return False
-
- def _lines_get(self, partner):
- moveline_obj = pooler.get_pool(self.cr.dbname).get('account.move.line')
- movelines = moveline_obj.search(self.cr, self.uid,
- [('partner_id', '=', partner.id),
- ('account_id.type', 'in', ['receivable', 'payable']),
- ('state', '<>', 'draft'), ('reconcile_id', '=', False)])
- movelines = moveline_obj.browse(self.cr, self.uid, movelines)
- return movelines
-
- def _message(self, obj, company):
- company_pool = pooler.get_pool(self.cr.dbname).get('res.company')
- message = company_pool.browse(self.cr, self.uid, company.id, {'lang':obj.lang}).overdue_msg
- return message.split('\n')
-
-report_sxw.report_sxw('report.account.overdue', 'res.partner',
- 'addons/account/report/account_print_overdue.rml', parser=Overdue)
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.report import report_sxw
+from openerp import pooler
+
+class Overdue(report_sxw.rml_parse):
+
+ def __init__(self, cr, uid, name, context):
+ super(Overdue, self).__init__(cr, uid, name, context=context)
+ self.localcontext.update({'time': time,
+ 'getLines': self._lines_get,
+ 'tel_get': self._tel_get,
+ 'message': self._message})
+ self.context = context
+
+ def _tel_get(self, partner):
+ if not partner:
+ return False
+ res_partner = pooler.get_pool(self.cr.dbname).get('res.partner')
+ addresses = res_partner.address_get(self.cr, self.uid, [partner.id], ['invoice'])
+ adr_id = addresses and addresses['invoice'] or False
+ if adr_id:
+ adr = res_partner_address.read(self.cr, self.uid, [adr_id])[0]
+ return adr['phone']
+ else:
+ return partner.phone or False
+ return False
+
+ def _lines_get(self, partner):
+ moveline_obj = pooler.get_pool(self.cr.dbname).get('account.move.line')
+ movelines = moveline_obj.search(self.cr, self.uid, [('partner_id', '=', partner.id),
+ ('account_id.type', 'in', ['receivable', 'payable']),
+ ('state', '<>', 'draft'),
+ ('reconcile_id', '=', False)])
+ movelines = moveline_obj.browse(self.cr, self.uid, movelines)
+ return movelines
+
+ def _message(self, obj, company):
+ company_pool = pooler.get_pool(self.cr.dbname).get('res.company')
+ message = company_pool.browse(self.cr, self.uid, company.id, {'lang': obj.lang}).overdue_msg
+ return message.split('\n')
+
+
+report_sxw.report_sxw('report.account.overdue', 'res.partner', 'addons/account/report/account_print_overdue.rml', parser=Overdue)
\ No newline at end of file
diff --git a/addons/account/report/account_print_overdue.sxw b/addons/account/report/account_print_overdue.sxw
index 2faddc7606c54..0cf80e37645bd 100644
Binary files a/addons/account/report/account_print_overdue.sxw and b/addons/account/report/account_print_overdue.sxw differ
diff --git a/addons/account/report/account_report.py b/addons/account/report/account_report.py
index d6cc784c76734..55b310f11a5ba 100644
--- a/addons/account/report/account_report.py
+++ b/addons/account/report/account_report.py
@@ -1,289 +1,218 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-from datetime import datetime
-from dateutil.relativedelta import relativedelta
-
-from openerp import pooler
-from openerp import tools
-from openerp.osv import fields,osv
-
-def _code_get(self, cr, uid, context=None):
- acc_type_obj = self.pool.get('account.account.type')
- ids = acc_type_obj.search(cr, uid, [])
- res = acc_type_obj.read(cr, uid, ids, ['code', 'name'], context)
- return [(r['code'], r['name']) for r in res]
-
-
-class report_account_receivable(osv.osv):
- _name = "report.account.receivable"
- _description = "Receivable accounts"
- _auto = False
- _columns = {
- 'name': fields.char('Week of Year', size=7, readonly=True),
- 'type': fields.selection(_code_get, 'Account Type', required=True),
- 'balance':fields.float('Balance', readonly=True),
- 'debit':fields.float('Debit', readonly=True),
- 'credit':fields.float('Credit', readonly=True),
- }
- _order = 'name desc'
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'report_account_receivable')
- cr.execute("""
- create or replace view report_account_receivable as (
- select
- min(l.id) as id,
- to_char(date,'YYYY:IW') as name,
- sum(l.debit-l.credit) as balance,
- sum(l.debit) as debit,
- sum(l.credit) as credit,
- a.type
- from
- account_move_line l
- left join
- account_account a on (l.account_id=a.id)
- where
- l.state <> 'draft'
- group by
- to_char(date,'YYYY:IW'), a.type
- )""")
-report_account_receivable()
-
- #a.type in ('receivable','payable')
-class temp_range(osv.osv):
- _name = 'temp.range'
- _description = 'A Temporary table used for Dashboard view'
-
- _columns = {
- 'name': fields.char('Range',size=64)
- }
-
-temp_range()
-
-class report_aged_receivable(osv.osv):
- _name = "report.aged.receivable"
- _description = "Aged Receivable Till Today"
- _auto = False
-
- def __init__(self, pool, cr):
- super(report_aged_receivable, self).__init__(pool, cr)
- self.called = False
-
- def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- """ To call the init() method timely
- """
- if context is None:context = {}
- if not self.called:
- self.init(cr, user)
- self.called = True # To make sure that init doesn't get called multiple times
-
- res = super(report_aged_receivable, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
- return res
-
- def _calc_bal(self, cr, uid, ids, name, args, context=None):
- res = {}
- for period in self.read(cr, uid, ids, ['name'], context=context):
- date1,date2 = period['name'].split(' to ')
- cr.execute("SELECT SUM(credit-debit) FROM account_move_line AS line, account_account as ac \
- WHERE (line.account_id=ac.id) AND ac.type='receivable' \
- AND (COALESCE(line.date,date) BETWEEN %s AND %s) \
- AND (reconcile_id IS NULL) AND ac.active",(str(date2),str(date1),))
- amount = cr.fetchone()
- amount = amount[0] or 0.00
- res[period['id']] = amount
-
- return res
-
- _columns = {
- 'name': fields.char('Month Range', size=7, readonly=True),
- 'balance': fields.function(_calc_bal, string='Balance', readonly=True),
- }
-
- def init(self, cr, uid=1):
- """ This view will be used in dashboard
- The reason writing this code here is, we need to check date range from today to first date of fiscal year.
- """
- pool_obj_fy = pooler.get_pool(cr.dbname).get('account.fiscalyear')
- today = time.strftime('%Y-%m-%d')
- fy_id = pool_obj_fy.find(cr, uid, exception=False)
- LIST_RANGES = []
- if fy_id:
- fy_start_date = pool_obj_fy.read(cr, uid, fy_id, ['date_start'])['date_start']
- fy_start_date = datetime.strptime(fy_start_date, '%Y-%m-%d')
- last_month_date = datetime.strptime(today, '%Y-%m-%d') - relativedelta(months=1)
-
- while (last_month_date > fy_start_date):
- LIST_RANGES.append(today + " to " + last_month_date.strftime('%Y-%m-%d'))
- today = (last_month_date- relativedelta(days=1)).strftime('%Y-%m-%d')
- last_month_date = datetime.strptime(today, '%Y-%m-%d') - relativedelta(months=1)
-
- LIST_RANGES.append(today +" to " + fy_start_date.strftime('%Y-%m-%d'))
- cr.execute('delete from temp_range')
-
- for range in LIST_RANGES:
- pooler.get_pool(cr.dbname).get('temp.range').create(cr, uid, {'name':range})
-
- cr.execute("""
- create or replace view report_aged_receivable as (
- select id,name from temp_range
- )""")
-
-report_aged_receivable()
-
-class report_invoice_created(osv.osv):
- _name = "report.invoice.created"
- _description = "Report of Invoices Created within Last 15 days"
- _auto = False
- _columns = {
- 'name': fields.char('Description', size=64, readonly=True),
- 'type': fields.selection([
- ('out_invoice','Customer Invoice'),
- ('in_invoice','Supplier Invoice'),
- ('out_refund','Customer Refund'),
- ('in_refund','Supplier Refund'),
- ],'Type', readonly=True),
- 'number': fields.char('Invoice Number', size=32, readonly=True),
- 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
- 'amount_untaxed': fields.float('Untaxed', readonly=True),
- 'amount_total': fields.float('Total', readonly=True),
- 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
- 'date_invoice': fields.date('Invoice Date', readonly=True),
- 'date_due': fields.date('Due Date', readonly=True),
- 'residual': fields.float('Residual', readonly=True),
- 'state': fields.selection([
- ('draft','Draft'),
- ('proforma','Pro-forma'),
- ('proforma2','Pro-forma'),
- ('open','Open'),
- ('paid','Done'),
- ('cancel','Cancelled')
- ],'Status', readonly=True),
- 'origin': fields.char('Source Document', size=64, readonly=True, help="Reference of the document that generated this invoice report."),
- 'create_date': fields.datetime('Create Date', readonly=True)
- }
- _order = 'create_date'
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'report_invoice_created')
- cr.execute("""create or replace view report_invoice_created as (
- select
- inv.id as id, inv.name as name, inv.type as type,
- inv.number as number, inv.partner_id as partner_id,
- inv.amount_untaxed as amount_untaxed,
- inv.amount_total as amount_total, inv.currency_id as currency_id,
- inv.date_invoice as date_invoice, inv.date_due as date_due,
- inv.residual as residual, inv.state as state,
- inv.origin as origin, inv.create_date as create_date
- from
- account_invoice inv
- where
- (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') <= CURRENT_DATE)
- AND
- (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') > (CURRENT_DATE-15))
- )""")
-report_invoice_created()
-
-class report_account_type_sales(osv.osv):
- _name = "report.account_type.sales"
- _description = "Report of the Sales by Account Type"
- _auto = False
- _columns = {
- 'name': fields.char('Year', size=64, required=False, readonly=True),
- 'period_id': fields.many2one('account.period', 'Force Period', readonly=True),
- 'product_id': fields.many2one('product.product', 'Product', readonly=True),
- 'quantity': fields.float('Quantity', readonly=True),
- 'user_type': fields.many2one('account.account.type', 'Account Type', readonly=True),
- 'amount_total': fields.float('Total', readonly=True),
- 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
- 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'),
- ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
- }
- _order = 'name desc,amount_total desc'
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'report_account_type_sales')
- cr.execute("""create or replace view report_account_type_sales as (
- select
- min(inv_line.id) as id,
- to_char(inv.date_invoice, 'YYYY') as name,
- to_char(inv.date_invoice,'MM') as month,
- sum(inv_line.price_subtotal) as amount_total,
- inv.currency_id as currency_id,
- inv.period_id,
- inv_line.product_id,
- sum(inv_line.quantity) as quantity,
- account.user_type
- from
- account_invoice_line inv_line
- inner join account_invoice inv on inv.id = inv_line.invoice_id
- inner join account_account account on account.id = inv_line.account_id
- where
- inv.state in ('open','paid')
- group by
- to_char(inv.date_invoice, 'YYYY'),to_char(inv.date_invoice,'MM'),inv.currency_id, inv.period_id, inv_line.product_id, account.user_type
- )""")
-report_account_type_sales()
-
-
-class report_account_sales(osv.osv):
- _name = "report.account.sales"
- _description = "Report of the Sales by Account"
- _auto = False
- _columns = {
- 'name': fields.char('Year', size=64, required=False, readonly=True, select=True),
- 'period_id': fields.many2one('account.period', 'Force Period', readonly=True),
- 'product_id': fields.many2one('product.product', 'Product', readonly=True),
- 'quantity': fields.float('Quantity', readonly=True),
- 'account_id': fields.many2one('account.account', 'Account', readonly=True),
- 'amount_total': fields.float('Total', readonly=True),
- 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
- 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'),
- ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
- }
- _order = 'name desc'
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'report_account_sales')
- cr.execute("""create or replace view report_account_sales as (
- select
- min(inv_line.id) as id,
- to_char(inv.date_invoice, 'YYYY') as name,
- to_char(inv.date_invoice,'MM') as month,
- sum(inv_line.price_subtotal) as amount_total,
- inv.currency_id as currency_id,
- inv.period_id,
- inv_line.product_id,
- sum(inv_line.quantity) as quantity,
- account.id as account_id
- from
- account_invoice_line inv_line
- inner join account_invoice inv on inv.id = inv_line.invoice_id
- inner join account_account account on account.id = inv_line.account_id
- where
- inv.state in ('open','paid')
- group by
- to_char(inv.date_invoice, 'YYYY'),to_char(inv.date_invoice,'MM'),inv.currency_id, inv.period_id, inv_line.product_id, account.id
- )""")
-report_account_sales()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+from openerp import pooler
+from openerp import tools
+from openerp.osv import fields, osv
+
+def _code_get(self, cr, uid, context = None):
+ acc_type_obj = self.pool.get('account.account.type')
+ ids = acc_type_obj.search(cr, uid, [])
+ res = acc_type_obj.read(cr, uid, ids, ['code', 'name'], context)
+ return [ (r['code'], r['name']) for r in res ]
+
+
+class report_account_receivable(osv.osv):
+ _name = 'report.account.receivable'
+ _description = 'Receivable accounts'
+ _auto = False
+ _columns = {'name': fields.char('Week of Year', size=7, readonly=True),
+ 'type': fields.selection(_code_get, 'Account Type', required=True),
+ 'balance': fields.float('Balance', readonly=True),
+ 'debit': fields.float('Debit', readonly=True),
+ 'credit': fields.float('Credit', readonly=True)}
+ _order = 'name desc'
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'report_account_receivable')
+ cr.execute("\n create or replace view report_account_receivable as (\n select\n min(l.id) as id,\n to_char(date,'YYYY:IW') as name,\n sum(l.debit-l.credit) as balance,\n sum(l.debit) as debit,\n sum(l.credit) as credit,\n a.type\n from\n account_move_line l\n left join\n account_account a on (l.account_id=a.id)\n where\n l.state <> 'draft'\n group by\n to_char(date,'YYYY:IW'), a.type\n )")
+
+
+report_account_receivable()
+
+class temp_range(osv.osv):
+ _name = 'temp.range'
+ _description = 'A Temporary table used for Dashboard view'
+ _columns = {'name': fields.char('Range', size=64)}
+
+
+temp_range()
+
+class report_aged_receivable(osv.osv):
+ _name = 'report.aged.receivable'
+ _description = 'Aged Receivable Till Today'
+ _auto = False
+
+ def __init__(self, pool, cr):
+ super(report_aged_receivable, self).__init__(pool, cr)
+ self.called = False
+
+ def fields_view_get(self, cr, user, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ """ To call the init() method timely
+ """
+ if context is None:
+ context = {}
+ if not self.called:
+ self.init(cr, user)
+ self.called = True
+ res = super(report_aged_receivable, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
+ return res
+
+ def _calc_bal(self, cr, uid, ids, name, args, context = None):
+ res = {}
+ for period in self.read(cr, uid, ids, ['name'], context=context):
+ date1, date2 = period['name'].split(' to ')
+ cr.execute("SELECT SUM(credit-debit) FROM account_move_line AS line, account_account as ac WHERE (line.account_id=ac.id) AND ac.type='receivable' AND (COALESCE(line.date,date) BETWEEN %s AND %s) AND (reconcile_id IS NULL) AND ac.active", (str(date2), str(date1)))
+ amount = cr.fetchone()
+ amount = amount[0] or 0.0
+ res[period['id']] = amount
+
+ return res
+
+ _columns = {'name': fields.char('Month Range', size=7, readonly=True),
+ 'balance': fields.function(_calc_bal, string='Balance', readonly=True)}
+
+ def init(self, cr, uid = 1):
+ """ This view will be used in dashboard
+ The reason writing this code here is, we need to check date range from today to first date of fiscal year.
+ """
+ pool_obj_fy = pooler.get_pool(cr.dbname).get('account.fiscalyear')
+ today = time.strftime('%Y-%m-%d')
+ fy_id = pool_obj_fy.find(cr, uid, exception=False)
+ LIST_RANGES = []
+ if fy_id:
+ fy_start_date = pool_obj_fy.read(cr, uid, fy_id, ['date_start'])['date_start']
+ fy_start_date = datetime.strptime(fy_start_date, '%Y-%m-%d')
+ last_month_date = datetime.strptime(today, '%Y-%m-%d') - relativedelta(months=1)
+ while last_month_date > fy_start_date:
+ LIST_RANGES.append(today + ' to ' + last_month_date.strftime('%Y-%m-%d'))
+ today = (last_month_date - relativedelta(days=1)).strftime('%Y-%m-%d')
+ last_month_date = datetime.strptime(today, '%Y-%m-%d') - relativedelta(months=1)
+
+ LIST_RANGES.append(today + ' to ' + fy_start_date.strftime('%Y-%m-%d'))
+ cr.execute('delete from temp_range')
+ for range in LIST_RANGES:
+ pooler.get_pool(cr.dbname).get('temp.range').create(cr, uid, {'name': range})
+
+ cr.execute('\n create or replace view report_aged_receivable as (\n select id,name from temp_range\n )')
+
+
+report_aged_receivable()
+
+class report_invoice_created(osv.osv):
+ _name = 'report.invoice.created'
+ _description = 'Report of Invoices Created within Last 15 days'
+ _auto = False
+ _columns = {'name': fields.char('Description', size=64, readonly=True),
+ 'type': fields.selection([('out_invoice', 'Customer Invoice'),
+ ('in_invoice', 'Supplier Invoice'),
+ ('out_refund', 'Customer Refund'),
+ ('in_refund', 'Supplier Refund')], 'Type', readonly=True),
+ 'number': fields.char('Invoice Number', size=32, readonly=True),
+ 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
+ 'amount_untaxed': fields.float('Untaxed', readonly=True),
+ 'amount_total': fields.float('Total', readonly=True),
+ 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
+ 'date_invoice': fields.date('Invoice Date', readonly=True),
+ 'date_due': fields.date('Due Date', readonly=True),
+ 'residual': fields.float('Residual', readonly=True),
+ 'state': fields.selection([('draft', 'Draft'),
+ ('proforma', 'Pro-forma'),
+ ('proforma2', 'Pro-forma'),
+ ('open', 'Open'),
+ ('paid', 'Done'),
+ ('cancel', 'Cancelled')], 'Status', readonly=True),
+ 'origin': fields.char('Source Document', size=64, readonly=True, help='Reference of the document that generated this invoice report.'),
+ 'create_date': fields.datetime('Create Date', readonly=True)}
+ _order = 'create_date'
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'report_invoice_created')
+ cr.execute("create or replace view report_invoice_created as (\n select\n inv.id as id, inv.name as name, inv.type as type,\n inv.number as number, inv.partner_id as partner_id,\n inv.amount_untaxed as amount_untaxed,\n inv.amount_total as amount_total, inv.currency_id as currency_id,\n inv.date_invoice as date_invoice, inv.date_due as date_due,\n inv.residual as residual, inv.state as state,\n inv.origin as origin, inv.create_date as create_date\n from\n account_invoice inv\n where\n (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') <= CURRENT_DATE)\n AND\n (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') > (CURRENT_DATE-15))\n )")
+
+
+report_invoice_created()
+
+class report_account_type_sales(osv.osv):
+ _name = 'report.account_type.sales'
+ _description = 'Report of the Sales by Account Type'
+ _auto = False
+ _columns = {'name': fields.char('Year', size=64, required=False, readonly=True),
+ 'period_id': fields.many2one('account.period', 'Force Period', readonly=True),
+ 'product_id': fields.many2one('product.product', 'Product', readonly=True),
+ 'quantity': fields.float('Quantity', readonly=True),
+ 'user_type': fields.many2one('account.account.type', 'Account Type', readonly=True),
+ 'amount_total': fields.float('Total', readonly=True),
+ 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
+ 'month': fields.selection([('01', 'January'),
+ ('02', 'February'),
+ ('03', 'March'),
+ ('04', 'April'),
+ ('05', 'May'),
+ ('06', 'June'),
+ ('07', 'July'),
+ ('08', 'August'),
+ ('09', 'September'),
+ ('10', 'October'),
+ ('11', 'November'),
+ ('12', 'December')], 'Month', readonly=True)}
+ _order = 'name desc,amount_total desc'
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'report_account_type_sales')
+ cr.execute("create or replace view report_account_type_sales as (\n select\n min(inv_line.id) as id,\n to_char(inv.date_invoice, 'YYYY') as name,\n to_char(inv.date_invoice,'MM') as month,\n sum(inv_line.price_subtotal) as amount_total,\n inv.currency_id as currency_id,\n inv.period_id,\n inv_line.product_id,\n sum(inv_line.quantity) as quantity,\n account.user_type\n from\n account_invoice_line inv_line\n inner join account_invoice inv on inv.id = inv_line.invoice_id\n inner join account_account account on account.id = inv_line.account_id\n where\n inv.state in ('open','paid')\n group by\n to_char(inv.date_invoice, 'YYYY'),to_char(inv.date_invoice,'MM'),inv.currency_id, inv.period_id, inv_line.product_id, account.user_type\n )")
+
+
+report_account_type_sales()
+
+class report_account_sales(osv.osv):
+ _name = 'report.account.sales'
+ _description = 'Report of the Sales by Account'
+ _auto = False
+ _columns = {'name': fields.char('Year', size=64, required=False, readonly=True, select=True),
+ 'period_id': fields.many2one('account.period', 'Force Period', readonly=True),
+ 'product_id': fields.many2one('product.product', 'Product', readonly=True),
+ 'quantity': fields.float('Quantity', readonly=True),
+ 'account_id': fields.many2one('account.account', 'Account', readonly=True),
+ 'amount_total': fields.float('Total', readonly=True),
+ 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
+ 'month': fields.selection([('01', 'January'),
+ ('02', 'February'),
+ ('03', 'March'),
+ ('04', 'April'),
+ ('05', 'May'),
+ ('06', 'June'),
+ ('07', 'July'),
+ ('08', 'August'),
+ ('09', 'September'),
+ ('10', 'October'),
+ ('11', 'November'),
+ ('12', 'December')], 'Month', readonly=True)}
+ _order = 'name desc'
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'report_account_sales')
+ cr.execute("create or replace view report_account_sales as (\n select\n min(inv_line.id) as id,\n to_char(inv.date_invoice, 'YYYY') as name,\n to_char(inv.date_invoice,'MM') as month,\n sum(inv_line.price_subtotal) as amount_total,\n inv.currency_id as currency_id,\n inv.period_id,\n inv_line.product_id,\n sum(inv_line.quantity) as quantity,\n account.id as account_id\n from\n account_invoice_line inv_line\n inner join account_invoice inv on inv.id = inv_line.invoice_id\n inner join account_account account on account.id = inv_line.account_id\n where\n inv.state in ('open','paid')\n group by\n to_char(inv.date_invoice, 'YYYY'),to_char(inv.date_invoice,'MM'),inv.currency_id, inv.period_id, inv_line.product_id, account.id\n )")
+
+
+report_account_sales()
\ No newline at end of file
diff --git a/addons/account/report/account_tax_report.py b/addons/account/report/account_tax_report.py
index 91b1514ba2a7f..429111abf6fc0 100644
--- a/addons/account/report/account_tax_report.py
+++ b/addons/account/report/account_tax_report.py
@@ -1,242 +1,191 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-
-from common_report_header import common_report_header
-from openerp.report import report_sxw
-
-class tax_report(report_sxw.rml_parse, common_report_header):
- _name = 'report.account.vat.declaration'
-
- def set_context(self, objects, data, ids, report_type=None):
- new_ids = ids
- res = {}
- self.period_ids = []
- period_obj = self.pool.get('account.period')
- self.display_detail = data['form']['display_detail']
- res['periods'] = ''
- res['fiscalyear'] = data['form'].get('fiscalyear_id', False)
-
- if data['form'].get('period_from', False) and data['form'].get('period_to', False):
- self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to'])
- periods_l = period_obj.read(self.cr, self.uid, self.period_ids, ['name'])
- for period in periods_l:
- if res['periods'] == '':
- res['periods'] = period['name']
- else:
- res['periods'] += ", "+ period['name']
- return super(tax_report, self).set_context(objects, data, new_ids, report_type=report_type)
-
- def __init__(self, cr, uid, name, context=None):
- super(tax_report, self).__init__(cr, uid, name, context=context)
- self.localcontext.update({
- 'time': time,
- 'get_codes': self._get_codes,
- 'get_general': self._get_general,
- 'get_currency': self._get_currency,
- 'get_lines': self._get_lines,
- 'get_fiscalyear': self._get_fiscalyear,
- 'get_account': self._get_account,
- 'get_start_period': self.get_start_period,
- 'get_end_period': self.get_end_period,
- 'get_basedon': self._get_basedon,
- })
-
- def _get_basedon(self, form):
- return form['form']['based_on']
-
- def _get_lines(self, based_on, company_id=False, parent=False, level=0, context=None):
- period_list = self.period_ids
- res = self._get_codes(based_on, company_id, parent, level, period_list, context=context)
- if period_list:
- res = self._add_codes(based_on, res, period_list, context=context)
- else:
- self.cr.execute ("select id from account_fiscalyear")
- fy = self.cr.fetchall()
- self.cr.execute ("select id from account_period where fiscalyear_id = %s",(fy[0][0],))
- periods = self.cr.fetchall()
- for p in periods:
- period_list.append(p[0])
- res = self._add_codes(based_on, res, period_list, context=context)
-
- i = 0
- top_result = []
- while i < len(res):
-
- res_dict = { 'code': res[i][1].code,
- 'name': res[i][1].name,
- 'debit': 0,
- 'credit': 0,
- 'tax_amount': res[i][1].sum_period,
- 'type': 1,
- 'level': res[i][0],
- 'pos': 0
- }
-
- top_result.append(res_dict)
- res_general = self._get_general(res[i][1].id, period_list, company_id, based_on, context=context)
- ind_general = 0
- while ind_general < len(res_general):
- res_general[ind_general]['type'] = 2
- res_general[ind_general]['pos'] = 0
- res_general[ind_general]['level'] = res_dict['level']
- top_result.append(res_general[ind_general])
- ind_general+=1
- i+=1
- return top_result
-
- def _get_general(self, tax_code_id, period_list, company_id, based_on, context=None):
- if not self.display_detail:
- return []
- res = []
- obj_account = self.pool.get('account.account')
- periods_ids = tuple(period_list)
- if based_on == 'payments':
- self.cr.execute('SELECT SUM(line.tax_amount) AS tax_amount, \
- SUM(line.debit) AS debit, \
- SUM(line.credit) AS credit, \
- COUNT(*) AS count, \
- account.id AS account_id, \
- account.name AS name, \
- account.code AS code \
- FROM account_move_line AS line, \
- account_account AS account, \
- account_move AS move \
- LEFT JOIN account_invoice invoice ON \
- (invoice.move_id = move.id) \
- WHERE line.state<>%s \
- AND line.tax_code_id = %s \
- AND line.account_id = account.id \
- AND account.company_id = %s \
- AND move.id = line.move_id \
- AND line.period_id IN %s \
- AND ((invoice.state = %s) \
- OR (invoice.id IS NULL)) \
- GROUP BY account.id,account.name,account.code', ('draft', tax_code_id,
- company_id, periods_ids, 'paid',))
-
- else:
- self.cr.execute('SELECT SUM(line.tax_amount) AS tax_amount, \
- SUM(line.debit) AS debit, \
- SUM(line.credit) AS credit, \
- COUNT(*) AS count, \
- account.id AS account_id, \
- account.name AS name, \
- account.code AS code \
- FROM account_move_line AS line, \
- account_account AS account, \
- account_move as move \
- WHERE line.state <> %s \
- AND line.move_id = move.id \
- AND line.tax_code_id = %s \
- AND line.account_id = account.id \
- AND account.company_id = %s \
- AND line.period_id IN %s\
- AND account.active \
- AND move.state <> %s \
- GROUP BY account.id,account.name,account.code', ('draft', tax_code_id,
- company_id, periods_ids, 'draft',))
- res = self.cr.dictfetchall()
-
- i = 0
- while i= int(accounts[bcl_rup_ind]['level']) and bcl_rup_ind >= 0 ):
- res_tot = { 'code': accounts[bcl_rup_ind]['code'],
- 'name': '',
- 'debit': 0,
- 'credit': 0,
- 'tax_amount': accounts[bcl_rup_ind]['tax_amount'],
- 'type': accounts[bcl_rup_ind]['type'],
- 'level': 0,
- 'pos': 0
- }
-
- if res_tot['type'] == 1:
- # on change le type pour afficher le total
- res_tot['type'] = 2
- result_accounts.append(res_tot)
- bcl_current_level = accounts[bcl_rup_ind]['level']
- bcl_rup_ind -= 1
-
- old_level = account_elem['level']
- result_accounts.append(account_elem)
- ind+=1
-
- return result_accounts
-
-report_sxw.report_sxw('report.account.vat.declaration', 'account.tax.code',
- 'addons/account/report/account_tax_report.rml', parser=tax_report, header="internal")
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from common_report_header import common_report_header
+from openerp.report import report_sxw
+
+class tax_report(report_sxw.rml_parse, common_report_header):
+ _name = 'report.account.vat.declaration'
+
+ def set_context(self, objects, data, ids, report_type = None):
+ new_ids = ids
+ res = {}
+ self.period_ids = []
+ period_obj = self.pool.get('account.period')
+ self.display_detail = data['form']['display_detail']
+ res['periods'] = ''
+ res['fiscalyear'] = data['form'].get('fiscalyear_id', False)
+ if data['form'].get('period_from', False) and data['form'].get('period_to', False):
+ self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to'])
+ periods_l = period_obj.read(self.cr, self.uid, self.period_ids, ['name'])
+ for period in periods_l:
+ if res['periods'] == '':
+ res['periods'] = period['name']
+ else:
+ res['periods'] += ', ' + period['name']
+
+ return super(tax_report, self).set_context(objects, data, new_ids, report_type=report_type)
+
+ def __init__(self, cr, uid, name, context = None):
+ super(tax_report, self).__init__(cr, uid, name, context=context)
+ self.localcontext.update({'time': time,
+ 'get_codes': self._get_codes,
+ 'get_general': self._get_general,
+ 'get_currency': self._get_currency,
+ 'get_lines': self._get_lines,
+ 'get_fiscalyear': self._get_fiscalyear,
+ 'get_account': self._get_account,
+ 'get_start_period': self.get_start_period,
+ 'get_end_period': self.get_end_period,
+ 'get_basedon': self._get_basedon})
+
+ def _get_basedon(self, form):
+ return form['form']['based_on']
+
+ def _get_lines(self, based_on, company_id = False, parent = False, level = 0, context = None):
+ period_list = self.period_ids
+ res = self._get_codes(based_on, company_id, parent, level, period_list, context=context)
+ if period_list:
+ res = self._add_codes(based_on, res, period_list, context=context)
+ else:
+ self.cr.execute('select id from account_fiscalyear')
+ fy = self.cr.fetchall()
+ self.cr.execute('select id from account_period where fiscalyear_id = %s', (fy[0][0],))
+ periods = self.cr.fetchall()
+ for p in periods:
+ period_list.append(p[0])
+
+ res = self._add_codes(based_on, res, period_list, context=context)
+ i = 0
+ top_result = []
+ while i < len(res):
+ res_dict = {'code': res[i][1].code,
+ 'name': res[i][1].name,
+ 'debit': 0,
+ 'credit': 0,
+ 'tax_amount': res[i][1].sum_period,
+ 'type': 1,
+ 'level': res[i][0],
+ 'pos': 0}
+ top_result.append(res_dict)
+ res_general = self._get_general(res[i][1].id, period_list, company_id, based_on, context=context)
+ ind_general = 0
+ while ind_general < len(res_general):
+ res_general[ind_general]['type'] = 2
+ res_general[ind_general]['pos'] = 0
+ res_general[ind_general]['level'] = res_dict['level']
+ top_result.append(res_general[ind_general])
+ ind_general += 1
+
+ i += 1
+
+ return top_result
+
+ def _get_general(self, tax_code_id, period_list, company_id, based_on, context = None):
+ if not self.display_detail:
+ return []
+ res = []
+ obj_account = self.pool.get('account.account')
+ periods_ids = tuple(period_list)
+ if based_on == 'payments':
+ self.cr.execute('SELECT SUM(line.tax_amount) AS tax_amount, SUM(line.debit) AS debit, SUM(line.credit) AS credit, COUNT(*) AS count, account.id AS account_id, account.name AS name, account.code AS code FROM account_move_line AS line, account_account AS account, account_move AS move LEFT JOIN account_invoice invoice ON (invoice.move_id = move.id) WHERE line.state<>%s AND line.tax_code_id = %s AND line.account_id = account.id AND account.company_id = %s AND move.id = line.move_id AND line.period_id IN %s AND ((invoice.state = %s) OR (invoice.id IS NULL)) GROUP BY account.id,account.name,account.code', ('draft',
+ tax_code_id,
+ company_id,
+ periods_ids,
+ 'paid'))
+ else:
+ self.cr.execute('SELECT SUM(line.tax_amount) AS tax_amount, SUM(line.debit) AS debit, SUM(line.credit) AS credit, COUNT(*) AS count, account.id AS account_id, account.name AS name, account.code AS code FROM account_move_line AS line, account_account AS account WHERE line.state <> %s AND line.tax_code_id = %s AND line.account_id = account.id AND account.company_id = %s AND line.period_id IN %s AND account.active GROUP BY account.id,account.name,account.code', ('draft',
+ tax_code_id,
+ company_id,
+ periods_ids))
+ res = self.cr.dictfetchall()
+ i = 0
+ while i < len(res):
+ res[i]['account'] = obj_account.browse(self.cr, self.uid, res[i]['account_id'], context=context)
+ i += 1
+
+ return res
+
+ def _get_codes(self, based_on, company_id, parent = False, level = 0, period_list = None, context = None):
+ obj_tc = self.pool.get('account.tax.code')
+ ids = obj_tc.search(self.cr, self.uid, [('parent_id', '=', parent), ('company_id', '=', company_id)], order='sequence', context=context)
+ res = []
+ for code in obj_tc.browse(self.cr, self.uid, ids, {'based_on': based_on}):
+ res.append(('..' * level, code))
+ res += self._get_codes(based_on, company_id, code.id, level + 1, context=context)
+
+ return res
+
+ def _add_codes(self, based_on, account_list = None, period_list = None, context = None):
+ if account_list is None:
+ account_list = []
+ if period_list is None:
+ period_list = []
+ res = []
+ obj_tc = self.pool.get('account.tax.code')
+ for account in account_list:
+ ids = obj_tc.search(self.cr, self.uid, [('id', '=', account[1].id)], context=context)
+ sum_tax_add = 0
+ for period_ind in period_list:
+ for code in obj_tc.browse(self.cr, self.uid, ids, {'period_id': period_ind,
+ 'based_on': based_on}):
+ sum_tax_add = sum_tax_add + code.sum_period
+
+ code.sum_period = sum_tax_add
+ res.append((account[0], code))
+
+ return res
+
+ def _get_currency(self, form, context = None):
+ return self.pool.get('res.company').browse(self.cr, self.uid, form['company_id'], context=context).currency_id.name
+
+ def sort_result(self, accounts, context = None):
+ result_accounts = []
+ ind = 0
+ old_level = 0
+ while ind < len(accounts):
+ account_elem = accounts[ind]
+ if account_elem['level'] < old_level:
+ bcl_current_level = old_level
+ bcl_rup_ind = ind - 1
+ while bcl_current_level >= int(accounts[bcl_rup_ind]['level']) and bcl_rup_ind >= 0:
+ res_tot = {'code': accounts[bcl_rup_ind]['code'],
+ 'name': '',
+ 'debit': 0,
+ 'credit': 0,
+ 'tax_amount': accounts[bcl_rup_ind]['tax_amount'],
+ 'type': accounts[bcl_rup_ind]['type'],
+ 'level': 0,
+ 'pos': 0}
+ if res_tot['type'] == 1:
+ res_tot['type'] = 2
+ result_accounts.append(res_tot)
+ bcl_current_level = accounts[bcl_rup_ind]['level']
+ bcl_rup_ind -= 1
+
+ old_level = account_elem['level']
+ result_accounts.append(account_elem)
+ ind += 1
+
+ return result_accounts
+
+
+report_sxw.report_sxw('report.account.vat.declaration', 'account.tax.code', 'addons/account/report/account_tax_report.rml', parser=tax_report, header='internal')
\ No newline at end of file
diff --git a/addons/account/report/account_treasury_report.py b/addons/account/report/account_treasury_report.py
index 1ee411708c770..e1a9e460238e2 100644
--- a/addons/account/report/account_treasury_report.py
+++ b/addons/account/report/account_treasury_report.py
@@ -1,83 +1,58 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from openerp import tools
-from openerp.osv import fields,osv
-import openerp.addons.decimal_precision as dp
-
-class account_treasury_report(osv.osv):
- _name = "account.treasury.report"
- _description = "Treasury Analysis"
- _auto = False
-
- def _compute_balances(self, cr, uid, ids, field_names, arg=None, context=None,
- query='', query_params=()):
- all_treasury_lines = self.search(cr, uid, [], context=context)
- all_companies = self.pool.get('res.company').search(cr, uid, [], context=context)
- current_sum = dict((company, 0.0) for company in all_companies)
- res = dict((id, dict((fn, 0.0) for fn in field_names)) for id in all_treasury_lines)
- for record in self.browse(cr, uid, all_treasury_lines, context=context):
- res[record.id]['starting_balance'] = current_sum[record.company_id.id]
- current_sum[record.company_id.id] += record.balance
- res[record.id]['ending_balance'] = current_sum[record.company_id.id]
- return res
-
- _columns = {
- 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscalyear', readonly=True),
- 'period_id': fields.many2one('account.period', 'Period', readonly=True),
- 'debit': fields.float('Debit', readonly=True),
- 'credit': fields.float('Credit', readonly=True),
- 'balance': fields.float('Balance', readonly=True),
- 'date': fields.date('Beginning of Period Date', readonly=True),
- 'starting_balance': fields.function(_compute_balances, digits_compute=dp.get_precision('Account'), string='Starting Balance', multi='balance'),
- 'ending_balance': fields.function(_compute_balances, digits_compute=dp.get_precision('Account'), string='Ending Balance', multi='balance'),
- 'company_id': fields.many2one('res.company', 'Company', readonly=True),
- }
-
- _order = 'date asc'
-
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'account_treasury_report')
- cr.execute("""
- create or replace view account_treasury_report as (
- select
- p.id as id,
- p.fiscalyear_id as fiscalyear_id,
- p.id as period_id,
- sum(l.debit) as debit,
- sum(l.credit) as credit,
- sum(l.debit-l.credit) as balance,
- p.date_start as date,
- am.company_id as company_id
- from
- account_move_line l
- left join account_account a on (l.account_id = a.id)
- left join account_move am on (am.id=l.move_id)
- left join account_period p on (am.period_id=p.id)
- where l.state != 'draft'
- and a.type = 'liquidity'
- group by p.id, p.fiscalyear_id, p.date_start, am.company_id
- )
- """)
-account_treasury_report()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp import tools
+from openerp.osv import fields, osv
+import openerp.addons.decimal_precision as dp
+
+class account_treasury_report(osv.osv):
+ _name = 'account.treasury.report'
+ _description = 'Treasury Analysis'
+ _auto = False
+
+ def _compute_balances(self, cr, uid, ids, field_names, arg = None, context = None, query = '', query_params = ()):
+ all_treasury_lines = self.search(cr, uid, [], context=context)
+ all_companies = self.pool.get('res.company').search(cr, uid, [], context=context)
+ current_sum = dict(((company, 0.0) for company in all_companies))
+ res = dict(((id, dict(((fn, 0.0) for fn in field_names))) for id in all_treasury_lines))
+ for record in self.browse(cr, uid, all_treasury_lines, context=context):
+ res[record.id]['starting_balance'] = current_sum[record.company_id.id]
+ current_sum[record.company_id.id] += record.balance
+ res[record.id]['ending_balance'] = current_sum[record.company_id.id]
+
+ return res
+
+ _columns = {'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscalyear', readonly=True),
+ 'period_id': fields.many2one('account.period', 'Period', readonly=True),
+ 'debit': fields.float('Debit', readonly=True),
+ 'credit': fields.float('Credit', readonly=True),
+ 'balance': fields.float('Balance', readonly=True),
+ 'date': fields.date('Beginning of Period Date', readonly=True),
+ 'starting_balance': fields.function(_compute_balances, digits_compute=dp.get_precision('Account'), string='Starting Balance', multi='balance'),
+ 'ending_balance': fields.function(_compute_balances, digits_compute=dp.get_precision('Account'), string='Ending Balance', multi='balance'),
+ 'company_id': fields.many2one('res.company', 'Company', readonly=True)}
+ _order = 'date asc'
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'account_treasury_report')
+ cr.execute("\n create or replace view account_treasury_report as (\n select\n p.id as id,\n p.fiscalyear_id as fiscalyear_id,\n p.id as period_id,\n sum(l.debit) as debit,\n sum(l.credit) as credit,\n sum(l.debit-l.credit) as balance,\n p.date_start as date,\n am.company_id as company_id\n from\n account_move_line l\n left join account_account a on (l.account_id = a.id)\n left join account_move am on (am.id=l.move_id)\n left join account_period p on (am.period_id=p.id)\n where l.state != 'draft'\n and a.type = 'liquidity'\n group by p.id, p.fiscalyear_id, p.date_start, am.company_id\n )\n ")
+
+
+account_treasury_report()
\ No newline at end of file
diff --git a/addons/account/report/common_report_header.py b/addons/account/report/common_report_header.py
index cedc4ccf5c41c..16676ac8c956a 100644
--- a/addons/account/report/common_report_header.py
+++ b/addons/account/report/common_report_header.py
@@ -1,145 +1,131 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from openerp import pooler
-from openerp.tools.translate import _
-
-class common_report_header(object):
-
- def _sum_debit(self, period_id=False, journal_id=False):
- if journal_id and isinstance(journal_id, int):
- journal_id = [journal_id]
- if period_id and isinstance(period_id, int):
- period_id = [period_id]
- if not journal_id:
- journal_id = self.journal_ids
- if not period_id:
- period_id = self.period_ids
- if not (period_id and journal_id):
- return 0.0
- self.cr.execute('SELECT SUM(debit) FROM account_move_line l '
- 'WHERE period_id IN %s AND journal_id IN %s ' + self.query_get_clause + ' ',
- (tuple(period_id), tuple(journal_id)))
- return self.cr.fetchone()[0] or 0.0
-
- def _sum_credit(self, period_id=False, journal_id=False):
- if journal_id and isinstance(journal_id, int):
- journal_id = [journal_id]
- if period_id and isinstance(period_id, int):
- period_id = [period_id]
- if not journal_id:
- journal_id = self.journal_ids
- if not period_id:
- period_id = self.period_ids
- if not (period_id and journal_id):
- return 0.0
- self.cr.execute('SELECT SUM(credit) FROM account_move_line l '
- 'WHERE period_id IN %s AND journal_id IN %s '+ self.query_get_clause+'',
- (tuple(period_id), tuple(journal_id)))
- return self.cr.fetchone()[0] or 0.0
-
- def _get_start_date(self, data):
- if data.get('form', False) and data['form'].get('date_from', False):
- return data['form']['date_from']
- return ''
-
- def _get_target_move(self, data):
- if data.get('form', False) and data['form'].get('target_move', False):
- if data['form']['target_move'] == 'all':
- return _('All Entries')
- return _('All Posted Entries')
- return ''
-
- def _get_end_date(self, data):
- if data.get('form', False) and data['form'].get('date_to', False):
- return data['form']['date_to']
- return ''
-
- def get_start_period(self, data):
- if data.get('form', False) and data['form'].get('period_from', False):
- return pooler.get_pool(self.cr.dbname).get('account.period').browse(self.cr,self.uid,data['form']['period_from']).name
- return ''
-
- def get_end_period(self, data):
- if data.get('form', False) and data['form'].get('period_to', False):
- return pooler.get_pool(self.cr.dbname).get('account.period').browse(self.cr, self.uid, data['form']['period_to']).name
- return ''
-
- def _get_account(self, data):
- if data.get('form', False) and data['form'].get('chart_account_id', False):
- return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).name
- return ''
-
- def _get_sortby(self, data):
- raise (_('Error!'), _('Not implemented.'))
-
- def _get_filter(self, data):
- if data.get('form', False) and data['form'].get('filter', False):
- if data['form']['filter'] == 'filter_date':
- return self._translate('Date')
- elif data['form']['filter'] == 'filter_period':
- return self._translate('Periods')
- return self._translate('No Filters')
-
- def _sum_debit_period(self, period_id, journal_id=None):
- journals = journal_id or self.journal_ids
- if not journals:
- return 0.0
- self.cr.execute('SELECT SUM(debit) FROM account_move_line l '
- 'WHERE period_id=%s AND journal_id IN %s '+ self.query_get_clause +'',
- (period_id, tuple(journals)))
-
- return self.cr.fetchone()[0] or 0.0
-
- def _sum_credit_period(self, period_id, journal_id=None):
- journals = journal_id or self.journal_ids
- if not journals:
- return 0.0
- self.cr.execute('SELECT SUM(credit) FROM account_move_line l '
- 'WHERE period_id=%s AND journal_id IN %s ' + self.query_get_clause +' ',
- (period_id, tuple(journals)))
- return self.cr.fetchone()[0] or 0.0
-
- def _get_fiscalyear(self, data):
- if data.get('form', False) and data['form'].get('fiscalyear_id', False):
- return pooler.get_pool(self.cr.dbname).get('account.fiscalyear').browse(self.cr, self.uid, data['form']['fiscalyear_id']).name
- return ''
-
- def _get_company(self, data):
- if data.get('form', False) and data['form'].get('chart_account_id', False):
- return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).company_id.name
- return ''
-
- def _get_journal(self, data):
- codes = []
- if data.get('form', False) and data['form'].get('journal_ids', False):
- self.cr.execute('select code from account_journal where id IN %s',(tuple(data['form']['journal_ids']),))
- codes = [x for x, in self.cr.fetchall()]
- return codes
-
- def _get_currency(self, data):
- if data.get('form', False) and data['form'].get('chart_account_id', False):
- return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).company_id.currency_id.symbol
- return ''
-
-#vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp import pooler
+from openerp.tools.translate import _
+
+class common_report_header(object):
+
+ def _sum_debit(self, period_id = False, journal_id = False):
+ if journal_id and isinstance(journal_id, int):
+ journal_id = [journal_id]
+ if period_id and isinstance(period_id, int):
+ period_id = [period_id]
+ if not journal_id:
+ journal_id = self.journal_ids
+ if not period_id:
+ period_id = self.period_ids
+ if not (period_id and journal_id):
+ return 0.0
+ self.cr.execute('SELECT SUM(debit) FROM account_move_line l WHERE period_id IN %s AND journal_id IN %s ' + self.query_get_clause + ' ', (tuple(period_id), tuple(journal_id)))
+ return self.cr.fetchone()[0] or 0.0
+
+ def _sum_credit(self, period_id = False, journal_id = False):
+ if journal_id and isinstance(journal_id, int):
+ journal_id = [journal_id]
+ if period_id and isinstance(period_id, int):
+ period_id = [period_id]
+ if not journal_id:
+ journal_id = self.journal_ids
+ if not period_id:
+ period_id = self.period_ids
+ if not (period_id and journal_id):
+ return 0.0
+ self.cr.execute('SELECT SUM(credit) FROM account_move_line l WHERE period_id IN %s AND journal_id IN %s ' + self.query_get_clause + '', (tuple(period_id), tuple(journal_id)))
+ return self.cr.fetchone()[0] or 0.0
+
+ def _get_start_date(self, data):
+ if data.get('form', False) and data['form'].get('date_from', False):
+ return data['form']['date_from']
+ return ''
+
+ def _get_target_move(self, data):
+ if data.get('form', False) and data['form'].get('target_move', False):
+ if data['form']['target_move'] == 'all':
+ return _('All Entries')
+ return _('All Posted Entries')
+ return ''
+
+ def _get_end_date(self, data):
+ if data.get('form', False) and data['form'].get('date_to', False):
+ return data['form']['date_to']
+ return ''
+
+ def get_start_period(self, data):
+ if data.get('form', False) and data['form'].get('period_from', False):
+ return pooler.get_pool(self.cr.dbname).get('account.period').browse(self.cr, self.uid, data['form']['period_from']).name
+ return ''
+
+ def get_end_period(self, data):
+ if data.get('form', False) and data['form'].get('period_to', False):
+ return pooler.get_pool(self.cr.dbname).get('account.period').browse(self.cr, self.uid, data['form']['period_to']).name
+ return ''
+
+ def _get_account(self, data):
+ if data.get('form', False) and data['form'].get('chart_account_id', False):
+ return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).name
+ return ''
+
+ def _get_sortby(self, data):
+ raise (_('Error!'), _('Not implemented.'))
+
+ def _get_filter(self, data):
+ if data.get('form', False) and data['form'].get('filter', False):
+ if data['form']['filter'] == 'filter_date':
+ return self._translate('Date')
+ if data['form']['filter'] == 'filter_period':
+ return self._translate('Periods')
+ return self._translate('No Filters')
+
+ def _sum_debit_period(self, period_id, journal_id = None):
+ journals = journal_id or self.journal_ids
+ if not journals:
+ return 0.0
+ self.cr.execute('SELECT SUM(debit) FROM account_move_line l WHERE period_id=%s AND journal_id IN %s ' + self.query_get_clause + '', (period_id, tuple(journals)))
+ return self.cr.fetchone()[0] or 0.0
+
+ def _sum_credit_period(self, period_id, journal_id = None):
+ journals = journal_id or self.journal_ids
+ if not journals:
+ return 0.0
+ self.cr.execute('SELECT SUM(credit) FROM account_move_line l WHERE period_id=%s AND journal_id IN %s ' + self.query_get_clause + ' ', (period_id, tuple(journals)))
+ return self.cr.fetchone()[0] or 0.0
+
+ def _get_fiscalyear(self, data):
+ if data.get('form', False) and data['form'].get('fiscalyear_id', False):
+ return pooler.get_pool(self.cr.dbname).get('account.fiscalyear').browse(self.cr, self.uid, data['form']['fiscalyear_id']).name
+ return ''
+
+ def _get_company(self, data):
+ if data.get('form', False) and data['form'].get('chart_account_id', False):
+ return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).company_id.name
+ return ''
+
+ def _get_journal(self, data):
+ codes = []
+ if data.get('form', False) and data['form'].get('journal_ids', False):
+ self.cr.execute('select code from account_journal where id IN %s', (tuple(data['form']['journal_ids']),))
+ codes = [ x for x, in self.cr.fetchall() ]
+ return codes
+
+ def _get_currency(self, data):
+ if data.get('form', False) and data['form'].get('chart_account_id', False):
+ return pooler.get_pool(self.cr.dbname).get('account.account').browse(self.cr, self.uid, data['form']['chart_account_id']).company_id.currency_id.symbol
+ return ''
\ No newline at end of file
diff --git a/addons/account/res_config_view.xml b/addons/account/res_config_view.xml
index 0bc18c9304b04..7977c0fc505fd 100644
--- a/addons/account/res_config_view.xml
+++ b/addons/account/res_config_view.xml
@@ -150,7 +150,7 @@
@@ -191,7 +191,7 @@
diff --git a/addons/account/security/account_security.xml b/addons/account/security/account_security.xml
index 65d3e95be54e4..9a2383de45b37 100644
--- a/addons/account/security/account_security.xml
+++ b/addons/account/security/account_security.xml
@@ -139,13 +139,6 @@
['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
-
- Account subscription line company rule
-
-
- ['|',('subscription_id.model_id.company_id','=',False),('subscription_id.model_id.company_id','child_of',[user.company_id.id])]
-
-
Invoice Line company rule
diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv
index d1f0bbab6b58a..4d991f0d8035a 100644
--- a/addons/account/security/ir.model.access.csv
+++ b/addons/account/security/ir.model.access.csv
@@ -98,3 +98,125 @@ access_account_sequence_fiscal_year_sale_manager,account.sequence.fiscalyear.sal
access_account_treasury_report_manager,account.treasury.report.manager,model_account_treasury_report,account.group_account_manager,1,0,0,0
access_account_financial_report,account.financial.report,model_account_financial_report,account.group_account_user,1,1,1,1
access_account_financial_report_invoice,account.financial.report invoice,model_account_financial_report,account.group_account_invoice,1,0,0,0
+access_account_tax_sale_banhang,account.tax banhang,model_account_tax,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_journal_sale_banhang,account.journal banhang,model_account_journal,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_invoice_tax_banhang,account.invoice.tax banhang,model_account_invoice_tax,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_sequence_fiscal_year_sale_banhang,account.sequence.fiscalyear.sale.banhang,model_account_sequence_fiscalyear,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_invoice_nhom_quan_ly_nguoidung_banhang,nhom_quan_ly_nguoidung_banhang invoice,model_account_invoice,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_invoice_line_nhom_quan_ly_nguoidung_banhang,nhom_quan_ly_nguoidung_banhang invoice line,model_account_invoice_line,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_move_banhang,account.move,model_account_move,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_account_move_line_banhang,account.move.line invoice,model_account_move_line,base.nhom_quan_ly_nguoidung_banhang,1,0,0,0
+access_product_product_account_pxk,product.product.account.user,product.model_product_product,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_payment_termpxk,account.payment.term,model_account_payment_term,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_payment_term_linepxk,account.payment.term.line,model_account_payment_term_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_account_typepxk,account.account.type,model_account_account_type,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_tax_internal_v,account.tax internal user,model_account_tax,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_accountpxk,account.account,model_account_account,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_account_pxk,account.account user,model_account_account,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_tax_codepxk,account.tax.code,model_account_tax_code,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_taxpxk,account.tax,model_account_tax,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_modelpxk,account.model,model_account_model,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_model_linepxk,account.model.line,model_account_model_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_subscriptionpxk,account.subscription,model_account_subscription,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_subscription_linepxk,account.subscription.line,model_account_subscription_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_bank_statementpxk,account.bank.statement,model_account_bank_statement,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_bank_statement_linepxk,account.bank.statement.line,model_account_bank_statement_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_analytic_accountpxk,account.analytic.account,analytic.model_account_analytic_account,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_analytic_journalpxk,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_analytic_journal_pxk,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_pxk,nhom_quan_ly_nguoidung_banhang invoice,model_account_invoice,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_pxk,nhom_quan_ly_nguoidung_banhang invoice line,model_account_invoice_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_move_pxk,account.move,model_account_move,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_move_line_pxk,account.move.line invoice,model_account_move_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_pxk,account.invoice user,model_account_invoice,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_pxk,account.invoice.line user,model_account_invoice_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_fiscal_positionpxk,account.fiscal.position all,model_account_fiscal_position,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_fiscal_position_taxpxk,account.fiscal.position.tax all,model_account_fiscal_position_tax,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_fiscal_position_accountpxk,account.fiscal.position all,model_account_fiscal_position_account,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_sequence_fiscal_year_pxk,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_pxk,account.invoice accountant,model_account_invoice,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_tax_code_pxk,account.tax.code accountant,model_account_tax_code,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_entries_report_pxk,account.entries.report employee,model_account_entries_report,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_cashbox_pxk,account.cashbox.line,model_account_cashbox_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_journal_cashbox_pxk,account.journal.cashbox.line,model_account_journal_cashbox_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_tax_pxk,account.invoice.tax accountant,model_account_invoice_tax,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_account_invoice_line_pxk,account.invoice.line accountant,model_account_invoice_line,base.nhom_quan_ly_trambanhang_pxk,1,0,1,0
+access_product_product_account_trambanhang_hoadon,product.product.account.user,product.model_product_product,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_payment_term_trambanhang_hoadon,account.payment.term,model_account_payment_term,base.nhom_quan_ly_trambanhang_hoadon,1,0,0,0
+access_account_payment_term_linetrambanhang_hoadon,account.payment.term.line,model_account_payment_term_line,base.nhom_quan_ly_trambanhang_hoadon,1,0,0,0
+access_account_account_type_trambanhang_hoadon,account.account.type,model_account_account_type,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_tax_internal_trambanhang_hoadon,account.tax internal user,model_account_tax,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_account_trambanhang_hoadon,account.account,model_account_account,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_account_trambanhang_hoadon,account.account user,model_account_account,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_tax_code_trambanhang_hoadon,account.tax.code,model_account_tax_code,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_tax_trambanhang_hoadon,account.tax,model_account_tax,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_model_trambanhang_hoadon,account.model,model_account_model,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_model_line_trambanhang_hoadon,account.model.line,model_account_model_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_subscription_trambanhang_hoadon,account.subscription,model_account_subscription,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_subscription_line_trambanhang_hoadon,account.subscription.line,model_account_subscription_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_bank_statement_trambanhang_hoadon,account.bank.statement,model_account_bank_statement,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_bank_statement_line_trambanhang_hoadon,account.bank.statement.line,model_account_bank_statement_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_analytic_account_trambanhang_hoadon,account.analytic.account,analytic.model_account_analytic_account,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_analytic_journal_trambanhang_hoadon,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_analytic_journal_trambanhang_hoadon,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_trambanhang_hoadon,nhom_quan_ly_nguoidung_banhang invoice,model_account_invoice,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_trambanhang_hoadon,nhom_quan_ly_nguoidung_banhang invoice line,model_account_invoice_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_move_trambanhang_hoadon,account.move,model_account_move,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_move_line_trambanhang_hoadon,account.move.line invoice,model_account_move_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_trambanhang_hoadon,account.invoice user,model_account_invoice,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_v,account.invoice.line user,model_account_invoice_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_fiscal_position_trambanhang_hoadon,account.fiscal.position all,model_account_fiscal_position,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_fiscal_position_tax_trambanhang_hoadon,account.fiscal.position.tax all,model_account_fiscal_position_tax,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_fiscal_position_account_trambanhang_hoadon,account.fiscal.position all,model_account_fiscal_position_account,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_sequence_fiscal_year_trambanhang_hoadon,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_trambanhang_hoadon,account.invoice accountant,model_account_invoice,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_tax_code_trambanhang_hoadon,account.tax.code accountant,model_account_tax_code,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_entries_report_trambanhang_hoadon,account.entries.report employee,model_account_entries_report,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_cashbox_trambanhang_hoadon,account.cashbox.line,model_account_cashbox_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_journal_cashbox_trambanhang_hoadon,account.journal.cashbox.line,model_account_journal_cashbox_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_tax_trambanhang_hoadon,account.invoice.tax accountant,model_account_invoice_tax,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_invoice_line_trambanhang_hoadon,account.invoice.line accountant,model_account_invoice_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_journal_trambanhang_hoadon,account.journal,model_account_journal,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_period_trambanhang_hoadon,account.period,model_account_period,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_journal_period_trambanhang_hoadon,account.journal.period manager,model_account_journal_period,base.nhom_quan_ly_trambanhang_hoadon,1,0,0,0
+access_account_analytic_line_trambanhang_hoadon,account.analytic.line manager,model_account_analytic_line,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_analytic_accounttrambanhang_hoadon,account.analytic.account,analytic.model_account_analytic_account,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_analytic_journaltrambanhang_hoadon,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_move_reconcile_uinvoicetrambanhang_hoadon,account.move.reconcile,model_account_move_reconcile,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_account_journal_period_uinvoicetrambanhang_hoadon,account.journal.period,model_account_journal_period,base.nhom_quan_ly_trambanhang_hoadon,1,1,1,1
+access_product_product_account_lxh_haiduong,product.product.account.user,product.model_product_product,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_payment_term_lxh_haiduong,account.payment.term,model_account_payment_term,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,1,1,0
+access_account_payment_term_line_lxh_haiduong,account.payment.term.line,model_account_payment_term_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,1,1,0
+access_account_account_type_lxh_haiduong,account.account.type,model_account_account_type,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_tax_internal_lxh_haiduong,account.tax internal user,model_account_tax,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_account_lxh_haiduong,account.account,model_account_account,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_account_lxh_haiduong,account.account user,model_account_account,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_tax_code_lxh_haiduong,account.tax.code,model_account_tax_code,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_taxpxk,account.tax,model_account_tax,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_model_lxh_haiduong,account.model,model_account_model,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_model_line_lxh_haiduong,account.model.line,model_account_model_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_subscription_lxh_haiduong,account.subscription,model_account_subscription,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_subscription_line_lxh_haiduong,account.subscription.line,model_account_subscription_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_bank_statement_lxh_haiduong,account.bank.statement,model_account_bank_statement,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_bank_statement_line_lxh_haiduong,account.bank.statement.line,model_account_bank_statement_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_analytic_account_lxh_haiduong,account.analytic.account,analytic.model_account_analytic_account,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_analytic_journal_lxh_haiduong,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_analytic_journal_lxh_haiduong,account.analytic.journal,model_account_analytic_journal,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_lxh_haiduong,nhom_quan_ly_nguoidung_banhang invoice,model_account_invoice,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_lxh_haiduong,nhom_quan_ly_nguoidung_banhang invoice line,model_account_invoice_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_move_lxh_haiduong,account.move,model_account_move,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_move_line_lxh_haiduong,account.move.line invoice,model_account_move_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_lxh_haiduong,account.invoice user,model_account_invoice,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_lxh_haiduong,account.invoice.line user,model_account_invoice_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_fiscal_position_lxh_haiduong,account.fiscal.position all,model_account_fiscal_position,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_fiscal_position_tax_lxh_haiduong,account.fiscal.position.tax all,model_account_fiscal_position_tax,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_fiscal_position_account_lxh_haiduong,account.fiscal.position all,model_account_fiscal_position_account,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_sequence_fiscal_year_lxh_haiduong,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_lxh_haiduong,account.invoice accountant,model_account_invoice,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_tax_code_lxh_haiduong,account.tax.code accountant,model_account_tax_code,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_entries_report_lxh_haiduong,account.entries.report employee,model_account_entries_report,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_cashbox_lxh_haiduong,account.cashbox.line,model_account_cashbox_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_journal_cashbox_lxh_haiduong,account.journal.cashbox.line,model_account_journal_cashbox_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_tax_lxh_haiduong,account.invoice.tax accountant,model_account_invoice_tax,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_line_lxh_haiduong,account.invoice.line accountant,model_account_invoice_line,base.nhom_quan_ly_trambanhang_lxh_haiduong,1,0,0,0
+access_account_invoice_phibaove_user,account.invoice.phibaove.user,model_account_invoice_phibaove,base.group_user,1,1,1,1
\ No newline at end of file
diff --git a/addons/account/static/src/js/account_move_line_quickadd.js b/addons/account/static/src/js/account_move_line_quickadd.js
index 0bbdb959d1781..0b904e19da6ed 100644
--- a/addons/account/static/src/js/account_move_line_quickadd.js
+++ b/addons/account/static/src/js/account_move_line_quickadd.js
@@ -22,7 +22,6 @@ openerp.account.quickadd = function (instance) {
start:function(){
var tmp = this._super.apply(this, arguments);
var self = this;
- var defs = [];
this.$el.parent().prepend(QWeb.render("AccountMoveLineQuickAdd", {widget: this}));
this.$el.parent().find('.oe_account_select_journal').change(function() {
@@ -42,17 +41,11 @@ openerp.account.quickadd = function (instance) {
self.$el.parent().find('.oe_account_select_period').removeAttr('disabled');
});
var mod = new instance.web.Model("account.move.line", self.dataset.context, self.dataset.domain);
- defs.push(mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) {
+ mod.call("default_get", [['journal_id','period_id'],self.dataset.context]).then(function(result) {
self.current_period = result['period_id'];
self.current_journal = result['journal_id'];
- }));
- defs.push(mod.call("list_journals", []).then(function(result) {
- self.journals = result;
- }));
- defs.push(mod.call("list_periods", []).then(function(result) {
- self.periods = result;
- }));
- return $.when(tmp, defs);
+ });
+ return tmp;
},
do_search: function(domain, context, group_by) {
var self = this;
@@ -60,31 +53,38 @@ openerp.account.quickadd = function (instance) {
this.last_context = context;
this.last_group_by = group_by;
this.old_search = _.bind(this._super, this);
- var o;
- self.$el.parent().find('.oe_account_select_journal').children().remove().end();
- self.$el.parent().find('.oe_account_select_journal').append(new Option('', ''));
- for (var i = 0;i < self.journals.length;i++){
- o = new Option(self.journals[i][1], self.journals[i][0]);
- if (self.journals[i][0] === self.current_journal){
- self.current_journal_type = self.journals[i][2];
- self.current_journal_currency = self.journals[i][3];
- self.current_journal_analytic = self.journals[i][4];
- $(o).attr('selected',true);
+ var mod = new instance.web.Model("account.move.line", context, domain);
+ return $.when(mod.call("list_journals", []).then(function(result) {
+ self.journals = result;
+ }),mod.call("list_periods", []).then(function(result) {
+ self.periods = result;
+ })).then(function () {
+ var o;
+ self.$el.parent().find('.oe_account_select_journal').children().remove().end();
+ self.$el.parent().find('.oe_account_select_journal').append(new Option('', ''));
+ for (var i = 0;i < self.journals.length;i++){
+ o = new Option(self.journals[i][1], self.journals[i][0]);
+ if (self.journals[i][0] === self.current_journal){
+ self.current_journal_type = self.journals[i][2];
+ self.current_journal_currency = self.journals[i][3];
+ self.current_journal_analytic = self.journals[i][4];
+ $(o).attr('selected',true);
+ }
+ self.$el.parent().find('.oe_account_select_journal').append(o);
}
- self.$el.parent().find('.oe_account_select_journal').append(o);
- }
- self.$el.parent().find('.oe_account_select_period').children().remove().end();
- self.$el.parent().find('.oe_account_select_period').append(new Option('', ''));
- for (var i = 0;i < self.periods.length;i++){
- o = new Option(self.periods[i][1], self.periods[i][0]);
- self.$el.parent().find('.oe_account_select_period').append(o);
- }
- self.$el.parent().find('.oe_account_select_period').val(self.current_period).attr('selected',true);
- return self.search_by_journal_period();
+ self.$el.parent().find('.oe_account_select_period').children().remove().end();
+ self.$el.parent().find('.oe_account_select_period').append(new Option('', ''));
+ for (var i = 0;i < self.periods.length;i++){
+ o = new Option(self.periods[i][1], self.periods[i][0]);
+ self.$el.parent().find('.oe_account_select_period').append(o);
+ }
+ self.$el.parent().find('.oe_account_select_period').val(self.current_period).attr('selected',true);
+ return self.search_by_journal_period();
+ });
},
search_by_journal_period: function() {
var self = this;
- var domain = [];
+ var domain = ['|',['debit', '!=', 0], ['credit', '!=', 0]];
if (self.current_journal !== null) domain.push(["journal_id", "=", self.current_journal]);
if (self.current_period !== null) domain.push(["period_id", "=", self.current_period]);
self.last_context["journal_id"] = self.current_journal === null ? false : self.current_journal;
@@ -93,9 +93,7 @@ openerp.account.quickadd = function (instance) {
self.last_context["journal_type"] = self.current_journal_type;
self.last_context["currency"] = self.current_journal_currency;
self.last_context["analytic_journal_id"] = self.current_journal_analytic;
- var compound_domain = new instance.web.CompoundDomain(self.last_domain, domain);
- self.dataset.domain = compound_domain.eval();
- return self.old_search(compound_domain, self.last_context, self.last_group_by);
+ return self.old_search(new instance.web.CompoundDomain(self.last_domain, domain), self.last_context, self.last_group_by);
},
});
};
diff --git a/addons/account/static/src/js/account_move_reconciliation.js b/addons/account/static/src/js/account_move_reconciliation.js
index 1629a16f5b392..cbc0abc4f4db0 100644
--- a/addons/account/static/src/js/account_move_reconciliation.js
+++ b/addons/account/static/src/js/account_move_reconciliation.js
@@ -49,7 +49,7 @@ openerp.account = function (instance) {
this.last_group_by = group_by;
this.old_search = _.bind(this._super, this);
var mod = new instance.web.Model("account.move.line", context, domain);
- return mod.call("list_partners_to_reconcile", [context, domain]).then(function(result) {
+ return mod.call("list_partners_to_reconcile", []).then(function(result) {
var current = self.current_partner !== null ? self.partners[self.current_partner][0] : null;
self.partners = result;
var index = _.find(_.range(self.partners.length), function(el) {
diff --git a/addons/account/test/account_fiscalyear_close.yml b/addons/account/test/account_fiscalyear_close.yml
index 73e34f2cca8db..1c3547ccefd88 100644
--- a/addons/account/test/account_fiscalyear_close.yml
+++ b/addons/account/test/account_fiscalyear_close.yml
@@ -4,32 +4,20 @@
!record {model: account.fiscalyear, id: account_fiscalyear_fiscalyear0}:
code: !eval "'FY%s'% (datetime.now().year+1)"
company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year-1)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year-1)"
- name: !eval "'Fiscal Year %s' %(datetime.now().year-1)"
+ date_start: !eval "'%s-01-01' %(datetime.now().year+1)"
+ date_stop: !eval "'%s-12-31' %(datetime.now().year+1)"
+ name: !eval "'Fiscal Year %s' %(datetime.now().year+1)"
-
- I generate periods for the new fiscalyear
+ I create a period for the opening entries for the new fiscalyear
-
- !python {model: account.fiscalyear}: |
- self.create_period(cr, uid, [ref("account_fiscalyear_fiscalyear0")])
--
- I create a new account invoice in the created fiscalyear
--
- !record {model: account.invoice, id: account_invoice_current1}:
- partner_id: base.res_partner_2
- date_invoice: !eval "'%s-01-02' %(datetime.now().year-1)"
- invoice_line:
- - partner_id: base.res_partner_2
- quantity: 1.0
- price_unit: 15.00
- name: Bying stuff
--
- I validate the invoice
--
- !python {model: account.invoice}: |
- import netsvc
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_validate(uid, 'account.invoice', ref('account.account_invoice_current1'), 'invoice_open', cr)
+ !record {model: account.period, id: account_period_jan11}:
+ company_id: base.main_company
+ date_start: !eval "'%s-01-01'% (datetime.now().year+1)"
+ date_stop: !eval "'%s-01-01'% (datetime.now().year+1)"
+ fiscalyear_id: account_fiscalyear_fiscalyear0
+ name: !eval "'OP %s' %(datetime.now().year+1)"
+ special: 1
+
-
I made modification in journal so it can move entries
-
@@ -43,40 +31,19 @@
company_id: base.main_company
centralisation: 1
-
- I call the Generate Fiscalyear Opening Entries wizard
+ I called the Generate Fiscalyear Opening Entries wizard
-
!record {model: account.fiscalyear.close, id: account_fiscalyear_close_0}:
- fy2_id: account.data_fiscalyear
- fy_id: account_fiscalyear_fiscalyear0
+ fy2_id: account_fiscalyear_fiscalyear0
+ fy_id: account.data_fiscalyear
journal_id: account.close_journal
- period_id: account.period_1
+ period_id: account_period_jan11
report_name: End of Fiscal Year Entry
-
I clicked on create Button
+
-
!python {model: account.fiscalyear.close}: |
self.data_save(cr, uid, [ref("account_fiscalyear_close_0")], {"lang": 'en_US',
"active_model": "ir.ui.menu", "active_ids": [ref("account.menu_wizard_fy_close")],
- "tz": False, "active_id": ref("account.menu_wizard_fy_close"), })
--
- I close the previous fiscalyear
--
- !record {model: account.fiscalyear.close.state, id: account_fiscalyear_close_state_0}:
- fy_id: account_fiscalyear_fiscalyear0
--
- I clicked on Close States Button to close fiscalyear
--
- !python {model: account.fiscalyear.close.state}: |
- self.data_save(cr, uid, [ref("account_fiscalyear_close_state_0")], {"lang": 'en_US',
- "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_wizard_fy_close_state")],
- "tz": False, "active_id": ref("account.menu_wizard_fy_close_state"), })
--
- I check that the fiscalyear state is now "Done"
--
- !assert {model: account.fiscalyear, id: account_fiscalyear_fiscalyear0, string: Fiscal Year is in Done state}:
- - state == 'done'
--
- I check that the past accounts are taken into account in partner credit
--
- !assert {model: res.partner, id: base.res_partner_2, string: Total Receivable does not takes unreconciled moves of previous years}:
- - credit == 15.0
+ "tz": False, "active_id": ref("account.menu_wizard_fy_close"), })
\ No newline at end of file
diff --git a/addons/account/test/account_fiscalyear_close_state.yml b/addons/account/test/account_fiscalyear_close_state.yml
new file mode 100644
index 0000000000000..18c7dd570ed4e
--- /dev/null
+++ b/addons/account/test/account_fiscalyear_close_state.yml
@@ -0,0 +1,19 @@
+-
+ I run the Close a Fiscalyear wizard to close the demo fiscalyear
+-
+ !record {model: account.fiscalyear.close.state, id: account_fiscalyear_close_state_0}:
+ fy_id: data_fiscalyear
+-
+ I clicked on Close States Button to close fiscalyear
+
+-
+ !python {model: account.fiscalyear.close.state}: |
+ self.data_save(cr, uid, [ref("account_fiscalyear_close_state_0")], {"lang": 'en_US',
+ "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_wizard_fy_close_state")],
+ "tz": False, "active_id": ref("account.menu_wizard_fy_close_state"), })
+-
+ I check that the fiscalyear state is now "Done"
+-
+ !assert {model: account.fiscalyear, id: data_fiscalyear, string: Fiscal Year is in Done state}:
+ - state == 'done'
+
diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py
index 02e9677ae0362..11fe4186db6f9 100644
--- a/addons/account/tests/__init__.py
+++ b/addons/account/tests/__init__.py
@@ -1,7 +1,4 @@
from . import test_tax
-from . import test_search
-fast_suite = [
- test_tax,
- test_search,
-]
+fast_suite = [test_tax,
+ ]
diff --git a/addons/account/wizard/account_report_partner_ledger_view.xml b/addons/account/wizard/account_report_partner_ledger_view.xml
index 61b57f87d7e8a..34c5d55e4c113 100644
--- a/addons/account/wizard/account_report_partner_ledger_view.xml
+++ b/addons/account/wizard/account_report_partner_ledger_view.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/addons/account_analytic_analysis/account_analytic_analysis.py b/addons/account_analytic_analysis/account_analytic_analysis.py
index 125ed72464d16..89f8fc54283e6 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis.py
+++ b/addons/account_analytic_analysis/account_analytic_analysis.py
@@ -1,680 +1,535 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-import datetime
-import logging
-import time
-
-from openerp.osv import osv, fields
-from openerp.osv.orm import intersect, except_orm
-import openerp.tools
-from openerp.tools.translate import _
-
-from openerp.addons.decimal_precision import decimal_precision as dp
-
-_logger = logging.getLogger(__name__)
-
-class account_analytic_account(osv.osv):
- _name = "account.analytic.account"
- _inherit = "account.analytic.account"
-
- def _analysis_all(self, cr, uid, ids, fields, arg, context=None):
- dp = 2
- res = dict([(i, {}) for i in ids])
- parent_ids = tuple(ids) #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
- accounts = self.browse(cr, uid, ids, context=context)
-
- for f in fields:
- if f == 'user_ids':
- cr.execute('SELECT MAX(id) FROM res_users')
- max_user = cr.fetchone()[0]
- if parent_ids:
- cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user ' \
- 'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
- result = cr.fetchall()
- else:
- result = []
- for id in ids:
- res[id][f] = [int((id * max_user) + x[0]) for x in result]
- elif f == 'month_ids':
- if parent_ids:
- cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month ' \
- 'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
- result = cr.fetchall()
- else:
- result = []
- for id in ids:
- res[id][f] = [int(id * 1000000 + int(x[0])) for x in result]
- elif f == 'last_worked_invoiced_date':
- for id in ids:
- res[id][f] = False
- if parent_ids:
- cr.execute("SELECT account_analytic_line.account_id, MAX(date) \
- FROM account_analytic_line \
- WHERE account_id IN %s \
- AND invoice_id IS NOT NULL \
- GROUP BY account_analytic_line.account_id;", (parent_ids,))
- for account_id, sum in cr.fetchall():
- if account_id not in res:
- res[account_id] = {}
- res[account_id][f] = sum
- elif f == 'ca_to_invoice':
- for id in ids:
- res[id][f] = 0.0
- res2 = {}
- for account in accounts:
- cr.execute("""
- SELECT product_id, sum(amount), user_id, to_invoice, sum(unit_amount), product_uom_id, line.name
- FROM account_analytic_line line
- LEFT JOIN account_analytic_journal journal ON (journal.id = line.journal_id)
- WHERE account_id = %s
- AND journal.type != 'purchase'
- AND invoice_id IS NULL
- AND to_invoice IS NOT NULL
- GROUP BY product_id, user_id, to_invoice, product_uom_id, line.name""", (account.id,))
-
- res[account.id][f] = 0.0
- for product_id, price, user_id, factor_id, qty, uom, line_name in cr.fetchall():
- price = -price
- if product_id:
- price = self.pool.get('account.analytic.line')._get_invoice_price(cr, uid, account, product_id, user_id, qty, context)
- factor = self.pool.get('hr_timesheet_invoice.factor').browse(cr, uid, factor_id, context=context)
- res[account.id][f] += price * qty * (100-factor.factor or 0.0) / 100.0
-
- # sum both result on account_id
- for id in ids:
- res[id][f] = round(res.get(id, {}).get(f, 0.0), dp) + round(res2.get(id, 0.0), 2)
- elif f == 'last_invoice_date':
- for id in ids:
- res[id][f] = False
- if parent_ids:
- cr.execute ("SELECT account_analytic_line.account_id, \
- DATE(MAX(account_invoice.date_invoice)) \
- FROM account_analytic_line \
- JOIN account_invoice \
- ON account_analytic_line.invoice_id = account_invoice.id \
- WHERE account_analytic_line.account_id IN %s \
- AND account_analytic_line.invoice_id IS NOT NULL \
- GROUP BY account_analytic_line.account_id",(parent_ids,))
- for account_id, lid in cr.fetchall():
- res[account_id][f] = lid
- elif f == 'last_worked_date':
- for id in ids:
- res[id][f] = False
- if parent_ids:
- cr.execute("SELECT account_analytic_line.account_id, MAX(date) \
- FROM account_analytic_line \
- WHERE account_id IN %s \
- AND invoice_id IS NULL \
- GROUP BY account_analytic_line.account_id",(parent_ids,))
- for account_id, lwd in cr.fetchall():
- if account_id not in res:
- res[account_id] = {}
- res[account_id][f] = lwd
- elif f == 'hours_qtt_non_invoiced':
- for id in ids:
- res[id][f] = 0.0
- if parent_ids:
- cr.execute("SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
- FROM account_analytic_line \
- JOIN account_analytic_journal \
- ON account_analytic_line.journal_id = account_analytic_journal.id \
- WHERE account_analytic_line.account_id IN %s \
- AND account_analytic_journal.type='general' \
- AND invoice_id IS NULL \
- AND to_invoice IS NOT NULL \
- GROUP BY account_analytic_line.account_id;",(parent_ids,))
- for account_id, sua in cr.fetchall():
- if account_id not in res:
- res[account_id] = {}
- res[account_id][f] = round(sua, dp)
- for id in ids:
- res[id][f] = round(res[id][f], dp)
- elif f == 'hours_quantity':
- for id in ids:
- res[id][f] = 0.0
- if parent_ids:
- cr.execute("SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
- FROM account_analytic_line \
- JOIN account_analytic_journal \
- ON account_analytic_line.journal_id = account_analytic_journal.id \
- WHERE account_analytic_line.account_id IN %s \
- AND account_analytic_journal.type='general' \
- GROUP BY account_analytic_line.account_id",(parent_ids,))
- ff = cr.fetchall()
- for account_id, hq in ff:
- if account_id not in res:
- res[account_id] = {}
- res[account_id][f] = round(hq, dp)
- for id in ids:
- res[id][f] = round(res[id][f], dp)
- elif f == 'ca_theorical':
- # TODO Take care of pricelist and purchase !
- for id in ids:
- res[id][f] = 0.0
- # Warning
- # This computation doesn't take care of pricelist !
- # Just consider list_price
- if parent_ids:
- cr.execute("""SELECT account_analytic_line.account_id AS account_id, \
- COALESCE(SUM((account_analytic_line.unit_amount * pt.list_price) \
- - (account_analytic_line.unit_amount * pt.list_price \
- * hr.factor)), 0.0) AS somme
- FROM account_analytic_line \
- LEFT JOIN account_analytic_journal \
- ON (account_analytic_line.journal_id = account_analytic_journal.id) \
- JOIN product_product pp \
- ON (account_analytic_line.product_id = pp.id) \
- JOIN product_template pt \
- ON (pp.product_tmpl_id = pt.id) \
- JOIN account_analytic_account a \
- ON (a.id=account_analytic_line.account_id) \
- JOIN hr_timesheet_invoice_factor hr \
- ON (hr.id=a.to_invoice) \
- WHERE account_analytic_line.account_id IN %s \
- AND a.to_invoice IS NOT NULL \
- AND account_analytic_journal.type IN ('purchase', 'general')
- GROUP BY account_analytic_line.account_id""",(parent_ids,))
- for account_id, sum in cr.fetchall():
- res[account_id][f] = round(sum, dp)
- return res
-
- def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- res_final = {}
- child_ids = tuple(ids) #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
- for i in child_ids:
- res[i] = 0.0
- if not child_ids:
- return res
-
- if child_ids:
- #Search all invoice lines not in cancelled state that refer to this analytic account
- inv_line_obj = self.pool.get("account.invoice.line")
- inv_lines = inv_line_obj.search(cr, uid, ['&', ('account_analytic_id', 'in', child_ids), ('invoice_id.state', 'not in', ['draft', 'cancel']), ('invoice_id.type', 'in', ['out_invoice', 'out_refund'])], context=context)
- for line in inv_line_obj.browse(cr, uid, inv_lines, context=context):
- if line.invoice_id.type == 'out_refund':
- res[line.account_analytic_id.id] -= line.price_subtotal
- else:
- res[line.account_analytic_id.id] += line.price_subtotal
-
- for acc in self.browse(cr, uid, res.keys(), context=context):
- res[acc.id] = res[acc.id] - (acc.timesheet_ca_invoiced or 0.0)
-
- res_final = res
- return res_final
-
- def _total_cost_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- res_final = {}
- child_ids = tuple(ids) #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
- for i in child_ids:
- res[i] = 0.0
- if not child_ids:
- return res
- if child_ids:
- cr.execute("""SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) \
- FROM account_analytic_line \
- JOIN account_analytic_journal \
- ON account_analytic_line.journal_id = account_analytic_journal.id \
- WHERE account_analytic_line.account_id IN %s \
- AND amount<0 \
- GROUP BY account_analytic_line.account_id""",(child_ids,))
- for account_id, sum in cr.fetchall():
- res[account_id] = round(sum,2)
- res_final = res
- return res_final
-
- def _remaining_hours_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- if account.quantity_max != 0:
- res[account.id] = account.quantity_max - account.hours_quantity
- else:
- res[account.id] = 0.0
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _remaining_hours_to_invoice_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = max(account.hours_qtt_est - account.timesheet_ca_invoiced, account.ca_to_invoice)
- return res
-
- def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = account.hours_quantity - account.hours_qtt_non_invoiced
- if res[account.id] < 0:
- res[account.id] = 0.0
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _revenue_per_hour_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- if account.hours_qtt_invoiced == 0:
- res[account.id]=0.0
- else:
- res[account.id] = account.ca_invoiced / account.hours_qtt_invoiced
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _real_margin_rate_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- if account.ca_invoiced == 0:
- res[account.id]=0.0
- elif account.total_cost != 0.0:
- res[account.id] = -(account.real_margin / account.total_cost) * 100
- else:
- res[account.id] = 0.0
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _fix_price_to_invoice_calc(self, cr, uid, ids, name, arg, context=None):
- sale_obj = self.pool.get('sale.order')
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = 0.0
- sale_ids = sale_obj.search(cr, uid, [('project_id','=', account.id), ('state', '=', 'manual')], context=context)
- for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
- res[account.id] += sale.amount_untaxed
- for invoice in sale.invoice_ids:
- if invoice.state != 'cancel':
- res[account.id] -= invoice.amount_untaxed
- return res
-
- def _timesheet_ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
- lines_obj = self.pool.get('account.analytic.line')
- res = {}
- inv_ids = []
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = 0.0
- line_ids = lines_obj.search(cr, uid, [('account_id','=', account.id), ('invoice_id','!=',False), ('to_invoice','!=', False), ('journal_id.type', '=', 'general'), ('invoice_id.type', 'in', ['out_invoice', 'out_refund'])], context=context)
- for line in lines_obj.browse(cr, uid, line_ids, context=context):
- if line.invoice_id not in inv_ids:
- inv_ids.append(line.invoice_id)
- if line.invoice_id.type == 'out_refund':
- res[account.id] -= line.invoice_id.amount_untaxed
- else:
- res[account.id] += line.invoice_id.amount_untaxed
- return res
-
- def _remaining_ca_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = max(account.amount_max - account.ca_invoiced, account.fix_price_to_invoice)
- return res
-
- def _real_margin_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = account.ca_invoiced + account.total_cost
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _theorical_margin_calc(self, cr, uid, ids, name, arg, context=None):
- res = {}
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id] = account.ca_theorical + account.total_cost
- for id in ids:
- res[id] = round(res.get(id, 0.0),2)
- return res
-
- def _is_overdue_quantity(self, cr, uid, ids, fieldnames, args, context=None):
- result = dict.fromkeys(ids, 0)
- for record in self.browse(cr, uid, ids, context=context):
- if record.quantity_max > 0.0:
- result[record.id] = int(record.hours_quantity >= record.quantity_max)
- else:
- result[record.id] = 0
- return result
-
- def _get_analytic_account(self, cr, uid, ids, context=None):
- result = set()
- for line in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):
- result.add(line.account_id.id)
- return list(result)
-
- def _get_total_estimation(self, account):
- tot_est = 0.0
- if account.fix_price_invoices:
- tot_est += account.amount_max
- if account.invoice_on_timesheets:
- tot_est += account.hours_qtt_est
- return tot_est
-
- def _get_total_invoiced(self, account):
- total_invoiced = 0.0
- if account.fix_price_invoices:
- total_invoiced += account.ca_invoiced
- if account.invoice_on_timesheets:
- total_invoiced += account.timesheet_ca_invoiced
- return total_invoiced
-
- def _get_total_remaining(self, account):
- total_remaining = 0.0
- if account.fix_price_invoices:
- total_remaining += account.remaining_ca
- if account.invoice_on_timesheets:
- total_remaining += account.remaining_hours_to_invoice
- return total_remaining
-
- def _get_total_toinvoice(self, account):
- total_toinvoice = 0.0
- if account.fix_price_invoices:
- total_toinvoice += account.fix_price_to_invoice
- if account.invoice_on_timesheets:
- total_toinvoice += account.ca_to_invoice
- return total_toinvoice
-
- def _sum_of_fields(self, cr, uid, ids, name, arg, context=None):
- res = dict([(i, {}) for i in ids])
- for account in self.browse(cr, uid, ids, context=context):
- res[account.id]['est_total'] = self._get_total_estimation(account)
- res[account.id]['invoiced_total'] = self._get_total_invoiced(account)
- res[account.id]['remaining_total'] = self._get_total_remaining(account)
- res[account.id]['toinvoice_total'] = self._get_total_toinvoice(account)
- return res
-
- _columns = {
- 'is_overdue_quantity' : fields.function(_is_overdue_quantity, method=True, type='boolean', string='Overdue Quantity',
- store={
- 'account.analytic.line' : (_get_analytic_account, None, 20),
- 'account.analytic.account': (lambda self, cr, uid, ids, c=None: ids, ['quantity_max'], 10),
- }),
- 'ca_invoiced': fields.function(_ca_invoiced_calc, type='float', string='Invoiced Amount',
- help="Total customer invoiced amount for this account.",
- digits_compute=dp.get_precision('Account')),
- 'total_cost': fields.function(_total_cost_calc, type='float', string='Total Costs',
- help="Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets.",
- digits_compute=dp.get_precision('Account')),
- 'ca_to_invoice': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Amount',
- help="If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs.",
- digits_compute=dp.get_precision('Account')),
- 'ca_theorical': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Theoretical Revenue',
- help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.",
- digits_compute=dp.get_precision('Account')),
- 'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Total Worked Time',
- help="Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."),
- 'last_invoice_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Last Invoice Date',
- help="If invoice from the costs, this is the date of the latest invoiced."),
- 'last_worked_invoiced_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Invoiced Cost',
- help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
- 'last_worked_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Cost/Work',
- help="Date of the latest work done on this account."),
- 'hours_qtt_non_invoiced': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Time',
- help="Number of time (hours/days) (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
- 'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, type='float', string='Invoiced Time',
- help="Number of time (hours/days) that can be invoiced plus those that already have been invoiced."),
- 'remaining_hours': fields.function(_remaining_hours_calc, type='float', string='Remaining Time',
- help="Computed using the formula: Maximum Time - Total Worked Time"),
- 'remaining_hours_to_invoice': fields.function(_remaining_hours_to_invoice_calc, type='float', string='Remaining Time',
- help="Computed using the formula: Maximum Time - Total Invoiced Time"),
- 'fix_price_to_invoice': fields.function(_fix_price_to_invoice_calc, type='float', string='Remaining Time',
- help="Sum of quotations for this contract."),
- 'timesheet_ca_invoiced': fields.function(_timesheet_ca_invoiced_calc, type='float', string='Remaining Time',
- help="Sum of timesheet lines invoiced for this contract."),
- 'remaining_ca': fields.function(_remaining_ca_calc, type='float', string='Remaining Revenue',
- help="Computed using the formula: Max Invoice Price - Invoiced Amount.",
- digits_compute=dp.get_precision('Account')),
- 'revenue_per_hour': fields.function(_revenue_per_hour_calc, type='float', string='Revenue per Time (real)',
- help="Computed using the formula: Invoiced Amount / Total Time",
- digits_compute=dp.get_precision('Account')),
- 'real_margin': fields.function(_real_margin_calc, type='float', string='Real Margin',
- help="Computed using the formula: Invoiced Amount - Total Costs.",
- digits_compute=dp.get_precision('Account')),
- 'theorical_margin': fields.function(_theorical_margin_calc, type='float', string='Theoretical Margin',
- help="Computed using the formula: Theoretical Revenue - Total Costs",
- digits_compute=dp.get_precision('Account')),
- 'real_margin_rate': fields.function(_real_margin_rate_calc, type='float', string='Real Margin Rate (%)',
- help="Computes using the formula: (Real Margin / Total Costs) * 100.",
- digits_compute=dp.get_precision('Account')),
- 'fix_price_invoices' : fields.boolean('Fixed Price'),
- 'invoice_on_timesheets' : fields.boolean("On Timesheets"),
- 'month_ids': fields.function(_analysis_all, multi='analytic_analysis', type='many2many', relation='account_analytic_analysis.summary.month', string='Month'),
- 'user_ids': fields.function(_analysis_all, multi='analytic_analysis', type="many2many", relation='account_analytic_analysis.summary.user', string='User'),
- 'hours_qtt_est': fields.float('Estimation of Hours to Invoice'),
- 'est_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Estimation"),
- 'invoiced_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Invoiced"),
- 'remaining_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total Remaining", help="Expectation of remaining income for this contract. Computed as the sum of remaining subtotals which, in turn, are computed as the maximum between '(Estimation - Invoiced)' and 'To Invoice' amounts"),
- 'toinvoice_total' : fields.function(_sum_of_fields, type="float",multi="sum_of_all", string="Total to Invoice", help=" Sum of everything that could be invoiced for this contract."),
- }
-
- def open_sale_order_lines(self,cr,uid,ids,context=None):
- if context is None:
- context = {}
- sale_ids = self.pool.get('sale.order').search(cr,uid,[('project_id','=',context.get('search_default_project_id',False)),('partner_id','in',context.get('search_default_partner_id',False))])
- names = [record.name for record in self.browse(cr, uid, ids, context=context)]
- name = _('Sales Order Lines of %s') % ','.join(names)
- return {
- 'type': 'ir.actions.act_window',
- 'name': name,
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'context': context,
- 'domain' : [('order_id','in',sale_ids)],
- 'res_model': 'sale.order.line',
- 'nodestroy': True,
- }
-
- def on_change_template(self, cr, uid, ids, template_id, context=None):
- if not template_id:
- return {}
- res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, context=context)
- if template_id and 'value' in res:
- template = self.browse(cr, uid, template_id, context=context)
- res['value']['fix_price_invoices'] = template.fix_price_invoices
- res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
- res['value']['hours_qtt_est'] = template.hours_qtt_est
- res['value']['amount_max'] = template.amount_max
- res['value']['to_invoice'] = template.to_invoice.id
- res['value']['pricelist_id'] = template.pricelist_id.id
- return res
-
- def cron_account_analytic_account(self, cr, uid, context=None):
- if context is None:
- context = {}
- remind = {}
-
- def fill_remind(key, domain, write_pending=False):
- base_domain = [
- ('type', '=', 'contract'),
- ('partner_id', '!=', False),
- ('manager_id', '!=', False),
- ('manager_id.email', '!=', False),
- ]
- base_domain.extend(domain)
-
- accounts_ids = self.search(cr, uid, base_domain, context=context, order='name asc')
- accounts = self.browse(cr, uid, accounts_ids, context=context)
- for account in accounts:
- if write_pending:
- account.write({'state' : 'pending'}, context=context)
- remind_user = remind.setdefault(account.manager_id.id, {})
- remind_type = remind_user.setdefault(key, {})
- remind_partner = remind_type.setdefault(account.partner_id, []).append(account)
-
- # Already expired
- fill_remind("old", [('state', 'in', ['pending'])])
-
- # Expires now
- fill_remind("new", [('state', 'in', ['draft', 'open']), '|', '&', ('date', '!=', False), ('date', '<=', time.strftime('%Y-%m-%d')), ('is_overdue_quantity', '=', True)], True)
-
- # Expires in less than 30 days
- fill_remind("future", [('state', 'in', ['draft', 'open']), ('date', '!=', False), ('date', '<', (datetime.datetime.now() + datetime.timedelta(30)).strftime("%Y-%m-%d"))])
-
- context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
- context['action_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'action_account_analytic_overdue_all')[1]
- template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'account_analytic_cron_email_template')[1]
- for user_id, data in remind.items():
- context["data"] = data
- _logger.debug("Sending reminder to uid %s", user_id)
- self.pool.get('email.template').send_mail(cr, uid, template_id, user_id, force_send=True, context=context)
-
- return True
-
- def onchange_invoice_on_timesheets(self, cr, uid, ids, invoice_on_timesheets, context=None):
- if not invoice_on_timesheets:
- return {}
- result = {'value': {'use_timesheets': True}}
- try:
- to_invoice = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'hr_timesheet_invoice', 'timesheet_invoice_factor1')
- result['value']['to_invoice'] = to_invoice[1]
- except ValueError:
- pass
- return result
-
-
- def hr_to_invoice_timesheets(self, cr, uid, ids, context=None):
- domain = [('invoice_id','=',False),('to_invoice','!=',False), ('journal_id.type', '=', 'general'), ('account_id', 'in', ids)]
- names = [record.name for record in self.browse(cr, uid, ids, context=context)]
- name = _('Timesheets to Invoice of %s') % ','.join(names)
- return {
- 'type': 'ir.actions.act_window',
- 'name': name,
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'domain' : domain,
- 'res_model': 'account.analytic.line',
- 'nodestroy': True,
- }
-
-
-
-class account_analytic_account_summary_user(osv.osv):
- _name = "account_analytic_analysis.summary.user"
- _description = "Hours Summary by User"
- _order='user'
- _auto = False
- _rec_name = 'user'
-
- def _unit_amount(self, cr, uid, ids, name, arg, context=None):
- res = {}
- account_obj = self.pool.get('account.analytic.account')
- cr.execute('SELECT MAX(id) FROM res_users')
- max_user = cr.fetchone()[0]
- account_ids = [int(str(x/max_user - (x%max_user == 0 and 1 or 0))) for x in ids]
- user_ids = [int(str(x-((x/max_user - (x%max_user == 0 and 1 or 0)) *max_user))) for x in ids]
- parent_ids = tuple(account_ids) #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
- if parent_ids:
- cr.execute('SELECT id, unit_amount ' \
- 'FROM account_analytic_analysis_summary_user ' \
- 'WHERE account_id IN %s ' \
- 'AND "user" IN %s',(parent_ids, tuple(user_ids),))
- for sum_id, unit_amount in cr.fetchall():
- res[sum_id] = unit_amount
- for id in ids:
- res[id] = round(res.get(id, 0.0), 2)
- return res
-
- _columns = {
- 'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
- 'unit_amount': fields.float('Total Time'),
- 'user': fields.many2one('res.users', 'User'),
- }
-
- def init(self, cr):
- openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_user')
- cr.execute('''CREATE OR REPLACE VIEW account_analytic_analysis_summary_user AS (
- with mu as
- (select max(id) as max_user from res_users)
- , lu AS
- (SELECT
- l.account_id AS account_id,
- coalesce(l.user_id, 0) AS user_id,
- SUM(l.unit_amount) AS unit_amount
- FROM account_analytic_line AS l,
- account_analytic_journal AS j
- WHERE (j.type = 'general' ) and (j.id=l.journal_id)
- GROUP BY l.account_id, l.user_id
- )
- select (lu.account_id * mu.max_user) + lu.user_id as id,
- lu.account_id as account_id,
- lu.user_id as "user",
- unit_amount
- from lu, mu)''')
-
-class account_analytic_account_summary_month(osv.osv):
- _name = "account_analytic_analysis.summary.month"
- _description = "Hours summary by month"
- _auto = False
- _rec_name = 'month'
-
- _columns = {
- 'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
- 'unit_amount': fields.float('Total Time'),
- 'month': fields.char('Month', size=32, readonly=True),
- }
-
- def init(self, cr):
- openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_month')
- cr.execute('CREATE VIEW account_analytic_analysis_summary_month AS (' \
- 'SELECT ' \
- '(TO_NUMBER(TO_CHAR(d.month, \'YYYYMM\'), \'999999\') + (d.account_id * 1000000::bigint))::bigint AS id, ' \
- 'd.account_id AS account_id, ' \
- 'TO_CHAR(d.month, \'Mon YYYY\') AS month, ' \
- 'TO_NUMBER(TO_CHAR(d.month, \'YYYYMM\'), \'999999\') AS month_id, ' \
- 'COALESCE(SUM(l.unit_amount), 0.0) AS unit_amount ' \
- 'FROM ' \
- '(SELECT ' \
- 'd2.account_id, ' \
- 'd2.month ' \
- 'FROM ' \
- '(SELECT ' \
- 'a.id AS account_id, ' \
- 'l.month AS month ' \
- 'FROM ' \
- '(SELECT ' \
- 'DATE_TRUNC(\'month\', l.date) AS month ' \
- 'FROM account_analytic_line AS l, ' \
- 'account_analytic_journal AS j ' \
- 'WHERE j.type = \'general\' ' \
- 'GROUP BY DATE_TRUNC(\'month\', l.date) ' \
- ') AS l, ' \
- 'account_analytic_account AS a ' \
- 'GROUP BY l.month, a.id ' \
- ') AS d2 ' \
- 'GROUP BY d2.account_id, d2.month ' \
- ') AS d ' \
- 'LEFT JOIN ' \
- '(SELECT ' \
- 'l.account_id AS account_id, ' \
- 'DATE_TRUNC(\'month\', l.date) AS month, ' \
- 'SUM(l.unit_amount) AS unit_amount ' \
- 'FROM account_analytic_line AS l, ' \
- 'account_analytic_journal AS j ' \
- 'WHERE (j.type = \'general\') and (j.id=l.journal_id) ' \
- 'GROUP BY l.account_id, DATE_TRUNC(\'month\', l.date) ' \
- ') AS l '
- 'ON (' \
- 'd.account_id = l.account_id ' \
- 'AND d.month = l.month' \
- ') ' \
- 'GROUP BY d.month, d.account_id ' \
- ')')
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import datetime
+import logging
+import time
+from openerp.osv import osv, fields
+from openerp.osv.orm import intersect, except_orm
+import openerp.tools
+from openerp.tools.translate import _
+from openerp.addons.decimal_precision import decimal_precision as dp
+_logger = logging.getLogger(__name__)
+
+class account_analytic_account(osv.osv):
+ _name = 'account.analytic.account'
+ _inherit = 'account.analytic.account'
+
+ def _analysis_all(self, cr, uid, ids, fields, arg, context = None):
+ dp = 2
+ res = dict([ (i, {}) for i in ids ])
+ parent_ids = tuple(ids)
+ accounts = self.browse(cr, uid, ids, context=context)
+ for f in fields:
+ if f == 'user_ids':
+ cr.execute('SELECT MAX(id) FROM res_users')
+ max_user = cr.fetchone()[0]
+ if parent_ids:
+ cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
+ result = cr.fetchall()
+ else:
+ result = []
+ for id in ids:
+ res[id][f] = [ int(id * max_user + x[0]) for x in result ]
+
+ elif f == 'month_ids':
+ if parent_ids:
+ cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
+ result = cr.fetchall()
+ else:
+ result = []
+ for id in ids:
+ res[id][f] = [ int(id * 1000000 + int(x[0])) for x in result ]
+
+ elif f == 'last_worked_invoiced_date':
+ for id in ids:
+ res[id][f] = False
+
+ if parent_ids:
+ cr.execute('SELECT account_analytic_line.account_id, MAX(date) FROM account_analytic_line WHERE account_id IN %s AND invoice_id IS NOT NULL GROUP BY account_analytic_line.account_id;', (parent_ids,))
+ for account_id, sum in cr.fetchall():
+ if account_id not in res:
+ res[account_id] = {}
+ res[account_id][f] = sum
+
+ elif f == 'ca_to_invoice':
+ for id in ids:
+ res[id][f] = 0.0
+
+ res2 = {}
+ for account in accounts:
+ cr.execute("\n SELECT product_id, sum(amount), user_id, to_invoice, sum(unit_amount), product_uom_id, line.name\n FROM account_analytic_line line\n LEFT JOIN account_analytic_journal journal ON (journal.id = line.journal_id)\n WHERE account_id = %s\n AND journal.type != 'purchase'\n AND invoice_id IS NULL\n AND to_invoice IS NOT NULL\n GROUP BY product_id, user_id, to_invoice, product_uom_id, line.name", (account.id,))
+ res[account.id][f] = 0.0
+ for product_id, price, user_id, factor_id, qty, uom, line_name in cr.fetchall():
+ price = -price
+ if product_id:
+ price = self.pool.get('account.analytic.line')._get_invoice_price(cr, uid, account, product_id, user_id, qty, context)
+ factor = self.pool.get('hr_timesheet_invoice.factor').browse(cr, uid, factor_id, context=context)
+ res[account.id][f] += price * qty * (100 - factor.factor or 0.0) / 100.0
+
+ for id in ids:
+ res[id][f] = round(res.get(id, {}).get(f, 0.0), dp) + round(res2.get(id, 0.0), 2)
+
+ elif f == 'last_invoice_date':
+ for id in ids:
+ res[id][f] = False
+
+ if parent_ids:
+ cr.execute('SELECT account_analytic_line.account_id, DATE(MAX(account_invoice.date_invoice)) FROM account_analytic_line JOIN account_invoice ON account_analytic_line.invoice_id = account_invoice.id WHERE account_analytic_line.account_id IN %s AND account_analytic_line.invoice_id IS NOT NULL GROUP BY account_analytic_line.account_id', (parent_ids,))
+ for account_id, lid in cr.fetchall():
+ res[account_id][f] = lid
+
+ elif f == 'last_worked_date':
+ for id in ids:
+ res[id][f] = False
+
+ if parent_ids:
+ cr.execute('SELECT account_analytic_line.account_id, MAX(date) FROM account_analytic_line WHERE account_id IN %s AND invoice_id IS NULL GROUP BY account_analytic_line.account_id', (parent_ids,))
+ for account_id, lwd in cr.fetchall():
+ if account_id not in res:
+ res[account_id] = {}
+ res[account_id][f] = lwd
+
+ elif f == 'hours_qtt_non_invoiced':
+ for id in ids:
+ res[id][f] = 0.0
+
+ if parent_ids:
+ cr.execute("SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) FROM account_analytic_line JOIN account_analytic_journal ON account_analytic_line.journal_id = account_analytic_journal.id WHERE account_analytic_line.account_id IN %s AND account_analytic_journal.type='general' AND invoice_id IS NULL AND to_invoice IS NOT NULL GROUP BY account_analytic_line.account_id;", (parent_ids,))
+ for account_id, sua in cr.fetchall():
+ if account_id not in res:
+ res[account_id] = {}
+ res[account_id][f] = round(sua, dp)
+
+ for id in ids:
+ res[id][f] = round(res[id][f], dp)
+
+ elif f == 'hours_quantity':
+ for id in ids:
+ res[id][f] = 0.0
+
+ if parent_ids:
+ cr.execute("SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) FROM account_analytic_line JOIN account_analytic_journal ON account_analytic_line.journal_id = account_analytic_journal.id WHERE account_analytic_line.account_id IN %s AND account_analytic_journal.type='general' GROUP BY account_analytic_line.account_id", (parent_ids,))
+ ff = cr.fetchall()
+ for account_id, hq in ff:
+ if account_id not in res:
+ res[account_id] = {}
+ res[account_id][f] = round(hq, dp)
+
+ for id in ids:
+ res[id][f] = round(res[id][f], dp)
+
+ elif f == 'ca_theorical':
+ for id in ids:
+ res[id][f] = 0.0
+
+ if parent_ids:
+ cr.execute("SELECT account_analytic_line.account_id AS account_id, COALESCE(SUM((account_analytic_line.unit_amount * pt.list_price) - (account_analytic_line.unit_amount * pt.list_price * hr.factor)), 0.0) AS somme\n FROM account_analytic_line LEFT JOIN account_analytic_journal ON (account_analytic_line.journal_id = account_analytic_journal.id) JOIN product_product pp ON (account_analytic_line.product_id = pp.id) JOIN product_template pt ON (pp.product_tmpl_id = pt.id) JOIN account_analytic_account a ON (a.id=account_analytic_line.account_id) JOIN hr_timesheet_invoice_factor hr ON (hr.id=a.to_invoice) WHERE account_analytic_line.account_id IN %s AND a.to_invoice IS NOT NULL AND account_analytic_journal.type IN ('purchase', 'general')\n GROUP BY account_analytic_line.account_id", (parent_ids,))
+ for account_id, sum in cr.fetchall():
+ res[account_id][f] = round(sum, dp)
+
+ return res
+
+ def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ res_final = {}
+ child_ids = tuple(ids)
+ for i in child_ids:
+ res[i] = 0.0
+
+ if not child_ids:
+ return res
+ if child_ids:
+ inv_line_obj = self.pool.get('account.invoice.line')
+ inv_lines = inv_line_obj.search(cr, uid, ['&', ('account_analytic_id', 'in', child_ids), ('invoice_id.state', '!=', 'cancel')], context=context)
+ for line in inv_line_obj.browse(cr, uid, inv_lines, context=context):
+ res[line.account_analytic_id.id] += line.price_subtotal
+
+ for acc in self.browse(cr, uid, res.keys(), context=context):
+ res[acc.id] = res[acc.id] - (acc.timesheet_ca_invoiced or 0.0)
+
+ res_final = res
+ return res_final
+
+ def _total_cost_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ res_final = {}
+ child_ids = tuple(ids)
+ for i in child_ids:
+ res[i] = 0.0
+
+ if not child_ids:
+ return res
+ if child_ids:
+ cr.execute('SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) FROM account_analytic_line JOIN account_analytic_journal ON account_analytic_line.journal_id = account_analytic_journal.id WHERE account_analytic_line.account_id IN %s AND amount<0 GROUP BY account_analytic_line.account_id', (child_ids,))
+ for account_id, sum in cr.fetchall():
+ res[account_id] = round(sum, 2)
+
+ res_final = res
+ return res_final
+
+ def _remaining_hours_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ if account.quantity_max != 0:
+ res[account.id] = account.quantity_max - account.hours_quantity
+ else:
+ res[account.id] = 0.0
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _remaining_hours_to_invoice_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = max(account.hours_qtt_est - account.timesheet_ca_invoiced, account.ca_to_invoice)
+
+ return res
+
+ def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = account.hours_quantity - account.hours_qtt_non_invoiced
+ if res[account.id] < 0:
+ res[account.id] = 0.0
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _revenue_per_hour_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ if account.hours_qtt_invoiced == 0:
+ res[account.id] = 0.0
+ else:
+ res[account.id] = account.ca_invoiced / account.hours_qtt_invoiced
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _real_margin_rate_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ if account.ca_invoiced == 0:
+ res[account.id] = 0.0
+ elif account.total_cost != 0.0:
+ res[account.id] = -(account.real_margin / account.total_cost) * 100
+ else:
+ res[account.id] = 0.0
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _fix_price_to_invoice_calc(self, cr, uid, ids, name, arg, context = None):
+ sale_obj = self.pool.get('sale.order')
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = 0.0
+ sale_ids = sale_obj.search(cr, uid, [('project_id', '=', account.id), ('state', '=', 'manual')], context=context)
+ for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
+ res[account.id] += sale.amount_untaxed
+ for invoice in sale.invoice_ids:
+ if invoice.state != 'cancel':
+ res[account.id] -= invoice.amount_untaxed
+
+ return res
+
+ def _timesheet_ca_invoiced_calc(self, cr, uid, ids, name, arg, context = None):
+ lines_obj = self.pool.get('account.analytic.line')
+ res = {}
+ inv_ids = []
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = 0.0
+ line_ids = lines_obj.search(cr, uid, [('account_id', '=', account.id),
+ ('invoice_id', '!=', False),
+ ('to_invoice', '!=', False),
+ ('journal_id.type', '=', 'general')], context=context)
+ for line in lines_obj.browse(cr, uid, line_ids, context=context):
+ if line.invoice_id not in inv_ids:
+ inv_ids.append(line.invoice_id)
+ res[account.id] += line.invoice_id.amount_untaxed
+
+ return res
+
+ def _remaining_ca_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = max(account.amount_max - account.ca_invoiced, account.fix_price_to_invoice)
+
+ return res
+
+ def _real_margin_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = account.ca_invoiced + account.total_cost
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _theorical_margin_calc(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id] = account.ca_theorical + account.total_cost
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ def _is_overdue_quantity(self, cr, uid, ids, fieldnames, args, context = None):
+ result = dict.fromkeys(ids, 0)
+ for record in self.browse(cr, uid, ids, context=context):
+ if record.quantity_max > 0.0:
+ result[record.id] = int(record.hours_quantity >= record.quantity_max)
+ else:
+ result[record.id] = 0
+
+ return result
+
+ def _get_analytic_account(self, cr, uid, ids, context = None):
+ result = set()
+ for line in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):
+ result.add(line.account_id.id)
+
+ return list(result)
+
+ def _get_total_estimation(self, account):
+ tot_est = 0.0
+ if account.fix_price_invoices:
+ tot_est += account.amount_max
+ if account.invoice_on_timesheets:
+ tot_est += account.hours_qtt_est
+ return tot_est
+
+ def _get_total_invoiced(self, account):
+ total_invoiced = 0.0
+ if account.fix_price_invoices:
+ total_invoiced += account.ca_invoiced
+ if account.invoice_on_timesheets:
+ total_invoiced += account.timesheet_ca_invoiced
+ return total_invoiced
+
+ def _get_total_remaining(self, account):
+ total_remaining = 0.0
+ if account.fix_price_invoices:
+ total_remaining += account.remaining_ca
+ if account.invoice_on_timesheets:
+ total_remaining += account.remaining_hours_to_invoice
+ return total_remaining
+
+ def _get_total_toinvoice(self, account):
+ total_toinvoice = 0.0
+ if account.fix_price_invoices:
+ total_toinvoice += account.fix_price_to_invoice
+ if account.invoice_on_timesheets:
+ total_toinvoice += account.ca_to_invoice
+ return total_toinvoice
+
+ def _sum_of_fields(self, cr, uid, ids, name, arg, context = None):
+ res = dict([ (i, {}) for i in ids ])
+ for account in self.browse(cr, uid, ids, context=context):
+ res[account.id]['est_total'] = self._get_total_estimation(account)
+ res[account.id]['invoiced_total'] = self._get_total_invoiced(account)
+ res[account.id]['remaining_total'] = self._get_total_remaining(account)
+ res[account.id]['toinvoice_total'] = self._get_total_toinvoice(account)
+
+ return res
+
+ _columns = {'is_overdue_quantity': fields.function(_is_overdue_quantity, method=True, type='boolean', string='Overdue Quantity', store={'account.analytic.line': (_get_analytic_account, None, 20)}),
+ 'ca_invoiced': fields.function(_ca_invoiced_calc, type='float', string='Invoiced Amount', help='Total customer invoiced amount for this account.', digits_compute=dp.get_precision('Account')),
+ 'total_cost': fields.function(_total_cost_calc, type='float', string='Total Costs', help='Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets.', digits_compute=dp.get_precision('Account')),
+ 'ca_to_invoice': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Amount', help='If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs.', digits_compute=dp.get_precision('Account')),
+ 'ca_theorical': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Theoretical Revenue', help='Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.', digits_compute=dp.get_precision('Account')),
+ 'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Total Worked Time', help="Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."),
+ 'last_invoice_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Last Invoice Date', help='If invoice from the costs, this is the date of the latest invoiced.'),
+ 'last_worked_invoiced_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Invoiced Cost', help='If invoice from the costs, this is the date of the latest work or cost that have been invoiced.'),
+ 'last_worked_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Cost/Work', help='Date of the latest work done on this account.'),
+ 'hours_qtt_non_invoiced': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Time', help="Number of time (hours/days) (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
+ 'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, type='float', string='Invoiced Time', help='Number of time (hours/days) that can be invoiced plus those that already have been invoiced.'),
+ 'remaining_hours': fields.function(_remaining_hours_calc, type='float', string='Remaining Time', help='Computed using the formula: Maximum Time - Total Worked Time'),
+ 'remaining_hours_to_invoice': fields.function(_remaining_hours_to_invoice_calc, type='float', string='Remaining Time', help='Computed using the formula: Maximum Time - Total Invoiced Time'),
+ 'fix_price_to_invoice': fields.function(_fix_price_to_invoice_calc, type='float', string='Remaining Time', help='Sum of quotations for this contract.'),
+ 'timesheet_ca_invoiced': fields.function(_timesheet_ca_invoiced_calc, type='float', string='Remaining Time', help='Sum of timesheet lines invoiced for this contract.'),
+ 'remaining_ca': fields.function(_remaining_ca_calc, type='float', string='Remaining Revenue', help='Computed using the formula: Max Invoice Price - Invoiced Amount.', digits_compute=dp.get_precision('Account')),
+ 'revenue_per_hour': fields.function(_revenue_per_hour_calc, type='float', string='Revenue per Time (real)', help='Computed using the formula: Invoiced Amount / Total Time', digits_compute=dp.get_precision('Account')),
+ 'real_margin': fields.function(_real_margin_calc, type='float', string='Real Margin', help='Computed using the formula: Invoiced Amount - Total Costs.', digits_compute=dp.get_precision('Account')),
+ 'theorical_margin': fields.function(_theorical_margin_calc, type='float', string='Theoretical Margin', help='Computed using the formula: Theoretical Revenue - Total Costs', digits_compute=dp.get_precision('Account')),
+ 'real_margin_rate': fields.function(_real_margin_rate_calc, type='float', string='Real Margin Rate (%)', help='Computes using the formula: (Real Margin / Total Costs) * 100.', digits_compute=dp.get_precision('Account')),
+ 'fix_price_invoices': fields.boolean('Fixed Price'),
+ 'invoice_on_timesheets': fields.boolean('On Timesheets'),
+ 'month_ids': fields.function(_analysis_all, multi='analytic_analysis', type='many2many', relation='account_analytic_analysis.summary.month', string='Month'),
+ 'user_ids': fields.function(_analysis_all, multi='analytic_analysis', type='many2many', relation='account_analytic_analysis.summary.user', string='User'),
+ 'hours_qtt_est': fields.float('Estimation of Hours to Invoice'),
+ 'est_total': fields.function(_sum_of_fields, type='float', multi='sum_of_all', string='Total Estimation'),
+ 'invoiced_total': fields.function(_sum_of_fields, type='float', multi='sum_of_all', string='Total Invoiced'),
+ 'remaining_total': fields.function(_sum_of_fields, type='float', multi='sum_of_all', string='Total Remaining', help="Expectation of remaining income for this contract. Computed as the sum of remaining subtotals which, in turn, are computed as the maximum between '(Estimation - Invoiced)' and 'To Invoice' amounts"),
+ 'toinvoice_total': fields.function(_sum_of_fields, type='float', multi='sum_of_all', string='Total to Invoice', help=' Sum of everything that could be invoiced for this contract.')}
+
+ def open_sale_order_lines(self, cr, uid, ids, context = None):
+ if context is None:
+ context = {}
+ sale_ids = self.pool.get('sale.order').search(cr, uid, [('project_id', '=', context.get('search_default_project_id', False)), ('partner_id', 'in', context.get('search_default_partner_id', False))])
+ names = [ record.name for record in self.browse(cr, uid, ids, context=context) ]
+ name = _('Sales Order Lines of %s') % ','.join(names)
+ return {'type': 'ir.actions.act_window',
+ 'name': name,
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'context': context,
+ 'domain': [('order_id', 'in', sale_ids)],
+ 'res_model': 'sale.order.line',
+ 'nodestroy': True}
+
+ def on_change_template(self, cr, uid, ids, template_id, context = None):
+ if not template_id:
+ return {}
+ res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, context=context)
+ if template_id and 'value' in res:
+ template = self.browse(cr, uid, template_id, context=context)
+ res['value']['fix_price_invoices'] = template.fix_price_invoices
+ res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
+ res['value']['hours_qtt_est'] = template.hours_qtt_est
+ res['value']['amount_max'] = template.amount_max
+ res['value']['to_invoice'] = template.to_invoice.id
+ res['value']['pricelist_id'] = template.pricelist_id.id
+ return res
+
+ def cron_account_analytic_account(self, cr, uid, context = None):
+ if context is None:
+ context = {}
+ remind = {}
+
+ def fill_remind(key, domain, write_pending = False):
+ base_domain = [('type', '=', 'contract'),
+ ('partner_id', '!=', False),
+ ('manager_id', '!=', False),
+ ('manager_id.email', '!=', False)]
+ base_domain.extend(domain)
+ accounts_ids = self.search(cr, uid, base_domain, context=context, order='name asc')
+ accounts = self.browse(cr, uid, accounts_ids, context=context)
+ for account in accounts:
+ if write_pending:
+ account.write({'state': 'pending'}, context=context)
+ remind_user = remind.setdefault(account.manager_id.id, {})
+ remind_type = remind_user.setdefault(key, {})
+ remind_partner = remind_type.setdefault(account.partner_id, []).append(account)
+
+ fill_remind('old', [('state', 'in', ['pending'])])
+ fill_remind('new', [('state', 'in', ['draft', 'open']),
+ '|',
+ '&',
+ ('date', '!=', False),
+ ('date', '<=', time.strftime('%Y-%m-%d')),
+ ('is_overdue_quantity', '=', True)], True)
+ fill_remind('future', [('state', 'in', ['draft', 'open']), ('date', '!=', False), ('date', '<', (datetime.datetime.now() + datetime.timedelta(30)).strftime('%Y-%m-%d'))])
+ context['base_url'] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
+ context['action_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'action_account_analytic_overdue_all')[1]
+ template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_analytic_analysis', 'account_analytic_cron_email_template')[1]
+ for user_id, data in remind.items():
+ context['data'] = data
+ _logger.debug('Sending reminder to uid %s', user_id)
+ self.pool.get('email.template').send_mail(cr, uid, template_id, user_id, force_send=True, context=context)
+
+ return True
+
+ def onchange_invoice_on_timesheets(self, cr, uid, ids, invoice_on_timesheets, context = None):
+ if not invoice_on_timesheets:
+ return {}
+ result = {'value': {'use_timesheets': True}}
+ try:
+ to_invoice = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'hr_timesheet_invoice', 'timesheet_invoice_factor1')
+ result['value']['to_invoice'] = to_invoice[1]
+ except ValueError:
+ pass
+
+ return result
+
+ def hr_to_invoice_timesheets(self, cr, uid, ids, context = None):
+ domain = [('invoice_id', '=', False),
+ ('to_invoice', '!=', False),
+ ('journal_id.type', '=', 'general'),
+ ('account_id', 'in', ids)]
+ names = [ record.name for record in self.browse(cr, uid, ids, context=context) ]
+ name = _('Timesheets to Invoice of %s') % ','.join(names)
+ return {'type': 'ir.actions.act_window',
+ 'name': name,
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'domain': domain,
+ 'res_model': 'account.analytic.line',
+ 'nodestroy': True}
+
+
+class account_analytic_account_summary_user(osv.osv):
+ _name = 'account_analytic_analysis.summary.user'
+ _description = 'Hours Summary by User'
+ _order = 'user'
+ _auto = False
+ _rec_name = 'user'
+
+ def _unit_amount(self, cr, uid, ids, name, arg, context = None):
+ res = {}
+ account_obj = self.pool.get('account.analytic.account')
+ cr.execute('SELECT MAX(id) FROM res_users')
+ max_user = cr.fetchone()[0]
+ account_ids = [ int(str(x / max_user - (x % max_user == 0 and 1 or 0))) for x in ids ]
+ user_ids = [ int(str(x - (x / max_user - (x % max_user == 0 and 1 or 0)) * max_user)) for x in ids ]
+ parent_ids = tuple(account_ids)
+ if parent_ids:
+ cr.execute('SELECT id, unit_amount FROM account_analytic_analysis_summary_user WHERE account_id IN %s AND "user" IN %s', (parent_ids, tuple(user_ids)))
+ for sum_id, unit_amount in cr.fetchall():
+ res[sum_id] = unit_amount
+
+ for id in ids:
+ res[id] = round(res.get(id, 0.0), 2)
+
+ return res
+
+ _columns = {'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
+ 'unit_amount': fields.float('Total Time'),
+ 'user': fields.many2one('res.users', 'User')}
+
+ def init(self, cr):
+ openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_user')
+ cr.execute('CREATE OR REPLACE VIEW account_analytic_analysis_summary_user AS (\n with mu as\n (select max(id) as max_user from res_users)\n , lu AS\n (SELECT \n l.account_id AS account_id, \n coalesce(l.user_id, 0) AS user_id, \n SUM(l.unit_amount) AS unit_amount \n FROM account_analytic_line AS l, \n account_analytic_journal AS j \n WHERE (j.type = \'general\' ) and (j.id=l.journal_id) \n GROUP BY l.account_id, l.user_id \n )\n select (lu.account_id * mu.max_user) + lu.user_id as id,\n lu.account_id as account_id,\n lu.user_id as "user",\n unit_amount\n from lu, mu)')
+
+
+class account_analytic_account_summary_month(osv.osv):
+ _name = 'account_analytic_analysis.summary.month'
+ _description = 'Hours summary by month'
+ _auto = False
+ _rec_name = 'month'
+ _columns = {'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
+ 'unit_amount': fields.float('Total Time'),
+ 'month': fields.char('Month', size=32, readonly=True)}
+
+ def init(self, cr):
+ openerp.tools.sql.drop_view_if_exists(cr, 'account_analytic_analysis_summary_month')
+ cr.execute("CREATE VIEW account_analytic_analysis_summary_month AS (SELECT (TO_NUMBER(TO_CHAR(d.month, 'YYYYMM'), '999999') + (d.account_id * 1000000::bigint))::bigint AS id, d.account_id AS account_id, TO_CHAR(d.month, 'Mon YYYY') AS month, TO_NUMBER(TO_CHAR(d.month, 'YYYYMM'), '999999') AS month_id, COALESCE(SUM(l.unit_amount), 0.0) AS unit_amount FROM (SELECT d2.account_id, d2.month FROM (SELECT a.id AS account_id, l.month AS month FROM (SELECT DATE_TRUNC('month', l.date) AS month FROM account_analytic_line AS l, account_analytic_journal AS j WHERE j.type = 'general' GROUP BY DATE_TRUNC('month', l.date) ) AS l, account_analytic_account AS a GROUP BY l.month, a.id ) AS d2 GROUP BY d2.account_id, d2.month ) AS d LEFT JOIN (SELECT l.account_id AS account_id, DATE_TRUNC('month', l.date) AS month, SUM(l.unit_amount) AS unit_amount FROM account_analytic_line AS l, account_analytic_journal AS j WHERE (j.type = 'general') and (j.id=l.journal_id) GROUP BY l.account_id, DATE_TRUNC('month', l.date) ) AS l ON (d.account_id = l.account_id AND d.month = l.month) GROUP BY d.month, d.account_id )")
\ No newline at end of file
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_cron.xml b/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
index 5690d4244eb43..4a9cf457c3f9a 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_cron.xml
@@ -4,9 +4,9 @@
Contract expiration reminder
- ${(object.email or '')|safe}
+ ${object.email or ''}
Contract expiration reminder ${user.company_id.name}
- ${object.email|safe}
+ ${object.email}
${object.lang}
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
index 3d7a2d3a9fbad..c70a2493be9c7 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
@@ -168,7 +168,6 @@
account.analytic.account.list.contract
account.analytic.account
-
@@ -193,7 +192,7 @@
-
+
).
-#
-# 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 .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-
-class sale_configuration(osv.osv_memory):
- _inherit = 'sale.config.settings'
-
- _columns = {
- 'group_template_required': fields.boolean("Mandatory use of templates.",
- implied_group='account_analytic_analysis.group_template_required',
- help="Allows you to set the template field as required when creating an analytic account or a contract."),
- }
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp.osv import fields, osv
+
+class sale_configuration(osv.osv_memory):
+ _inherit = 'sale.config.settings'
+ _columns = {'group_template_required': fields.boolean('Mandatory use of templates.', implied_group='account_analytic_analysis.group_template_required', help='Allows you to set the template field as required when creating an analytic account or a contract.')}
\ No newline at end of file
diff --git a/addons/account_analytic_analysis/static/src/css/Makefile b/addons/account_analytic_analysis/static/src/css/Makefile
new file mode 100644
index 0000000000000..21462c06dccb1
--- /dev/null
+++ b/addons/account_analytic_analysis/static/src/css/Makefile
@@ -0,0 +1,3 @@
+analytic.css: analytic.sass
+ sass -t expanded analytic.sass analytic.css
+
diff --git a/addons/account_analytic_default/account_analytic_default.py b/addons/account_analytic_default/account_analytic_default.py
index 488cb0d9c25c3..6c2d74698fd83 100644
--- a/addons/account_analytic_default/account_analytic_default.py
+++ b/addons/account_analytic_default/account_analytic_default.py
@@ -1,123 +1,122 @@
-# -*- coding: utf-8 -*-
-###############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-
-from openerp.osv import fields, osv
-
-class account_analytic_default(osv.osv):
- _name = "account.analytic.default"
- _description = "Analytic Distribution"
- _rec_name = "analytic_id"
- _order = "sequence"
- _columns = {
- 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of analytic distribution"),
- 'analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
- 'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Select a product which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this product, it will automatically take this as an analytic account)"),
- 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='cascade', help="Select a partner which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this partner, it will automatically take this as an analytic account)"),
- 'user_id': fields.many2one('res.users', 'User', ondelete='cascade', help="Select a user which will use analytic account specified in analytic default."),
- 'company_id': fields.many2one('res.company', 'Company', ondelete='cascade', help="Select a company which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this company, it will automatically take this as an analytic account)"),
- 'date_start': fields.date('Start Date', help="Default start date for this Analytic Account."),
- 'date_stop': fields.date('End Date', help="Default end date for this Analytic Account."),
- }
-
- def account_get(self, cr, uid, product_id=None, partner_id=None, user_id=None, date=None, context=None):
- domain = []
- if product_id:
- domain += ['|', ('product_id', '=', product_id)]
- domain += [('product_id','=', False)]
- if partner_id:
- domain += ['|', ('partner_id', '=', partner_id)]
- domain += [('partner_id', '=', False)]
- if user_id:
- domain += ['|',('user_id', '=', user_id)]
- domain += [('user_id','=', False)]
- if date:
- domain += ['|', ('date_start', '<=', date), ('date_start', '=', False)]
- domain += ['|', ('date_stop', '>=', date), ('date_stop', '=', False)]
- best_index = -1
- res = False
- for rec in self.browse(cr, uid, self.search(cr, uid, domain, context=context), context=context):
- index = 0
- if rec.product_id: index += 1
- if rec.partner_id: index += 1
- if rec.user_id: index += 1
- if rec.date_start: index += 1
- if rec.date_stop: index += 1
- if index > best_index:
- res = rec
- best_index = index
- return res
-
-account_analytic_default()
-
-class account_invoice_line(osv.osv):
- _inherit = "account.invoice.line"
- _description = "Invoice Line"
-
- def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None):
- res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id=currency_id, context=context, company_id=company_id)
- rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context)
- if rec:
- res_prod['value'].update({'account_analytic_id': rec.analytic_id.id})
- else:
- res_prod['value'].update({'account_analytic_id': False})
- return res_prod
-
-account_invoice_line()
-
-
-class stock_picking(osv.osv):
- _inherit = "stock.picking"
-
- def _get_account_analytic_invoice(self, cursor, user, picking, move_line):
- partner_id = picking.partner_id and picking.partner_id.id or False
- rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id , user, time.strftime('%Y-%m-%d'), context={})
-
- if rec:
- return rec.analytic_id.id
-
- return super(stock_picking, self)._get_account_analytic_invoice(cursor, user, picking, move_line)
-
-stock_picking()
-
-class sale_order_line(osv.osv):
- _inherit = "sale.order.line"
-
- # Method overridden to set the analytic account by default on criterion match
- def invoice_line_create(self, cr, uid, ids, context=None):
- create_ids = super(sale_order_line, self).invoice_line_create(cr, uid, ids, context=context)
- if not ids:
- return create_ids
- sale_line = self.browse(cr, uid, ids[0], context=context)
- inv_line_obj = self.pool.get('account.invoice.line')
- anal_def_obj = self.pool.get('account.analytic.default')
-
- for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
- rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, time.strftime('%Y-%m-%d'), context=context)
-
- if rec:
- inv_line_obj.write(cr, uid, [line.id], {'account_analytic_id': rec.analytic_id.id}, context=context)
- return create_ids
-
-sale_order_line()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.osv import fields, osv
+
+class account_analytic_default(osv.osv):
+ _name = 'account.analytic.default'
+ _description = 'Analytic Distribution'
+ _rec_name = 'analytic_id'
+ _order = 'sequence'
+ _columns = {'sequence': fields.integer('Sequence', help='Gives the sequence order when displaying a list of analytic distribution'),
+ 'analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
+ 'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help='Select a product which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this product, it will automatically take this as an analytic account)'),
+ 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='cascade', help='Select a partner which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this partner, it will automatically take this as an analytic account)'),
+ 'user_id': fields.many2one('res.users', 'User', ondelete='cascade', help='Select a user which will use analytic account specified in analytic default.'),
+ 'company_id': fields.many2one('res.company', 'Company', ondelete='cascade', help='Select a company which will use analytic account specified in analytic default (e.g. create new customer invoice or Sales order if we select this company, it will automatically take this as an analytic account)'),
+ 'date_start': fields.date('Start Date', help='Default start date for this Analytic Account.'),
+ 'date_stop': fields.date('End Date', help='Default end date for this Analytic Account.')}
+
+ def account_get(self, cr, uid, product_id = None, partner_id = None, user_id = None, date = None, context = None):
+ domain = []
+ if product_id:
+ domain += ['|', ('product_id', '=', product_id)]
+ domain += [('product_id', '=', False)]
+ if partner_id:
+ domain += ['|', ('partner_id', '=', partner_id)]
+ domain += [('partner_id', '=', False)]
+ if user_id:
+ domain += ['|', ('user_id', '=', user_id)]
+ domain += [('user_id', '=', False)]
+ if date:
+ domain += ['|', ('date_start', '<=', date), ('date_start', '=', False)]
+ domain += ['|', ('date_stop', '>=', date), ('date_stop', '=', False)]
+ best_index = -1
+ res = False
+ for rec in self.browse(cr, uid, self.search(cr, uid, domain, context=context), context=context):
+ index = 0
+ if rec.product_id:
+ index += 1
+ if rec.partner_id:
+ index += 1
+ if rec.user_id:
+ index += 1
+ if rec.date_start:
+ index += 1
+ if rec.date_stop:
+ index += 1
+ if index > best_index:
+ res = rec
+ best_index = index
+
+ return res
+
+
+account_analytic_default()
+
+class account_invoice_line(osv.osv):
+ _inherit = 'account.invoice.line'
+ _description = 'Invoice Line'
+
+ def product_id_change(self, cr, uid, ids, product, uom_id, qty = 0, name = '', type = 'out_invoice', partner_id = False, fposition_id = False, price_unit = False, currency_id = False, context = None, company_id = None):
+ res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id=currency_id, context=context, company_id=company_id)
+ rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context)
+ if rec:
+ res_prod['value'].update({'account_analytic_id': rec.analytic_id.id})
+ else:
+ res_prod['value'].update({'account_analytic_id': False})
+ return res_prod
+
+
+account_invoice_line()
+
+class stock_picking(osv.osv):
+ _inherit = 'stock.picking'
+
+ def _get_account_analytic_invoice(self, cursor, user, picking, move_line):
+ partner_id = picking.partner_id and picking.partner_id.id or False
+ rec = self.pool.get('account.analytic.default').account_get(cursor, user, move_line.product_id.id, partner_id, user, time.strftime('%Y-%m-%d'), context={})
+ if rec:
+ return rec.analytic_id.id
+ return super(stock_picking, self)._get_account_analytic_invoice(cursor, user, picking, move_line)
+
+
+stock_picking()
+
+class sale_order_line(osv.osv):
+ _inherit = 'sale.order.line'
+
+ def invoice_line_create(self, cr, uid, ids, context = None):
+ create_ids = super(sale_order_line, self).invoice_line_create(cr, uid, ids, context=context)
+ if not ids:
+ return create_ids
+ sale_line = self.browse(cr, uid, ids[0], context=context)
+ inv_line_obj = self.pool.get('account.invoice.line')
+ anal_def_obj = self.pool.get('account.analytic.default')
+ for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
+ rec = anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, sale_line.order_id.user_id.id, time.strftime('%Y-%m-%d'), context=context)
+ if rec:
+ inv_line_obj.write(cr, uid, [line.id], {'account_analytic_id': rec.analytic_id.id}, context=context)
+
+ return create_ids
+
+
+sale_order_line()
\ No newline at end of file
diff --git a/addons/account_analytic_default/images/analytic_defaults.jpeg b/addons/account_analytic_default/images/analytic_defaults.jpeg
new file mode 100644
index 0000000000000..2f85c83e4d45b
Binary files /dev/null and b/addons/account_analytic_default/images/analytic_defaults.jpeg differ
diff --git a/addons/account_analytic_plans/account_analytic_plans.py b/addons/account_analytic_plans/account_analytic_plans.py
index 0db70291ea58d..61cf000dc861e 100644
--- a/addons/account_analytic_plans/account_analytic_plans.py
+++ b/addons/account_analytic_plans/account_analytic_plans.py
@@ -1,497 +1,481 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-from lxml import etree
-
-from openerp.osv import fields, osv
-from openerp import tools
-from openerp.tools.translate import _
-
-class one2many_mod2(fields.one2many):
- def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
- if context is None:
- context = {}
- res = {}
- for id in ids:
- res[id] = []
- ids2 = None
- if 'journal_id' in context:
- journal = obj.pool.get('account.journal').browse(cr, user, context['journal_id'], context=context)
- pnum = int(name[7]) -1
- plan = journal.plan_id
- if plan and len(plan.plan_ids) > pnum:
- acc_id = plan.plan_ids[pnum].root_analytic_id.id
- ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids),('analytic_account_id','child_of',[acc_id])], limit=self._limit)
- if ids2 is None:
- ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit)
- for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
- res[r[self._fields_id]].append( r['id'] )
- return res
-
-class account_analytic_line(osv.osv):
- _inherit = 'account.analytic.line'
- _description = 'Analytic Line'
-
- def _get_amount(self, cr, uid, ids, name, args, context=None):
- res = {}
- for id in ids:
- res.setdefault(id, 0.0)
- for line in self.browse(cr, uid, ids, context=context):
- amount = line.move_id and line.move_id.amount_currency * (line.percentage / 100) or 0.0
- res[line.id] = amount
- return res
-
- _columns = {
- 'amount_currency': fields.function(_get_amount, string="Amount Currency", type="float", store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True),
- 'percentage': fields.float('Percentage')
- }
-
-account_analytic_line()
-
-class account_analytic_plan(osv.osv):
- _name = "account.analytic.plan"
- _description = "Analytic Plan"
- _columns = {
- 'name': fields.char('Analytic Plan', size=64, required=True, select=True),
- 'plan_ids': fields.one2many('account.analytic.plan.line', 'plan_id', 'Analytic Plans'),
- }
-
-account_analytic_plan()
-
-class account_analytic_plan_line(osv.osv):
- _name = "account.analytic.plan.line"
- _description = "Analytic Plan Line"
- _order = "sequence, id"
- _columns = {
- 'plan_id': fields.many2one('account.analytic.plan','Analytic Plan',required=True),
- 'name': fields.char('Plan Name', size=64, required=True, select=True),
- 'sequence': fields.integer('Sequence'),
- 'root_analytic_id': fields.many2one('account.analytic.account', 'Root Account', help="Root account of this plan.", required=False),
- 'min_required': fields.float('Minimum Allowed (%)'),
- 'max_required': fields.float('Maximum Allowed (%)'),
- }
- _defaults = {
- 'min_required': 100.0,
- 'max_required': 100.0,
- }
-
-account_analytic_plan_line()
-
-class account_analytic_plan_instance(osv.osv):
- _name = "account.analytic.plan.instance"
- _description = "Analytic Plan Instance"
- _columns = {
- 'name': fields.char('Analytic Distribution', size=64),
- 'code': fields.char('Distribution Code', size=16),
- 'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal' ),
- 'account_ids': fields.one2many('account.analytic.plan.instance.line', 'plan_id', 'Account Id'),
- 'account1_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account1 Id'),
- 'account2_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account2 Id'),
- 'account3_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account3 Id'),
- 'account4_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account4 Id'),
- 'account5_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account5 Id'),
- 'account6_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account6 Id'),
- 'plan_id': fields.many2one('account.analytic.plan', "Model's Plan"),
- }
-
- def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
- if context is None:
- context = {}
- journal_obj = self.pool.get('account.journal')
- if context.get('journal_id', False):
- journal = journal_obj.browse(cr, user, [context['journal_id']], context=context)[0]
- analytic_journal = journal.analytic_journal_id and journal.analytic_journal_id.id or False
- args.append('|')
- args.append(('journal_id', '=', analytic_journal))
- args.append(('journal_id', '=', False))
- res = super(account_analytic_plan_instance, self).search(cr, user, args, offset=offset, limit=limit, order=order,
- context=context, count=count)
- return res
-
- def copy(self, cr, uid, id, default=None, context=None):
- if not default:
- default = {}
- default.update({'account1_ids':False, 'account2_ids':False, 'account3_ids':False,
- 'account4_ids':False, 'account5_ids':False, 'account6_ids':False})
- return super(account_analytic_plan_instance, self).copy(cr, uid, id, default, context=context)
-
- def _default_journal(self, cr, uid, context=None):
- if context is None:
- context = {}
- journal_obj = self.pool.get('account.journal')
- if context.has_key('journal_id') and context['journal_id']:
- journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
- if journal.analytic_journal_id:
- return journal.analytic_journal_id.id
- return False
-
- _defaults = {
- 'plan_id': False,
- 'journal_id': _default_journal,
- }
- def name_get(self, cr, uid, ids, context=None):
- res = []
- for inst in self.browse(cr, uid, ids, context=context):
- name = inst.name or '/'
- if name and inst.code:
- name=name+' ('+inst.code+')'
- res.append((inst.id, name))
- return res
-
- def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
- args = args or []
- if name:
- ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context or {})
- if not ids:
- ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context or {})
- else:
- ids = self.search(cr, uid, args, limit=limit, context=context or {})
- return self.name_get(cr, uid, ids, context or {})
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if context is None:
- context = {}
- wiz_id = self.pool.get('ir.actions.act_window').search(cr, uid, [("name","=","analytic.plan.create.model.action")], context=context)
- res = super(account_analytic_plan_instance,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
- journal_obj = self.pool.get('account.journal')
- analytic_plan_obj = self.pool.get('account.analytic.plan')
- if (res['type']=='form'):
- plan_id = False
- if context.get('journal_id', False):
- plan_id = journal_obj.browse(cr, uid, int(context['journal_id']), context=context).plan_id
- elif context.get('plan_id', False):
- plan_id = analytic_plan_obj.browse(cr, uid, int(context['plan_id']), context=context)
-
- if plan_id:
- i=1
- res['arch'] = """"
- doc = etree.fromstring(res['arch'].encode('utf8'))
- xarch, xfields = self._view_look_dom_arch(cr, uid, doc, view_id, context=context)
- res['arch'] = xarch
- res['fields'] = xfields
- return res
- else:
- return res
-
- def create(self, cr, uid, vals, context=None):
- journal_obj = self.pool.get('account.journal')
- ana_plan_instance_obj = self.pool.get('account.analytic.plan.instance')
- acct_anal_acct = self.pool.get('account.analytic.account')
- acct_anal_plan_line_obj = self.pool.get('account.analytic.plan.line')
- if context and context.get('journal_id'):
- journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
-
- pids = ana_plan_instance_obj.search(cr, uid, [('name','=',vals['name']), ('code','=',vals['code']), ('plan_id','<>',False)], context=context)
- if pids:
- raise osv.except_osv(_('Error!'), _('A model with this name and code already exists.'))
-
- res = acct_anal_plan_line_obj.search(cr, uid, [('plan_id','=',journal.plan_id.id)], context=context)
- for i in res:
- total_per_plan = 0
- item = acct_anal_plan_line_obj.browse(cr, uid, i, context=context)
- temp_list = ['account1_ids','account2_ids','account3_ids','account4_ids','account5_ids','account6_ids']
- for l in temp_list:
- if vals.has_key(l):
- for tempo in vals[l]:
- if acct_anal_acct.search(cr, uid, [('parent_id', 'child_of', [item.root_analytic_id.id]), ('id', '=', tempo[2]['analytic_account_id'])], context=context):
- total_per_plan += tempo[2]['rate']
- if total_per_plan < item.min_required or total_per_plan > item.max_required:
- raise osv.except_osv(_('Error!'),_('The total should be between %s and %s.') % (str(item.min_required), str(item.max_required)))
-
- return super(account_analytic_plan_instance, self).create(cr, uid, vals, context=context)
-
- def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
- if context is None:
- context = {}
- this = self.browse(cr, uid, ids[0], context=context)
- invoice_line_obj = self.pool.get('account.invoice.line')
- if this.plan_id and not vals.has_key('plan_id'):
- #this instance is a model, so we have to create a new plan instance instead of modifying it
- #copy the existing model
- temp_id = self.copy(cr, uid, this.id, None, context=context)
- #get the list of the invoice line that were linked to the model
- lists = invoice_line_obj.search(cr, uid, [('analytics_id','=',this.id)], context=context)
- #make them link to the copy
- invoice_line_obj.write(cr, uid, lists, {'analytics_id':temp_id}, context=context)
-
- #and finally modify the old model to be not a model anymore
- vals['plan_id'] = False
- if not vals.has_key('name'):
- vals['name'] = this.name and (str(this.name)+'*') or "*"
- if not vals.has_key('code'):
- vals['code'] = this.code and (str(this.code)+'*') or "*"
- return super(account_analytic_plan_instance, self).write(cr, uid, ids, vals, context=context)
-
-account_analytic_plan_instance()
-
-class account_analytic_plan_instance_line(osv.osv):
- _name = "account.analytic.plan.instance.line"
- _description = "Analytic Instance Line"
- _rec_name = "analytic_account_id"
- _columns = {
- 'plan_id': fields.many2one('account.analytic.plan.instance', 'Plan Id'),
- 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, domain=[('type','<>','view')]),
- 'rate': fields.float('Rate (%)', required=True),
- }
- _defaults = {
- 'rate': 100.0
- }
- def name_get(self, cr, uid, ids, context=None):
- if not ids:
- return []
- reads = self.read(cr, uid, ids, ['analytic_account_id'], context=context)
- res = []
- for record in reads:
- res.append((record['id'], record['analytic_account_id']))
- return res
-
-account_analytic_plan_instance_line()
-
-class account_journal(osv.osv):
- _inherit = "account.journal"
- _name = "account.journal"
- _columns = {
- 'plan_id': fields.many2one('account.analytic.plan', 'Analytic Plans'),
- }
-
-account_journal()
-
-class account_invoice_line(osv.osv):
- _inherit = "account.invoice.line"
- _name = "account.invoice.line"
- _columns = {
- 'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution'),
- }
-
- def create(self, cr, uid, vals, context=None):
- if 'analytics_id' in vals and isinstance(vals['analytics_id'], tuple):
- vals['analytics_id'] = vals['analytics_id'][0]
- return super(account_invoice_line, self).create(cr, uid, vals, context=context)
-
- def move_line_get_item(self, cr, uid, line, context=None):
- res = super(account_invoice_line, self).move_line_get_item(cr, uid, line, context=context)
- res ['analytics_id'] = line.analytics_id and line.analytics_id.id or False
- return res
-
- def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None):
- res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context, company_id=company_id)
- rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context)
- if rec and rec.analytics_id:
- res_prod['value'].update({'analytics_id': rec.analytics_id.id})
- return res_prod
-
-account_invoice_line()
-
-class account_move_line(osv.osv):
-
- _inherit = "account.move.line"
- _name = "account.move.line"
- _columns = {
- 'analytics_id':fields.many2one('account.analytic.plan.instance', 'Analytic Distribution'),
- }
-
- def _default_get_move_form_hook(self, cursor, user, data):
- data = super(account_move_line, self)._default_get_move_form_hook(cursor, user, data)
- if data.has_key('analytics_id'):
- del(data['analytics_id'])
- return data
-
- def create_analytic_lines(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- super(account_move_line, self).create_analytic_lines(cr, uid, ids, context=context)
- analytic_line_obj = self.pool.get('account.analytic.line')
- for line in self.browse(cr, uid, ids, context=context):
- if line.analytics_id:
- if not line.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal.") % (line.journal_id.name,))
-
- toremove = analytic_line_obj.search(cr, uid, [('move_id','=',line.id)], context=context)
- if toremove:
- analytic_line_obj.unlink(cr, uid, toremove, context=context)
- for line2 in line.analytics_id.account_ids:
- val = (line.credit or 0.0) - (line.debit or 0.0)
- amt=val * (line2.rate/100)
- al_vals={
- 'name': line.name,
- 'date': line.date,
- 'account_id': line2.analytic_account_id.id,
- 'unit_amount': line.quantity,
- 'product_id': line.product_id and line.product_id.id or False,
- 'product_uom_id': line.product_uom_id and line.product_uom_id.id or False,
- 'amount': amt,
- 'general_account_id': line.account_id.id,
- 'move_id': line.id,
- 'journal_id': line.journal_id.analytic_journal_id.id,
- 'ref': line.ref,
- 'percentage': line2.rate
- }
- analytic_line_obj.create(cr, uid, al_vals, context=context)
- return True
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if context is None:
- context = {}
- result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
- return result
-
-account_move_line()
-
-class account_invoice(osv.osv):
- _name = "account.invoice"
- _inherit = "account.invoice"
-
- def line_get_convert(self, cr, uid, x, part, date, context=None):
- res=super(account_invoice,self).line_get_convert(cr, uid, x, part, date, context=context)
- res['analytics_id'] = x.get('analytics_id', False)
- return res
-
- def _get_analytic_lines(self, cr, uid, id, context=None):
- inv = self.browse(cr, uid, [id])[0]
- cur_obj = self.pool.get('res.currency')
- invoice_line_obj = self.pool.get('account.invoice.line')
- acct_ins_obj = self.pool.get('account.analytic.plan.instance')
- company_currency = inv.company_id.currency_id.id
- if inv.type in ('out_invoice', 'in_refund'):
- sign = 1
- else:
- sign = -1
-
- iml = invoice_line_obj.move_line_get(cr, uid, inv.id, context=context)
-
- for il in iml:
- if il.get('analytics_id', False):
-
- if inv.type in ('in_invoice', 'in_refund'):
- ref = inv.reference
- else:
- ref = self._convert_ref(cr, uid, inv.number)
- obj_move_line = acct_ins_obj.browse(cr, uid, il['analytics_id'], context=context)
- ctx = context.copy()
- ctx.update({'date': inv.date_invoice})
- amount_calc = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, il['price'], context=ctx) * sign
- qty = il['quantity']
- il['analytic_lines'] = []
- for line2 in obj_move_line.account_ids:
- amt = amount_calc * (line2.rate/100)
- qtty = qty* (line2.rate/100)
- al_vals = {
- 'name': il['name'],
- 'date': inv['date_invoice'],
- 'unit_amount': qtty,
- 'product_id': il['product_id'],
- 'account_id': line2.analytic_account_id.id,
- 'amount': amt,
- 'product_uom_id': il['uos_id'],
- 'general_account_id': il['account_id'],
- 'journal_id': self._get_journal_analytic(cr, uid, inv.type),
- 'ref': ref,
- }
- il['analytic_lines'].append((0, 0, al_vals))
- return iml
-
-account_invoice()
-
-class account_analytic_plan(osv.osv):
- _inherit = "account.analytic.plan"
- _columns = {
- 'default_instance_id': fields.many2one('account.analytic.plan.instance', 'Default Entries'),
- }
-account_analytic_plan()
-
-class analytic_default(osv.osv):
- _inherit = "account.analytic.default"
- _columns = {
- 'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution'),
- }
-
-analytic_default()
-
-class sale_order_line(osv.osv):
- _inherit = "sale.order.line"
-
- # Method overridden to set the analytic account by default on criterion match
- def invoice_line_create(self, cr, uid, ids, context=None):
- create_ids = super(sale_order_line,self).invoice_line_create(cr, uid, ids, context=context)
- inv_line_obj = self.pool.get('account.invoice.line')
- acct_anal_def_obj = self.pool.get('account.analytic.default')
- if ids:
- sale_line = self.browse(cr, uid, ids[0], context=context)
- for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
- rec = acct_anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'), context)
-
- if rec:
- inv_line_obj.write(cr, uid, [line.id], {'analytics_id': rec.analytics_id.id}, context=context)
- return create_ids
-
-sale_order_line()
-
-
-class account_bank_statement(osv.osv):
- _inherit = "account.bank.statement"
- _name = "account.bank.statement"
-
- def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None):
- result = super(account_bank_statement,self)._prepare_bank_move_line(cr, uid, st_line,
- move_id, amount, company_currency_id, context=context)
- result['analytics_id'] = st_line.analytics_id.id
- return result
-
- def button_confirm_bank(self, cr, uid, ids, context=None):
- super(account_bank_statement,self).button_confirm_bank(cr, uid, ids, context=context)
- for st in self.browse(cr, uid, ids, context=context):
- for st_line in st.line_ids:
- if st_line.analytics_id:
- if not st.journal_id.analytic_journal_id:
- raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal.") % (st.journal_id.name,))
- if not st_line.amount:
- continue
- return True
-
-account_bank_statement()
-
-
-class account_bank_statement_line(osv.osv):
- _inherit = "account.bank.statement.line"
- _name = "account.bank.statement.line"
- _columns = {
- 'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution'),
- }
-account_bank_statement_line()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from lxml import etree
+from openerp.osv import fields, osv
+from openerp import tools
+from openerp.tools.translate import _
+
+class one2many_mod2(fields.one2many):
+
+ def get(self, cr, obj, ids, name, user = None, offset = 0, context = None, values = None):
+ if context is None:
+ context = {}
+ res = {}
+ for id in ids:
+ res[id] = []
+
+ ids2 = None
+ if 'journal_id' in context:
+ journal = obj.pool.get('account.journal').browse(cr, user, context['journal_id'], context=context)
+ pnum = int(name[7]) - 1
+ plan = journal.plan_id
+ if plan and len(plan.plan_ids) > pnum:
+ acc_id = plan.plan_ids[pnum].root_analytic_id.id
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids), ('analytic_account_id', 'child_of', [acc_id])], limit=self._limit)
+ if ids2 is None:
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids)], limit=self._limit)
+ for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ res[r[self._fields_id]].append(r['id'])
+
+ return res
+
+
+class account_analytic_line(osv.osv):
+ _inherit = 'account.analytic.line'
+ _description = 'Analytic Line'
+
+ def _get_amount(self, cr, uid, ids, name, args, context = None):
+ res = {}
+ for id in ids:
+ res.setdefault(id, 0.0)
+
+ for line in self.browse(cr, uid, ids, context=context):
+ amount = line.move_id and line.move_id.amount_currency * (line.percentage / 100) or 0.0
+ res[line.id] = amount
+
+ return res
+
+ _columns = {'amount_currency': fields.function(_get_amount, string='Amount Currency', type='float', store=True, help='The amount expressed in the related account currency if not equal to the company one.', readonly=True),
+ 'percentage': fields.float('Percentage')}
+
+
+account_analytic_line()
+
+class account_analytic_plan(osv.osv):
+ _name = 'account.analytic.plan'
+ _description = 'Analytic Plan'
+ _columns = {'name': fields.char('Analytic Plan', size=64, required=True, select=True),
+ 'plan_ids': fields.one2many('account.analytic.plan.line', 'plan_id', 'Analytic Plans')}
+
+
+account_analytic_plan()
+
+class account_analytic_plan_line(osv.osv):
+ _name = 'account.analytic.plan.line'
+ _description = 'Analytic Plan Line'
+ _order = 'sequence, id'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan', 'Analytic Plan', required=True),
+ 'name': fields.char('Plan Name', size=64, required=True, select=True),
+ 'sequence': fields.integer('Sequence'),
+ 'root_analytic_id': fields.many2one('account.analytic.account', 'Root Account', help='Root account of this plan.', required=False),
+ 'min_required': fields.float('Minimum Allowed (%)'),
+ 'max_required': fields.float('Maximum Allowed (%)')}
+ _defaults = {'min_required': 100.0,
+ 'max_required': 100.0}
+
+
+account_analytic_plan_line()
+
+class account_analytic_plan_instance(osv.osv):
+ _name = 'account.analytic.plan.instance'
+ _description = 'Analytic Plan Instance'
+ _columns = {'name': fields.char('Analytic Distribution', size=64),
+ 'code': fields.char('Distribution Code', size=16),
+ 'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal'),
+ 'account_ids': fields.one2many('account.analytic.plan.instance.line', 'plan_id', 'Account Id'),
+ 'account1_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account1 Id'),
+ 'account2_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account2 Id'),
+ 'account3_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account3 Id'),
+ 'account4_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account4 Id'),
+ 'account5_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account5 Id'),
+ 'account6_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account6 Id'),
+ 'plan_id': fields.many2one('account.analytic.plan', "Model's Plan")}
+
+ def search(self, cr, user, args, offset = 0, limit = None, order = None, context = None, count = False):
+ if context is None:
+ context = {}
+ journal_obj = self.pool.get('account.journal')
+ if context.get('journal_id', False):
+ journal = journal_obj.browse(cr, user, [context['journal_id']], context=context)[0]
+ analytic_journal = journal.analytic_journal_id and journal.analytic_journal_id.id or False
+ args.append('|')
+ args.append(('journal_id', '=', analytic_journal))
+ args.append(('journal_id', '=', False))
+ res = super(account_analytic_plan_instance, self).search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count)
+ return res
+
+ def copy(self, cr, uid, id, default = None, context = None):
+ if not default:
+ default = {}
+ default.update({'account1_ids': False,
+ 'account2_ids': False,
+ 'account3_ids': False,
+ 'account4_ids': False,
+ 'account5_ids': False,
+ 'account6_ids': False})
+ return super(account_analytic_plan_instance, self).copy(cr, uid, id, default, context=context)
+
+ def _default_journal(self, cr, uid, context = None):
+ if context is None:
+ context = {}
+ journal_obj = self.pool.get('account.journal')
+ if context.has_key('journal_id') and context['journal_id']:
+ journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
+ if journal.analytic_journal_id:
+ return journal.analytic_journal_id.id
+ return False
+
+ _defaults = {'plan_id': False,
+ 'journal_id': _default_journal}
+
+ def name_get(self, cr, uid, ids, context = None):
+ res = []
+ for inst in self.browse(cr, uid, ids, context=context):
+ name = inst.name or '/'
+ if name and inst.code:
+ name = name + ' (' + inst.code + ')'
+ res.append((inst.id, name))
+
+ return res
+
+ def name_search(self, cr, uid, name, args = None, operator = 'ilike', context = None, limit = 100):
+ args = args or []
+ if name:
+ ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context or {})
+ if not ids:
+ ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context or {})
+ else:
+ ids = self.search(cr, uid, args, limit=limit, context=context or {})
+ return self.name_get(cr, uid, ids, context or {})
+
+ def fields_view_get(self, cr, uid, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ if context is None:
+ context = {}
+ wiz_id = self.pool.get('ir.actions.act_window').search(cr, uid, [('name', '=', 'analytic.plan.create.model.action')], context=context)
+ res = super(account_analytic_plan_instance, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
+ journal_obj = self.pool.get('account.journal')
+ analytic_plan_obj = self.pool.get('account.analytic.plan')
+ if res['type'] == 'form':
+ plan_id = False
+ if context.get('journal_id', False):
+ plan_id = journal_obj.browse(cr, uid, int(context['journal_id']), context=context).plan_id
+ elif context.get('plan_id', False):
+ plan_id = analytic_plan_obj.browse(cr, uid, int(context['plan_id']), context=context)
+ if plan_id:
+ i = 1
+ res['arch'] = ''
+ doc = etree.fromstring(res['arch'].encode('utf8'))
+ xarch, xfields = self._view_look_dom_arch(cr, uid, doc, view_id, context=context)
+ res['arch'] = xarch
+ res['fields'] = xfields
+ return res
+ else:
+ return res
+ return
+
+ def create(self, cr, uid, vals, context = None):
+ journal_obj = self.pool.get('account.journal')
+ ana_plan_instance_obj = self.pool.get('account.analytic.plan.instance')
+ acct_anal_acct = self.pool.get('account.analytic.account')
+ acct_anal_plan_line_obj = self.pool.get('account.analytic.plan.line')
+ if context and 'journal_id' in context:
+ journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
+ pids = ana_plan_instance_obj.search(cr, uid, [('name', '=', vals['name']), ('code', '=', vals['code']), ('plan_id', '<>', False)], context=context)
+ if pids:
+ raise osv.except_osv(_('Error!'), _('A model with this name and code already exists.'))
+ res = acct_anal_plan_line_obj.search(cr, uid, [('plan_id', '=', journal.plan_id.id)], context=context)
+ for i in res:
+ total_per_plan = 0
+ item = acct_anal_plan_line_obj.browse(cr, uid, i, context=context)
+ temp_list = ['account1_ids',
+ 'account2_ids',
+ 'account3_ids',
+ 'account4_ids',
+ 'account5_ids',
+ 'account6_ids']
+ for l in temp_list:
+ if vals.has_key(l):
+ for tempo in vals[l]:
+ if acct_anal_acct.search(cr, uid, [('parent_id', 'child_of', [item.root_analytic_id.id]), ('id', '=', tempo[2]['analytic_account_id'])], context=context):
+ total_per_plan += tempo[2]['rate']
+
+ if total_per_plan < item.min_required or total_per_plan > item.max_required:
+ raise osv.except_osv(_('Error!'), _('The total should be between %s and %s.') % (str(item.min_required), str(item.max_required)))
+
+ return super(account_analytic_plan_instance, self).create(cr, uid, vals, context=context)
+
+ def write(self, cr, uid, ids, vals, context = None, check = True, update_check = True):
+ if context is None:
+ context = {}
+ this = self.browse(cr, uid, ids[0], context=context)
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ if this.plan_id and not vals.has_key('plan_id'):
+ temp_id = self.copy(cr, uid, this.id, None, context=context)
+ lists = invoice_line_obj.search(cr, uid, [('analytics_id', '=', this.id)], context=context)
+ invoice_line_obj.write(cr, uid, lists, {'analytics_id': temp_id}, context=context)
+ vals['plan_id'] = False
+ if not vals.has_key('name'):
+ vals['name'] = this.name and str(this.name) + '*' or '*'
+ if not vals.has_key('code'):
+ vals['code'] = this.code and str(this.code) + '*' or '*'
+ return super(account_analytic_plan_instance, self).write(cr, uid, ids, vals, context=context)
+
+
+account_analytic_plan_instance()
+
+class account_analytic_plan_instance_line(osv.osv):
+ _name = 'account.analytic.plan.instance.line'
+ _description = 'Analytic Instance Line'
+ _rec_name = 'analytic_account_id'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan.instance', 'Plan Id'),
+ 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, domain=[('type', '<>', 'view')]),
+ 'rate': fields.float('Rate (%)', required=True)}
+ _defaults = {'rate': 100.0}
+
+ def name_get(self, cr, uid, ids, context = None):
+ if not ids:
+ return []
+ reads = self.read(cr, uid, ids, ['analytic_account_id'], context=context)
+ res = []
+ for record in reads:
+ res.append((record['id'], record['analytic_account_id']))
+
+ return res
+
+
+account_analytic_plan_instance_line()
+
+class account_journal(osv.osv):
+ _inherit = 'account.journal'
+ _name = 'account.journal'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan', 'Analytic Plans')}
+
+
+account_journal()
+
+class account_invoice_line(osv.osv):
+ _inherit = 'account.invoice.line'
+ _name = 'account.invoice.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+ def create(self, cr, uid, vals, context = None):
+ if 'analytics_id' in vals and isinstance(vals['analytics_id'], tuple):
+ vals['analytics_id'] = vals['analytics_id'][0]
+ return super(account_invoice_line, self).create(cr, uid, vals, context=context)
+
+ def move_line_get_item(self, cr, uid, line, context = None):
+ res = super(account_invoice_line, self).move_line_get_item(cr, uid, line, context=context)
+ res['analytics_id'] = line.analytics_id and line.analytics_id.id or False
+ return res
+
+ def product_id_change(self, cr, uid, ids, product, uom_id, qty = 0, name = '', type = 'out_invoice', partner_id = False, fposition_id = False, price_unit = False, currency_id = False, context = None, company_id = None):
+ res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context, company_id=company_id)
+ rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context)
+ if rec and rec.analytics_id:
+ res_prod['value'].update({'analytics_id': rec.analytics_id.id})
+ return res_prod
+
+
+account_invoice_line()
+
+class account_move_line(osv.osv):
+ _inherit = 'account.move.line'
+ _name = 'account.move.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+ def _default_get_move_form_hook(self, cursor, user, data):
+ data = super(account_move_line, self)._default_get_move_form_hook(cursor, user, data)
+ if data.has_key('analytics_id'):
+ del data['analytics_id']
+ return data
+
+ def create_analytic_lines(self, cr, uid, ids, context = None):
+ if context is None:
+ context = {}
+ super(account_move_line, self).create_analytic_lines(cr, uid, ids, context=context)
+ analytic_line_obj = self.pool.get('account.analytic.line')
+ for line in self.browse(cr, uid, ids, context=context):
+ if line.analytics_id:
+ if not line.journal_id.analytic_journal_id:
+ raise osv.except_osv(_('No Analytic Journal!'), _("You have to define an analytic journal on the '%s' journal.") % (line.journal_id.name,))
+ toremove = analytic_line_obj.search(cr, uid, [('move_id', '=', line.id)], context=context)
+ if toremove:
+ analytic_line_obj.unlink(cr, uid, toremove, context=context)
+ for line2 in line.analytics_id.account_ids:
+ val = (line.credit or 0.0) - (line.debit or 0.0)
+ amt = val * (line2.rate / 100)
+ al_vals = {'name': line.name,
+ 'date': line.date,
+ 'account_id': line2.analytic_account_id.id,
+ 'unit_amount': line.quantity,
+ 'product_id': line.product_id and line.product_id.id or False,
+ 'product_uom_id': line.product_uom_id and line.product_uom_id.id or False,
+ 'amount': amt,
+ 'general_account_id': line.account_id.id,
+ 'move_id': line.id,
+ 'journal_id': line.journal_id.analytic_journal_id.id,
+ 'ref': line.ref,
+ 'percentage': line2.rate}
+ analytic_line_obj.create(cr, uid, al_vals, context=context)
+
+ return True
+
+ def fields_view_get(self, cr, uid, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ if context is None:
+ context = {}
+ result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
+ return result
+
+
+account_move_line()
+
+class account_invoice(osv.osv):
+ _name = 'account.invoice'
+ _inherit = 'account.invoice'
+
+ def line_get_convert(self, cr, uid, x, part, date, context = None):
+ res = super(account_invoice, self).line_get_convert(cr, uid, x, part, date, context=context)
+ res['analytics_id'] = x.get('analytics_id', False)
+ return res
+
+ def _get_analytic_lines(self, cr, uid, id, context = None):
+ inv = self.browse(cr, uid, [id])[0]
+ cur_obj = self.pool.get('res.currency')
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ acct_ins_obj = self.pool.get('account.analytic.plan.instance')
+ company_currency = inv.company_id.currency_id.id
+ if inv.type in ('out_invoice', 'in_refund'):
+ sign = 1
+ else:
+ sign = -1
+ iml = invoice_line_obj.move_line_get(cr, uid, inv.id, context=context)
+ for il in iml:
+ if il.get('analytics_id', False):
+ if inv.type in ('in_invoice', 'in_refund'):
+ ref = inv.reference
+ else:
+ ref = self._convert_ref(cr, uid, inv.number)
+ obj_move_line = acct_ins_obj.browse(cr, uid, il['analytics_id'], context=context)
+ ctx = context.copy()
+ ctx.update({'date': inv.date_invoice})
+ amount_calc = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, il['price'], context=ctx) * sign
+ qty = il['quantity']
+ il['analytic_lines'] = []
+ for line2 in obj_move_line.account_ids:
+ amt = amount_calc * (line2.rate / 100)
+ qtty = qty * (line2.rate / 100)
+ al_vals = {'name': il['name'],
+ 'date': inv['date_invoice'],
+ 'unit_amount': qtty,
+ 'product_id': il['product_id'],
+ 'account_id': line2.analytic_account_id.id,
+ 'amount': amt,
+ 'product_uom_id': il['uos_id'],
+ 'general_account_id': il['account_id'],
+ 'journal_id': self._get_journal_analytic(cr, uid, inv.type),
+ 'ref': ref}
+ il['analytic_lines'].append((0, 0, al_vals))
+
+ return iml
+
+
+account_invoice()
+
+class account_analytic_plan(osv.osv):
+ _inherit = 'account.analytic.plan'
+ _columns = {'default_instance_id': fields.many2one('account.analytic.plan.instance', 'Default Entries')}
+
+
+account_analytic_plan()
+
+class analytic_default(osv.osv):
+ _inherit = 'account.analytic.default'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+
+analytic_default()
+
+class sale_order_line(osv.osv):
+ _inherit = 'sale.order.line'
+
+ def invoice_line_create(self, cr, uid, ids, context = None):
+ create_ids = super(sale_order_line, self).invoice_line_create(cr, uid, ids, context=context)
+ inv_line_obj = self.pool.get('account.invoice.line')
+ acct_anal_def_obj = self.pool.get('account.analytic.default')
+ if ids:
+ sale_line = self.browse(cr, uid, ids[0], context=context)
+ for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
+ rec = acct_anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'), context)
+ if rec:
+ inv_line_obj.write(cr, uid, [line.id], {'analytics_id': rec.analytics_id.id}, context=context)
+
+ return create_ids
+
+
+sale_order_line()
+
+class account_bank_statement(osv.osv):
+ _inherit = 'account.bank.statement'
+ _name = 'account.bank.statement'
+
+ def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context = None):
+ account_move_line_pool = self.pool.get('account.move.line')
+ account_bank_statement_line_pool = self.pool.get('account.bank.statement.line')
+ st_line = account_bank_statement_line_pool.browse(cr, uid, st_line_id, context=context)
+ result = super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line_id, company_currency_id, st_line_number, context=context)
+ move = st_line.move_ids and st_line.move_ids[0] or False
+ if move:
+ for line in move.line_id:
+ account_move_line_pool.write(cr, uid, [line.id], {'analytics_id': st_line.analytics_id.id}, context=context)
+
+ return result
+
+ def button_confirm_bank(self, cr, uid, ids, context = None):
+ super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
+ for st in self.browse(cr, uid, ids, context=context):
+ for st_line in st.line_ids:
+ if st_line.analytics_id:
+ if not st.journal_id.analytic_journal_id:
+ raise osv.except_osv(_('No Analytic Journal!'), _("You have to define an analytic journal on the '%s' journal.") % (st.journal_id.name,))
+ if not st_line.amount:
+ continue
+
+ return True
+
+
+account_bank_statement()
+
+class account_bank_statement_line(osv.osv):
+ _inherit = 'account.bank.statement.line'
+ _name = 'account.bank.statement.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+
+account_bank_statement_line()
\ No newline at end of file
diff --git a/addons/account_analytic_plans/account_analytic_plans_view.xml b/addons/account_analytic_plans/account_analytic_plans_view.xml
index 500d6a1a404f5..42b17ae06c3fb 100644
--- a/addons/account_analytic_plans/account_analytic_plans_view.xml
+++ b/addons/account_analytic_plans/account_analytic_plans_view.xml
@@ -74,7 +74,7 @@
-
+
diff --git a/addons/account_analytic_plans/images/analytic_plan.jpeg b/addons/account_analytic_plans/images/analytic_plan.jpeg
new file mode 100644
index 0000000000000..9e784051d23d1
Binary files /dev/null and b/addons/account_analytic_plans/images/analytic_plan.jpeg differ
diff --git a/addons/account_analytic_plans/report/crossovered_analytic.py b/addons/account_analytic_plans/report/crossovered_analytic.py
index b572fc3e8039b..0013471b645c0 100644
--- a/addons/account_analytic_plans/report/crossovered_analytic.py
+++ b/addons/account_analytic_plans/report/crossovered_analytic.py
@@ -1,219 +1,161 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-
-from openerp.report import report_sxw
-
-class crossovered_analytic(report_sxw.rml_parse):
- def __init__(self, cr, uid, name, context):
- super(crossovered_analytic, self).__init__(cr, uid, name, context = context)
- self.localcontext.update( {
- 'time': time,
- 'lines': self._lines,
- 'ref_lines': self._ref_lines,
- 'find_children': self.find_children,
- })
- self.base_amount = 0.00
-
- def find_children(self, ref_ids):
- if not ref_ids: return []
- to_return_ids = []
- final_list = []
- parent_list = []
- set_list = []
- analytic_obj = self.pool.get('account.analytic.account')
- for id in ref_ids:
- # to avoid duplicate entries
- if id not in to_return_ids:
- to_return_ids.append(analytic_obj.search(self.cr,self.uid,[('parent_id','child_of',[id])]))
- data_accnt = analytic_obj.browse(self.cr,self.uid,to_return_ids[0])
- for data in data_accnt:
- if data.parent_id and data.parent_id.id == ref_ids[0]:
- parent_list.append(data.id)
- final_list.append(ref_ids[0])
- set_list = self.set_account(parent_list)
- final_list.extend(set_list)
- return final_list #to_return_ids[0]
-
- def set_account(self, cats):
- lst = []
- category = self.pool.get('account.analytic.account').read(self.cr, self.uid, cats)
- for cat in category:
- lst.append(cat['id'])
- if cat['child_ids']:
- lst.extend(self.set_account(cat['child_ids']))
- return lst
-
- def _ref_lines(self, form):
- result = []
- res = {}
- acc_pool = self.pool.get('account.analytic.account')
- line_pool = self.pool.get('account.analytic.line')
-
- self.dict_acc_ref = {}
- filters = [
- 'date >= %(date1)s',
- 'date <= %(date2)s',
- ]
- params = {
- 'date1': form['date1'],
- 'date2': form['date2']
- }
- if form['journal_ids']:
- filters.append('journal_id IN %(journal_ids)s')
- params['journal_ids'] = tuple(form['journal_ids'])
- else:
- filters.append('journal_id IS NOT NULL')
-
- self.cr.execute(
- "SELECT id FROM account_analytic_line WHERE " + ' AND '.join(filters),
- params
- )
-
- l_ids = self.cr.fetchall()
- line_ids = [x[0] for x in l_ids]
-
- obj_line = line_pool.browse(self.cr,self.uid,line_ids)
-
- #this structure will be usefull for easily knowing the account_analytic_line that are related to the reference account. At this purpose, we save the move_id of analytic lines.
- self.dict_acc_ref[form['ref']] = []
- children_list = acc_pool.search(self.cr, self.uid, [('parent_id', 'child_of', [form['ref']])])
- for obj in obj_line:
- if obj.account_id.id in children_list:
- if obj.move_id and obj.move_id.id not in self.dict_acc_ref[form['ref']]:
- self.dict_acc_ref[form['ref']].append(obj.move_id.id)
-
- res['ref_name'] = acc_pool.name_get(self.cr, self.uid, [form['ref']])[0][1]
- res['ref_code'] = acc_pool.browse(self.cr, self.uid, form['ref']).code
-
- self.final_list = children_list
- selected_ids = line_pool.search(self.cr, self.uid, [('account_id', 'in' ,self.final_list)])
-
- res['ref_qty'] = 0.0
- res['ref_amt'] = 0.0
- self.base_amount = 0.0
-
- if selected_ids:
- params['selected_ids'] = tuple(selected_ids)
- filters = [
- 'aal.account_id = aaa.id',
- 'aal.id IN %(selected_ids)s',
- 'aal.date >= %(date1)s',
- 'aal.date <= %(date2)s',
- ]
- if form['journal_ids']:
- filters.append('aal.journal_id in %(journal_ids)s')
- else:
- filters.append('aal.journal_id IS NOT NULL')
-
- self.cr.execute(
- "SELECT SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty"
- " FROM account_analytic_line AS aal, account_analytic_account AS aaa"
- " WHERE " + ' AND '.join(filters),
- params
- )
- info=self.cr.dictfetchall()
- res['ref_qty'] = info[0]['qty']
- res['ref_amt'] = info[0]['amt']
- self.base_amount = info[0]['amt']
- result.append(res)
- return result
-
- def _lines(self, form, ids=None):
- if ids is None:
- ids = {}
- if not ids:
- ids = self.ids
-
- filters = [
- 'aal.account_id = aaa.id',
- 'aal.date >= %(date1)s',
- 'aal.date <= %(date2)s',
- ]
- params = {
- 'date1': form['date1'],
- 'date2': form['date2'],
- }
- if form['journal_ids']:
- filters.append('aal.journal_id IN %(journal_ids)s')
- params['journal_ids'] = tuple(form['journal_ids'])
- else:
- filters.append('aal.journal_id IS NOT NULL')
-
- acc_pool = self.pool.get('account.analytic.account')
- line_pool = self.pool.get('account.analytic.line')
- acc_id = []
- final = []
- self.list_ids = []
-
- self.final_list = self.find_children(ids)
-
- for acc_id in self.final_list:
- selected_ids = line_pool.search(self.cr, self.uid, [('account_id','=',acc_id), ('move_id', 'in', self.dict_acc_ref[form['ref']])])
- if selected_ids:
- filters.append('aal.id IN %(selected_ids)s')
- params['selected_ids'] = tuple(selected_ids)
-
- self.cr.execute(
- "SELECT aaa.code AS code, SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty, aaa.name AS acc_name, aal.account_id AS id"
- " FROM account_analytic_line AS aal, account_analytic_account AS aaa"
- " WHERE " + ' AND '.join(filters)
- + " GROUP BY aal.account_id,aaa.name,aaa.code ORDER BY aal.account_id"
- )
- res = self.cr.dictfetchall()
- if res:
- for element in res:
- if self.base_amount <> 0.00:
- element['perc'] = (element['amt'] / self.base_amount) * 100.00
- else:
- element['perc'] = 0.00
- else:
- result = {}
- res = []
- result['id'] = acc_id
- data_account = acc_pool.browse(self.cr, self.uid, acc_id)
- result['acc_name'] = data_account.name
- result['code'] = data_account.code
- result['amt'] = result['qty'] = result['perc'] = 0.00
- if not form['empty_line']:
- res.append(result)
- else:
- result = {}
- res = []
- result['id'] = acc_id
- data_account = acc_pool.browse(self.cr, self.uid, acc_id)
- result['acc_name'] = data_account.name
- result['code'] = data_account.code
- result['amt'] = result['qty'] = result['perc'] = 0.00
- if not form['empty_line']:
- res.append(result)
-
- for item in res:
- obj_acc = acc_pool.name_get(self.cr,self.uid,[item['id']])
- item['acc_name'] = obj_acc[0][1]
- final.append(item)
- return final
-
-report_sxw.report_sxw('report.account.analytic.account.crossovered.analytic', 'account.analytic.account', 'addons/account_analytic_plans/report/crossovered_analytic.rml',parser = crossovered_analytic, header='internal')
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.report import report_sxw
+
+class crossovered_analytic(report_sxw.rml_parse):
+
+ def __init__(self, cr, uid, name, context):
+ super(crossovered_analytic, self).__init__(cr, uid, name, context=context)
+ self.localcontext.update({'time': time,
+ 'lines': self._lines,
+ 'ref_lines': self._ref_lines,
+ 'find_children': self.find_children})
+ self.base_amount = 0.0
+
+ def find_children(self, ref_ids):
+ if not ref_ids:
+ return []
+ to_return_ids = []
+ final_list = []
+ parent_list = []
+ set_list = []
+ analytic_obj = self.pool.get('account.analytic.account')
+ for id in ref_ids:
+ if id not in to_return_ids:
+ to_return_ids.append(analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [id])]))
+
+ data_accnt = analytic_obj.browse(self.cr, self.uid, to_return_ids[0])
+ for data in data_accnt:
+ if data.parent_id and data.parent_id.id == ref_ids[0]:
+ parent_list.append(data.id)
+
+ final_list.append(ref_ids[0])
+ set_list = self.set_account(parent_list)
+ final_list.extend(set_list)
+ return final_list
+
+ def set_account(self, cats):
+ lst = []
+ category = self.pool.get('account.analytic.account').read(self.cr, self.uid, cats)
+ for cat in category:
+ lst.append(cat['id'])
+ if cat['child_ids']:
+ lst.extend(self.set_account(cat['child_ids']))
+
+ return lst
+
+ def _ref_lines(self, form):
+ result = []
+ res = {}
+ acc_pool = self.pool.get('account.analytic.account')
+ line_pool = self.pool.get('account.analytic.line')
+ self.dict_acc_ref = {}
+ if form['journal_ids']:
+ journal = ' in (' + ','.join(map(lambda x: str(x), form['journal_ids'])) + ')'
+ else:
+ journal = 'is not null'
+ query_general = 'SELECT id FROM account_analytic_line WHERE (journal_id ' + journal + ") AND date>='" + str(form['date1']) + "' AND date<='" + str(form['date2']) + "'"
+ self.cr.execute(query_general)
+ l_ids = self.cr.fetchall()
+ line_ids = [ x[0] for x in l_ids ]
+ obj_line = line_pool.browse(self.cr, self.uid, line_ids)
+ self.dict_acc_ref[form['ref']] = []
+ children_list = acc_pool.search(self.cr, self.uid, [('parent_id', 'child_of', [form['ref']])])
+ for obj in obj_line:
+ if obj.account_id.id in children_list:
+ if obj.move_id and obj.move_id.id not in self.dict_acc_ref[form['ref']]:
+ self.dict_acc_ref[form['ref']].append(obj.move_id.id)
+
+ res['ref_name'] = acc_pool.name_get(self.cr, self.uid, [form['ref']])[0][1]
+ res['ref_code'] = acc_pool.browse(self.cr, self.uid, form['ref']).code
+ self.final_list = children_list
+ selected_ids = line_pool.search(self.cr, self.uid, [('account_id', 'in', self.final_list)])
+ res['ref_qty'] = 0.0
+ res['ref_amt'] = 0.0
+ self.base_amount = 0.0
+ if selected_ids:
+ query = 'SELECT SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty FROM account_analytic_line AS aal, account_analytic_account AS aaa WHERE aal.account_id = aaa.id AND aal.id IN (' + ','.join(map(str, selected_ids)) + ') AND (aal.journal_id ' + journal + ") AND aal.date>='" + str(form['date1']) + "' AND aal.date<='" + str(form['date2']) + "'"
+ self.cr.execute(query)
+ info = self.cr.dictfetchall()
+ res['ref_qty'] = info[0]['qty']
+ res['ref_amt'] = info[0]['amt']
+ self.base_amount = info[0]['amt']
+ result.append(res)
+ return result
+
+ def _lines(self, form, ids = None):
+ if ids is None:
+ ids = {}
+ if not ids:
+ ids = self.ids
+ if form['journal_ids']:
+ journal = ' in (' + ','.join(map(lambda x: str(x), form['journal_ids'])) + ')'
+ else:
+ journal = 'is not null'
+ acc_pool = self.pool.get('account.analytic.account')
+ line_pool = self.pool.get('account.analytic.line')
+ acc_id = []
+ final = []
+ self.list_ids = []
+ self.final_list = self.find_children(ids)
+ for acc_id in self.final_list:
+ selected_ids = line_pool.search(self.cr, self.uid, [('account_id', '=', acc_id), ('move_id', 'in', self.dict_acc_ref[form['ref']])])
+ if selected_ids:
+ query = 'SELECT aaa.code AS code, SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty, aaa.name AS acc_name, aal.account_id AS id FROM account_analytic_line AS aal, account_analytic_account AS aaa WHERE aal.account_id=aaa.id AND aal.id IN (' + ','.join(map(str, selected_ids)) + ') AND (aal.journal_id ' + journal + ") AND aal.date>='" + str(form['date1']) + "' AND aal.date<='" + str(form['date2']) + "' GROUP BY aal.account_id,aaa.name,aaa.code ORDER BY aal.account_id"
+ self.cr.execute(query)
+ res = self.cr.dictfetchall()
+ if res:
+ for element in res:
+ if self.base_amount != 0.0:
+ element['perc'] = element['amt'] / self.base_amount * 100.0
+ else:
+ element['perc'] = 0.0
+
+ else:
+ result = {}
+ res = []
+ result['id'] = acc_id
+ data_account = acc_pool.browse(self.cr, self.uid, acc_id)
+ result['acc_name'] = data_account.name
+ result['code'] = data_account.code
+ result['amt'] = result['qty'] = result['perc'] = 0.0
+ if not form['empty_line']:
+ res.append(result)
+ else:
+ result = {}
+ res = []
+ result['id'] = acc_id
+ data_account = acc_pool.browse(self.cr, self.uid, acc_id)
+ result['acc_name'] = data_account.name
+ result['code'] = data_account.code
+ result['amt'] = result['qty'] = result['perc'] = 0.0
+ if not form['empty_line']:
+ res.append(result)
+ for item in res:
+ obj_acc = acc_pool.name_get(self.cr, self.uid, [item['id']])
+ item['acc_name'] = obj_acc[0][1]
+ final.append(item)
+
+ return final
+
+
+report_sxw.report_sxw('report.account.analytic.account.crossovered.analytic', 'account.analytic.account', 'addons/account_analytic_plans/report/crossovered_analytic.rml', parser=crossovered_analytic, header='internal')
\ No newline at end of file
diff --git a/addons/account_analytic_plans/wizard/account_crossovered_analytic.py b/addons/account_analytic_plans/wizard/account_crossovered_analytic.py
index 640443c8a0b0d..2ec51a1ef0c4d 100644
--- a/addons/account_analytic_plans/wizard/account_crossovered_analytic.py
+++ b/addons/account_analytic_plans/wizard/account_crossovered_analytic.py
@@ -1,76 +1,61 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-
-from openerp.osv import fields, osv
-from openerp.tools.translate import _
-
-class account_crossovered_analytic(osv.osv_memory):
- _name = "account.crossovered.analytic"
- _description = "Print Crossovered Analytic"
- _columns = {
- 'date1': fields.date('Start Date', required=True),
- 'date2': fields.date('End Date', required=True),
- 'journal_ids': fields.many2many('account.analytic.journal', 'crossovered_journal_rel', 'crossover_id', 'journal_id', 'Analytic Journal'),
- 'ref': fields.many2one('account.analytic.account', 'Analytic Account Reference', required=True),
- 'empty_line': fields.boolean('Dont show empty lines'),
- }
- _defaults = {
- 'date1': lambda *a: time.strftime('%Y-01-01'),
- 'date2': lambda *a: time.strftime('%Y-%m-%d'),
- }
-
- def print_report(self, cr, uid, ids, context=None):
- cr.execute('SELECT account_id FROM account_analytic_line')
- res = cr.fetchall()
- acc_ids = [x[0] for x in res]
-
- data = self.read(cr, uid, ids, [], context=context)[0]
- data['ref'] = data['ref'][0]
-
- obj_acc = self.pool.get('account.analytic.account').browse(cr, uid, data['ref'], context=context)
- name = obj_acc.name
-
- account_ids = self.pool.get('account.analytic.account').search(cr, uid, [('parent_id', 'child_of', [data['ref']])], context=context)
-
- flag = True
- for acc in account_ids:
- if acc in acc_ids:
- flag = False
- break
- if flag:
- raise osv.except_osv(_('User Error!'),_('There are no analytic lines related to account %s.' % name))
-
- datas = {
- 'ids': [],
- 'model': 'account.analytic.account',
- 'form': data
- }
- return {
- 'type': 'ir.actions.report.xml',
- 'report_name': 'account.analytic.account.crossovered.analytic',
- 'datas': datas,
- }
-
-account_crossovered_analytic()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+class account_crossovered_analytic(osv.osv_memory):
+ _name = 'account.crossovered.analytic'
+ _description = 'Print Crossovered Analytic'
+ _columns = {'date1': fields.date('Start Date', required=True),
+ 'date2': fields.date('End Date', required=True),
+ 'journal_ids': fields.many2many('account.analytic.journal', 'crossovered_journal_rel', 'crossover_id', 'journal_id', 'Analytic Journal'),
+ 'ref': fields.many2one('account.analytic.account', 'Analytic Account Reference', required=True),
+ 'empty_line': fields.boolean('Dont show empty lines')}
+ _defaults = {'date1': lambda *a: time.strftime('%Y-01-01'),
+ 'date2': lambda *a: time.strftime('%Y-%m-%d')}
+
+ def print_report(self, cr, uid, ids, context = None):
+ cr.execute('SELECT account_id FROM account_analytic_line')
+ res = cr.fetchall()
+ acc_ids = [ x[0] for x in res ]
+ data = self.read(cr, uid, ids, [], context=context)[0]
+ data['ref'] = data['ref'][0]
+ obj_acc = self.pool.get('account.analytic.account').browse(cr, uid, data['ref'], context=context)
+ name = obj_acc.name
+ account_ids = self.pool.get('account.analytic.account').search(cr, uid, [('parent_id', 'child_of', [data['ref']])], context=context)
+ flag = True
+ for acc in account_ids:
+ if acc in acc_ids:
+ flag = False
+ break
+
+ if flag:
+ raise osv.except_osv(_('User Error!'), _('There are no analytic lines related to account %s.' % name))
+ datas = {'ids': [],
+ 'model': 'account.analytic.account',
+ 'form': data}
+ return {'type': 'ir.actions.report.xml',
+ 'report_name': 'account.analytic.account.crossovered.analytic',
+ 'datas': datas}
+
+
+account_crossovered_analytic()
\ No newline at end of file
diff --git a/addons/account_analytic_plans/wizard/analytic_plan_create_model.py b/addons/account_analytic_plans/wizard/analytic_plan_create_model.py
index 7038a6f102512..5ef71634456b6 100644
--- a/addons/account_analytic_plans/wizard/analytic_plan_create_model.py
+++ b/addons/account_analytic_plans/wizard/analytic_plan_create_model.py
@@ -1,60 +1,56 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from openerp.osv import osv
-from openerp.tools.translate import _
-
-class analytic_plan_create_model(osv.osv_memory):
- _name = "analytic.plan.create.model"
- _description = "analytic.plan.create.model"
-
- def activate(self, cr, uid, ids, context=None):
- plan_obj = self.pool.get('account.analytic.plan.instance')
- mod_obj = self.pool.get('ir.model.data')
- anlytic_plan_obj = self.pool.get('account.analytic.plan')
- if context is None:
- context = {}
- if 'active_id' in context and context['active_id']:
- plan = plan_obj.browse(cr, uid, context['active_id'], context=context)
- if (not plan.name) or (not plan.code):
- raise osv.except_osv(_('Error!'), _('Please put a name and a code before saving the model.'))
- pids = anlytic_plan_obj.search(cr, uid, [], context=context)
- if not pids:
- raise osv.except_osv(_('Error!'), _('There is no analytic plan defined.'))
- plan_obj.write(cr, uid, [context['active_id']], {'plan_id':pids[0]}, context=context)
-
- model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'),('name', '=', 'view_analytic_plan_create_model')], context=context)
- resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
- return {
- 'name': _('Distribution Model Saved'),
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'analytic.plan.create.model',
- 'views': [(resource_id,'form')],
- 'type': 'ir.actions.act_window',
- 'target': 'new',
- }
- else:
- return {'type': 'ir.actions.act_window_close'}
-
-analytic_plan_create_model()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp.osv import osv
+from openerp.tools.translate import _
+
+class analytic_plan_create_model(osv.osv_memory):
+ _name = 'analytic.plan.create.model'
+ _description = 'analytic.plan.create.model'
+
+ def activate(self, cr, uid, ids, context = None):
+ plan_obj = self.pool.get('account.analytic.plan.instance')
+ mod_obj = self.pool.get('ir.model.data')
+ anlytic_plan_obj = self.pool.get('account.analytic.plan')
+ if context is None:
+ context = {}
+ if 'active_id' in context and context['active_id']:
+ plan = plan_obj.browse(cr, uid, context['active_id'], context=context)
+ if not plan.name or not plan.code:
+ raise osv.except_osv(_('Error!'), _('Please put a name and a code before saving the model.'))
+ pids = anlytic_plan_obj.search(cr, uid, [], context=context)
+ if not pids:
+ raise osv.except_osv(_('Error!'), _('There is no analytic plan defined.'))
+ plan_obj.write(cr, uid, [context['active_id']], {'plan_id': pids[0]}, context=context)
+ model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'view_analytic_plan_create_model')], context=context)
+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
+ return {'name': _('Distribution Model Saved'),
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'analytic.plan.create.model',
+ 'views': [(resource_id, 'form')],
+ 'type': 'ir.actions.act_window',
+ 'target': 'new'}
+ else:
+ return {'type': 'ir.actions.act_window_close'}
+ return
+
+
+analytic_plan_create_model()
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/__init__.py b/addons/account_anglo_saxon/account_analytic_plans/__init__.py
new file mode 100644
index 0000000000000..a5c371fa6ec4e
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import account_analytic_plans
+import wizard
+import report
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/__openerp__.py b/addons/account_anglo_saxon/account_analytic_plans/__openerp__.py
new file mode 100644
index 0000000000000..af5b5654b9926
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/__openerp__.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+
+{
+ 'name': 'Multiple Analytic Plans',
+ 'version': '1.0',
+ 'category': 'Accounting & Finance',
+ 'description': """
+This module allows to use several analytic plans according to the general journal.
+==================================================================================
+
+Here multiple analytic lines are created when the invoice or the entries
+are confirmed.
+
+For example, you can define the following analytic structure:
+-------------------------------------------------------------
+ * **Projects**
+ * Project 1
+ + SubProj 1.1
+
+ + SubProj 1.2
+
+ * Project 2
+
+ * **Salesman**
+ * Eric
+
+ * Fabien
+
+Here, we have two plans: Projects and Salesman. An invoice line must be able to write analytic entries in the 2 plans: SubProj 1.1 and Fabien. The amount can also be split.
+
+The following example is for an invoice that touches the two subprojects and assigned to one salesman:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+**Plan1:**
+
+ * SubProject 1.1 : 50%
+
+ * SubProject 1.2 : 50%
+
+**Plan2:**
+ Eric: 100%
+
+So when this line of invoice will be confirmed, it will generate 3 analytic lines,for one account entry.
+
+The analytic plan validates the minimum and maximum percentage at the time of creation of distribution models.
+ """,
+ 'author': 'OpenERP SA',
+ 'website': 'http://www.openerp.com',
+ 'images': ['images/analytic_plan.jpeg'],
+ 'depends': ['account', 'account_analytic_default'],
+ 'data': [
+ 'security/account_analytic_plan_security.xml',
+ 'security/ir.model.access.csv',
+ 'account_analytic_plans_view.xml',
+ 'account_analytic_plans_report.xml',
+ 'wizard/analytic_plan_create_model_view.xml',
+ 'wizard/account_crossovered_analytic_view.xml',
+ ],
+ 'demo': [],
+ 'test': ['test/acount_analytic_plans_report.yml'],
+ 'installable': True,
+ 'auto_install': False,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans.py b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans.py
new file mode 100644
index 0000000000000..61cf000dc861e
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans.py
@@ -0,0 +1,481 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from lxml import etree
+from openerp.osv import fields, osv
+from openerp import tools
+from openerp.tools.translate import _
+
+class one2many_mod2(fields.one2many):
+
+ def get(self, cr, obj, ids, name, user = None, offset = 0, context = None, values = None):
+ if context is None:
+ context = {}
+ res = {}
+ for id in ids:
+ res[id] = []
+
+ ids2 = None
+ if 'journal_id' in context:
+ journal = obj.pool.get('account.journal').browse(cr, user, context['journal_id'], context=context)
+ pnum = int(name[7]) - 1
+ plan = journal.plan_id
+ if plan and len(plan.plan_ids) > pnum:
+ acc_id = plan.plan_ids[pnum].root_analytic_id.id
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids), ('analytic_account_id', 'child_of', [acc_id])], limit=self._limit)
+ if ids2 is None:
+ ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids)], limit=self._limit)
+ for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ res[r[self._fields_id]].append(r['id'])
+
+ return res
+
+
+class account_analytic_line(osv.osv):
+ _inherit = 'account.analytic.line'
+ _description = 'Analytic Line'
+
+ def _get_amount(self, cr, uid, ids, name, args, context = None):
+ res = {}
+ for id in ids:
+ res.setdefault(id, 0.0)
+
+ for line in self.browse(cr, uid, ids, context=context):
+ amount = line.move_id and line.move_id.amount_currency * (line.percentage / 100) or 0.0
+ res[line.id] = amount
+
+ return res
+
+ _columns = {'amount_currency': fields.function(_get_amount, string='Amount Currency', type='float', store=True, help='The amount expressed in the related account currency if not equal to the company one.', readonly=True),
+ 'percentage': fields.float('Percentage')}
+
+
+account_analytic_line()
+
+class account_analytic_plan(osv.osv):
+ _name = 'account.analytic.plan'
+ _description = 'Analytic Plan'
+ _columns = {'name': fields.char('Analytic Plan', size=64, required=True, select=True),
+ 'plan_ids': fields.one2many('account.analytic.plan.line', 'plan_id', 'Analytic Plans')}
+
+
+account_analytic_plan()
+
+class account_analytic_plan_line(osv.osv):
+ _name = 'account.analytic.plan.line'
+ _description = 'Analytic Plan Line'
+ _order = 'sequence, id'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan', 'Analytic Plan', required=True),
+ 'name': fields.char('Plan Name', size=64, required=True, select=True),
+ 'sequence': fields.integer('Sequence'),
+ 'root_analytic_id': fields.many2one('account.analytic.account', 'Root Account', help='Root account of this plan.', required=False),
+ 'min_required': fields.float('Minimum Allowed (%)'),
+ 'max_required': fields.float('Maximum Allowed (%)')}
+ _defaults = {'min_required': 100.0,
+ 'max_required': 100.0}
+
+
+account_analytic_plan_line()
+
+class account_analytic_plan_instance(osv.osv):
+ _name = 'account.analytic.plan.instance'
+ _description = 'Analytic Plan Instance'
+ _columns = {'name': fields.char('Analytic Distribution', size=64),
+ 'code': fields.char('Distribution Code', size=16),
+ 'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal'),
+ 'account_ids': fields.one2many('account.analytic.plan.instance.line', 'plan_id', 'Account Id'),
+ 'account1_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account1 Id'),
+ 'account2_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account2 Id'),
+ 'account3_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account3 Id'),
+ 'account4_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account4 Id'),
+ 'account5_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account5 Id'),
+ 'account6_ids': one2many_mod2('account.analytic.plan.instance.line', 'plan_id', 'Account6 Id'),
+ 'plan_id': fields.many2one('account.analytic.plan', "Model's Plan")}
+
+ def search(self, cr, user, args, offset = 0, limit = None, order = None, context = None, count = False):
+ if context is None:
+ context = {}
+ journal_obj = self.pool.get('account.journal')
+ if context.get('journal_id', False):
+ journal = journal_obj.browse(cr, user, [context['journal_id']], context=context)[0]
+ analytic_journal = journal.analytic_journal_id and journal.analytic_journal_id.id or False
+ args.append('|')
+ args.append(('journal_id', '=', analytic_journal))
+ args.append(('journal_id', '=', False))
+ res = super(account_analytic_plan_instance, self).search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count)
+ return res
+
+ def copy(self, cr, uid, id, default = None, context = None):
+ if not default:
+ default = {}
+ default.update({'account1_ids': False,
+ 'account2_ids': False,
+ 'account3_ids': False,
+ 'account4_ids': False,
+ 'account5_ids': False,
+ 'account6_ids': False})
+ return super(account_analytic_plan_instance, self).copy(cr, uid, id, default, context=context)
+
+ def _default_journal(self, cr, uid, context = None):
+ if context is None:
+ context = {}
+ journal_obj = self.pool.get('account.journal')
+ if context.has_key('journal_id') and context['journal_id']:
+ journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
+ if journal.analytic_journal_id:
+ return journal.analytic_journal_id.id
+ return False
+
+ _defaults = {'plan_id': False,
+ 'journal_id': _default_journal}
+
+ def name_get(self, cr, uid, ids, context = None):
+ res = []
+ for inst in self.browse(cr, uid, ids, context=context):
+ name = inst.name or '/'
+ if name and inst.code:
+ name = name + ' (' + inst.code + ')'
+ res.append((inst.id, name))
+
+ return res
+
+ def name_search(self, cr, uid, name, args = None, operator = 'ilike', context = None, limit = 100):
+ args = args or []
+ if name:
+ ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context or {})
+ if not ids:
+ ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context or {})
+ else:
+ ids = self.search(cr, uid, args, limit=limit, context=context or {})
+ return self.name_get(cr, uid, ids, context or {})
+
+ def fields_view_get(self, cr, uid, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ if context is None:
+ context = {}
+ wiz_id = self.pool.get('ir.actions.act_window').search(cr, uid, [('name', '=', 'analytic.plan.create.model.action')], context=context)
+ res = super(account_analytic_plan_instance, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
+ journal_obj = self.pool.get('account.journal')
+ analytic_plan_obj = self.pool.get('account.analytic.plan')
+ if res['type'] == 'form':
+ plan_id = False
+ if context.get('journal_id', False):
+ plan_id = journal_obj.browse(cr, uid, int(context['journal_id']), context=context).plan_id
+ elif context.get('plan_id', False):
+ plan_id = analytic_plan_obj.browse(cr, uid, int(context['plan_id']), context=context)
+ if plan_id:
+ i = 1
+ res['arch'] = ''
+ doc = etree.fromstring(res['arch'].encode('utf8'))
+ xarch, xfields = self._view_look_dom_arch(cr, uid, doc, view_id, context=context)
+ res['arch'] = xarch
+ res['fields'] = xfields
+ return res
+ else:
+ return res
+ return
+
+ def create(self, cr, uid, vals, context = None):
+ journal_obj = self.pool.get('account.journal')
+ ana_plan_instance_obj = self.pool.get('account.analytic.plan.instance')
+ acct_anal_acct = self.pool.get('account.analytic.account')
+ acct_anal_plan_line_obj = self.pool.get('account.analytic.plan.line')
+ if context and 'journal_id' in context:
+ journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
+ pids = ana_plan_instance_obj.search(cr, uid, [('name', '=', vals['name']), ('code', '=', vals['code']), ('plan_id', '<>', False)], context=context)
+ if pids:
+ raise osv.except_osv(_('Error!'), _('A model with this name and code already exists.'))
+ res = acct_anal_plan_line_obj.search(cr, uid, [('plan_id', '=', journal.plan_id.id)], context=context)
+ for i in res:
+ total_per_plan = 0
+ item = acct_anal_plan_line_obj.browse(cr, uid, i, context=context)
+ temp_list = ['account1_ids',
+ 'account2_ids',
+ 'account3_ids',
+ 'account4_ids',
+ 'account5_ids',
+ 'account6_ids']
+ for l in temp_list:
+ if vals.has_key(l):
+ for tempo in vals[l]:
+ if acct_anal_acct.search(cr, uid, [('parent_id', 'child_of', [item.root_analytic_id.id]), ('id', '=', tempo[2]['analytic_account_id'])], context=context):
+ total_per_plan += tempo[2]['rate']
+
+ if total_per_plan < item.min_required or total_per_plan > item.max_required:
+ raise osv.except_osv(_('Error!'), _('The total should be between %s and %s.') % (str(item.min_required), str(item.max_required)))
+
+ return super(account_analytic_plan_instance, self).create(cr, uid, vals, context=context)
+
+ def write(self, cr, uid, ids, vals, context = None, check = True, update_check = True):
+ if context is None:
+ context = {}
+ this = self.browse(cr, uid, ids[0], context=context)
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ if this.plan_id and not vals.has_key('plan_id'):
+ temp_id = self.copy(cr, uid, this.id, None, context=context)
+ lists = invoice_line_obj.search(cr, uid, [('analytics_id', '=', this.id)], context=context)
+ invoice_line_obj.write(cr, uid, lists, {'analytics_id': temp_id}, context=context)
+ vals['plan_id'] = False
+ if not vals.has_key('name'):
+ vals['name'] = this.name and str(this.name) + '*' or '*'
+ if not vals.has_key('code'):
+ vals['code'] = this.code and str(this.code) + '*' or '*'
+ return super(account_analytic_plan_instance, self).write(cr, uid, ids, vals, context=context)
+
+
+account_analytic_plan_instance()
+
+class account_analytic_plan_instance_line(osv.osv):
+ _name = 'account.analytic.plan.instance.line'
+ _description = 'Analytic Instance Line'
+ _rec_name = 'analytic_account_id'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan.instance', 'Plan Id'),
+ 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, domain=[('type', '<>', 'view')]),
+ 'rate': fields.float('Rate (%)', required=True)}
+ _defaults = {'rate': 100.0}
+
+ def name_get(self, cr, uid, ids, context = None):
+ if not ids:
+ return []
+ reads = self.read(cr, uid, ids, ['analytic_account_id'], context=context)
+ res = []
+ for record in reads:
+ res.append((record['id'], record['analytic_account_id']))
+
+ return res
+
+
+account_analytic_plan_instance_line()
+
+class account_journal(osv.osv):
+ _inherit = 'account.journal'
+ _name = 'account.journal'
+ _columns = {'plan_id': fields.many2one('account.analytic.plan', 'Analytic Plans')}
+
+
+account_journal()
+
+class account_invoice_line(osv.osv):
+ _inherit = 'account.invoice.line'
+ _name = 'account.invoice.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+ def create(self, cr, uid, vals, context = None):
+ if 'analytics_id' in vals and isinstance(vals['analytics_id'], tuple):
+ vals['analytics_id'] = vals['analytics_id'][0]
+ return super(account_invoice_line, self).create(cr, uid, vals, context=context)
+
+ def move_line_get_item(self, cr, uid, line, context = None):
+ res = super(account_invoice_line, self).move_line_get_item(cr, uid, line, context=context)
+ res['analytics_id'] = line.analytics_id and line.analytics_id.id or False
+ return res
+
+ def product_id_change(self, cr, uid, ids, product, uom_id, qty = 0, name = '', type = 'out_invoice', partner_id = False, fposition_id = False, price_unit = False, currency_id = False, context = None, company_id = None):
+ res_prod = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context, company_id=company_id)
+ rec = self.pool.get('account.analytic.default').account_get(cr, uid, product, partner_id, uid, time.strftime('%Y-%m-%d'), context=context)
+ if rec and rec.analytics_id:
+ res_prod['value'].update({'analytics_id': rec.analytics_id.id})
+ return res_prod
+
+
+account_invoice_line()
+
+class account_move_line(osv.osv):
+ _inherit = 'account.move.line'
+ _name = 'account.move.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+ def _default_get_move_form_hook(self, cursor, user, data):
+ data = super(account_move_line, self)._default_get_move_form_hook(cursor, user, data)
+ if data.has_key('analytics_id'):
+ del data['analytics_id']
+ return data
+
+ def create_analytic_lines(self, cr, uid, ids, context = None):
+ if context is None:
+ context = {}
+ super(account_move_line, self).create_analytic_lines(cr, uid, ids, context=context)
+ analytic_line_obj = self.pool.get('account.analytic.line')
+ for line in self.browse(cr, uid, ids, context=context):
+ if line.analytics_id:
+ if not line.journal_id.analytic_journal_id:
+ raise osv.except_osv(_('No Analytic Journal!'), _("You have to define an analytic journal on the '%s' journal.") % (line.journal_id.name,))
+ toremove = analytic_line_obj.search(cr, uid, [('move_id', '=', line.id)], context=context)
+ if toremove:
+ analytic_line_obj.unlink(cr, uid, toremove, context=context)
+ for line2 in line.analytics_id.account_ids:
+ val = (line.credit or 0.0) - (line.debit or 0.0)
+ amt = val * (line2.rate / 100)
+ al_vals = {'name': line.name,
+ 'date': line.date,
+ 'account_id': line2.analytic_account_id.id,
+ 'unit_amount': line.quantity,
+ 'product_id': line.product_id and line.product_id.id or False,
+ 'product_uom_id': line.product_uom_id and line.product_uom_id.id or False,
+ 'amount': amt,
+ 'general_account_id': line.account_id.id,
+ 'move_id': line.id,
+ 'journal_id': line.journal_id.analytic_journal_id.id,
+ 'ref': line.ref,
+ 'percentage': line2.rate}
+ analytic_line_obj.create(cr, uid, al_vals, context=context)
+
+ return True
+
+ def fields_view_get(self, cr, uid, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ if context is None:
+ context = {}
+ result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
+ return result
+
+
+account_move_line()
+
+class account_invoice(osv.osv):
+ _name = 'account.invoice'
+ _inherit = 'account.invoice'
+
+ def line_get_convert(self, cr, uid, x, part, date, context = None):
+ res = super(account_invoice, self).line_get_convert(cr, uid, x, part, date, context=context)
+ res['analytics_id'] = x.get('analytics_id', False)
+ return res
+
+ def _get_analytic_lines(self, cr, uid, id, context = None):
+ inv = self.browse(cr, uid, [id])[0]
+ cur_obj = self.pool.get('res.currency')
+ invoice_line_obj = self.pool.get('account.invoice.line')
+ acct_ins_obj = self.pool.get('account.analytic.plan.instance')
+ company_currency = inv.company_id.currency_id.id
+ if inv.type in ('out_invoice', 'in_refund'):
+ sign = 1
+ else:
+ sign = -1
+ iml = invoice_line_obj.move_line_get(cr, uid, inv.id, context=context)
+ for il in iml:
+ if il.get('analytics_id', False):
+ if inv.type in ('in_invoice', 'in_refund'):
+ ref = inv.reference
+ else:
+ ref = self._convert_ref(cr, uid, inv.number)
+ obj_move_line = acct_ins_obj.browse(cr, uid, il['analytics_id'], context=context)
+ ctx = context.copy()
+ ctx.update({'date': inv.date_invoice})
+ amount_calc = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, il['price'], context=ctx) * sign
+ qty = il['quantity']
+ il['analytic_lines'] = []
+ for line2 in obj_move_line.account_ids:
+ amt = amount_calc * (line2.rate / 100)
+ qtty = qty * (line2.rate / 100)
+ al_vals = {'name': il['name'],
+ 'date': inv['date_invoice'],
+ 'unit_amount': qtty,
+ 'product_id': il['product_id'],
+ 'account_id': line2.analytic_account_id.id,
+ 'amount': amt,
+ 'product_uom_id': il['uos_id'],
+ 'general_account_id': il['account_id'],
+ 'journal_id': self._get_journal_analytic(cr, uid, inv.type),
+ 'ref': ref}
+ il['analytic_lines'].append((0, 0, al_vals))
+
+ return iml
+
+
+account_invoice()
+
+class account_analytic_plan(osv.osv):
+ _inherit = 'account.analytic.plan'
+ _columns = {'default_instance_id': fields.many2one('account.analytic.plan.instance', 'Default Entries')}
+
+
+account_analytic_plan()
+
+class analytic_default(osv.osv):
+ _inherit = 'account.analytic.default'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+
+analytic_default()
+
+class sale_order_line(osv.osv):
+ _inherit = 'sale.order.line'
+
+ def invoice_line_create(self, cr, uid, ids, context = None):
+ create_ids = super(sale_order_line, self).invoice_line_create(cr, uid, ids, context=context)
+ inv_line_obj = self.pool.get('account.invoice.line')
+ acct_anal_def_obj = self.pool.get('account.analytic.default')
+ if ids:
+ sale_line = self.browse(cr, uid, ids[0], context=context)
+ for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
+ rec = acct_anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'), context)
+ if rec:
+ inv_line_obj.write(cr, uid, [line.id], {'analytics_id': rec.analytics_id.id}, context=context)
+
+ return create_ids
+
+
+sale_order_line()
+
+class account_bank_statement(osv.osv):
+ _inherit = 'account.bank.statement'
+ _name = 'account.bank.statement'
+
+ def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context = None):
+ account_move_line_pool = self.pool.get('account.move.line')
+ account_bank_statement_line_pool = self.pool.get('account.bank.statement.line')
+ st_line = account_bank_statement_line_pool.browse(cr, uid, st_line_id, context=context)
+ result = super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line_id, company_currency_id, st_line_number, context=context)
+ move = st_line.move_ids and st_line.move_ids[0] or False
+ if move:
+ for line in move.line_id:
+ account_move_line_pool.write(cr, uid, [line.id], {'analytics_id': st_line.analytics_id.id}, context=context)
+
+ return result
+
+ def button_confirm_bank(self, cr, uid, ids, context = None):
+ super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
+ for st in self.browse(cr, uid, ids, context=context):
+ for st_line in st.line_ids:
+ if st_line.analytics_id:
+ if not st.journal_id.analytic_journal_id:
+ raise osv.except_osv(_('No Analytic Journal!'), _("You have to define an analytic journal on the '%s' journal.") % (st.journal_id.name,))
+ if not st_line.amount:
+ continue
+
+ return True
+
+
+account_bank_statement()
+
+class account_bank_statement_line(osv.osv):
+ _inherit = 'account.bank.statement.line'
+ _name = 'account.bank.statement.line'
+ _columns = {'analytics_id': fields.many2one('account.analytic.plan.instance', 'Analytic Distribution')}
+
+
+account_bank_statement_line()
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_report.xml b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_report.xml
new file mode 100644
index 0000000000000..05d4c5b445c8c
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_report.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_view.xml b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_view.xml
new file mode 100644
index 0000000000000..42b17ae06c3fb
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/account_analytic_plans_view.xml
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+ account.journal.form.inherit
+ account.journal
+
+
+
+
+
+
+
+
+
+ account.move.form.inherit
+ account.move
+
+
+
+
+
+
+
+
+
+
+
+
+ account.move.line.form.inherit
+ account.move.line
+
+
+
+
+
+
+
+
+
+ account.move.line.form.inherit1
+ account.move.line
+ 2
+
+
+
+
+
+
+
+
+
+ account.move.line.tree.inherit
+ account.move.line
+ 2
+
+
+
+
+
+
+
+
+
+
+
+ account.analytic.plan.instance.form
+ account.analytic.plan.instance
+
+
+
+
+
+
+ account.analytic.plan.instance.tree
+ account.analytic.plan.instance
+
+
+
+
+
+
+
+
+
+
+
+ Analytic Distribution's Models
+ ir.actions.act_window
+ account.analytic.plan.instance
+ [('plan_id','<>',False)]
+ form
+ tree,form
+
+
+
+
+
+ account.analytic.plan.instance.line.form
+ account.analytic.plan.instance.line
+
+
+
+
+
+
+ account.analytic.plan.instance.line.tree
+ account.analytic.plan.instance.line
+
+
+
+
+
+
+
+
+
+
+ account.analytic.plan.search
+ account.analytic.plan
+
+
+
+
+
+
+
+
+ account.analytic.plan.form
+ account.analytic.plan
+
+
+
+
+
+
+ account.analytic.plan.tree
+ account.analytic.plan
+
+
+
+
+
+
+
+
+
+ Analytic Plan
+ ir.actions.act_window
+ account.analytic.plan
+ form
+ tree,form
+
+
+
+
+
+
+
+ account.analytic.plan.line.form
+ account.analytic.plan.line
+
+
+
+
+
+
+ account.analytic.plan.line.tree
+ account.analytic.plan.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ account.analytic.default.form.plans
+ account.analytic.default
+
+
+
+
+
+
+
+
+ account.analytic.default.tree.plans
+ account.analytic.default
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ account.bank.statement.form.inherit
+ account.bank.statement
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/images/analytic_plan.jpeg b/addons/account_anglo_saxon/account_analytic_plans/images/analytic_plan.jpeg
new file mode 100644
index 0000000000000..9e784051d23d1
Binary files /dev/null and b/addons/account_anglo_saxon/account_analytic_plans/images/analytic_plan.jpeg differ
diff --git a/addons/account_anglo_saxon/account_analytic_plans/report/__init__.py b/addons/account_anglo_saxon/account_analytic_plans/report/__init__.py
new file mode 100644
index 0000000000000..2d401a6f1d8ad
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/report/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+import crossovered_analytic
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.py b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.py
new file mode 100644
index 0000000000000..0013471b645c0
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.py
@@ -0,0 +1,161 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.report import report_sxw
+
+class crossovered_analytic(report_sxw.rml_parse):
+
+ def __init__(self, cr, uid, name, context):
+ super(crossovered_analytic, self).__init__(cr, uid, name, context=context)
+ self.localcontext.update({'time': time,
+ 'lines': self._lines,
+ 'ref_lines': self._ref_lines,
+ 'find_children': self.find_children})
+ self.base_amount = 0.0
+
+ def find_children(self, ref_ids):
+ if not ref_ids:
+ return []
+ to_return_ids = []
+ final_list = []
+ parent_list = []
+ set_list = []
+ analytic_obj = self.pool.get('account.analytic.account')
+ for id in ref_ids:
+ if id not in to_return_ids:
+ to_return_ids.append(analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [id])]))
+
+ data_accnt = analytic_obj.browse(self.cr, self.uid, to_return_ids[0])
+ for data in data_accnt:
+ if data.parent_id and data.parent_id.id == ref_ids[0]:
+ parent_list.append(data.id)
+
+ final_list.append(ref_ids[0])
+ set_list = self.set_account(parent_list)
+ final_list.extend(set_list)
+ return final_list
+
+ def set_account(self, cats):
+ lst = []
+ category = self.pool.get('account.analytic.account').read(self.cr, self.uid, cats)
+ for cat in category:
+ lst.append(cat['id'])
+ if cat['child_ids']:
+ lst.extend(self.set_account(cat['child_ids']))
+
+ return lst
+
+ def _ref_lines(self, form):
+ result = []
+ res = {}
+ acc_pool = self.pool.get('account.analytic.account')
+ line_pool = self.pool.get('account.analytic.line')
+ self.dict_acc_ref = {}
+ if form['journal_ids']:
+ journal = ' in (' + ','.join(map(lambda x: str(x), form['journal_ids'])) + ')'
+ else:
+ journal = 'is not null'
+ query_general = 'SELECT id FROM account_analytic_line WHERE (journal_id ' + journal + ") AND date>='" + str(form['date1']) + "' AND date<='" + str(form['date2']) + "'"
+ self.cr.execute(query_general)
+ l_ids = self.cr.fetchall()
+ line_ids = [ x[0] for x in l_ids ]
+ obj_line = line_pool.browse(self.cr, self.uid, line_ids)
+ self.dict_acc_ref[form['ref']] = []
+ children_list = acc_pool.search(self.cr, self.uid, [('parent_id', 'child_of', [form['ref']])])
+ for obj in obj_line:
+ if obj.account_id.id in children_list:
+ if obj.move_id and obj.move_id.id not in self.dict_acc_ref[form['ref']]:
+ self.dict_acc_ref[form['ref']].append(obj.move_id.id)
+
+ res['ref_name'] = acc_pool.name_get(self.cr, self.uid, [form['ref']])[0][1]
+ res['ref_code'] = acc_pool.browse(self.cr, self.uid, form['ref']).code
+ self.final_list = children_list
+ selected_ids = line_pool.search(self.cr, self.uid, [('account_id', 'in', self.final_list)])
+ res['ref_qty'] = 0.0
+ res['ref_amt'] = 0.0
+ self.base_amount = 0.0
+ if selected_ids:
+ query = 'SELECT SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty FROM account_analytic_line AS aal, account_analytic_account AS aaa WHERE aal.account_id = aaa.id AND aal.id IN (' + ','.join(map(str, selected_ids)) + ') AND (aal.journal_id ' + journal + ") AND aal.date>='" + str(form['date1']) + "' AND aal.date<='" + str(form['date2']) + "'"
+ self.cr.execute(query)
+ info = self.cr.dictfetchall()
+ res['ref_qty'] = info[0]['qty']
+ res['ref_amt'] = info[0]['amt']
+ self.base_amount = info[0]['amt']
+ result.append(res)
+ return result
+
+ def _lines(self, form, ids = None):
+ if ids is None:
+ ids = {}
+ if not ids:
+ ids = self.ids
+ if form['journal_ids']:
+ journal = ' in (' + ','.join(map(lambda x: str(x), form['journal_ids'])) + ')'
+ else:
+ journal = 'is not null'
+ acc_pool = self.pool.get('account.analytic.account')
+ line_pool = self.pool.get('account.analytic.line')
+ acc_id = []
+ final = []
+ self.list_ids = []
+ self.final_list = self.find_children(ids)
+ for acc_id in self.final_list:
+ selected_ids = line_pool.search(self.cr, self.uid, [('account_id', '=', acc_id), ('move_id', 'in', self.dict_acc_ref[form['ref']])])
+ if selected_ids:
+ query = 'SELECT aaa.code AS code, SUM(aal.amount) AS amt, SUM(aal.unit_amount) AS qty, aaa.name AS acc_name, aal.account_id AS id FROM account_analytic_line AS aal, account_analytic_account AS aaa WHERE aal.account_id=aaa.id AND aal.id IN (' + ','.join(map(str, selected_ids)) + ') AND (aal.journal_id ' + journal + ") AND aal.date>='" + str(form['date1']) + "' AND aal.date<='" + str(form['date2']) + "' GROUP BY aal.account_id,aaa.name,aaa.code ORDER BY aal.account_id"
+ self.cr.execute(query)
+ res = self.cr.dictfetchall()
+ if res:
+ for element in res:
+ if self.base_amount != 0.0:
+ element['perc'] = element['amt'] / self.base_amount * 100.0
+ else:
+ element['perc'] = 0.0
+
+ else:
+ result = {}
+ res = []
+ result['id'] = acc_id
+ data_account = acc_pool.browse(self.cr, self.uid, acc_id)
+ result['acc_name'] = data_account.name
+ result['code'] = data_account.code
+ result['amt'] = result['qty'] = result['perc'] = 0.0
+ if not form['empty_line']:
+ res.append(result)
+ else:
+ result = {}
+ res = []
+ result['id'] = acc_id
+ data_account = acc_pool.browse(self.cr, self.uid, acc_id)
+ result['acc_name'] = data_account.name
+ result['code'] = data_account.code
+ result['amt'] = result['qty'] = result['perc'] = 0.0
+ if not form['empty_line']:
+ res.append(result)
+ for item in res:
+ obj_acc = acc_pool.name_get(self.cr, self.uid, [item['id']])
+ item['acc_name'] = obj_acc[0][1]
+ final.append(item)
+
+ return final
+
+
+report_sxw.report_sxw('report.account.analytic.account.crossovered.analytic', 'account.analytic.account', 'addons/account_analytic_plans/report/crossovered_analytic.rml', parser=crossovered_analytic, header='internal')
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.rml b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.rml
new file mode 100644
index 0000000000000..48e7c13b0a1c1
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.rml
@@ -0,0 +1,304 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Account Name
+ |
+
+ Code
+ |
+
+ Quantity
+ |
+
+ Amount
+ |
+
+ Perc(%)
+ |
+
+
+
+
+
+
+ Crossovered Analytic
+
+
+
+
+
+
+ From Date
+ |
+
+ To Date
+ |
+
+ Company
+ |
+
+ Currency
+ |
+
+ Printing date
+ |
+
+
+
+
+
+ [[ formatLang(data['form']['date1'],date=True) ]]
+ |
+
+ [[ formatLang(data['form']['date2'],date=True) ]]
+ |
+
+ [[ company.name ]]
+ |
+
+ [[ company.currency_id.name ]]
+ |
+
+ [[ formatLang(time.strftime('%Y-%m-%d'),date=True) ]] at [[ time.strftime('%H:%M:%S') ]]
+ |
+
+
+
+
+
+ Analytic Account Reference:
+
+
+
+
+
+
+ Account Name
+ |
+
+ Code
+ |
+
+ Quantity
+ |
+
+ Amount
+ |
+
+ Perc(%)
+ |
+
+
+
+ [[ repeatIn(ref_lines(data['form']),'a') ]]
+
+
+
+ [[ a['ref_name'] ]]
+ |
+
+ [[ a['ref_code'] ]]
+ |
+
+ [[ a['ref_qty'] and formatLang(a['ref_qty']) ]]
+ |
+
+ [[ a['ref_amt'] and formatLang(a['ref_amt'], currency_obj=company.currency_id) ]]
+ |
+
+ 100.00%
+ |
+
+
+
+
+
+
+ Analytic Account :
+
+
+
+
+
+
+ Account Name
+ |
+
+ Code
+ |
+
+ Quantity
+ |
+
+ Amount
+ |
+
+ Percentage
+ |
+
+
+
+ [[ repeatIn(lines(data['form']),'a') ]]
+
+
+
+ [[ a['acc_name'] ]]
+ |
+
+ [[ a['code'] ]]
+ |
+
+ [[formatLang(a['qty']) ]]
+ |
+
+ [[ formatLang(a['amt'], currency_obj=company.currency_id) ]]
+ |
+
+ [[ formatLang(a['perc']) ]]%
+ |
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.sxw b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.sxw
new file mode 100644
index 0000000000000..e1c1cc9c6f374
Binary files /dev/null and b/addons/account_anglo_saxon/account_analytic_plans/report/crossovered_analytic.sxw differ
diff --git a/addons/account_anglo_saxon/account_analytic_plans/security/account_analytic_plan_security.xml b/addons/account_anglo_saxon/account_analytic_plans/security/account_analytic_plan_security.xml
new file mode 100644
index 0000000000000..1c379bb0f30d5
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/security/account_analytic_plan_security.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/security/ir.model.access.csv b/addons/account_anglo_saxon/account_analytic_plans/security/ir.model.access.csv
new file mode 100644
index 0000000000000..9ba40d5c1c3fd
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/security/ir.model.access.csv
@@ -0,0 +1,6 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_account_analytic_plan,account.analytic.plan,model_account_analytic_plan,account.group_account_user,1,1,1,1
+access_account_analytic_plan_line,account.analytic.plan.line,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
+access_account_analytic_plan_instance,account.analytic.plan.instance,model_account_analytic_plan_instance,account.group_account_user,1,1,1,1
+access_account_analytic_plan_instance_line,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,account.group_account_user,1,1,1,1
+access_account_analytic_plan_line_invoice,account.analytic.plan.line.invoice,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
diff --git a/addons/account_anglo_saxon/account_analytic_plans/test/acount_analytic_plans_report.yml b/addons/account_anglo_saxon/account_analytic_plans/test/acount_analytic_plans_report.yml
new file mode 100644
index 0000000000000..0990b9ba5f936
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/test/acount_analytic_plans_report.yml
@@ -0,0 +1,9 @@
+-
+ Print the Crossovered Analytic Report in Normal mode
+-
+ !python {model: account.analytic.account}: |
+ import netsvc, tools, os, time
+ data_dict = {'model': 'account.analytic.account', 'form': {'date1':time.strftime("%Y-01-01"),'date2':time.strftime('%Y-%m-%d'),'journal_ids':[6,0,(ref('account.cose_journal_sale'))],'ref':ref('account.analytic_root'),'empty_line':True,'id':ref('account.analytic_root'),'context':{}}}
+ (data, format) = netsvc.LocalService('report.account.analytic.account.crossovered.analytic').create(cr, uid, [ref('account.analytic_root')], data_dict, {})
+ if tools.config['test_report_directory']:
+ file(os.path.join(tools.config['test_report_directory'], 'account_analytic_plans-crossovered_analyitic.'+format), 'wb+').write(data)
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/wizard/__init__.py b/addons/account_anglo_saxon/account_analytic_plans/wizard/__init__.py
new file mode 100644
index 0000000000000..f5c73701ae156
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/wizard/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+import analytic_plan_create_model
+import account_crossovered_analytic
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic.py b/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic.py
new file mode 100644
index 0000000000000..2ec51a1ef0c4d
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+class account_crossovered_analytic(osv.osv_memory):
+ _name = 'account.crossovered.analytic'
+ _description = 'Print Crossovered Analytic'
+ _columns = {'date1': fields.date('Start Date', required=True),
+ 'date2': fields.date('End Date', required=True),
+ 'journal_ids': fields.many2many('account.analytic.journal', 'crossovered_journal_rel', 'crossover_id', 'journal_id', 'Analytic Journal'),
+ 'ref': fields.many2one('account.analytic.account', 'Analytic Account Reference', required=True),
+ 'empty_line': fields.boolean('Dont show empty lines')}
+ _defaults = {'date1': lambda *a: time.strftime('%Y-01-01'),
+ 'date2': lambda *a: time.strftime('%Y-%m-%d')}
+
+ def print_report(self, cr, uid, ids, context = None):
+ cr.execute('SELECT account_id FROM account_analytic_line')
+ res = cr.fetchall()
+ acc_ids = [ x[0] for x in res ]
+ data = self.read(cr, uid, ids, [], context=context)[0]
+ data['ref'] = data['ref'][0]
+ obj_acc = self.pool.get('account.analytic.account').browse(cr, uid, data['ref'], context=context)
+ name = obj_acc.name
+ account_ids = self.pool.get('account.analytic.account').search(cr, uid, [('parent_id', 'child_of', [data['ref']])], context=context)
+ flag = True
+ for acc in account_ids:
+ if acc in acc_ids:
+ flag = False
+ break
+
+ if flag:
+ raise osv.except_osv(_('User Error!'), _('There are no analytic lines related to account %s.' % name))
+ datas = {'ids': [],
+ 'model': 'account.analytic.account',
+ 'form': data}
+ return {'type': 'ir.actions.report.xml',
+ 'report_name': 'account.analytic.account.crossovered.analytic',
+ 'datas': datas}
+
+
+account_crossovered_analytic()
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic_view.xml b/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic_view.xml
new file mode 100644
index 0000000000000..07e2ca19cd99e
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/wizard/account_crossovered_analytic_view.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ account.crossovered.analytic.form
+ account.crossovered.analytic
+
+
+
+
+
+
+ Crossovered Analytic
+ ir.actions.act_window
+ account.crossovered.analytic
+ form
+ form
+ new
+
+
+
+
+ Crossovered Analytic
+ client_print_multi
+
+ action
+ account.analytic.account
+
+
+
+
diff --git a/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model.py b/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model.py
new file mode 100644
index 0000000000000..5ef71634456b6
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp.osv import osv
+from openerp.tools.translate import _
+
+class analytic_plan_create_model(osv.osv_memory):
+ _name = 'analytic.plan.create.model'
+ _description = 'analytic.plan.create.model'
+
+ def activate(self, cr, uid, ids, context = None):
+ plan_obj = self.pool.get('account.analytic.plan.instance')
+ mod_obj = self.pool.get('ir.model.data')
+ anlytic_plan_obj = self.pool.get('account.analytic.plan')
+ if context is None:
+ context = {}
+ if 'active_id' in context and context['active_id']:
+ plan = plan_obj.browse(cr, uid, context['active_id'], context=context)
+ if not plan.name or not plan.code:
+ raise osv.except_osv(_('Error!'), _('Please put a name and a code before saving the model.'))
+ pids = anlytic_plan_obj.search(cr, uid, [], context=context)
+ if not pids:
+ raise osv.except_osv(_('Error!'), _('There is no analytic plan defined.'))
+ plan_obj.write(cr, uid, [context['active_id']], {'plan_id': pids[0]}, context=context)
+ model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'view_analytic_plan_create_model')], context=context)
+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
+ return {'name': _('Distribution Model Saved'),
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'analytic.plan.create.model',
+ 'views': [(resource_id, 'form')],
+ 'type': 'ir.actions.act_window',
+ 'target': 'new'}
+ else:
+ return {'type': 'ir.actions.act_window_close'}
+ return
+
+
+analytic_plan_create_model()
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model_view.xml b/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model_view.xml
new file mode 100644
index 0000000000000..fdc7fa6868a09
--- /dev/null
+++ b/addons/account_anglo_saxon/account_analytic_plans/wizard/analytic_plan_create_model_view.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ analytic.plan.create.model.msg.form
+ analytic.plan.create.model
+
+
+
+
+
+
+ analytic.plan.create.model.form
+ analytic.plan.create.model
+
+
+
+
+
+
+
+ analytic.plan.create.model.action
+ ir.actions.act_window
+ analytic.plan.create.model
+ form
+ form
+ new
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/images/account_anglo_saxon.jpeg b/addons/account_anglo_saxon/images/account_anglo_saxon.jpeg
new file mode 100644
index 0000000000000..b5d17d23fa963
Binary files /dev/null and b/addons/account_anglo_saxon/images/account_anglo_saxon.jpeg differ
diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py
index 8942baabfd032..dff6308f16b5c 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -1,496 +1,444 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-from datetime import datetime
-from dateutil.relativedelta import relativedelta
-
-from openerp.osv import fields, osv
-import openerp.addons.decimal_precision as dp
-from tools.translate import _
-
-class account_asset_category(osv.osv):
- _name = 'account.asset.category'
- _description = 'Asset category'
-
- _columns = {
- 'name': fields.char('Name', size=64, required=True, select=1),
- 'note': fields.text('Note'),
- 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),
- 'account_asset_id': fields.many2one('account.account', 'Asset Account', required=True, domain=[('type','=','other')]),
- 'account_depreciation_id': fields.many2one('account.account', 'Depreciation Account', required=True, domain=[('type','=','other')]),
- 'account_expense_depreciation_id': fields.many2one('account.account', 'Depr. Expense Account', required=True, domain=[('type','=','other')]),
- 'journal_id': fields.many2one('account.journal', 'Journal', required=True),
- 'company_id': fields.many2one('res.company', 'Company', required=True),
- 'method': fields.selection([('linear','Linear'),('degressive','Degressive')], 'Computation Method', required=True, help="Choose the method to use to compute the amount of depreciation lines.\n"\
- " * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n" \
- " * Degressive: Calculated on basis of: Residual Value * Degressive Factor"),
- 'method_number': fields.integer('Number of Depreciations', help="The number of depreciations needed to depreciate your asset"),
- 'method_period': fields.integer('Period Length', help="State here the time between 2 depreciations, in months", required=True),
- 'method_progress_factor': fields.float('Degressive Factor'),
- 'method_time': fields.selection([('number','Number of Depreciations'),('end','Ending Date')], 'Time Method', required=True,
- help="Choose the method to use to compute the dates and number of depreciation lines.\n"\
- " * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \
- " * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
- 'method_end': fields.date('Ending date'),
- 'prorata':fields.boolean('Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'),
- 'open_asset': fields.boolean('Skip Draft State', help="Check this if you want to automatically confirm the assets of this category when created by invoices."),
- }
-
- _defaults = {
- 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'account.asset.category', context=context),
- 'method': 'linear',
- 'method_number': 5,
- 'method_time': 'number',
- 'method_period': 12,
- 'method_progress_factor': 0.3,
- }
-
- def onchange_account_asset(self, cr, uid, ids, account_asset_id, context=None):
- res = {'value':{}}
- if account_asset_id:
- res['value'] = {'account_depreciation_id': account_asset_id}
- return res
-
-account_asset_category()
-
-class account_asset_asset(osv.osv):
- _name = 'account.asset.asset'
- _description = 'Asset'
-
- def unlink(self, cr, uid, ids, context=None):
- for asset in self.browse(cr, uid, ids, context=context):
- if asset.account_move_line_ids:
- raise osv.except_osv(_('Error!'), _('You cannot delete an asset that contains posted depreciation lines.'))
- return super(account_asset_asset, self).unlink(cr, uid, ids, context=context)
-
- def _get_period(self, cr, uid, context=None):
- ctx = dict(context or {}, account_period_prefer_normal=True)
- periods = self.pool.get('account.period').find(cr, uid, context=ctx)
- if periods:
- return periods[0]
- else:
- return False
-
- def _get_last_depreciation_date(self, cr, uid, ids, context=None):
- """
- @param id: ids of a account.asset.asset objects
- @return: Returns a dictionary of the effective dates of the last depreciation entry made for given asset ids. If there isn't any, return the purchase date of this asset
- """
- cr.execute("""
- SELECT a.id as id, COALESCE(MAX(l.date),a.purchase_date) AS date
- FROM account_asset_asset a
- LEFT JOIN account_move_line l ON (l.asset_id = a.id)
- WHERE a.id IN %s
- GROUP BY a.id, a.purchase_date """, (tuple(ids),))
- return dict(cr.fetchall())
-
- def _compute_board_amount(self, cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=None):
- #by default amount = 0
- amount = 0
- if i == undone_dotation_number:
- amount = residual_amount
- else:
- if asset.method == 'linear':
- amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
- if asset.prorata:
- amount = amount_to_depr / asset.method_number
- days = total_days - float(depreciation_date.strftime('%j'))
- if i == 1:
- amount = (amount_to_depr / asset.method_number) / total_days * days
- elif i == undone_dotation_number:
- amount = (amount_to_depr / asset.method_number) / total_days * (total_days - days)
- elif asset.method == 'degressive':
- amount = residual_amount * asset.method_progress_factor
- if asset.prorata:
- days = total_days - float(depreciation_date.strftime('%j'))
- if i == 1:
- amount = (residual_amount * asset.method_progress_factor) / total_days * days
- elif i == undone_dotation_number:
- amount = (residual_amount * asset.method_progress_factor) / total_days * (total_days - days)
- return amount
-
- def _compute_board_undone_dotation_nb(self, cr, uid, asset, depreciation_date, total_days, context=None):
- undone_dotation_number = asset.method_number
- if asset.method_time == 'end':
- end_date = datetime.strptime(asset.method_end, '%Y-%m-%d')
- undone_dotation_number = 0
- while depreciation_date <= end_date:
- depreciation_date = (datetime(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+asset.method_period))
- undone_dotation_number += 1
- if asset.prorata:
- undone_dotation_number += 1
- return undone_dotation_number
-
- def compute_depreciation_board(self, cr, uid, ids, context=None):
- depreciation_lin_obj = self.pool.get('account.asset.depreciation.line')
- currency_obj = self.pool.get('res.currency')
- for asset in self.browse(cr, uid, ids, context=context):
- if asset.value_residual == 0.0:
- continue
- posted_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_check', '=', True)],order='depreciation_date desc')
- old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)])
- if old_depreciation_line_ids:
- depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context)
-
- amount_to_depr = residual_amount = asset.value_residual
- if asset.prorata:
- depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d')
- else:
- # depreciation_date = 1st January of purchase year
- purchase_date = datetime.strptime(asset.purchase_date, '%Y-%m-%d')
- #if we already have some previous validated entries, starting date isn't 1st January but last entry + method period
- if (len(posted_depreciation_line_ids)>0):
- last_depreciation_date = datetime.strptime(depreciation_lin_obj.browse(cr,uid,posted_depreciation_line_ids[0],context=context).depreciation_date, '%Y-%m-%d')
- depreciation_date = (last_depreciation_date+relativedelta(months=+asset.method_period))
- else:
- depreciation_date = datetime(purchase_date.year, 1, 1)
- day = depreciation_date.day
- month = depreciation_date.month
- year = depreciation_date.year
- total_days = (year % 4) and 365 or 366
-
- undone_dotation_number = self._compute_board_undone_dotation_nb(cr, uid, asset, depreciation_date, total_days, context=context)
- for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
- i = x + 1
- amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context)
- residual_amount -= amount
- vals = {
- 'amount': amount,
- 'asset_id': asset.id,
- 'sequence': i,
- 'name': str(asset.id) +'/' + str(i),
- 'remaining_value': residual_amount,
- 'depreciated_value': (asset.purchase_value - asset.salvage_value) - (residual_amount + amount),
- 'depreciation_date': depreciation_date.strftime('%Y-%m-%d'),
- }
- depreciation_lin_obj.create(cr, uid, vals, context=context)
- # Considering Depr. Period as months
- depreciation_date = (datetime(year, month, day) + relativedelta(months=+asset.method_period))
- day = depreciation_date.day
- month = depreciation_date.month
- year = depreciation_date.year
- return True
-
- def validate(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- return self.write(cr, uid, ids, {
- 'state':'open'
- }, context)
-
- def set_to_close(self, cr, uid, ids, context=None):
- return self.write(cr, uid, ids, {'state': 'close'}, context=context)
-
- def set_to_draft(self, cr, uid, ids, context=None):
- return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
-
- def _amount_residual(self, cr, uid, ids, name, args, context=None):
- cr.execute("""SELECT
- l.asset_id as id, SUM(abs(l.debit-l.credit)) AS amount
- FROM
- account_move_line l
- WHERE
- l.asset_id IN %s GROUP BY l.asset_id """, (tuple(ids),))
- res=dict(cr.fetchall())
- for asset in self.browse(cr, uid, ids, context):
- company_currency = asset.company_id.currency_id.id
- current_currency = asset.currency_id.id
- amount = self.pool['res.currency'].compute(cr, uid, company_currency, current_currency, res.get(asset.id, 0.0), context=context)
- res[asset.id] = asset.purchase_value - amount - asset.salvage_value
- for id in ids:
- res.setdefault(id, 0.0)
- return res
-
- def onchange_company_id(self, cr, uid, ids, company_id=False, context=None):
- val = {}
- if company_id:
- company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
- if company.currency_id.company_id and company.currency_id.company_id.id != company_id:
- val['currency_id'] = False
- else:
- val['currency_id'] = company.currency_id.id
- return {'value': val}
-
- def onchange_purchase_salvage_value(self, cr, uid, ids, purchase_value, salvage_value, context=None):
- val = {}
- for asset in self.browse(cr, uid, ids, context=context):
- if purchase_value:
- val['value_residual'] = purchase_value - salvage_value
- if salvage_value:
- val['value_residual'] = purchase_value - salvage_value
- return {'value': val}
-
- _columns = {
- 'account_move_line_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft':[('readonly',False)]}),
- 'name': fields.char('Asset Name', size=64, required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'code': fields.char('Reference', size=32, readonly=True, states={'draft':[('readonly',False)]}),
- 'purchase_value': fields.float('Gross Value', required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'currency_id': fields.many2one('res.currency','Currency',required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'note': fields.text('Note'),
- 'category_id': fields.many2one('account.asset.category', 'Asset Category', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'parent_id': fields.many2one('account.asset.asset', 'Parent Asset', readonly=True, states={'draft':[('readonly',False)]}),
- 'child_ids': fields.one2many('account.asset.asset', 'parent_id', 'Children Assets'),
- 'purchase_date': fields.date('Purchase Date', required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'state': fields.selection([('draft','Draft'),('open','Running'),('close','Close')], 'Status', required=True,
- help="When an asset is created, the status is 'Draft'.\n" \
- "If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n" \
- "You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status."),
- 'active': fields.boolean('Active'),
- 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True, states={'draft':[('readonly',False)]}),
- 'method': fields.selection([('linear','Linear'),('degressive','Degressive')], 'Computation Method', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose the method to use to compute the amount of depreciation lines.\n"\
- " * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n" \
- " * Degressive: Calculated on basis of: Residual Value * Degressive Factor"),
- 'method_number': fields.integer('Number of Depreciations', readonly=True, states={'draft':[('readonly',False)]}, help="The number of depreciations needed to depreciate your asset"),
- 'method_period': fields.integer('Number of Months in a Period', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="The amount of time between two depreciations, in months"),
- 'method_end': fields.date('Ending Date', readonly=True, states={'draft':[('readonly',False)]}),
- 'method_progress_factor': fields.float('Degressive Factor', readonly=True, states={'draft':[('readonly',False)]}),
- 'value_residual': fields.function(_amount_residual, method=True, digits_compute=dp.get_precision('Account'), string='Residual Value'),
- 'method_time': fields.selection([('number','Number of Depreciations'),('end','Ending Date')], 'Time Method', required=True, readonly=True, states={'draft':[('readonly',False)]},
- help="Choose the method to use to compute the dates and number of depreciation lines.\n"\
- " * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \
- " * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
- 'prorata':fields.boolean('Prorata Temporis', readonly=True, states={'draft':[('readonly',False)]}, help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'),
- 'history_ids': fields.one2many('account.asset.history', 'asset_id', 'History', readonly=True),
- 'depreciation_line_ids': fields.one2many('account.asset.depreciation.line', 'asset_id', 'Depreciation Lines', readonly=True, states={'draft':[('readonly',False)],'open':[('readonly',False)]}),
- 'salvage_value': fields.float('Salvage Value', digits_compute=dp.get_precision('Account'), help="It is the amount you plan to have that you cannot depreciate.", readonly=True, states={'draft':[('readonly',False)]}),
- }
- _defaults = {
- 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'account.asset.code'),
- 'purchase_date': lambda obj, cr, uid, context: time.strftime('%Y-%m-%d'),
- 'active': True,
- 'state': 'draft',
- 'method': 'linear',
- 'method_number': 5,
- 'method_time': 'number',
- 'method_period': 12,
- 'method_progress_factor': 0.3,
- 'currency_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.currency_id.id,
- 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'account.asset.asset',context=context),
- }
-
- def _check_recursion(self, cr, uid, ids, context=None, parent=None):
- return super(account_asset_asset, self)._check_recursion(cr, uid, ids, context=context, parent=parent)
-
- def _check_prorata(self, cr, uid, ids, context=None):
- for asset in self.browse(cr, uid, ids, context=context):
- if asset.prorata and asset.method_time != 'number':
- return False
- return True
-
- _constraints = [
- (_check_recursion, 'Error ! You cannot create recursive assets.', ['parent_id']),
- (_check_prorata, 'Prorata temporis can be applied only for time method "number of depreciations".', ['prorata']),
- ]
-
- def onchange_category_id(self, cr, uid, ids, category_id, context=None):
- res = {'value':{}}
- asset_categ_obj = self.pool.get('account.asset.category')
- if category_id:
- category_obj = asset_categ_obj.browse(cr, uid, category_id, context=context)
- res['value'] = {
- 'method': category_obj.method,
- 'method_number': category_obj.method_number,
- 'method_time': category_obj.method_time,
- 'method_period': category_obj.method_period,
- 'method_progress_factor': category_obj.method_progress_factor,
- 'method_end': category_obj.method_end,
- 'prorata': category_obj.prorata,
- }
- return res
-
- def onchange_method_time(self, cr, uid, ids, method_time='number', context=None):
- res = {'value': {}}
- if method_time != 'number':
- res['value'] = {'prorata': False}
- return res
-
- def copy(self, cr, uid, id, default=None, context=None):
- if default is None:
- default = {}
- if context is None:
- context = {}
- default.update({'depreciation_line_ids': [], 'account_move_line_ids': [], 'history_ids': [], 'state': 'draft'})
- return super(account_asset_asset, self).copy(cr, uid, id, default, context=context)
-
- def _compute_entries(self, cr, uid, ids, period_id, context=None):
- result = []
- period_obj = self.pool.get('account.period')
- depreciation_obj = self.pool.get('account.asset.depreciation.line')
- period = period_obj.browse(cr, uid, period_id, context=context)
- depreciation_ids = depreciation_obj.search(cr, uid, [('asset_id', 'in', ids), ('depreciation_date', '<=', period.date_stop), ('depreciation_date', '>=', period.date_start), ('move_check', '=', False)], context=context)
- if context is None:
- context = {}
- context.update({'depreciation_date':period.date_stop})
- return depreciation_obj.create_move(cr, uid, depreciation_ids, context=context)
-
- def create(self, cr, uid, vals, context=None):
- asset_id = super(account_asset_asset, self).create(cr, uid, vals, context=context)
- self.compute_depreciation_board(cr, uid, [asset_id], context=context)
- return asset_id
-
- def open_entries(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- context.update({'search_default_asset_id': ids, 'default_asset_id': ids})
- return {
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'account.move.line',
- 'view_id': False,
- 'type': 'ir.actions.act_window',
- 'context': context,
- }
-
-account_asset_asset()
-
-class account_asset_depreciation_line(osv.osv):
- _name = 'account.asset.depreciation.line'
- _description = 'Asset depreciation line'
-
- def _get_move_check(self, cr, uid, ids, name, args, context=None):
- res = {}
- for line in self.browse(cr, uid, ids, context=context):
- res[line.id] = bool(line.move_id)
- return res
-
- _columns = {
- 'name': fields.char('Depreciation Name', size=64, required=True, select=1),
- 'sequence': fields.integer('Sequence', required=True),
- 'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True, ondelete='cascade'),
- 'parent_state': fields.related('asset_id', 'state', type='char', string='State of Asset'),
- 'amount': fields.float('Current Depreciation', digits_compute=dp.get_precision('Account'), required=True),
- 'remaining_value': fields.float('Next Period Depreciation', digits_compute=dp.get_precision('Account'),required=True),
- 'depreciated_value': fields.float('Amount Already Depreciated', required=True),
- 'depreciation_date': fields.date('Depreciation Date', select=1),
- 'move_id': fields.many2one('account.move', 'Depreciation Entry'),
- 'move_check': fields.function(_get_move_check, method=True, type='boolean', string='Posted', store=True)
- }
-
- def create_move(self, cr, uid, ids, context=None):
- can_close = False
- if context is None:
- context = {}
- asset_obj = self.pool.get('account.asset.asset')
- period_obj = self.pool.get('account.period')
- move_obj = self.pool.get('account.move')
- move_line_obj = self.pool.get('account.move.line')
- currency_obj = self.pool.get('res.currency')
- created_move_ids = []
- asset_ids = []
- for line in self.browse(cr, uid, ids, context=context):
- depreciation_date = context.get('depreciation_date') or line.depreciation_date or time.strftime('%Y-%m-%d')
- ctx = dict(context, account_period_prefer_normal=True)
- period_ids = period_obj.find(cr, uid, depreciation_date, context=ctx)
- company_currency = line.asset_id.company_id.currency_id.id
- current_currency = line.asset_id.currency_id.id
- context.update({'date': depreciation_date})
- amount = currency_obj.compute(cr, uid, current_currency, company_currency, line.amount, context=context)
- sign = (line.asset_id.category_id.journal_id.type == 'purchase' and 1) or -1
- asset_name = "/"
- reference = line.asset_id.name
- move_vals = {
- 'name': asset_name,
- 'date': depreciation_date,
- 'ref': reference,
- 'period_id': period_ids and period_ids[0] or False,
- 'journal_id': line.asset_id.category_id.journal_id.id,
- }
- move_id = move_obj.create(cr, uid, move_vals, context=context)
- journal_id = line.asset_id.category_id.journal_id.id
- partner_id = line.asset_id.partner_id.id
- move_line_obj.create(cr, uid, {
- 'name': asset_name,
- 'ref': reference,
- 'move_id': move_id,
- 'account_id': line.asset_id.category_id.account_depreciation_id.id,
- 'debit': 0.0,
- 'credit': amount,
- 'period_id': period_ids and period_ids[0] or False,
- 'journal_id': journal_id,
- 'partner_id': partner_id,
- 'currency_id': company_currency != current_currency and current_currency or False,
- 'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
- 'date': depreciation_date,
- })
- move_line_obj.create(cr, uid, {
- 'name': asset_name,
- 'ref': reference,
- 'move_id': move_id,
- 'account_id': line.asset_id.category_id.account_expense_depreciation_id.id,
- 'credit': 0.0,
- 'debit': amount,
- 'period_id': period_ids and period_ids[0] or False,
- 'journal_id': journal_id,
- 'partner_id': partner_id,
- 'currency_id': company_currency != current_currency and current_currency or False,
- 'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
- 'analytic_account_id': line.asset_id.category_id.account_analytic_id.id,
- 'date': depreciation_date,
- 'asset_id': line.asset_id.id
- })
- self.write(cr, uid, line.id, {'move_id': move_id}, context=context)
- created_move_ids.append(move_id)
- asset_ids.append(line.asset_id.id)
- # we re-evaluate the assets to determine whether we can close them
- for asset in asset_obj.browse(cr, uid, list(set(asset_ids)), context=context):
- if currency_obj.is_zero(cr, uid, asset.currency_id, asset.value_residual):
- asset.write({'state': 'close'})
- return created_move_ids
-
-account_asset_depreciation_line()
-
-class account_move_line(osv.osv):
- _inherit = 'account.move.line'
- _columns = {
- 'asset_id': fields.many2one('account.asset.asset', 'Asset', ondelete="restrict"),
- 'entry_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft':[('readonly',False)]}),
-
- }
-account_move_line()
-
-class account_asset_history(osv.osv):
- _name = 'account.asset.history'
- _description = 'Asset history'
- _columns = {
- 'name': fields.char('History name', size=64, select=1),
- 'user_id': fields.many2one('res.users', 'User', required=True),
- 'date': fields.date('Date', required=True),
- 'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True),
- 'method_time': fields.selection([('number','Number of Depreciations'),('end','Ending Date')], 'Time Method', required=True,
- help="The method to use to compute the dates and number of depreciation lines.\n"\
- "Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \
- "Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
- 'method_number': fields.integer('Number of Depreciations', help="The number of depreciations needed to depreciate your asset"),
- 'method_period': fields.integer('Period Length', help="Time in month between two depreciations"),
- 'method_end': fields.date('Ending date'),
- 'note': fields.text('Note'),
- }
- _order = 'date desc'
- _defaults = {
- 'date': lambda *args: time.strftime('%Y-%m-%d'),
- 'user_id': lambda self, cr, uid, ctx: uid
- }
-
-account_asset_history()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+from openerp.osv import fields, osv
+import openerp.addons.decimal_precision as dp
+from tools.translate import _
+
+class account_asset_category(osv.osv):
+ _name = 'account.asset.category'
+ _description = 'Asset category'
+ _columns = {'name': fields.char('Name', size=64, required=True, select=1),
+ 'note': fields.text('Note'),
+ 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),
+ 'account_asset_id': fields.many2one('account.account', 'Asset Account', required=True),
+ 'account_depreciation_id': fields.many2one('account.account', 'Depreciation Account', required=True),
+ 'account_expense_depreciation_id': fields.many2one('account.account', 'Depr. Expense Account', required=True),
+ 'journal_id': fields.many2one('account.journal', 'Journal', required=True),
+ 'company_id': fields.many2one('res.company', 'Company', required=True),
+ 'method': fields.selection([('linear', 'Linear'), ('degressive', 'Degressive')], 'Computation Method', required=True, help='Choose the method to use to compute the amount of depreciation lines.\n * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n * Degressive: Calculated on basis of: Residual Value * Degressive Factor'),
+ 'method_number': fields.integer('Number of Depreciations', help='The number of depreciations needed to depreciate your asset'),
+ 'method_period': fields.integer('Period Length', help='State here the time between 2 depreciations, in months', required=True),
+ 'method_progress_factor': fields.float('Degressive Factor'),
+ 'method_time': fields.selection([('number', 'Number of Depreciations'), ('end', 'Ending Date')], 'Time Method', required=True, help="Choose the method to use to compute the dates and number of depreciation lines.\n * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
+ 'method_end': fields.date('Ending date'),
+ 'prorata': fields.boolean('Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'),
+ 'open_asset': fields.boolean('Skip Draft State', help='Check this if you want to automatically confirm the assets of this category when created by invoices.')}
+ _defaults = {'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'account.asset.category', context=context),
+ 'method': 'linear',
+ 'method_number': 5,
+ 'method_time': 'number',
+ 'method_period': 12,
+ 'method_progress_factor': 0.3}
+
+ def onchange_account_asset(self, cr, uid, ids, account_asset_id, context = None):
+ res = {'value': {}}
+ if account_asset_id:
+ res['value'] = {'account_depreciation_id': account_asset_id}
+ return res
+
+
+account_asset_category()
+
+class account_asset_asset(osv.osv):
+ _name = 'account.asset.asset'
+ _description = 'Asset'
+
+ def unlink(self, cr, uid, ids, context = None):
+ for asset in self.browse(cr, uid, ids, context=context):
+ if asset.account_move_line_ids:
+ raise osv.except_osv(_('Error!'), _('You cannot delete an asset that contains posted depreciation lines.'))
+
+ return super(account_asset_asset, self).unlink(cr, uid, ids, context=context)
+
+ def _get_period(self, cr, uid, context = None):
+ ctx = dict(context or {}, account_period_prefer_normal=True)
+ periods = self.pool.get('account.period').find(cr, uid, context=ctx)
+ if periods:
+ return periods[0]
+ else:
+ return False
+
+ def _get_last_depreciation_date(self, cr, uid, ids, context = None):
+ """
+ @param id: ids of a account.asset.asset objects
+ @return: Returns a dictionary of the effective dates of the last depreciation entry made for given asset ids. If there isn't any, return the purchase date of this asset
+ """
+ cr.execute('\n SELECT a.id as id, COALESCE(MAX(l.date),a.purchase_date) AS date\n FROM account_asset_asset a\n LEFT JOIN account_move_line l ON (l.asset_id = a.id)\n WHERE a.id IN %s\n GROUP BY a.id, a.purchase_date ', (tuple(ids),))
+ return dict(cr.fetchall())
+
+ def _compute_board_amount(self, cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context = None):
+ amount = 0
+ if i == undone_dotation_number:
+ amount = residual_amount
+ elif asset.method == 'linear':
+ amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
+ if asset.prorata:
+ amount = amount_to_depr / asset.method_number
+ days = total_days - float(depreciation_date.strftime('%j'))
+ if i == 1:
+ amount = amount_to_depr / asset.method_number / total_days * days
+ elif i == undone_dotation_number:
+ amount = amount_to_depr / asset.method_number / total_days * (total_days - days)
+ elif asset.method == 'degressive':
+ amount = residual_amount * asset.method_progress_factor
+ if asset.prorata:
+ days = total_days - float(depreciation_date.strftime('%j'))
+ if i == 1:
+ amount = residual_amount * asset.method_progress_factor / total_days * days
+ elif i == undone_dotation_number:
+ amount = residual_amount * asset.method_progress_factor / total_days * (total_days - days)
+ return amount
+
+ def _compute_board_undone_dotation_nb(self, cr, uid, asset, depreciation_date, total_days, context = None):
+ undone_dotation_number = asset.method_number
+ if asset.method_time == 'end':
+ end_date = datetime.strptime(asset.method_end, '%Y-%m-%d')
+ undone_dotation_number = 0
+ while depreciation_date <= end_date:
+ depreciation_date = datetime(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+asset.method_period)
+ undone_dotation_number += 1
+
+ if asset.prorata:
+ undone_dotation_number += 1
+ return undone_dotation_number
+
+ def compute_depreciation_board(self, cr, uid, ids, context = None):
+ depreciation_lin_obj = self.pool.get('account.asset.depreciation.line')
+ currency_obj = self.pool.get('res.currency')
+ for asset in self.browse(cr, uid, ids, context=context):
+ if asset.value_residual == 0.0:
+ continue
+ posted_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_check', '=', True)], order='depreciation_date desc')
+ old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)])
+ if old_depreciation_line_ids:
+ depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context)
+ amount_to_depr = residual_amount = asset.value_residual
+ if asset.prorata:
+ depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d')
+ else:
+ purchase_date = datetime.strptime(asset.purchase_date, '%Y-%m-%d')
+ if len(posted_depreciation_line_ids) > 0:
+ last_depreciation_date = datetime.strptime(depreciation_lin_obj.browse(cr, uid, posted_depreciation_line_ids[0], context=context).depreciation_date, '%Y-%m-%d')
+ depreciation_date = last_depreciation_date + relativedelta(months=+asset.method_period)
+ else:
+ depreciation_date = datetime(purchase_date.year, 1, 1)
+ day = depreciation_date.day
+ month = depreciation_date.month
+ year = depreciation_date.year
+ total_days = year % 4 and 365 or 366
+ undone_dotation_number = self._compute_board_undone_dotation_nb(cr, uid, asset, depreciation_date, total_days, context=context)
+ for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
+ i = x + 1
+ amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context)
+ company_currency = asset.company_id.currency_id.id
+ current_currency = asset.currency_id.id
+ amount = currency_obj.compute(cr, uid, current_currency, company_currency, amount, context=context)
+ residual_amount -= amount
+ vals = {'amount': amount,
+ 'asset_id': asset.id,
+ 'sequence': i,
+ 'name': str(asset.id) + '/' + str(i),
+ 'remaining_value': residual_amount,
+ 'depreciated_value': asset.purchase_value - asset.salvage_value - (residual_amount + amount),
+ 'depreciation_date': depreciation_date.strftime('%Y-%m-%d')}
+ depreciation_lin_obj.create(cr, uid, vals, context=context)
+ depreciation_date = datetime(year, month, day) + relativedelta(months=+asset.method_period)
+ day = depreciation_date.day
+ month = depreciation_date.month
+ year = depreciation_date.year
+
+ return True
+
+ def validate(self, cr, uid, ids, context = None):
+ if context is None:
+ context = {}
+ return self.write(cr, uid, ids, {'state': 'open'}, context)
+
+ def set_to_close(self, cr, uid, ids, context = None):
+ return self.write(cr, uid, ids, {'state': 'close'}, context=context)
+
+ def set_to_draft(self, cr, uid, ids, context = None):
+ return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
+
+ def _amount_residual(self, cr, uid, ids, name, args, context = None):
+ cr.execute('SELECT\n l.asset_id as id, SUM(abs(l.debit-l.credit)) AS amount\n FROM\n account_move_line l\n WHERE\n l.asset_id IN %s GROUP BY l.asset_id ', (tuple(ids),))
+ res = dict(cr.fetchall())
+ for asset in self.browse(cr, uid, ids, context):
+ res[asset.id] = asset.purchase_value - res.get(asset.id, 0.0) - asset.salvage_value
+
+ for id in ids:
+ res.setdefault(id, 0.0)
+
+ return res
+
+ def onchange_company_id(self, cr, uid, ids, company_id = False, context = None):
+ val = {}
+ if company_id:
+ company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
+ if company.currency_id.company_id and company.currency_id.company_id.id != company_id:
+ val['currency_id'] = False
+ else:
+ val['currency_id'] = company.currency_id.id
+ return {'value': val}
+
+ def onchange_purchase_salvage_value(self, cr, uid, ids, purchase_value, salvage_value, context = None):
+ val = {}
+ for asset in self.browse(cr, uid, ids, context=context):
+ if purchase_value:
+ val['value_residual'] = purchase_value - salvage_value
+ if salvage_value:
+ val['value_residual'] = purchase_value - salvage_value
+
+ return {'value': val}
+
+ _columns = {'account_move_line_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft': [('readonly', False)]}),
+ 'name': fields.char('Asset Name', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'code': fields.char('Reference', size=32, readonly=True, states={'draft': [('readonly', False)]}),
+ 'purchase_value': fields.float('Gross Value', required=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'note': fields.text('Note'),
+ 'category_id': fields.many2one('account.asset.category', 'Asset Category', required=True, change_default=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'parent_id': fields.many2one('account.asset.asset', 'Parent Asset', readonly=True, states={'draft': [('readonly', False)]}),
+ 'child_ids': fields.one2many('account.asset.asset', 'parent_id', 'Children Assets'),
+ 'purchase_date': fields.date('Purchase Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
+ 'state': fields.selection([('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')], 'Status', required=True, help="When an asset is created, the status is 'Draft'.\nIf the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\nYou can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status."),
+ 'active': fields.boolean('Active'),
+ 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True, states={'draft': [('readonly', False)]}),
+ 'method': fields.selection([('linear', 'Linear'), ('degressive', 'Degressive')], 'Computation Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, help='Choose the method to use to compute the amount of depreciation lines.\n * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n * Degressive: Calculated on basis of: Residual Value * Degressive Factor'),
+ 'method_number': fields.integer('Number of Depreciations', readonly=True, states={'draft': [('readonly', False)]}, help='The number of depreciations needed to depreciate your asset'),
+ 'method_period': fields.integer('Number of Months in a Period', required=True, readonly=True, states={'draft': [('readonly', False)]}, help='The amount of time between two depreciations, in months'),
+ 'method_end': fields.date('Ending Date', readonly=True, states={'draft': [('readonly', False)]}),
+ 'method_progress_factor': fields.float('Degressive Factor', readonly=True, states={'draft': [('readonly', False)]}),
+ 'value_residual': fields.function(_amount_residual, method=True, digits_compute=dp.get_precision('Account'), string='Residual Value'),
+ 'method_time': fields.selection([('number', 'Number of Depreciations'), ('end', 'Ending Date')], 'Time Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Choose the method to use to compute the dates and number of depreciation lines.\n * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
+ 'prorata': fields.boolean('Prorata Temporis', readonly=True, states={'draft': [('readonly', False)]}, help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'),
+ 'history_ids': fields.one2many('account.asset.history', 'asset_id', 'History', readonly=True),
+ 'depreciation_line_ids': fields.one2many('account.asset.depreciation.line', 'asset_id', 'Depreciation Lines', readonly=True, states={'draft': [('readonly', False)],
+ 'open': [('readonly', False)]}),
+ 'salvage_value': fields.float('Salvage Value', digits_compute=dp.get_precision('Account'), help='It is the amount you plan to have that you cannot depreciate.', readonly=True, states={'draft': [('readonly', False)]})}
+ _defaults = {'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'account.asset.code'),
+ 'purchase_date': lambda obj, cr, uid, context: time.strftime('%Y-%m-%d'),
+ 'active': True,
+ 'state': 'draft',
+ 'method': 'linear',
+ 'method_number': 5,
+ 'method_time': 'number',
+ 'method_period': 12,
+ 'method_progress_factor': 0.3,
+ 'currency_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.currency_id.id,
+ 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'account.asset.asset', context=context)}
+
+ def _check_recursion(self, cr, uid, ids, context = None, parent = None):
+ return super(account_asset_asset, self)._check_recursion(cr, uid, ids, context=context, parent=parent)
+
+ def _check_prorata(self, cr, uid, ids, context = None):
+ for asset in self.browse(cr, uid, ids, context=context):
+ if asset.prorata and asset.method_time != 'number':
+ return False
+
+ return True
+
+ _constraints = [(_check_recursion, 'Error ! You cannot create recursive assets.', ['parent_id']), (_check_prorata, 'Prorata temporis can be applied only for time method "number of depreciations".', ['prorata'])]
+
+ def onchange_category_id(self, cr, uid, ids, category_id, context = None):
+ res = {'value': {}}
+ asset_categ_obj = self.pool.get('account.asset.category')
+ if category_id:
+ category_obj = asset_categ_obj.browse(cr, uid, category_id, context=context)
+ res['value'] = {'method': category_obj.method,
+ 'method_number': category_obj.method_number,
+ 'method_time': category_obj.method_time,
+ 'method_period': category_obj.method_period,
+ 'method_progress_factor': category_obj.method_progress_factor,
+ 'method_end': category_obj.method_end,
+ 'prorata': category_obj.prorata}
+ return res
+
+ def onchange_method_time(self, cr, uid, ids, method_time = 'number', context = None):
+ res = {'value': {}}
+ if method_time != 'number':
+ res['value'] = {'prorata': False}
+ return res
+
+ def copy(self, cr, uid, id, default = None, context = None):
+ if default is None:
+ default = {}
+ if context is None:
+ context = {}
+ default.update({'depreciation_line_ids': [],
+ 'state': 'draft'})
+ return super(account_asset_asset, self).copy(cr, uid, id, default, context=context)
+
+ def _compute_entries(self, cr, uid, ids, period_id, context = None):
+ result = []
+ period_obj = self.pool.get('account.period')
+ depreciation_obj = self.pool.get('account.asset.depreciation.line')
+ period = period_obj.browse(cr, uid, period_id, context=context)
+ depreciation_ids = depreciation_obj.search(cr, uid, [('asset_id', 'in', ids),
+ ('depreciation_date', '<=', period.date_stop),
+ ('depreciation_date', '>=', period.date_start),
+ ('move_check', '=', False)], context=context)
+ if context is None:
+ context = {}
+ context.update({'depreciation_date': period.date_stop})
+ return depreciation_obj.create_move(cr, uid, depreciation_ids, context=context)
+
+ def create(self, cr, uid, vals, context = None):
+ asset_id = super(account_asset_asset, self).create(cr, uid, vals, context=context)
+ self.compute_depreciation_board(cr, uid, [asset_id], context=context)
+ return asset_id
+
+ def open_entries(self, cr, uid, ids, context = None):
+ if context is None:
+ context = {}
+ context.update({'search_default_asset_id': ids,
+ 'default_asset_id': ids})
+ return {'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'account.move.line',
+ 'view_id': False,
+ 'type': 'ir.actions.act_window',
+ 'context': context}
+
+
+account_asset_asset()
+
+class account_asset_depreciation_line(osv.osv):
+ _name = 'account.asset.depreciation.line'
+ _description = 'Asset depreciation line'
+
+ def _get_move_check(self, cr, uid, ids, name, args, context = None):
+ res = {}
+ for line in self.browse(cr, uid, ids, context=context):
+ res[line.id] = bool(line.move_id)
+
+ return res
+
+ _columns = {'name': fields.char('Depreciation Name', size=64, required=True, select=1),
+ 'sequence': fields.integer('Sequence', required=True),
+ 'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True, ondelete='cascade'),
+ 'parent_state': fields.related('asset_id', 'state', type='char', string='State of Asset'),
+ 'amount': fields.float('Current Depreciation', digits_compute=dp.get_precision('Account'), required=True),
+ 'remaining_value': fields.float('Next Period Depreciation', digits_compute=dp.get_precision('Account'), required=True),
+ 'depreciated_value': fields.float('Amount Already Depreciated', required=True),
+ 'depreciation_date': fields.date('Depreciation Date', select=1),
+ 'move_id': fields.many2one('account.move', 'Depreciation Entry'),
+ 'move_check': fields.function(_get_move_check, method=True, type='boolean', string='Posted', store=True)}
+
+ def create_move(self, cr, uid, ids, context = None):
+ can_close = False
+ if context is None:
+ context = {}
+ asset_obj = self.pool.get('account.asset.asset')
+ period_obj = self.pool.get('account.period')
+ move_obj = self.pool.get('account.move')
+ move_line_obj = self.pool.get('account.move.line')
+ currency_obj = self.pool.get('res.currency')
+ created_move_ids = []
+ asset_ids = []
+ for line in self.browse(cr, uid, ids, context=context):
+ depreciation_date = context.get('depreciation_date') or time.strftime('%Y-%m-%d')
+ ctx = dict(context, account_period_prefer_normal=True)
+ period_ids = period_obj.find(cr, uid, depreciation_date, context=ctx)
+ company_currency = line.asset_id.company_id.currency_id.id
+ current_currency = line.asset_id.currency_id.id
+ context.update({'date': depreciation_date})
+ amount = currency_obj.compute(cr, uid, current_currency, company_currency, line.amount, context=context)
+ sign = line.asset_id.category_id.journal_id.type == 'purchase' and 1 or -1
+ asset_name = line.asset_id.name
+ reference = line.name
+ move_vals = {'name': asset_name,
+ 'date': depreciation_date,
+ 'ref': reference,
+ 'period_id': period_ids and period_ids[0] or False,
+ 'journal_id': line.asset_id.category_id.journal_id.id}
+ move_id = move_obj.create(cr, uid, move_vals, context=context)
+ journal_id = line.asset_id.category_id.journal_id.id
+ partner_id = line.asset_id.partner_id.id
+ move_line_obj.create(cr, uid, {'name': asset_name,
+ 'ref': reference,
+ 'move_id': move_id,
+ 'account_id': line.asset_id.category_id.account_depreciation_id.id,
+ 'debit': 0.0,
+ 'credit': amount,
+ 'period_id': period_ids and period_ids[0] or False,
+ 'journal_id': journal_id,
+ 'partner_id': partner_id,
+ 'currency_id': company_currency != current_currency and current_currency or False,
+ 'amount_currency': company_currency != current_currency and -sign * line.amount or 0.0,
+ 'date': depreciation_date})
+ move_line_obj.create(cr, uid, {'name': asset_name,
+ 'ref': reference,
+ 'move_id': move_id,
+ 'account_id': line.asset_id.category_id.account_expense_depreciation_id.id,
+ 'credit': 0.0,
+ 'debit': amount,
+ 'period_id': period_ids and period_ids[0] or False,
+ 'journal_id': journal_id,
+ 'partner_id': partner_id,
+ 'currency_id': company_currency != current_currency and current_currency or False,
+ 'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
+ 'analytic_account_id': line.asset_id.category_id.account_analytic_id.id,
+ 'date': depreciation_date,
+ 'asset_id': line.asset_id.id})
+ self.write(cr, uid, line.id, {'move_id': move_id}, context=context)
+ created_move_ids.append(move_id)
+ asset_ids.append(line.asset_id.id)
+
+ for asset in asset_obj.browse(cr, uid, list(set(asset_ids)), context=context):
+ if currency_obj.is_zero(cr, uid, asset.currency_id, asset.value_residual):
+ asset.write({'state': 'close'})
+
+ return created_move_ids
+
+
+account_asset_depreciation_line()
+
+class account_move_line(osv.osv):
+ _inherit = 'account.move.line'
+ _columns = {'asset_id': fields.many2one('account.asset.asset', 'Asset', ondelete='restrict'),
+ 'entry_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft': [('readonly', False)]})}
+
+
+account_move_line()
+
+class account_asset_history(osv.osv):
+ _name = 'account.asset.history'
+ _description = 'Asset history'
+ _columns = {'name': fields.char('History name', size=64, select=1),
+ 'user_id': fields.many2one('res.users', 'User', required=True),
+ 'date': fields.date('Date', required=True),
+ 'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True),
+ 'method_time': fields.selection([('number', 'Number of Depreciations'), ('end', 'Ending Date')], 'Time Method', required=True, help="The method to use to compute the dates and number of depreciation lines.\nNumber of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\nEnding Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
+ 'method_number': fields.integer('Number of Depreciations', help='The number of depreciations needed to depreciate your asset'),
+ 'method_period': fields.integer('Period Length', help='Time in month between two depreciations'),
+ 'method_end': fields.date('Ending date'),
+ 'note': fields.text('Note')}
+ _order = 'date desc'
+ _defaults = {'date': lambda *args: time.strftime('%Y-%m-%d'),
+ 'user_id': lambda self, cr, uid, ctx: uid}
+
+
+account_asset_history()
\ No newline at end of file
diff --git a/addons/account_asset/account_asset_demo.xml b/addons/account_asset/account_asset_demo.xml
index ec18c4a5df6a8..5b1a4b03be62a 100644
--- a/addons/account_asset/account_asset_demo.xml
+++ b/addons/account_asset/account_asset_demo.xml
@@ -41,7 +41,7 @@
open
-
+
CEO's Car
diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py
index 4b235c874c385..906e43fd04ede 100644
--- a/addons/account_asset/account_asset_invoice.py
+++ b/addons/account_asset/account_asset_invoice.py
@@ -1,71 +1,68 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-
-class account_invoice(osv.osv):
-
- _inherit = 'account.invoice'
- def action_number(self, cr, uid, ids, *args, **kargs):
- result = super(account_invoice, self).action_number(cr, uid, ids, *args, **kargs)
- for inv in self.browse(cr, uid, ids):
- self.pool.get('account.invoice.line').asset_create(cr, uid, inv.invoice_line)
- return result
-
- def line_get_convert(self, cr, uid, x, part, date, context=None):
- res = super(account_invoice, self).line_get_convert(cr, uid, x, part, date, context=context)
- res['asset_id'] = x.get('asset_id', False)
- return res
-
-account_invoice()
-
-class account_invoice_line(osv.osv):
-
- _inherit = 'account.invoice.line'
- _columns = {
- 'asset_category_id': fields.many2one('account.asset.category', 'Asset Category'),
- }
- def asset_create(self, cr, uid, lines, context=None):
- context = context or {}
- asset_obj = self.pool.get('account.asset.asset')
- for line in lines:
- if line.asset_category_id:
- vals = {
- 'name': line.name,
- 'code': line.invoice_id.number or False,
- 'category_id': line.asset_category_id.id,
- 'purchase_value': line.price_subtotal,
- 'period_id': line.invoice_id.period_id.id,
- 'partner_id': line.invoice_id.partner_id.id,
- 'company_id': line.invoice_id.company_id.id,
- 'currency_id': line.invoice_id.currency_id.id,
- 'purchase_date' : line.invoice_id.date_invoice,
- }
- changed_vals = asset_obj.onchange_category_id(cr, uid, [], vals['category_id'], context=context)
- vals.update(changed_vals['value'])
- asset_id = asset_obj.create(cr, uid, vals, context=context)
- if line.asset_category_id.open_asset:
- asset_obj.validate(cr, uid, [asset_id], context=context)
- return True
-
-account_invoice_line()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp.osv import fields, osv
+
+class account_invoice(osv.osv):
+ _inherit = 'account.invoice'
+
+ def action_number(self, cr, uid, ids, *args):
+ result = super(account_invoice, self).action_number(cr, uid, ids, *args)
+ for inv in self.browse(cr, uid, ids):
+ self.pool.get('account.invoice.line').asset_create(cr, uid, inv.invoice_line)
+
+ return result
+
+ def line_get_convert(self, cr, uid, x, part, date, context = None):
+ res = super(account_invoice, self).line_get_convert(cr, uid, x, part, date, context=context)
+ res['asset_id'] = x.get('asset_id', False)
+ return res
+
+
+account_invoice()
+
+class account_invoice_line(osv.osv):
+ _inherit = 'account.invoice.line'
+ _columns = {'asset_category_id': fields.many2one('account.asset.category', 'Asset Category')}
+
+ def asset_create(self, cr, uid, lines, context = None):
+ context = context or {}
+ asset_obj = self.pool.get('account.asset.asset')
+ for line in lines:
+ if line.asset_category_id:
+ vals = {'name': line.name,
+ 'code': line.invoice_id.number or False,
+ 'category_id': line.asset_category_id.id,
+ 'purchase_value': line.price_subtotal,
+ 'period_id': line.invoice_id.period_id.id,
+ 'partner_id': line.invoice_id.partner_id.id,
+ 'company_id': line.invoice_id.company_id.id,
+ 'currency_id': line.invoice_id.currency_id.id,
+ 'purchase_date': line.invoice_id.date_invoice}
+ changed_vals = asset_obj.onchange_category_id(cr, uid, [], vals['category_id'], context=context)
+ vals.update(changed_vals['value'])
+ asset_id = asset_obj.create(cr, uid, vals, context=context)
+ if line.asset_category_id.open_asset:
+ asset_obj.validate(cr, uid, [asset_id], context=context)
+
+ return True
+
+
+account_invoice_line()
\ No newline at end of file
diff --git a/addons/account_asset/report/account_asset_report.py b/addons/account_asset/report/account_asset_report.py
index 1554880ac38a2..f22c8712bc0b9 100644
--- a/addons/account_asset/report/account_asset_report.py
+++ b/addons/account_asset/report/account_asset_report.py
@@ -1,87 +1,48 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from openerp import tools
-from openerp.osv import fields, osv
-
-class asset_asset_report(osv.osv):
- _name = "asset.asset.report"
- _description = "Assets Analysis"
- _auto = False
- _columns = {
- 'name': fields.char('Year', size=16, required=False, readonly=True),
- 'purchase_date': fields.date('Purchase Date', readonly=True),
- 'depreciation_date': fields.date('Depreciation Date', readonly=True),
- 'asset_id': fields.many2one('account.asset.asset', string='Asset', readonly=True),
- 'asset_category_id': fields.many2one('account.asset.category',string='Asset category'),
- 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
- 'state': fields.selection([('draft','Draft'),('open','Running'),('close','Close')], 'Status', readonly=True),
- 'depreciation_value': fields.float('Amount of Depreciation Lines', readonly=True),
- 'move_check': fields.boolean('Posted', readonly=True),
- 'nbr': fields.integer('# of Depreciation Lines', readonly=True),
- 'gross_value': fields.float('Gross Amount', readonly=True),
- 'posted_value': fields.float('Posted Amount', readonly=True),
- 'unposted_value': fields.float('Unposted Amount', readonly=True),
- 'company_id': fields.many2one('res.company', 'Company', readonly=True),
- }
-
- def init(self, cr):
- tools.drop_view_if_exists(cr, 'asset_asset_report')
- cr.execute("""
- create or replace view asset_asset_report as (
- select
- min(dl.id) as id,
- dl.name as name,
- dl.depreciation_date as depreciation_date,
- a.purchase_date as purchase_date,
- (CASE WHEN (select min(d.id) from account_asset_depreciation_line as d
- left join account_asset_asset as ac ON (ac.id=d.asset_id)
- where a.id=ac.id) = min(dl.id)
- THEN a.purchase_value
- ELSE 0
- END) as gross_value,
- dl.amount as depreciation_value,
- (CASE WHEN dl.move_check
- THEN dl.amount
- ELSE 0
- END) as posted_value,
- (CASE WHEN NOT dl.move_check
- THEN dl.amount
- ELSE 0
- END) as unposted_value,
- dl.asset_id as asset_id,
- dl.move_check as move_check,
- a.category_id as asset_category_id,
- a.partner_id as partner_id,
- a.state as state,
- count(dl.*) as nbr,
- a.company_id as company_id
- from account_asset_depreciation_line dl
- left join account_asset_asset a on (dl.asset_id=a.id)
- group by
- dl.amount,dl.asset_id,dl.depreciation_date,dl.name,
- a.purchase_date, dl.move_check, a.state, a.category_id, a.partner_id, a.company_id,
- a.purchase_value, a.id, a.salvage_value
- )""")
-
-asset_asset_report()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from openerp import tools
+from openerp.osv import fields, osv
+
+class asset_asset_report(osv.osv):
+ _name = 'asset.asset.report'
+ _description = 'Assets Analysis'
+ _auto = False
+ _columns = {'name': fields.char('Year', size=16, required=False, readonly=True),
+ 'purchase_date': fields.date('Purchase Date', readonly=True),
+ 'depreciation_date': fields.date('Depreciation Date', readonly=True),
+ 'asset_id': fields.many2one('account.asset.asset', string='Asset', readonly=True),
+ 'asset_category_id': fields.many2one('account.asset.category', string='Asset category'),
+ 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
+ 'state': fields.selection([('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')], 'Status', readonly=True),
+ 'depreciation_value': fields.float('Amount of Depreciation Lines', readonly=True),
+ 'move_check': fields.boolean('Posted', readonly=True),
+ 'nbr': fields.integer('# of Depreciation Lines', readonly=True),
+ 'gross_value': fields.float('Gross Amount', readonly=True),
+ 'posted_value': fields.float('Posted Amount', readonly=True),
+ 'unposted_value': fields.float('Unposted Amount', readonly=True),
+ 'company_id': fields.many2one('res.company', 'Company', readonly=True)}
+
+ def init(self, cr):
+ tools.drop_view_if_exists(cr, 'asset_asset_report')
+ cr.execute('\n \t create or replace view asset_asset_report as (\n select \n min(dl.id) as id,\n dl.name as name,\n dl.depreciation_date as depreciation_date,\n a.purchase_date as purchase_date,\n (CASE WHEN (select min(d.id) from account_asset_depreciation_line as d\n left join account_asset_asset as ac ON (ac.id=d.asset_id)\n where a.id=ac.id) = min(dl.id)\n THEN a.purchase_value\n ELSE 0\n END) as gross_value,\n dl.amount as depreciation_value, \n (CASE WHEN dl.move_check\n THEN dl.amount\n ELSE 0\n END) as posted_value,\n (CASE WHEN NOT dl.move_check\n THEN dl.amount\n ELSE 0\n END) as unposted_value,\n dl.asset_id as asset_id,\n dl.move_check as move_check,\n a.category_id as asset_category_id,\n a.partner_id as partner_id,\n a.state as state,\n count(dl.*) as nbr,\n a.company_id as company_id\n from account_asset_depreciation_line dl\n left join account_asset_asset a on (dl.asset_id=a.id)\n group by \n dl.amount,dl.asset_id,dl.depreciation_date,dl.name,\n a.purchase_date, dl.move_check, a.state, a.category_id, a.partner_id, a.company_id,\n a.purchase_value, a.id, a.salvage_value\n )')
+
+
+asset_asset_report()
\ No newline at end of file
diff --git a/addons/account_asset/test/account_asset_demo.yml b/addons/account_asset/test/account_asset_demo.yml
index 56d4d7ce8ac8a..c0871d05268a6 100644
--- a/addons/account_asset/test/account_asset_demo.yml
+++ b/addons/account_asset/test/account_asset_demo.yml
@@ -6,46 +6,4 @@
category_id: account_asset_category_sale
-
!record {model: account.asset.asset, id: account_asset_asset_vehicles0}:
- method_number: 5
--
- !record {model: account.fiscalyear, id: data_fiscalyear_plus1}:
- company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year+1)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year+1)"
- name: !eval "'Fiscal Year X %s' %(datetime.now().year+1)"
- code: !eval "'FY%s' %(datetime.now().year+1)"
--
- !record {model: account.fiscalyear, id: data_fiscalyear_plus2}:
- company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year+2)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year+2)"
- name: !eval "'Fiscal Year X %s' %(datetime.now().year+2)"
- code: !eval "'FY%s' %(datetime.now().year+2)"
--
- !record {model: account.fiscalyear, id: data_fiscalyear_plus3}:
- company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year+3)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year+3)"
- name: !eval "'Fiscal Year X %s' %(datetime.now().year+3)"
- code: !eval "'FY%s' %(datetime.now().year+3)"
--
- !record {model: account.fiscalyear, id: data_fiscalyear_plus4}:
- company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year+4)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year+4)"
- name: !eval "'Fiscal Year X %s' %(datetime.now().year+4)"
- code: !eval "'FY%s' %(datetime.now().year+4)"
--
- !record {model: account.fiscalyear, id: data_fiscalyear_plus5}:
- company_id: base.main_company
- date_start: !eval "'%s-01-01' %(datetime.now().year+5)"
- date_stop: !eval "'%s-12-31' %(datetime.now().year+5)"
- name: !eval "'Fiscal Year X %s' %(datetime.now().year+5)"
- code: !eval "'FY%s' %(datetime.now().year+5)"
--
- !python {model: account.fiscalyear}: |
- self.create_period(cr, uid, [ref("data_fiscalyear_plus1")])
- self.create_period(cr, uid, [ref("data_fiscalyear_plus2")])
- self.create_period(cr, uid, [ref("data_fiscalyear_plus3")])
- self.create_period(cr, uid, [ref("data_fiscalyear_plus4")])
- self.create_period(cr, uid, [ref("data_fiscalyear_plus5")])
+ method_number: 10
diff --git a/addons/account_asset/wizard/account_asset_change_duration.py b/addons/account_asset/wizard/account_asset_change_duration.py
index 7b256e4739146..4187203367590 100644
--- a/addons/account_asset/wizard/account_asset_change_duration.py
+++ b/addons/account_asset/wizard/account_asset_change_duration.py
@@ -1,113 +1,123 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-import time
-from lxml import etree
-
-from openerp.osv import fields, osv
-
-class asset_modify(osv.osv_memory):
- _name = 'asset.modify'
- _description = 'Modify Asset'
-
- def _get_asset_method_time(self, cr, uid, ids, field_name, arg, context=None):
- if ids and len(ids) == 1 and context.get('active_id'):
- asset = self.pool['account.asset.asset'].browse(cr, uid, context.get('active_id'), context=context)
- return {ids[0]: asset.method_time}
- else:
- return dict.fromkeys(ids, False)
-
- _columns = {
- 'name': fields.char('Reason', size=64, required=True),
- 'method_number': fields.integer('Number of Depreciations', required=True),
- 'method_period': fields.integer('Period Length'),
- 'method_end': fields.date('Ending date'),
- 'note': fields.text('Notes'),
- 'asset_method_time': fields.function(_get_asset_method_time, type='char', string='Asset Method Time', readonly=True),
- }
-
- def default_get(self, cr, uid, fields, context=None):
- """ To get default values for the object.
- @param self: The object pointer.
- @param cr: A database cursor
- @param uid: ID of the user currently logged in
- @param fields: List of fields for which we want default values
- @param context: A standard dictionary
- @return: A dictionary which of fields with values.
- """
- if not context:
- context = {}
- asset_obj = self.pool.get('account.asset.asset')
- res = super(asset_modify, self).default_get(cr, uid, fields, context=context)
- asset_id = context.get('active_id', False)
- asset = asset_obj.browse(cr, uid, asset_id, context=context)
- if 'name' in fields:
- res.update({'name': asset.name})
- if 'method_number' in fields and asset.method_time == 'number':
- res.update({'method_number': asset.method_number})
- if 'method_period' in fields:
- res.update({'method_period': asset.method_period})
- if 'method_end' in fields and asset.method_time == 'end':
- res.update({'method_end': asset.method_end})
- if context.get('active_id'):
- res['asset_method_time'] = self._get_asset_method_time(cr, uid, [0], 'asset_method_time', [], context=context)[0]
- return res
-
- def modify(self, cr, uid, ids, context=None):
- """ Modifies the duration of asset for calculating depreciation
- and maintains the history of old values.
- @param self: The object pointer.
- @param cr: A database cursor
- @param uid: ID of the user currently logged in
- @param ids: List of Ids
- @param context: A standard dictionary
- @return: Close the wizard.
- """
- if not context:
- context = {}
- asset_obj = self.pool.get('account.asset.asset')
- history_obj = self.pool.get('account.asset.history')
- asset_id = context.get('active_id', False)
- asset = asset_obj.browse(cr, uid, asset_id, context=context)
- data = self.browse(cr, uid, ids[0], context=context)
- history_vals = {
- 'asset_id': asset_id,
- 'name': data.name,
- 'method_time': asset.method_time,
- 'method_number': asset.method_number,
- 'method_period': asset.method_period,
- 'method_end': asset.method_end,
- 'user_id': uid,
- 'date': time.strftime('%Y-%m-%d'),
- 'note': data.note,
- }
- history_obj.create(cr, uid, history_vals, context=context)
- asset_vals = {
- 'method_number': data.method_number,
- 'method_period': data.method_period,
- 'method_end': data.method_end,
- }
- asset_obj.write(cr, uid, [asset_id], asset_vals, context=context)
- asset_obj.compute_depreciation_board(cr, uid, [asset_id], context=context)
- return {'type': 'ir.actions.act_window_close'}
-
-asset_modify()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import time
+from lxml import etree
+from openerp.osv import fields, osv
+
+class asset_modify(osv.osv_memory):
+ _name = 'asset.modify'
+ _description = 'Modify Asset'
+ _columns = {'name': fields.char('Reason', size=64, required=True),
+ 'method_number': fields.integer('Number of Depreciations', required=True),
+ 'method_period': fields.integer('Period Length'),
+ 'method_end': fields.date('Ending date'),
+ 'note': fields.text('Notes')}
+
+ def fields_view_get(self, cr, uid, view_id = None, view_type = 'form', context = None, toolbar = False, submenu = False):
+ """ Returns views and fields for current model.
+ @param cr: A database cursor
+ @param user: ID of the user currently logged in
+ @param view_id: list of fields, which required to read signatures
+ @param view_type: defines a view type. it can be one of (form, tree, graph, calender, gantt, search, mdx)
+ @param context: context arguments, like lang, time zone
+ @param toolbar: contains a list of reports, wizards, and links related to current model
+
+ @return: Returns a dictionary that contains definition for fields, views, and toolbars
+ """
+ if not context:
+ context = {}
+ asset_obj = self.pool.get('account.asset.asset')
+ result = super(asset_modify, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
+ asset_id = context.get('active_id', False)
+ active_model = context.get('active_model', '')
+ if active_model == 'account.asset.asset' and asset_id:
+ asset = asset_obj.browse(cr, uid, asset_id, context=context)
+ doc = etree.XML(result['arch'])
+ if asset.method_time == 'number':
+ node = doc.xpath("//field[@name='method_end']")[0]
+ node.set('invisible', '1')
+ elif asset.method_time == 'end':
+ node = doc.xpath("//field[@name='method_number']")[0]
+ node.set('invisible', '1')
+ result['arch'] = etree.tostring(doc)
+ return result
+
+ def default_get(self, cr, uid, fields, context = None):
+ """ To get default values for the object.
+ @param self: The object pointer.
+ @param cr: A database cursor
+ @param uid: ID of the user currently logged in
+ @param fields: List of fields for which we want default values
+ @param context: A standard dictionary
+ @return: A dictionary which of fields with values.
+ """
+ if not context:
+ context = {}
+ asset_obj = self.pool.get('account.asset.asset')
+ res = super(asset_modify, self).default_get(cr, uid, fields, context=context)
+ asset_id = context.get('active_id', False)
+ asset = asset_obj.browse(cr, uid, asset_id, context=context)
+ if 'name' in fields:
+ res.update({'name': asset.name})
+ if 'method_number' in fields and asset.method_time == 'number':
+ res.update({'method_number': asset.method_number})
+ if 'method_period' in fields:
+ res.update({'method_period': asset.method_period})
+ if 'method_end' in fields and asset.method_time == 'end':
+ res.update({'method_end': asset.method_end})
+ return res
+
+ def modify(self, cr, uid, ids, context = None):
+ """ Modifies the duration of asset for calculating depreciation
+ and maintains the history of old values.
+ @param self: The object pointer.
+ @param cr: A database cursor
+ @param uid: ID of the user currently logged in
+ @param ids: List of Ids
+ @param context: A standard dictionary
+ @return: Close the wizard.
+ """
+ if not context:
+ context = {}
+ asset_obj = self.pool.get('account.asset.asset')
+ history_obj = self.pool.get('account.asset.history')
+ asset_id = context.get('active_id', False)
+ asset = asset_obj.browse(cr, uid, asset_id, context=context)
+ data = self.browse(cr, uid, ids[0], context=context)
+ history_vals = {'asset_id': asset_id,
+ 'name': data.name,
+ 'method_time': asset.method_time,
+ 'method_number': asset.method_number,
+ 'method_period': asset.method_period,
+ 'method_end': asset.method_end,
+ 'user_id': uid,
+ 'date': time.strftime('%Y-%m-%d'),
+ 'note': data.note}
+ history_obj.create(cr, uid, history_vals, context=context)
+ asset_vals = {'method_number': data.method_number,
+ 'method_period': data.method_period,
+ 'method_end': data.method_end}
+ asset_obj.write(cr, uid, [asset_id], asset_vals, context=context)
+ asset_obj.compute_depreciation_board(cr, uid, [asset_id], context=context)
+ return {'type': 'ir.actions.act_window_close'}
+
+
+asset_modify()
\ No newline at end of file
diff --git a/addons/account_asset/wizard/account_asset_change_duration_view.xml b/addons/account_asset/wizard/account_asset_change_duration_view.xml
index e7dd7e134fd3a..bb848e6db5d5a 100644
--- a/addons/account_asset/wizard/account_asset_change_duration_view.xml
+++ b/addons/account_asset/wizard/account_asset_change_duration_view.xml
@@ -7,14 +7,13 @@
asset.modify
| |