diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py
index e1b9078ec3f..ebbd5459cea 100644
--- a/addons/account/__openerp__.py
+++ b/addons/account/__openerp__.py
@@ -19,11 +19,11 @@
#
##############################################################################
{
- "name" : "eInvoicing",
- "version" : "1.1",
- "author" : "OpenERP SA",
- "category": 'Accounting & Finance',
- "description": """
+ 'name' : 'eInvoicing',
+ 'version' : '1.1',
+ 'author' : 'OpenERP SA',
+ 'category' : 'Accounting & Finance',
+ 'description' : """
Accounting and Financial Management.
====================================
@@ -44,14 +44,13 @@ Creates a dashboard for accountants that includes:
* Company Analysis
* Graph of Treasury
-The processes like maintaining of general ledger is done through the defined financial Journals (entry move line orgrouping is maintained through journal) for a particular
-financial year and for preparation of vouchers there is a module named account_voucher.
+The processes like maintaining of general ledger is done through the defined financial Journals (entry move line orgrouping is maintained through journal)
+for a particular financial year and for preparation of vouchers there is a module named account_voucher.
""",
'website': 'http://www.openerp.com',
'images' : ['images/accounts.jpeg','images/bank_statement.jpeg','images/cash_register.jpeg','images/chart_of_accounts.jpeg','images/customer_invoice.jpeg','images/journal_entries.jpeg'],
- 'init_xml': [],
- "depends" : ["base_setup", "product", "analytic", "process", "board", "edi"],
- 'update_xml': [
+ 'depends' : ['base_setup', 'product', 'analytic', 'process', 'board', 'edi'],
+ 'data': [
'security/account_security.xml',
'security/ir.model.access.csv',
'account_menuitem.xml',
@@ -64,6 +63,8 @@ financial year and for preparation of vouchers there is a module named account_v
'wizard/account_use_model_view.xml',
'account_installer.xml',
'wizard/account_period_close_view.xml',
+ 'wizard/account_reconcile_view.xml',
+ 'wizard/account_unreconcile_view.xml',
'account_view.xml',
'account_report.xml',
'account_financial_report_data.xml',
@@ -86,14 +87,12 @@ financial year and for preparation of vouchers there is a module named account_v
'wizard/account_journal_select_view.xml',
'wizard/account_change_currency_view.xml',
'wizard/account_validate_move_view.xml',
- 'wizard/account_unreconcile_view.xml',
'wizard/account_report_general_ledger_view.xml',
'wizard/account_invoice_state_view.xml',
'wizard/account_report_partner_balance_view.xml',
'wizard/account_report_account_balance_view.xml',
'wizard/account_report_aged_partner_balance_view.xml',
'wizard/account_report_partner_ledger_view.xml',
- 'wizard/account_reconcile_view.xml',
'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml',
'wizard/account_financial_report_view.xml',
@@ -122,12 +121,20 @@ financial year and for preparation of vouchers there is a module named account_v
'ir_sequence_view.xml',
'company_view.xml',
'board_account_view.xml',
- "edi/invoice_action_data.xml",
- "account_bank_view.xml",
- "res_config_view.xml",
- "account_pre_install.yml"
+ 'edi/invoice_action_data.xml',
+ 'account_bank_view.xml',
+ 'res_config_view.xml',
+ 'account_pre_install.yml'
],
- 'demo_xml': [
+ 'js': [
+ 'static/src/js/account_move_reconciliation.js',
+ ],
+ 'qweb' : [
+ "static/src/xml/account_move_reconciliation.xml",
+ ],
+ 'css':['static/src/css/account_move_reconciliation.css'
+ ],
+ 'demo': [
'demo/account_demo.xml',
'project/project_demo.xml',
'project/analytic_account_demo.xml',
diff --git a/addons/account/account.py b/addons/account/account.py
index fa30b20f2ca..c2e6f3d1221 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -30,6 +30,8 @@ from osv import fields, osv
import decimal_precision as dp
from tools.translate import _
from tools.float_utils import float_round
+from openerp import SUPERUSER_ID
+
_logger = logging.getLogger(__name__)
@@ -109,7 +111,7 @@ class account_payment_term_line(osv.osv):
'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \
"If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."),
'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."),
- 'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True),
+ 'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True, ondelete='cascade'),
}
_defaults = {
'value': 'balance',
@@ -179,7 +181,7 @@ class account_account_type(osv.osv):
'Balance' will generally be used for cash accounts.
'Detail' will copy each existing journal item of the previous year, even the reconciled ones.
'Unreconciled' will copy only the journal items that were unreconciled on the first day of the new fiscal year."""),
- 'report_type': fields.function(_get_current_report_type, fnct_inv=_save_report_type, type='selection', string='P&L / BS Category',
+ 'report_type': fields.function(_get_current_report_type, fnct_inv=_save_report_type, type='selection', string='P&L / BS Category', store=True,
selection= [('none','/'),
('income', _('Profit & Loss (Income account)')),
('expense', _('Profit & Loss (Expense account)')),
@@ -582,6 +584,8 @@ class account_account(osv.osv):
def name_get(self, cr, uid, ids, context=None):
if not ids:
return []
+ if isinstance(ids, (int, long)):
+ ids = [ids]
reads = self.read(cr, uid, ids, ['name', 'code'], context=context)
res = []
for record in reads:
@@ -597,7 +601,7 @@ class account_account(osv.osv):
if not default:
default = {}
default = default.copy()
- default['code'] = (account['code'] or '') + '(copy)'
+ default.update(code=_("%s (copy)") % (account['code'] or ''))
if not local:
done_list = []
if account.id in done_list:
@@ -744,9 +748,11 @@ class account_journal(osv.osv):
'profit_account_id' : fields.many2one('account.account', 'Profit Account'),
'loss_account_id' : fields.many2one('account.account', 'Loss Account'),
'internal_account_id' : fields.many2one('account.account', 'Internal Transfers Account', select=1),
+ 'cash_control' : fields.boolean('Cash Control', help='If you want the journal should be control at opening/closing, check this option'),
}
_defaults = {
+ 'cash_control' : False,
'with_last_closing_balance' : False,
'user_id': lambda self, cr, uid, context: uid,
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
@@ -776,9 +782,10 @@ class account_journal(osv.osv):
if not default:
default = {}
default = default.copy()
- default['code'] = (journal['code'] or '') + '(copy)'
- default['name'] = (journal['name'] or '') + '(copy)'
- default['sequence_id'] = False
+ default.update(
+ code=_("%s (copy)") % (journal['code'] or ''),
+ name=_("%s (copy)") % (journal['name'] or ''),
+ sequence_id=False)
return super(account_journal, self).copy(cr, uid, id, default, context=context)
def write(self, cr, uid, ids, vals, context=None):
@@ -815,7 +822,7 @@ class account_journal(osv.osv):
if not 'sequence_id' in vals or not vals['sequence_id']:
# if we have the right to create a journal, we should be able to
# create it's sequence.
- vals.update({'sequence_id': self.create_sequence(cr, 1, vals, context)})
+ vals.update({'sequence_id': self.create_sequence(cr, SUPERUSER_ID, vals, context)})
return super(account_journal, self).create(cr, uid, vals, context)
def name_get(self, cr, user, ids, context=None):
@@ -830,6 +837,10 @@ class account_journal(osv.osv):
@return: Returns a list of tupples containing id, name
"""
+ if not ids:
+ return []
+ if isinstance(ids, (int, long)):
+ ids = [ids]
result = self.browse(cr, user, ids, context=context)
res = []
for rs in result:
@@ -1369,7 +1380,7 @@ class account_move(osv.osv):
balance = 0.0
for line in line_ids:
if line[2]:
- balance += (line[2]['debit'] or 0.00)- (line[2]['credit'] or 0.00)
+ balance += (line[2].get('debit',0.00)- (line[2].get('credit',0.00)))
return {'value': {'balance': balance}}
def write(self, cr, uid, ids, vals, context=None):
@@ -1392,7 +1403,7 @@ class account_move(osv.osv):
if not l[0]:
l[2].update({
'reconcile_id':False,
- 'reconcil_partial_id':False,
+ 'reconcile_partial_id':False,
'analytic_lines':False,
'invoice':False,
'ref':False,
@@ -1854,7 +1865,7 @@ class account_tax(osv.osv):
def get_precision_tax():
def change_digit_tax(cr):
- res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, 'Account')
+ res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, 'Account')
return (16, res+2)
return change_digit_tax
@@ -2332,6 +2343,16 @@ class account_model(osv.osv):
return move_ids
+ def onchange_journal_id(self, cr, uid, ids, journal_id, context=None):
+ company_id = False
+
+ if journal_id:
+ journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
+ if journal.company_id.id:
+ company_id = journal.company_id.id
+
+ return {'value': {'company_id': company_id}}
+
account_model()
class account_model_line(osv.osv):
@@ -2510,22 +2531,25 @@ class account_account_template(osv.osv):
'nocreate': False,
}
- def _check_type(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- accounts = self.browse(cr, uid, ids, context=context)
- for account in accounts:
- if account.parent_id and account.parent_id.type != 'view':
- return False
- return True
-
_check_recursion = check_cycle
_constraints = [
(_check_recursion, 'Error!\nYou cannot create recursive account templates.', ['parent_id']),
- (_check_type, 'Configuration Error!\nYou cannot define children to an account that has internal type other than "View".', ['type']),
-
]
+ def create(self, cr, uid, vals, context=None):
+ if 'parent_id' in vals:
+ parent = self.read(cr, uid, [vals['parent_id']], ['type'])
+ if parent and parent[0]['type'] != 'view':
+ raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'."))
+ return super(account_account_template, self).create(cr, uid, vals, context=context)
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if 'parent_id' in vals:
+ parent = self.read(cr, uid, [vals['parent_id']], ['type'])
+ if parent and parent[0]['type'] != 'view':
+ raise osv.except_osv(_('Warning!'), _("You may only select a parent account of type 'View'."))
+ return super(account_account_template, self).write(cr, uid, ids, vals, context=context)
+
def name_get(self, cr, uid, ids, context=None):
if not ids:
return []
@@ -2993,6 +3017,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
_columns = {
'company_id':fields.many2one('res.company', 'Company', required=True),
+ 'currency_id': fields.many2one('res.currency', 'Currency', help="Currency as per company's country."),
'only_one_chart_template': fields.boolean('Only One Chart Template Available'),
'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True),
'bank_accounts_id': fields.one2many('account.bank.accounts.wizard', 'bank_account_id', 'Cash and Banks', required=True),
@@ -3003,6 +3028,13 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'purchase_tax_rate': fields.float('Purchase Tax(%)'),
'complete_tax_set': fields.boolean('Complete Set of Taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'),
}
+
+ def onchange_company_id(self, cr, uid, ids, company_id, context=None):
+ currency_id = False
+ if company_id:
+ currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id
+ return {'value': {'currency_id': currency_id}}
+
def onchange_tax_rate(self, cr, uid, ids, rate=False, context=None):
return {'value': {'purchase_tax_rate': rate or False}}
@@ -3033,6 +3065,13 @@ class wizard_multi_charts_accounts(osv.osv_memory):
res.update({'bank_accounts_id': [{'acc_name': _('Cash'), 'account_type': 'cash'},{'acc_name': _('Bank'), 'account_type': 'bank'}]})
if 'company_id' in fields:
res.update({'company_id': self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0].company_id.id})
+ if 'currency_id' in fields:
+ company_id = res.get('company_id') or False
+ if company_id:
+ company_obj = self.pool.get('res.company')
+ country_id = company_obj.browse(cr, uid, company_id, context=context).country_id.id
+ currency_id = company_obj.on_change_country(cr, uid, company_id, country_id, context=context)['value']['currency_id']
+ res.update({'currency_id': currency_id})
ids = self.pool.get('account.chart.template').search(cr, uid, [('visible', '=', True)], context=context)
if ids:
@@ -3337,19 +3376,18 @@ class wizard_multi_charts_accounts(osv.osv_memory):
ir_values_obj = self.pool.get('ir.values')
obj_wizard = self.browse(cr, uid, ids[0])
company_id = obj_wizard.company_id.id
+ self.pool.get('res.company').write(cr, uid, [company_id], {'currency_id': obj_wizard.currency_id.id})
# If the floats for sale/purchase rates have been filled, create templates from them
self._create_tax_templates_from_rates(cr, uid, obj_wizard, company_id, context=context)
# Install all the templates objects and generate the real objects
acc_template_ref, taxes_ref, tax_code_ref = self._install_template(cr, uid, obj_wizard.chart_template_id.id, company_id, code_digits=obj_wizard.code_digits, obj_wizard=obj_wizard, context=context)
- # write values of default taxes for product
+ # write values of default taxes for product as super user
if obj_wizard.sale_tax and taxes_ref:
- ir_values_obj.set(cr, uid, key='default', key2=False, name="taxes_id", company=company_id,
- models =[('product.product',False)], value=[taxes_ref[obj_wizard.sale_tax.id]])
+ ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "taxes_id", [taxes_ref[obj_wizard.sale_tax.id]], for_all_users=True, company_id=company_id)
if obj_wizard.purchase_tax and taxes_ref:
- ir_values_obj.set(cr, uid, key='default', key2=False, name="supplier_taxes_id", company=company_id,
- models =[('product.product',False)], value=[taxes_ref[obj_wizard.purchase_tax.id]])
+ ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "supplier_taxes_id", [taxes_ref[obj_wizard.purchase_tax.id]], for_all_users=True, company_id=company_id)
# Create Bank journals
self._create_bank_journals_from_o2m(cr, uid, obj_wizard, company_id, acc_template_ref, context=context)
diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py
index ef146128a67..e44d2acd163 100644
--- a/addons/account/account_bank.py
+++ b/addons/account/account_bank.py
@@ -43,11 +43,15 @@ class bank(osv.osv):
"Return the name to use when creating a bank journal"
return (bank.bank_name or '') + ' ' + bank.acc_number
- def _prepare_name_get(self, cr, uid, bank_type_obj, bank_obj, context=None):
- """Add ability to have %(currency_name)s in the format_layout of
- res.partner.bank.type"""
- bank_obj._data[bank_obj.id]['currency_name'] = bank_obj.currency_id and bank_obj.currency_id.name or ''
- return super(bank, self)._prepare_name_get(cr, uid, bank_type_obj, bank_obj, context=context)
+ def _prepare_name_get(self, cr, uid, bank_dicts, context=None):
+ """Add ability to have %(currency_name)s in the format_layout of res.partner.bank.type"""
+ currency_ids = list(set(data['currency_id'][0] for data in bank_dicts if data['currency_id']))
+ currencies = self.pool.get('res.currency').browse(cr, uid, currency_ids, context=context)
+ currency_name = dict((currency.id, currency.name) for currency in currencies)
+
+ for data in bank_dicts:
+ data['currency_name'] = data['currency_id'] and currency_name[data['currency_id'][0]] or ''
+ return super(bank, self)._prepare_name_get(cr, uid, bank_dicts, context=context)
def post_write(self, cr, uid, ids, context={}):
if isinstance(ids, (int, long)):
diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py
index 8df291a98d1..9889eadf387 100644
--- a/addons/account/account_bank_statement.py
+++ b/addons/account/account_bank_statement.py
@@ -304,7 +304,7 @@ class account_bank_statement(osv.osv):
'date': st_line.date,
'ref': st_line.ref,
'move_id': move_id,
- 'partner_id': partner_id,
+ 'partner_id': par_id,
'account_id': acc_id,
'credit': credit,
'debit': debit,
@@ -430,7 +430,7 @@ class account_bank_statement(osv.osv):
'name': st_number,
'balance_end_real': st.balance_end
}, context=context)
- self.message_append_note(cr, uid, [st.id], body=_('Statement %s is confirmed, journal items are created.') % (st_number,), context=context)
+ self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st_number,), context=context)
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
def button_cancel(self, cr, uid, ids, context=None):
@@ -447,11 +447,13 @@ class account_bank_statement(osv.osv):
return self.write(cr, uid, done, {'state':'draft'}, context=context)
def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
- cr.execute('SELECT balance_end_real \
- FROM account_bank_statement \
- WHERE journal_id = %s AND NOT state = %s \
- ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
- res = cr.fetchone()
+ res = False
+ if journal_id:
+ cr.execute('SELECT balance_end_real \
+ FROM account_bank_statement \
+ WHERE journal_id = %s AND NOT state = %s \
+ ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
+ res = cr.fetchone()
return res and res[0] or 0.0
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
diff --git a/addons/account/account_bank_view.xml b/addons/account/account_bank_view.xml
index 8ceb8a91885..ef793a1bef5 100644
--- a/addons/account/account_bank_view.xml
+++ b/addons/account/account_bank_view.xml
@@ -15,7 +15,7 @@
-
+
@@ -28,7 +28,7 @@
-
+
diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py
index 9af0dcf60f4..17fa05d5f24 100644
--- a/addons/account/account_cash_statement.py
+++ b/addons/account/account_cash_statement.py
@@ -194,12 +194,27 @@ class account_cash_statement(osv.osv):
journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
if journal and (journal.type == 'cash') and not vals.get('details_ids'):
vals['details_ids'] = []
+
+ last_pieces = None
+
+ if journal.with_last_closing_balance == True:
+ domain = [('journal_id', '=', journal.id),
+ ('state', '=', 'confirm')]
+ last_bank_statement_ids = self.search(cr, uid, domain, limit=1, order='create_date desc', context=context)
+ if last_bank_statement_ids:
+ last_bank_statement = self.browse(cr, uid, last_bank_statement_ids[0], context=context)
+
+ last_pieces = dict(
+ (line.pieces, line.number_closing) for line in last_bank_statement.details_ids
+ )
+
for value in journal.cashbox_line_ids:
nested_values = {
'number_closing' : 0,
- 'number_opening' : 0,
+ 'number_opening' : last_pieces.get(value.pieces, 0) if isinstance(last_pieces, dict) else 0,
'pieces' : value.pieces
}
+
vals['details_ids'].append([0, False, nested_values])
res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml
index c92d4eda602..58e824a6250 100644
--- a/addons/account/account_installer.xml
+++ b/addons/account/account_installer.xml
@@ -14,8 +14,12 @@
+
+ Select a configuration package to setup automatically your
+ taxes and chart of accounts.
+
-
+
@@ -32,7 +36,7 @@
- Configure your Chart of Accounts
+ Configure Accounting Datair.actions.act_windowaccount.installer
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index 012bde42eff..aff38d71cfe 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -214,7 +214,7 @@ class account_invoice(osv.osv):
\n* The \'Cancelled\' state is used when user cancel invoice.'),
'sent': fields.boolean('Sent', readonly=True, help="It indicates that the invoice has been sent."),
'date_invoice': fields.date('Invoice Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="Keep empty to use the current date"),
- 'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True,
+ 'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}, select=True,
help="If you use payment terms, the due date will be computed automatically at the generation "\
"of accounting entries. If you keep the payment term and the due date empty, it means direct payment. The payment term may compute several due dates, for example 50% now, 50% in one month."),
'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}),
@@ -253,7 +253,7 @@ class account_invoice(osv.osv):
'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'journal_id': fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'company_id': fields.many2one('res.company', 'Company', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'check_total': fields.float('Verification Total', digits_compute=dp.get_precision('Account'), states={'open':[('readonly',True)],'close':[('readonly',True)]}),
+ 'check_total': fields.float('Verification Total', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}),
'reconciled': fields.function(_reconciled, string='Paid/Reconciled', type='boolean',
store={
'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
@@ -395,18 +395,23 @@ class account_invoice(osv.osv):
template_id = template and template[1] or False
res = mod_obj.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')
res_id = res and res[1] or False
- ctx = dict(context, active_model='account.invoice', active_id=ids[0])
- ctx.update({'mail.compose.template_id': template_id})
+ ctx = dict(context)
+ ctx.update({
+ 'default_model': 'account.invoice',
+ 'default_res_id': ids[0],
+ 'default_use_template': True,
+ 'default_template_id': template_id,
+ })
return {
- 'view_type': 'form',
- 'view_mode': 'form',
- 'res_model': 'mail.compose.message',
- 'views': [(res_id, 'form')],
- 'view_id': res_id,
- 'type': 'ir.actions.act_window',
- 'target': 'new',
- 'context': ctx,
- 'nodestroy': True,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'mail.compose.message',
+ 'views': [(res_id, 'form')],
+ 'view_id': res_id,
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'context': ctx,
+ 'nodestroy': True,
}
def confirm_paid(self, cr, uid, ids, context=None):
@@ -767,17 +772,20 @@ class account_invoice(osv.osv):
if not key in tax_key:
raise osv.except_osv(_('Warning!'), _('Taxes are missing!\nClick on compute button.'))
- def compute_invoice_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines):
+ def compute_invoice_totals(self, cr, uid, inv, company_currency, ref, invoice_move_lines, context=None):
+ if context is None:
+ context={}
total = 0
total_currency = 0
cur_obj = self.pool.get('res.currency')
for i in invoice_move_lines:
if inv.currency_id.id != company_currency:
+ context.update({'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
i['currency_id'] = inv.currency_id.id
i['amount_currency'] = i['price']
i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id,
company_currency, i['price'],
- context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')})
+ context=context)
else:
i['amount_currency'] = False
i['currency_id'] = False
@@ -887,7 +895,7 @@ class account_invoice(osv.osv):
# create one move line for the total and possibly adjust the other lines amount
total = 0
total_currency = 0
- total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml)
+ total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml, context=ctx)
acc_id = inv.account_id.id
name = inv['name'] or '/'
@@ -1045,7 +1053,7 @@ class account_invoice(osv.osv):
if obj_inv.type in ('out_invoice', 'out_refund'):
ctx = self.get_log_context(cr, uid, context=ctx)
message = _("Invoice '%s' is validated.") % name
- self.message_append_note(cr, uid, [inv_id], body=message, context=context)
+ self.message_post(cr, uid, [inv_id], body=message, context=context)
return True
def action_cancel(self, cr, uid, ids, *args):
@@ -1095,10 +1103,10 @@ class account_invoice(osv.osv):
if not ids:
return []
types = {
- 'out_invoice': 'CI: ',
- 'in_invoice': 'SI: ',
- 'out_refund': 'OR: ',
- 'in_refund': 'SR: ',
+ 'out_invoice': 'Invoice ',
+ 'in_invoice': 'Sup. Invoice ',
+ 'out_refund': 'Refund ',
+ 'in_refund': 'Supplier Refund ',
}
return [(r['id'], (r['number']) or types[r['type']] + (r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
@@ -1127,7 +1135,7 @@ class account_invoice(osv.osv):
return map(lambda x: (0,0,x), lines)
def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None):
- invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id'])
+ invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id', 'company_id'])
obj_invoice_line = self.pool.get('account.invoice.line')
obj_invoice_tax = self.pool.get('account.invoice.tax')
obj_journal = self.pool.get('account.journal')
@@ -1175,7 +1183,7 @@ class account_invoice(osv.osv):
'name': description,
})
# take the id part of the tuple returned for many2one fields
- for field in ('partner_id',
+ for field in ('partner_id', 'company_id',
'account_id', 'currency_id', 'payment_term', 'journal_id'):
invoice[field] = invoice[field] and invoice[field][0]
# create the new invoice
@@ -1275,7 +1283,7 @@ class account_invoice(osv.osv):
# TODO: use currency's formatting function
msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining).") % \
(name, pay_amount, code, invoice.amount_total, code, total, code)
- self.message_append_note(cr, uid, [inv_id], body=msg, context=context)
+ self.message_post(cr, uid, [inv_id], body=msg, context=context)
self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context)
# Update the stored value (fields.function), so we write to trigger recompute
@@ -1288,24 +1296,25 @@ class account_invoice(osv.osv):
def _get_document_type(self, type):
type_dict = {
- 'out_invoice': 'Customer invoice',
- 'in_invoice': 'Supplier invoice',
- 'out_refund': 'Customer Refund',
- 'in_refund': 'Supplier Refund',
+ # Translation markers will have no effect at runtime, only used to properly flag export
+ 'out_invoice': _('Customer invoice'),
+ 'in_invoice': _('Supplier invoice'),
+ 'out_refund': _('Customer Refund'),
+ 'in_refund': _('Supplier Refund'),
}
return type_dict.get(type, 'Invoice')
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id],body=_("%s created.") % (self._get_document_type(obj.type)), context=context)
+ self.message_post(cr, uid, [obj.id], body=_("%s created.") % (_(self._get_document_type(obj.type))), context=context)
def confirm_paid_send_note(self, cr, uid, ids, context=None):
- for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id], body=_("%s paid.") % (self._get_document_type(obj.type)), context=context)
+ for obj in self.browse(cr, uid, ids, context=context):
+ self.message_post(cr, uid, [obj.id], body=_("%s paid.") % (_(self._get_document_type(obj.type))), context=context)
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id], body=_("%s cancelled.") % (self._get_document_type(obj.type)), context=context)
+ self.message_post(cr, uid, [obj.id], body=_("%s cancelled.") % (_(self._get_document_type(obj.type))), context=context)
account_invoice()
@@ -1361,10 +1370,16 @@ class account_invoice_line(osv.osv):
'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
}
+
+ def _default_account_id(self, cr, uid, ids, context=None):
+ prop = self.pool.get('ir.property').get(cr, uid, 'property_account_income_categ', 'product.category', context=context)
+ return prop and prop.id or False
+
_defaults = {
'quantity': 1,
'discount': 0.0,
'price_unit': _price_unit_default,
+ 'account_id': _default_account_id,
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
@@ -1473,10 +1488,11 @@ class account_invoice_line(osv.osv):
prod = self.pool.get('product.product').browse(cr, uid, product, context=context)
prod_uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context)
if prod.uom_id.category_id.id != prod_uom.category_id.id:
- warning = {
+ warning = {
'title': _('Warning!'),
'message': _('The selected unit of measure is not compatible with the unit of measure of the product.')
- }
+ }
+ res['value'].update({'uos_id': prod.uom_id.id})
return {'value': res['value'], 'warning': warning}
return res
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 143c5514141..1c4d83106ca 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -127,7 +127,7 @@
-
+
@@ -184,24 +184,30 @@
name="account_id" groups="account.group_account_user"/>
-
+
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
@@ -265,7 +271,7 @@
-
+
@@ -326,8 +332,8 @@
-
-
@@ -357,16 +361,6 @@
action="action_account_analytic_journal_tree"
id="account_analytic_journal_print" parent="account.next_id_40"/>
-
-
-
account.journal.form.1account.journal
diff --git a/addons/account/res_config.py b/addons/account/res_config.py
index 658f87962ff..ea903654a4e 100644
--- a/addons/account/res_config.py
+++ b/addons/account/res_config.py
@@ -43,18 +43,18 @@ class account_config_settings(osv.osv_memory):
string='Default company currency', help="Main currency of the company."),
'paypal_account': fields.related('company_id', 'paypal_account', type='char', size=128,
string='Paypal account', help="Paypal account (email) for receiving online payments (credit card, etc.) If you set a paypal account, the customer will be able to pay your invoices or quotations with a button \"Pay with Paypal\" in automated emails or through the OpenERP portal."),
- 'company_footer': fields.related('company_id', 'rml_footer2', type='char', size=250, readonly=True,
- string='Bank accounts on reports will display as followed', help="Bank accounts as printed in the footer of each customer document. This is for information purpose only, you should configure these bank accounts through the above button \"Configure Bank Accounts\"."),
+ 'company_footer': fields.related('company_id', 'rml_footer', type='text', readonly=True,
+ string='Bank accounts footer preview', help="Bank accounts as printed in the footer of each printed document"),
'has_chart_of_accounts': fields.boolean('Company has a chart of accounts'),
'chart_template_id': fields.many2one('account.chart.template', 'Template', domain="[('visible','=', True)]"),
'code_digits': fields.integer('# of Digits', help="No. of digits to use for account code"),
'tax_calculation_rounding_method': fields.related('company_id',
'tax_calculation_rounding_method', type='selection', selection=[
- ('round_per_line', 'Round per Line'),
- ('round_globally', 'Round Globally'),
+ ('round_per_line', 'Round per line'),
+ ('round_globally', 'Round globally'),
], string='Tax calculation rounding method',
- help="If you select 'Round per Line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round Globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
+ help="If you select 'Round per line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
'sale_tax': fields.many2one("account.tax.template", "Default sale tax"),
'purchase_tax': fields.many2one("account.tax.template", "Default purchase tax"),
'sale_tax_rate': fields.float('Sales tax (%)'),
@@ -72,40 +72,40 @@ class account_config_settings(osv.osv_memory):
'sale_refund_journal_id': fields.many2one('account.journal', 'Sale refund journal'),
'sale_refund_sequence_prefix': fields.related('sale_refund_journal_id', 'sequence_id', 'prefix', type='char', string='Credit note sequence'),
'sale_refund_sequence_next': fields.related('sale_refund_journal_id', 'sequence_id', 'number_next', type='integer', string='Next credit note number'),
- 'purchase_journal_id': fields.many2one('account.journal', 'Purchase Journal'),
+ 'purchase_journal_id': fields.many2one('account.journal', 'Purchase journal'),
'purchase_sequence_prefix': fields.related('purchase_journal_id', 'sequence_id', 'prefix', type='char', string='Supplier invoice sequence'),
'purchase_sequence_next': fields.related('purchase_journal_id', 'sequence_id', 'number_next', type='integer', string='Next supplier invoice number'),
'purchase_refund_journal_id': fields.many2one('account.journal', 'Purchase refund journal'),
'purchase_refund_sequence_prefix': fields.related('purchase_refund_journal_id', 'sequence_id', 'prefix', type='char', string='Supplier credit note sequence'),
'purchase_refund_sequence_next': fields.related('purchase_refund_journal_id', 'sequence_id', 'number_next', type='integer', string='Next supplier credit note number'),
- 'module_account_check_writing': fields.boolean('pay your suppliers by check',
+ 'module_account_check_writing': fields.boolean('Pay your suppliers by check',
help="""This allows you to check writing and printing.
This installs the module account_check_writing."""),
- 'module_account_accountant': fields.boolean('full accounting features: journals, legal statements, chart of accounts, etc.',
+ 'module_account_accountant': fields.boolean('Full accounting features: journals, legal statements, chart of accounts, etc.',
help="""If you do not check this box, you will be able to do invoicing & payments, but not accounting (Journal Items, Chart of Accounts, ...)"""),
- 'module_account_asset': fields.boolean('assets management',
+ 'module_account_asset': fields.boolean('Assets management',
help="""This allows you to manage the assets owned by a company or a person.
It keeps track of the depreciation occurred on those assets, and creates account move for those depreciation lines.
This installs the module account_asset. If you do not check this box, you will be able to do invoicing & payments,
but not accounting (Journal Items, Chart of Accounts, ...)"""),
- 'module_account_budget': fields.boolean('budget management',
+ 'module_account_budget': fields.boolean('Budget management',
help="""This allows accountants to manage analytic and crossovered budgets.
Once the master budgets and the budgets are defined,
the project managers can set the planned amount on each analytic account.
This installs the module account_budget."""),
- 'module_account_payment': fields.boolean('manage payment orders',
+ 'module_account_payment': fields.boolean('Manage payment orders',
help="""This allows you to create and manage your payment orders, with purposes to
* serve as base for an easy plug-in of various automated payment mechanisms, and
* provide a more efficient way to manage invoice payments.
This installs the module account_payment."""),
- 'module_account_voucher': fields.boolean('manage customer payments',
+ 'module_account_voucher': fields.boolean('Manage customer payments',
help="""This includes all the basic requirements of voucher entries for bank, cash, sales, purchase, expense, contra, etc.
This installs the module account_voucher."""),
- 'module_account_followup': fields.boolean('manage customer payment follow-ups',
+ 'module_account_followup': fields.boolean('Manage customer payment follow-ups',
help="""This allows to automate letters for unpaid invoices, with multi-level recalls.
This installs the module account_followup."""),
- 'group_proforma_invoices': fields.boolean('allow pro-forma invoices',
+ 'group_proforma_invoices': fields.boolean('Allow pro-forma invoices',
implied_group='account.group_proforma_invoices',
help="Allows you to put invoices in pro-forma state."),
'default_sale_tax': fields.many2one('account.tax', 'Default sale tax',
@@ -114,6 +114,9 @@ class account_config_settings(osv.osv_memory):
help="This purchase tax will be assigned by default on new products."),
'decimal_precision': fields.integer('Decimal precision on journal entries',
help="""As an example, a decimal precision of 2 will allow journal entries like: 9.99 EUR, whereas a decimal precision of 4 will allow journal entries like: 0.0231 EUR."""),
+ 'group_multi_currency': fields.boolean('Allow multi currencies',
+ implied_group='base.group_multi_currency',
+ help="Allows you multi currency environment"),
}
def _default_company(self, cr, uid, context=None):
@@ -145,42 +148,45 @@ class account_config_settings(osv.osv_memory):
def onchange_company_id(self, cr, uid, ids, company_id):
# update related fields
- company = self.pool.get('res.company').browse(cr, uid, company_id)
- has_chart_of_accounts = company_id not in self.pool.get('account.installer').get_unconfigured_cmp(cr, uid)
- fiscalyear_count = self.pool.get('account.fiscalyear').search_count(cr, uid,
- [('date_start', '<=', time.strftime('%Y-%m-%d')), ('date_stop', '>=', time.strftime('%Y-%m-%d')),
- ('company_id', '=', company_id)])
- values = {
- 'expects_chart_of_accounts': company.expects_chart_of_accounts,
- 'currency_id': company.currency_id.id,
- 'paypal_account': company.paypal_account,
- 'company_footer': company.rml_footer2,
- 'has_chart_of_accounts': has_chart_of_accounts,
- 'has_fiscal_year': bool(fiscalyear_count),
- 'chart_template_id': False,
- 'tax_calculation_rounding_method': company.tax_calculation_rounding_method,
- }
- # update journals and sequences
- for journal_type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'):
- for suffix in ('_journal_id', '_sequence_prefix', '_sequence_next'):
- values[journal_type + suffix] = False
- journal_obj = self.pool.get('account.journal')
- journal_ids = journal_obj.search(cr, uid, [('company_id', '=', company_id)])
- for journal in journal_obj.browse(cr, uid, journal_ids):
- if journal.type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'):
- values.update({
- journal.type + '_journal_id': journal.id,
- journal.type + '_sequence_prefix': journal.sequence_id.prefix,
- journal.type + '_sequence_next': journal.sequence_id.number_next,
- })
- # update taxes
- ir_values = self.pool.get('ir.values')
- taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id)
- supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id)
- values.update({
- 'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id,
- 'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id,
- })
+ values = {}
+ values['currency_id'] = False
+ if company_id:
+ company = self.pool.get('res.company').browse(cr, uid, company_id)
+ has_chart_of_accounts = company_id not in self.pool.get('account.installer').get_unconfigured_cmp(cr, uid)
+ fiscalyear_count = self.pool.get('account.fiscalyear').search_count(cr, uid,
+ [('date_start', '<=', time.strftime('%Y-%m-%d')), ('date_stop', '>=', time.strftime('%Y-%m-%d')),
+ ('company_id', '=', company_id)])
+ values = {
+ 'expects_chart_of_accounts': company.expects_chart_of_accounts,
+ 'currency_id': company.currency_id.id,
+ 'paypal_account': company.paypal_account,
+ 'company_footer': company.rml_footer,
+ 'has_chart_of_accounts': has_chart_of_accounts,
+ 'has_fiscal_year': bool(fiscalyear_count),
+ 'chart_template_id': False,
+ 'tax_calculation_rounding_method': company.tax_calculation_rounding_method,
+ }
+ # update journals and sequences
+ for journal_type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'):
+ for suffix in ('_journal_id', '_sequence_prefix', '_sequence_next'):
+ values[journal_type + suffix] = False
+ journal_obj = self.pool.get('account.journal')
+ journal_ids = journal_obj.search(cr, uid, [('company_id', '=', company_id)])
+ for journal in journal_obj.browse(cr, uid, journal_ids):
+ if journal.type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'):
+ values.update({
+ journal.type + '_journal_id': journal.id,
+ journal.type + '_sequence_prefix': journal.sequence_id.prefix,
+ journal.type + '_sequence_next': journal.sequence_id.number_next,
+ })
+ # update taxes
+ ir_values = self.pool.get('ir.values')
+ taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id)
+ supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id)
+ values.update({
+ 'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id,
+ 'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id,
+ })
return {'value': values}
def onchange_chart_template_id(self, cr, uid, ids, chart_template_id, context=None):
@@ -217,6 +223,16 @@ class account_config_settings(osv.osv_memory):
return {'value': {'date_stop': end_date.strftime('%Y-%m-%d')}}
return {}
+ def open_company_form(self, cr, uid, ids, context=None):
+ config = self.browse(cr, uid, ids[0], context)
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Configure your Company',
+ 'res_model': 'res.company',
+ 'res_id': config.company_id.id,
+ 'view_mode': 'form',
+ }
+
def set_default_taxes(self, cr, uid, ids, context=None):
""" set default sale and purchase taxes for products """
ir_values = self.pool.get('ir.values')
diff --git a/addons/account/res_config_view.xml b/addons/account/res_config_view.xml
index 79a65f70414..d7618fbff5a 100644
--- a/addons/account/res_config_view.xml
+++ b/addons/account/res_config_view.xml
@@ -121,6 +121,10 @@
+ Use contracts to follow tasks, issues, timesheets or invoicing based on
+ work done, expenses and/or sales orders. OpenERP will automatically manage
+ the alerts for the renewal of the contracts to the right salesperson.
+