merge from trunk

bzr revid: goran.kliska@slobodni-programi.hr-20121210111404-jcwlv3nsa16bu8zq
This commit is contained in:
Goran Kliska 2012-12-10 12:14:04 +01:00
commit afbb6ef717
9829 changed files with 2604434 additions and 1987861 deletions

View File

@ -19,10 +19,10 @@
# #
############################################################################## ##############################################################################
import partner
import account import account
import installer import installer
import project import project
import partner
import account_invoice import account_invoice
import account_bank_statement import account_bank_statement
import account_bank import account_bank
@ -37,4 +37,6 @@ import ir_sequence
import company import company
import res_currency import res_currency
import edi import edi
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -19,42 +19,38 @@
# #
############################################################################## ##############################################################################
{ {
"name" : "eInvoicing", 'name' : 'eInvoicing',
"version" : "1.1", 'version' : '1.1',
"author" : "OpenERP SA", 'author' : 'OpenERP SA',
"category": 'Accounting & Finance', 'category' : 'Accounting & Finance',
'complexity': "easy", 'description' : """
"description": """
Accounting and Financial Management. Accounting and Financial Management.
==================================== ====================================
Financial and accounting module that covers: Financial and accounting module that covers:
-------------------------------------------- --------------------------------------------
General accountings * General Accounting
Cost / Analytic accounting * Cost/Analytic accounting
Third party accounting * Third party accounting
Taxes management * Taxes management
Budgets * Budgets
Customer and Supplier Invoices * Customer and Supplier Invoices
Bank statements * Bank statements
Reconciliation process by partner * Reconciliation process by partner
Creates a dashboard for accountants that includes: Creates a dashboard for accountants that includes:
-------------------------------------------------- --------------------------------------------------
* List of Customer Invoice to Approve * List of Customer Invoice to Approve
* Company Analysis * Company Analysis
* Graph of Aged Receivables * Graph of Treasury
* Graph of Treasury
The processes like maintaining of general ledger is done through the defined financial Journals (entry move line or The processes like maintaining of general ledger is done through the defined financial Journals (entry move line orgrouping is maintained through journal)
grouping is maintained through journal) for a particular financial year and for preparation of vouchers there is a for a particular financial year and for preparation of vouchers there is a module named account_voucher.
module named account_voucher.
""", """,
'website': 'http://www.openerp.com', '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'], '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'],
"depends" : ["base_setup", "product", "analytic", "process", "board", "edi"], 'data': [
'update_xml': [
'security/account_security.xml', 'security/account_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'account_menuitem.xml', 'account_menuitem.xml',
@ -67,6 +63,8 @@ module named account_voucher.
'wizard/account_use_model_view.xml', 'wizard/account_use_model_view.xml',
'account_installer.xml', 'account_installer.xml',
'wizard/account_period_close_view.xml', 'wizard/account_period_close_view.xml',
'wizard/account_reconcile_view.xml',
'wizard/account_unreconcile_view.xml',
'account_view.xml', 'account_view.xml',
'account_report.xml', 'account_report.xml',
'account_financial_report_data.xml', 'account_financial_report_data.xml',
@ -75,7 +73,6 @@ module named account_voucher.
'wizard/account_fiscalyear_close_state.xml', 'wizard/account_fiscalyear_close_state.xml',
'wizard/account_chart_view.xml', 'wizard/account_chart_view.xml',
'wizard/account_tax_chart_view.xml', 'wizard/account_tax_chart_view.xml',
'wizard/account_move_journal_view.xml',
'wizard/account_move_line_reconcile_select_view.xml', 'wizard/account_move_line_reconcile_select_view.xml',
'wizard/account_open_closed_fiscalyear_view.xml', 'wizard/account_open_closed_fiscalyear_view.xml',
'wizard/account_move_line_unreconcile_select_view.xml', 'wizard/account_move_line_unreconcile_select_view.xml',
@ -89,23 +86,23 @@ module named account_voucher.
'wizard/account_journal_select_view.xml', 'wizard/account_journal_select_view.xml',
'wizard/account_change_currency_view.xml', 'wizard/account_change_currency_view.xml',
'wizard/account_validate_move_view.xml', 'wizard/account_validate_move_view.xml',
'wizard/account_unreconcile_view.xml',
'wizard/account_report_general_ledger_view.xml', 'wizard/account_report_general_ledger_view.xml',
'wizard/account_invoice_state_view.xml', 'wizard/account_invoice_state_view.xml',
'wizard/account_report_partner_balance_view.xml', 'wizard/account_report_partner_balance_view.xml',
'wizard/account_report_account_balance_view.xml', 'wizard/account_report_account_balance_view.xml',
'wizard/account_report_aged_partner_balance_view.xml', 'wizard/account_report_aged_partner_balance_view.xml',
'wizard/account_report_partner_ledger_view.xml', 'wizard/account_report_partner_ledger_view.xml',
'wizard/account_reconcile_view.xml',
'wizard/account_reconcile_partner_process_view.xml', 'wizard/account_reconcile_partner_process_view.xml',
'wizard/account_automatic_reconcile_view.xml', 'wizard/account_automatic_reconcile_view.xml',
'wizard/account_financial_report_view.xml', 'wizard/account_financial_report_view.xml',
'wizard/pos_box.xml',
'project/wizard/project_account_analytic_line_view.xml', 'project/wizard/project_account_analytic_line_view.xml',
'account_end_fy.xml', 'account_end_fy.xml',
'account_invoice_view.xml', 'account_invoice_view.xml',
'partner_view.xml', 'partner_view.xml',
'data/account_data.xml', 'data/account_data.xml',
'data/data_account_type.xml', 'data/data_account_type.xml',
'data/configurable_account_chart.xml',
'account_invoice_workflow.xml', 'account_invoice_workflow.xml',
'project/project_view.xml', 'project/project_view.xml',
'project/project_report.xml', 'project/project_report.xml',
@ -123,17 +120,28 @@ module named account_voucher.
'ir_sequence_view.xml', 'ir_sequence_view.xml',
'company_view.xml', 'company_view.xml',
'board_account_view.xml', 'board_account_view.xml',
"edi/invoice_action_data.xml", 'edi/invoice_action_data.xml',
"account_bank_view.xml", 'account_bank_view.xml',
"account_pre_install.yml" 'res_config_view.xml',
'account_pre_install.yml'
], ],
'demo_xml': [ 'js': [
'static/src/js/account_move_reconciliation.js',
'static/src/js/account_move_line_quickadd.js',
],
'qweb' : [
"static/src/xml/account_move_reconciliation.xml",
"static/src/xml/account_move_line_quickadd.xml",
],
'css':['static/src/css/account_move_reconciliation.css'
],
'demo': [
'demo/account_demo.xml', 'demo/account_demo.xml',
'project/project_demo.xml', 'project/project_demo.xml',
'project/analytic_account_demo.xml', 'project/analytic_account_demo.xml',
'demo/account_minimal.xml', 'demo/account_minimal.xml',
'demo/account_invoice_demo.xml', 'demo/account_invoice_demo.xml',
# 'account_unit_test.xml', 'account_unit_test.xml',
], ],
'test': [ 'test': [
'test/account_customer_invoice.yml', 'test/account_customer_invoice.yml',
@ -144,14 +152,13 @@ module named account_voucher.
'test/account_use_model.yml', 'test/account_use_model.yml',
'test/account_validate_account_move.yml', 'test/account_validate_account_move.yml',
'test/account_fiscalyear_close.yml', 'test/account_fiscalyear_close.yml',
'test/account_bank_statement.yml', #'test/account_bank_statement.yml',
'test/account_cash_statement.yml', #'test/account_cash_statement.yml',
'test/test_edi_invoice.yml', 'test/test_edi_invoice.yml',
'test/account_report.yml', 'test/account_report.yml',
'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear 'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear
], ],
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,
'certificate': '0080331923549',
} }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

File diff suppressed because it is too large Load Diff

View File

@ -27,19 +27,18 @@ class account_analytic_line(osv.osv):
_inherit = 'account.analytic.line' _inherit = 'account.analytic.line'
_description = 'Analytic Line' _description = 'Analytic Line'
_columns = { _columns = {
'product_uom_id': fields.many2one('product.uom', 'UoM'), 'product_uom_id': fields.many2one('product.uom', 'Unit of Measure'),
'product_id': fields.many2one('product.product', 'Product'), 'product_id': fields.many2one('product.product', 'Product'),
'general_account_id': fields.many2one('account.account', 'General Account', required=True, ondelete='restrict'), 'general_account_id': fields.many2one('account.account', 'General Account', required=True, ondelete='restrict'),
'move_id': fields.many2one('account.move.line', 'Move Line', ondelete='cascade', select=True), 'move_id': fields.many2one('account.move.line', 'Move Line', ondelete='cascade', select=True),
'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='restrict', select=True), 'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='restrict', select=True),
'code': fields.char('Code', size=8), 'code': fields.char('Code', size=8),
'ref': fields.char('Ref.', size=64), 'ref': fields.char('Ref.', size=64),
'currency_id': fields.related('move_id', 'currency_id', type='many2one', relation='res.currency', string='Account currency', store=True, help="The related account currency if not equal to the company one.", readonly=True), 'currency_id': fields.related('move_id', 'currency_id', type='many2one', relation='res.currency', string='Account Currency', store=True, help="The related account currency if not equal to the company one.", readonly=True),
'amount_currency': fields.related('move_id', 'amount_currency', type='float', string='Amount currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True), 'amount_currency': fields.related('move_id', 'amount_currency', type='float', string='Amount Currency', store=True, help="The amount expressed in the related account currency if not equal to the company one.", readonly=True),
} }
_defaults = { _defaults = {
'date': fields.date.context_today,
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', context=c), 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', context=c),
} }
_order = 'date desc' _order = 'date desc'
@ -87,18 +86,18 @@ class account_analytic_line(osv.osv):
if not a: if not a:
a = prod.categ_id.property_account_expense_categ.id a = prod.categ_id.property_account_expense_categ.id
if not a: if not a:
raise osv.except_osv(_('Error !'), raise osv.except_osv(_('Error!'),
_('There is no expense account defined ' \ _('There is no expense account defined ' \
'for this product: "%s" (id:%d)') % \ 'for this product: "%s" (id:%d).') % \
(prod.name, prod.id,)) (prod.name, prod.id,))
else: else:
a = prod.product_tmpl_id.property_account_income.id a = prod.product_tmpl_id.property_account_income.id
if not a: if not a:
a = prod.categ_id.property_account_income_categ.id a = prod.categ_id.property_account_income_categ.id
if not a: if not a:
raise osv.except_osv(_('Error !'), raise osv.except_osv(_('Error!'),
_('There is no income account defined ' \ _('There is no income account defined ' \
'for this product: "%s" (id:%d)') % \ 'for this product: "%s" (id:%d).') % \
(prod.name, prod_id,)) (prod.name, prod_id,))
flag = False flag = False
@ -108,7 +107,7 @@ class account_analytic_line(osv.osv):
if journal_id: if journal_id:
journal = analytic_journal_obj.browse(cr, uid, journal_id, context=context) journal = analytic_journal_obj.browse(cr, uid, journal_id, context=context)
if journal.type == 'sale': if journal.type == 'sale':
product_price_type_ids = product_price_type_obj.search(cr, uid, [('field','=','list_price')], context) product_price_type_ids = product_price_type_obj.search(cr, uid, [('field','=','list_price')], context=context)
if product_price_type_ids: if product_price_type_ids:
pricetype = product_price_type_obj.browse(cr, uid, product_price_type_ids, context=context)[0] pricetype = product_price_type_obj.browse(cr, uid, product_price_type_ids, context=context)[0]
# Take the company currency as the reference one # Take the company currency as the reference one

View File

@ -29,12 +29,12 @@ class bank(osv.osv):
'currency_id': fields.related('journal_id', 'currency', type="many2one", relation='res.currency', readonly=True, 'currency_id': fields.related('journal_id', 'currency', type="many2one", relation='res.currency', readonly=True,
string="Currency", help="Currency of the related account journal."), string="Currency", help="Currency of the related account journal."),
} }
def create(self, cr, uid, data, context={}): def create(self, cr, uid, data, context=None):
result = super(bank, self).create(cr, uid, data, context=context) result = super(bank, self).create(cr, uid, data, context=context)
self.post_write(cr, uid, [result], context=context) self.post_write(cr, uid, [result], context=context)
return result return result
def write(self, cr, uid, ids, data, context={}): def write(self, cr, uid, ids, data, context=None):
result = super(bank, self).write(cr, uid, ids, data, context=context) result = super(bank, self).write(cr, uid, ids, data, context=context)
self.post_write(cr, uid, ids, context=context) self.post_write(cr, uid, ids, context=context)
return result return result
@ -43,7 +43,17 @@ class bank(osv.osv):
"Return the name to use when creating a bank journal" "Return the name to use when creating a bank journal"
return (bank.bank_name or '') + ' ' + bank.acc_number return (bank.bank_name or '') + ' ' + bank.acc_number
def post_write(self, cr, uid, ids, 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.get('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.get('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=None):
if isinstance(ids, (int, long)): if isinstance(ids, (int, long)):
ids = [ids] ids = [ids]
@ -79,11 +89,6 @@ class bank(osv.osv):
} }
acc_bank_id = obj_acc.create(cr,uid,acc,context=context) acc_bank_id = obj_acc.create(cr,uid,acc,context=context)
# Get the journal view id
data_id = obj_data.search(cr, uid, [('model','=','account.journal.view'), ('name','=','account_journal_bank_view')])
data = obj_data.browse(cr, uid, data_id[0], context=context)
view_id_cash = data.res_id
jour_obj = self.pool.get('account.journal') jour_obj = self.pool.get('account.journal')
new_code = 1 new_code = 1
while True: while True:
@ -102,7 +107,6 @@ class bank(osv.osv):
'analytic_journal_id': False, 'analytic_journal_id': False,
'default_credit_account_id': acc_bank_id, 'default_credit_account_id': acc_bank_id,
'default_debit_account_id': acc_bank_id, 'default_debit_account_id': acc_bank_id,
'view_id': view_id_cash
} }
journal_id = jour_obj.create(cr, uid, vals_journal, context=context) journal_id = jour_obj.create(cr, uid, vals_journal, context=context)

View File

@ -26,24 +26,18 @@ from tools.translate import _
import decimal_precision as dp import decimal_precision as dp
class account_bank_statement(osv.osv): class account_bank_statement(osv.osv):
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
seq = 0
if 'line_ids' in vals: if 'line_ids' in vals:
new_line_ids = [] for idx, line in enumerate(vals['line_ids']):
for line in vals['line_ids']: line[2]['sequence'] = idx + 1
seq += 1
line[2]['sequence'] = seq
return super(account_bank_statement, self).create(cr, uid, vals, context=context) return super(account_bank_statement, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
res = super(account_bank_statement, self).write(cr, uid, ids, vals, context=context) res = super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
account_bank_statement_line_obj = self.pool.get('account.bank.statement.line') account_bank_statement_line_obj = self.pool.get('account.bank.statement.line')
for statement in self.browse(cr, uid, ids, context): for statement in self.browse(cr, uid, ids, context):
seq = 0 for idx, line in enumerate(statement.line_ids):
for line in statement.line_ids: account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': idx + 1}, context=context)
seq += 1
account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': seq}, context=context)
return res return res
def _default_journal_id(self, cr, uid, context=None): def _default_journal_id(self, cr, uid, context=None):
@ -51,49 +45,23 @@ class account_bank_statement(osv.osv):
context = {} context = {}
journal_pool = self.pool.get('account.journal') journal_pool = self.pool.get('account.journal')
journal_type = context.get('journal_type', False) journal_type = context.get('journal_type', False)
journal_id = False
company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=context) company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=context)
if journal_type: if journal_type:
ids = journal_pool.search(cr, uid, [('type', '=', journal_type),('company_id','=',company_id)]) ids = journal_pool.search(cr, uid, [('type', '=', journal_type),('company_id','=',company_id)])
if ids: if ids:
journal_id = ids[0] return ids[0]
return journal_id return False
def _end_balance(self, cursor, user, ids, name, attr, context=None): def _end_balance(self, cursor, user, ids, name, attr, context=None):
res_currency_obj = self.pool.get('res.currency')
res_users_obj = self.pool.get('res.users')
res = {} res = {}
for statement in self.browse(cursor, user, ids, context=context):
company_currency_id = res_users_obj.browse(cursor, user, user,
context=context).company_id.currency_id.id
statements = self.browse(cursor, user, ids, context=context)
for statement in statements:
res[statement.id] = statement.balance_start res[statement.id] = statement.balance_start
currency_id = statement.currency.id for line in statement.line_ids:
for line in statement.move_line_ids: res[statement.id] += line.amount
if line.debit > 0:
if line.account_id.id == \
statement.journal_id.default_debit_account_id.id:
res[statement.id] += res_currency_obj.compute(cursor,
user, company_currency_id, currency_id,
line.debit, context=context)
else:
if line.account_id.id == \
statement.journal_id.default_credit_account_id.id:
res[statement.id] -= res_currency_obj.compute(cursor,
user, company_currency_id, currency_id,
line.credit, context=context)
if statement.state in ('draft', 'open'):
for line in statement.line_ids:
res[statement.id] += line.amount
for r in res:
res[r] = round(res[r], 2)
return res return res
def _get_period(self, cr, uid, context=None): def _get_period(self, cr, uid, context=None):
periods = self.pool.get('account.period').find(cr, uid) periods = self.pool.get('account.period').find(cr, uid,context=context)
if periods: if periods:
return periods[0] return periods[0]
return False return False
@ -127,8 +95,9 @@ class account_bank_statement(osv.osv):
_order = "date desc, id desc" _order = "date desc, id desc"
_name = "account.bank.statement" _name = "account.bank.statement"
_description = "Bank Statement" _description = "Bank Statement"
_inherit = ['mail.thread']
_columns = { _columns = {
'name': fields.char('Name', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement 'name': fields.char('Reference', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement
'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True), 'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True),
'journal_id': fields.many2one('account.journal', 'Journal', required=True, 'journal_id': fields.many2one('account.journal', 'Journal', required=True,
readonly=True, states={'draft':[('readonly',False)]}), readonly=True, states={'draft':[('readonly',False)]}),
@ -140,7 +109,7 @@ class account_bank_statement(osv.osv):
states={'confirm': [('readonly', True)]}), states={'confirm': [('readonly', True)]}),
'balance_end': fields.function(_end_balance, 'balance_end': fields.function(_end_balance,
store = { store = {
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10), 'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids','balance_start'], 10),
'account.bank.statement.line': (_get_statement, ['amount'], 10), 'account.bank.statement.line': (_get_statement, ['amount'], 10),
}, },
string="Computed Balance", help='Balance as calculated based on Starting Balance and transaction lines'), string="Computed Balance", help='Balance as calculated based on Starting Balance and transaction lines'),
@ -153,9 +122,9 @@ class account_bank_statement(osv.osv):
'state': fields.selection([('draft', 'New'), 'state': fields.selection([('draft', 'New'),
('open','Open'), # used by cash statements ('open','Open'), # used by cash statements
('confirm', 'Closed')], ('confirm', 'Closed')],
'State', required=True, readonly="1", 'Status', required=True, readonly="1",
help='When new statement is created the state will be \'Draft\'.\n' help='When new statement is created the status will be \'Draft\'.\n'
'And after getting confirmation from the bank it will be in \'Confirmed\' state.'), 'And after getting confirmation from the bank it will be in \'Confirmed\' status.'),
'currency': fields.function(_currency, string='Currency', 'currency': fields.function(_currency, string='Currency',
type='many2one', relation='res.currency'), type='many2one', relation='res.currency'),
'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'), 'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'),
@ -204,7 +173,158 @@ class account_bank_statement(osv.osv):
def button_dummy(self, cr, uid, ids, context=None): def button_dummy(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {}, context=context) return self.write(cr, uid, ids, {}, context=context)
def _prepare_move(self, cr, uid, st_line, st_line_number, context=None):
"""Prepare the dict of values to create the move from a
statement line. This method may be overridden to implement custom
move generation (making sure to call super() to establish
a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:param char st_line_number: will be used as the name of the generated account move
:return: dict of value to create() the account.move
"""
return {
'journal_id': st_line.statement_id.journal_id.id,
'period_id': st_line.statement_id.period_id.id,
'date': st_line.date,
'name': st_line_number,
'ref': st_line.ref,
}
def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id,
context=None):
"""Compute the args to build the dict of values to create the bank move line from a
statement line by calling the _prepare_move_line_vals. This method may be
overridden to implement custom move generation (making sure to call super() to
establish a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:param int/long move_id: ID of the account.move to link the move line
:param float amount: amount of the move line
:param int/long company_currency_id: ID of currency of the concerned company
:return: dict of value to create() the bank account.move.line
"""
anl_id = st_line.analytic_account_id and st_line.analytic_account_id.id or False
debit = ((amount<0) and -amount) or 0.0
credit = ((amount>0) and amount) or 0.0
cur_id = False
amt_cur = False
if st_line.statement_id.currency.id <> company_currency_id:
cur_id = st_line.statement_id.currency.id
if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id:
cur_id = st_line.account_id.currency_id.id
if cur_id:
res_currency_obj = self.pool.get('res.currency')
amt_cur = -res_currency_obj.compute(cr, uid, company_currency_id, cur_id, amount, context=context)
res = self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit,
amount_currency=amt_cur, currency_id=cur_id, analytic_id=anl_id, context=context)
return res
def _get_counter_part_account(sefl, cr, uid, st_line, context=None):
"""Retrieve the account to use in the counterpart move.
This method may be overridden to implement custom move generation (making sure to
call super() to establish a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:return: int/long of the account.account to use as counterpart
"""
if st_line.amount >= 0:
return st_line.statement_id.journal_id.default_credit_account_id.id
return st_line.statement_id.journal_id.default_debit_account_id.id
def _get_counter_part_partner(sefl, cr, uid, st_line, context=None):
"""Retrieve the partner to use in the counterpart move.
This method may be overridden to implement custom move generation (making sure to
call super() to establish a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:return: int/long of the res.partner to use as counterpart
"""
return st_line.partner_id and st_line.partner_id.id or False
def _prepare_counterpart_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id,
context=None):
"""Compute the args to build the dict of values to create the counter part move line from a
statement line by calling the _prepare_move_line_vals. This method may be
overridden to implement custom move generation (making sure to call super() to
establish a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:param int/long move_id: ID of the account.move to link the move line
:param float amount: amount of the move line
:param int/long account_id: ID of account to use as counter part
:param int/long company_currency_id: ID of currency of the concerned company
:return: dict of value to create() the bank account.move.line
"""
account_id = self._get_counter_part_account(cr, uid, st_line, context=context)
partner_id = self._get_counter_part_partner(cr, uid, st_line, context=context)
debit = ((amount > 0) and amount) or 0.0
credit = ((amount < 0) and -amount) or 0.0
cur_id = False
amt_cur = False
if st_line.statement_id.currency.id <> company_currency_id:
amt_cur = st_line.amount
cur_id = st_line.statement_id.currency.id
return self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit,
amount_currency = amt_cur, currency_id = cur_id, account_id = account_id,
partner_id = partner_id, context=context)
def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id = False,
amount_currency= False, account_id = False, analytic_id = False,
partner_id = False, context=None):
"""Prepare the dict of values to create the move line from a
statement line. All non-mandatory args will replace the default computed one.
This method may be overridden to implement custom move generation (making sure to
call super() to establish a clean extension chain).
:param browse_record st_line: account.bank.statement.line record to
create the move from.
:param int/long move_id: ID of the account.move to link the move line
:param float debit: debit amount of the move line
:param float credit: credit amount of the move line
:param int/long currency_id: ID of currency of the move line to create
:param float amount_currency: amount of the debit/credit expressed in the currency_id
:param int/long account_id: ID of the account to use in the move line if different
from the statement line account ID
:param int/long analytic_id: ID of analytic account to put on the move line
:param int/long partner_id: ID of the partner to put on the move line
:return: dict of value to create() the account.move.line
"""
acc_id = account_id or st_line.account_id.id
cur_id = currency_id or st_line.statement_id.currency.id
par_id = partner_id or (((st_line.partner_id) and st_line.partner_id.id) or False)
return {
'name': st_line.name,
'date': st_line.date,
'ref': st_line.ref,
'move_id': move_id,
'partner_id': par_id,
'account_id': acc_id,
'credit': credit,
'debit': debit,
'statement_id': st_line.statement_id.id,
'journal_id': st_line.statement_id.journal_id.id,
'period_id': st_line.statement_id.period_id.id,
'currency_id': amount_currency and cur_id,
'amount_currency': amount_currency,
'analytic_account_id': analytic_id,
}
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None): def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
"""Create the account move from the statement line.
:param int/long st_line_id: ID of the account.bank.statement.line to create the move from.
:param int/long company_currency_id: ID of the res.currency of the company
:param char st_line_number: will be used as the name of the generated account move
:return: ID of the account.move created
"""
if context is None: if context is None:
context = {} context = {}
res_currency_obj = self.pool.get('res.currency') res_currency_obj = self.pool.get('res.currency')
@ -216,89 +336,35 @@ class account_bank_statement(osv.osv):
context.update({'date': st_line.date}) context.update({'date': st_line.date})
move_id = account_move_obj.create(cr, uid, { move_vals = self._prepare_move(cr, uid, st_line, st_line_number, context=context)
'journal_id': st.journal_id.id, move_id = account_move_obj.create(cr, uid, move_vals, context=context)
'period_id': st.period_id.id,
'date': st_line.date,
'name': st_line_number,
'ref': st_line.ref,
}, context=context)
account_bank_statement_line_obj.write(cr, uid, [st_line.id], { account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
'move_ids': [(4, move_id, False)] 'move_ids': [(4, move_id, False)]
}) })
torec = [] torec = []
if st_line.amount >= 0:
account_id = st.journal_id.default_credit_account_id.id
else:
account_id = st.journal_id.default_debit_account_id.id
acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id
context.update({ context.update({
'res.currency.compute.account': acc_cur, 'res.currency.compute.account': acc_cur,
}) })
amount = res_currency_obj.compute(cr, uid, st.currency.id, amount = res_currency_obj.compute(cr, uid, st.currency.id,
company_currency_id, st_line.amount, context=context) company_currency_id, st_line.amount, context=context)
val = { bank_move_vals = self._prepare_bank_move_line(cr, uid, st_line, move_id, amount,
'name': st_line.name, company_currency_id, context=context)
'date': st_line.date, move_line_id = account_move_line_obj.create(cr, uid, bank_move_vals, context=context)
'ref': st_line.ref,
'move_id': move_id,
'partner_id': ((st_line.partner_id) and st_line.partner_id.id) or False,
'account_id': (st_line.account_id) and st_line.account_id.id,
'credit': ((amount>0) and amount) or 0.0,
'debit': ((amount<0) and -amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': st.period_id.id,
'currency_id': st.currency.id,
'analytic_account_id': st_line.analytic_account_id and st_line.analytic_account_id.id or False
}
if st.currency.id <> company_currency_id:
amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
st.currency.id, amount, context=context)
val['amount_currency'] = -amount_cur
if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id:
val['currency_id'] = st_line.account_id.currency_id.id
amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
st_line.account_id.currency_id.id, amount, context=context)
val['amount_currency'] = -amount_cur
move_line_id = account_move_line_obj.create(cr, uid, val, context=context)
torec.append(move_line_id) torec.append(move_line_id)
# Fill the secondary amount/currency counterpart_move_vals = self._prepare_counterpart_move_line(cr, uid, st_line, move_id,
# if currency is not the same than the company amount, company_currency_id, context=context)
amount_currency = False account_move_line_obj.create(cr, uid, counterpart_move_vals, context=context)
currency_id = False
if st.currency.id <> company_currency_id:
amount_currency = st_line.amount
currency_id = st.currency.id
account_move_line_obj.create(cr, uid, {
'name': st_line.name,
'date': st_line.date,
'ref': st_line.ref,
'move_id': move_id,
'partner_id': ((st_line.partner_id) and st_line.partner_id.id) or False,
'account_id': account_id,
'credit': ((amount < 0) and -amount) or 0.0,
'debit': ((amount > 0) and amount) or 0.0,
'statement_id': st.id,
'journal_id': st.journal_id.id,
'period_id': st.period_id.id,
'amount_currency': amount_currency,
'currency_id': currency_id,
}, context=context)
for line in account_move_line_obj.browse(cr, uid, [x.id for x in for line in account_move_line_obj.browse(cr, uid, [x.id for x in
account_move_obj.browse(cr, uid, move_id, account_move_obj.browse(cr, uid, move_id,
context=context).line_id], context=context).line_id],
context=context): context=context):
if line.state <> 'valid': if line.state <> 'valid':
raise osv.except_osv(_('Error !'), raise osv.except_osv(_('Error!'),
_('Journal item "%s" is not valid.') % line.name) _('Journal item "%s" is not valid.') % line.name)
# Bank statements will not consider boolean on journal entry_posted # Bank statements will not consider boolean on journal entry_posted
@ -310,8 +376,8 @@ class account_bank_statement(osv.osv):
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None): def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
st = self.browse(cr, uid, st_id, context=context) st = self.browse(cr, uid, st_id, context=context)
if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_cash) < 0.0001)): if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)):
raise osv.except_osv(_('Error !'), raise osv.except_osv(_('Error!'),
_('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)') % (st.balance_end_real, st.balance_end)) _('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)') % (st.balance_end_real, st.balance_end))
return True return True
@ -335,7 +401,7 @@ class account_bank_statement(osv.osv):
self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) self.balance_check(cr, uid, st.id, journal_type=j_type, context=context)
if (not st.journal_id.default_credit_account_id) \ if (not st.journal_id.default_credit_account_id) \
or (not st.journal_id.default_debit_account_id): or (not st.journal_id.default_debit_account_id):
raise osv.except_osv(_('Configuration Error !'), raise osv.except_osv(_('Configuration Error!'),
_('Please verify that an account is defined in the journal.')) _('Please verify that an account is defined in the journal.'))
if not st.name == '/': if not st.name == '/':
@ -349,7 +415,7 @@ class account_bank_statement(osv.osv):
for line in st.move_line_ids: for line in st.move_line_ids:
if line.state <> 'valid': if line.state <> 'valid':
raise osv.except_osv(_('Error !'), raise osv.except_osv(_('Error!'),
_('The account entries lines are not in valid state.')) _('The account entries lines are not in valid state.'))
for st_line in st.line_ids: for st_line in st.line_ids:
if st_line.analytic_account_id: if st_line.analytic_account_id:
@ -364,7 +430,7 @@ class account_bank_statement(osv.osv):
'name': st_number, 'name': st_number,
'balance_end_real': st.balance_end 'balance_end_real': st.balance_end
}, context=context) }, context=context)
self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,)) 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) return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
def button_cancel(self, cr, uid, ids, context=None): def button_cancel(self, cr, uid, ids, context=None):
@ -380,17 +446,25 @@ class account_bank_statement(osv.osv):
done.append(st.id) done.append(st.id)
return self.write(cr, uid, done, {'state':'draft'}, context=context) return self.write(cr, uid, done, {'state':'draft'}, context=context)
def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
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): def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
cr.execute('SELECT balance_end_real \ if not journal_id:
FROM account_bank_statement \ return {}
WHERE journal_id = %s AND NOT state = %s \ balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
res = cr.fetchone() journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['company_id', 'currency'], context=context)
balance_start = res and res[0] or 0.0
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context)
account_id = journal_data['default_debit_account_id']
company_id = journal_data['company_id'] company_id = journal_data['company_id']
return {'value': {'balance_start': balance_start, 'account_id': account_id, 'company_id': company_id}} currency_id = journal_data['currency'] or self.pool.get('res.company').browse(cr, uid, company_id[0], context=context).currency_id.id
return {'value': {'balance_start': balance_start, 'company_id': company_id, 'currency': currency_id}}
def unlink(self, cr, uid, ids, context=None): def unlink(self, cr, uid, ids, context=None):
stat = self.read(cr, uid, ids, ['state'], context=context) stat = self.read(cr, uid, ids, ['state'], context=context)
@ -399,7 +473,7 @@ class account_bank_statement(osv.osv):
if t['state'] in ('draft'): if t['state'] in ('draft'):
unlink_ids.append(t['id']) unlink_ids.append(t['id'])
else: else:
raise osv.except_osv(_('Invalid action !'), _('In order to delete a bank statement, you must first cancel it to delete related journal items.')) raise osv.except_osv(_('Invalid Action!'), _('In order to delete a bank statement, you must first cancel it to delete related journal items.'))
osv.osv.unlink(self, cr, uid, unlink_ids, context=context) osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
return True return True
@ -412,6 +486,19 @@ class account_bank_statement(osv.osv):
default['move_line_ids'] = [] default['move_line_ids'] = []
return super(account_bank_statement, self).copy(cr, uid, id, default, context=context) return super(account_bank_statement, self).copy(cr, uid, id, default, context=context)
def button_journal_entries(self, cr, uid, ids, context=None):
ctx = (context or {}).copy()
ctx['journal_id'] = self.browse(cr, uid, ids[0], context=context).journal_id.id
return {
'view_type':'form',
'view_mode':'tree',
'res_model':'account.move.line',
'view_id':False,
'type':'ir.actions.act_window',
'domain':[('statement_id','in',ids)],
'context':ctx,
}
account_bank_statement() account_bank_statement()
class account_bank_statement_line(osv.osv): class account_bank_statement_line(osv.osv):

View File

@ -9,14 +9,13 @@
<record id="view_partner_bank_form_inherit" model="ir.ui.view"> <record id="view_partner_bank_form_inherit" model="ir.ui.view">
<field name="name">Partner Bank Accounts - Journal</field> <field name="name">Partner Bank Accounts - Journal</field>
<field name="model">res.partner.bank</field> <field name="model">res.partner.bank</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_bank_form"/> <field name="inherit_id" ref="base.view_partner_bank_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<group name="bank" position="after"> <group name="bank" position="after">
<group name="accounting" col="2" colspan="2" attrs="{'invisible': [('company_id','=', False)]}" groups="base.group_extended"> <group name="accounting" col="2" colspan="2" attrs="{'invisible': [('company_id','=', False)]}">
<separator string="Accounting Information" colspan="2"/> <separator string="Accounting Information" colspan="2"/>
<field name="journal_id"/> <field name="journal_id"/>
<field name="currency_id"/> <field name="currency_id" groups="base.group_multi_currency"/>
</group> </group>
</group> </group>
</field> </field>
@ -26,11 +25,10 @@
<record id="view_partner_bank_tree_add_currency" model="ir.ui.view"> <record id="view_partner_bank_tree_add_currency" model="ir.ui.view">
<field name="name">Partner Bank Accounts - Add currency on tree</field> <field name="name">Partner Bank Accounts - Add currency on tree</field>
<field name="model">res.partner.bank</field> <field name="model">res.partner.bank</field>
<field name="type">tree</field>
<field name="inherit_id" ref="base.view_partner_bank_tree"/> <field name="inherit_id" ref="base.view_partner_bank_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="acc_number" position="after"> <field name="acc_number" position="after">
<field name="currency_id"/> <field name="currency_id" groups="base.group_multi_currency"/>
</field> </field>
</field> </field>
</record> </record>
@ -42,7 +40,17 @@
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="context" eval="{'default_partner_id':ref('base.main_partner'), 'company_hide':False, 'default_company_id':ref('base.main_company'), 'search_default_my_bank':1}"/> <field name="context" eval="{'default_partner_id':ref('base.main_partner'), 'company_hide':False, 'default_company_id':ref('base.main_company'), 'search_default_my_bank':1}"/>
<field name="help">Configure your company's bank account and select those that must appear on the report footer. You can reorder banks in the list view. If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.</field> <field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to setup a new bank account.
</p><p>
Configure your company's bank account and select those that must
appear on the report footer.
</p><p>
If you use the accounting application of OpenERP, journals and
accounts will be created automatically based on these data.
</p>
</field>
</record> </record>
<menuitem <menuitem
sequence="0" sequence="0"
@ -50,13 +58,5 @@
id="menu_action_bank_tree" id="menu_action_bank_tree"
action="action_bank_tree"/> action="action_bank_tree"/>
<record id="account_configuration_bank_todo" model="ir.actions.todo">
<field name="action_id" ref="action_bank_tree"/>
<field name="category_id" ref="category_accounting_configuration"/>
<field name="sequence">4</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -32,7 +32,7 @@ class account_cashbox_line(osv.osv):
_name = 'account.cashbox.line' _name = 'account.cashbox.line'
_description = 'CashBox Line' _description = 'CashBox Line'
_rec_name = 'number' _rec_name = 'pieces'
def _sub_total(self, cr, uid, ids, name, arg, context=None): def _sub_total(self, cr, uid, ids, name, arg, context=None):
@ -43,24 +43,27 @@ class account_cashbox_line(osv.osv):
""" """
res = {} res = {}
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
res[obj.id] = obj.pieces * obj.number res[obj.id] = {
'subtotal_opening' : obj.pieces * obj.number_opening,
'subtotal_closing' : obj.pieces * obj.number_closing,
}
return res return res
def on_change_sub(self, cr, uid, ids, pieces, number, *a): def on_change_sub_opening(self, cr, uid, ids, pieces, number, *a):
""" Compute the subtotal for the opening """
return {'value' : {'subtotal_opening' : (pieces * number) or 0.0 }}
""" Calculates Sub total on change of number def on_change_sub_closing(self, cr, uid, ids, pieces, number, *a):
@param pieces: Names of fields. """ Compute the subtotal for the closing """
@param number: return {'value' : {'subtotal_closing' : (pieces * number) or 0.0 }}
"""
sub = pieces * number
return {'value': {'subtotal': sub or 0.0}}
_columns = { _columns = {
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')), 'pieces': fields.float('Unit of Currency', digits_compute=dp.get_precision('Account')),
'number': fields.integer('Number'), 'number_opening' : fields.integer('Number of Units', help='Opening Unit Numbers'),
'subtotal': fields.function(_sub_total, string='Sub Total', type='float', digits_compute=dp.get_precision('Account')), 'number_closing' : fields.integer('Number of Units', help='Closing Unit Numbers'),
'starting_id': fields.many2one('account.bank.statement', ondelete='cascade'), 'subtotal_opening': fields.function(_sub_total, string='Opening Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'ending_id': fields.many2one('account.bank.statement', ondelete='cascade'), 'subtotal_closing': fields.function(_sub_total, string='Closing Subtotal', type='float', digits_compute=dp.get_precision('Account'), multi='subtotal'),
'bank_statement_id' : fields.many2one('account.bank.statement', ondelete='cascade'),
} }
account_cashbox_line() account_cashbox_line()
@ -69,39 +72,24 @@ class account_cash_statement(osv.osv):
_inherit = 'account.bank.statement' _inherit = 'account.bank.statement'
def _get_starting_balance(self, cr, uid, ids, context=None): def _update_balances(self, cr, uid, ids, context=None):
"""
""" Find starting balance Set starting and ending balances according to pieces count
@param name: Names of fields.
@param arg: User defined arguments
@return: Dictionary of values.
""" """
res = {} res = {}
for statement in self.browse(cr, uid, ids, context=context): for statement in self.browse(cr, uid, ids, context=context):
amount_total = 0.0 if (statement.journal_id.type not in ('cash',)) or (not statement.journal_id.cash_control):
if statement.journal_id.type not in('cash'):
continue continue
start = end = 0
for line in statement.starting_details_ids: for line in statement.details_ids:
amount_total+= line.pieces * line.number start += line.subtotal_opening
res[statement.id] = { end += line.subtotal_closing
'balance_start': amount_total data = {
'balance_start': start,
'balance_end_real': end,
} }
return res res[statement.id] = data
super(account_cash_statement, self).write(cr, uid, [statement.id], data, context=context)
def _balance_end_cash(self, cr, uid, ids, name, arg, context=None):
""" Find ending balance "
@param name: Names of fields.
@param arg: User defined arguments
@return: Dictionary of values.
"""
res = {}
for statement in self.browse(cr, uid, ids, context=context):
amount_total = 0.0
for line in statement.ending_details_ids:
amount_total += line.pieces * line.number
res[statement.id] = amount_total
return res return res
def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None): def _get_sum_entry_encoding(self, cr, uid, ids, name, arg, context=None):
@ -111,13 +99,10 @@ class account_cash_statement(osv.osv):
@param arg: User defined arguments @param arg: User defined arguments
@return: Dictionary of values. @return: Dictionary of values.
""" """
res2 = {} res = {}
for statement in self.browse(cr, uid, ids, context=context): for statement in self.browse(cr, uid, ids, context=context):
encoding_total=0.0 res[statement.id] = sum((line.amount for line in statement.line_ids), 0.0)
for line in statement.line_ids: return res
encoding_total += line.amount
res2[statement.id] = encoding_total
return res2
def _get_company(self, cr, uid, context=None): def _get_company(self, cr, uid, context=None):
user_pool = self.pool.get('res.users') user_pool = self.pool.get('res.users')
@ -128,96 +113,113 @@ class account_cash_statement(osv.osv):
company_id = company_pool.search(cr, uid, []) company_id = company_pool.search(cr, uid, [])
return company_id and company_id[0] or False return company_id and company_id[0] or False
def _get_cash_open_box_lines(self, cr, uid, context=None): def _get_statement_from_line(self, cr, uid, ids, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'cash')], context=context)
if journal_ids:
results = self.search(cr, uid, [('journal_id', 'in', journal_ids),('state', '=', 'confirm')], context=context)
if results:
cash_st = self.browse(cr, uid, results, context=context)[0]
for cash_line in cash_st.ending_details_ids:
for r in res:
if cash_line.pieces == r['pieces']:
r['number'] = cash_line.number
return res
def _get_default_cash_close_box_lines(self, cr, uid, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append(dct)
return res
def _get_cash_close_box_lines(self, cr, uid, context=None):
res = []
curr = [1, 2, 5, 10, 20, 50, 100, 500]
for rs in curr:
dct = {
'pieces': rs,
'number': 0
}
res.append((0, 0, dct))
return res
def _get_cash_open_close_box_lines(self, cr, uid, context=None):
res = {}
start_l = []
end_l = []
starting_details = self._get_cash_open_box_lines(cr, uid, context=context)
ending_details = self._get_default_cash_close_box_lines(cr, uid, context)
for start in starting_details:
start_l.append((0, 0, start))
for end in ending_details:
end_l.append((0, 0, end))
res['start'] = start_l
res['end'] = end_l
return res
def _get_statement(self, cr, uid, ids, context=None):
result = {} result = {}
for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context): for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context):
result[line.statement_id.id] = True result[line.statement_id.id] = True
return result.keys() return result.keys()
def _compute_difference(self, cr, uid, ids, fieldnames, args, context=None):
result = dict.fromkeys(ids, 0.0)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = obj.balance_end_real - obj.balance_end
return result
def _compute_last_closing_balance(self, cr, uid, ids, fieldnames, args, context=None):
result = dict.fromkeys(ids, 0.0)
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'draft':
statement_ids = self.search(cr, uid,
[('journal_id', '=', obj.journal_id.id),('state', '=', 'confirm')],
order='create_date desc',
limit=1,
context=context
)
if not statement_ids:
continue
else:
st = self.browse(cr, uid, statement_ids[0], context=context)
result[obj.id] = st.balance_end_real
return result
def onchange_journal_id(self, cr, uid, ids, journal_id, context=None):
result = super(account_cash_statement, self).onchange_journal_id(cr, uid, ids, journal_id)
if not journal_id:
return result
statement_ids = self.search(cr, uid,
[('journal_id', '=', journal_id),('state', '=', 'confirm')],
order='create_date desc',
limit=1,
context=context
)
if not statement_ids:
return result
st = self.browse(cr, uid, statement_ids[0], context=context)
result.setdefault('value', {}).update({'last_closing_balance' : st.balance_end_real})
return result
_columns = { _columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Cash Transaction", help="Total cash transactions", 'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Transactions",
store = { store = {
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids'], 10), 'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement.line': (_get_statement, ['amount'], 10), 'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),
}), }),
'closing_date': fields.datetime("Closed On"), 'closing_date': fields.datetime("Closed On"),
'balance_end_cash': fields.function(_balance_end_cash, store=True, string='Closing Balance', help="Closing balance based on cashBox"), 'details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='CashBox Lines'),
'starting_details_ids': fields.one2many('account.cashbox.line', 'starting_id', string='Opening Cashbox'), 'opening_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Opening Cashbox Lines'),
'ending_details_ids': fields.one2many('account.cashbox.line', 'ending_id', string='Closing Cashbox'), 'closing_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Closing Cashbox Lines'),
'user_id': fields.many2one('res.users', 'Responsible', required=False), 'user_id': fields.many2one('res.users', 'Responsible', required=False),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
'last_closing_balance' : fields.function(_compute_last_closing_balance, method=True, string='Last Closing Balance', type='float'),
} }
_defaults = { _defaults = {
'state': 'draft', 'state': 'draft',
'date': lambda self,cr,uid,context={}: context.get('date', time.strftime("%Y-%m-%d %H:%M:%S")), 'date': lambda self, cr, uid, context={}: context.get('date', time.strftime("%Y-%m-%d %H:%M:%S")),
'user_id': lambda self, cr, uid, context=None: uid, 'user_id': lambda self, cr, uid, context=None: uid,
'starting_details_ids': _get_cash_open_box_lines, }
'ending_details_ids': _get_default_cash_close_box_lines
}
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
if self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context).type == 'cash': journal = False
amount_total = 0.0 if vals.get('journal_id'):
for line in vals.get('starting_details_ids',[]): journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
if line and len(line)==3 and line[2]: if journal and (journal.type == 'cash') and not vals.get('details_ids'):
amount_total+= line[2]['pieces'] * line[2]['number'] vals['details_ids'] = []
vals.update(balance_start= amount_total)
return super(account_cash_statement, self).create(cr, uid, vals, context=context) 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' : 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)
self._update_balances(cr, uid, [res_id], context)
return res_id
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
""" """
@ -233,34 +235,9 @@ class account_cash_statement(osv.osv):
@return: True on success, False otherwise @return: True on success, False otherwise
""" """
super(account_cash_statement, self).write(cr, uid, ids, vals, context=context) res = super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
res = self._get_starting_balance(cr, uid, ids) self._update_balances(cr, uid, ids, context)
for rs in res: return res
super(account_cash_statement, self).write(cr, uid, [rs], res.get(rs))
return True
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
""" Changes balance start and starting details if journal_id changes"
@param statement_id: Changed statement_id
@param journal_id: Changed journal_id
@return: Dictionary of changed values
"""
res = {}
balance_start = 0.0
if not journal_id:
res.update({
'balance_start': balance_start
})
return res
return super(account_cash_statement, self).onchange_journal_id(cr, uid, statement_id, journal_id, context=context)
def _equal_balance(self, cr, uid, cash_id, context=None):
statement = self.browse(cr, uid, cash_id, context=context)
self.write(cr, uid, [cash_id], {'balance_end_real': statement.balance_end})
statement.balance_end_real = statement.balance_end
if statement.balance_end != statement.balance_end_cash:
return False
return True
def _user_allow(self, cr, uid, statement_id, context=None): def _user_allow(self, cr, uid, statement_id, context=None):
return True return True
@ -276,7 +253,7 @@ class account_cash_statement(osv.osv):
for statement in statement_pool.browse(cr, uid, ids, context=context): for statement in statement_pool.browse(cr, uid, ids, context=context):
vals = {} vals = {}
if not self._user_allow(cr, uid, statement.id, context=context): if not self._user_allow(cr, uid, statement.id, context=context):
raise osv.except_osv(_('Error !'), (_('User %s does not have rights to access %s journal !') % (statement.user_id.name, statement.journal_id.name))) raise osv.except_osv(_('Error!'), (_('You do not have rights to open this %s journal !') % (statement.journal_id.name, )))
if statement.name and statement.name == '/': if statement.name and statement.name == '/':
c = {'fiscalyear_id': statement.period_id.fiscalyear_id.id} c = {'fiscalyear_id': statement.period_id.fiscalyear_id.id}
@ -294,13 +271,6 @@ class account_cash_statement(osv.osv):
self.write(cr, uid, [statement.id], vals, context=context) self.write(cr, uid, [statement.id], vals, context=context)
return True return True
def balance_check(self, cr, uid, cash_id, journal_type='bank', context=None):
if journal_type == 'bank':
return super(account_cash_statement, self).balance_check(cr, uid, cash_id, journal_type, context)
if not self._equal_balance(cr, uid, cash_id, context):
raise osv.except_osv(_('Error !'), _('The closing balance should be the same than the computed balance!'))
return True
def statement_close(self, cr, uid, ids, journal_type='bank', context=None): def statement_close(self, cr, uid, ids, journal_type='bank', context=None):
if journal_type == 'bank': if journal_type == 'bank':
return super(account_cash_statement, self).statement_close(cr, uid, ids, journal_type, context) return super(account_cash_statement, self).statement_close(cr, uid, ids, journal_type, context)
@ -317,16 +287,67 @@ class account_cash_statement(osv.osv):
def button_confirm_cash(self, cr, uid, ids, context=None): def button_confirm_cash(self, cr, uid, ids, context=None):
super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context) super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context)
return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context) absl_proxy = self.pool.get('account.bank.statement.line')
def button_cancel(self, cr, uid, ids, context=None): TABLES = ((_('Profit'), 'profit_account_id'), (_('Loss'), 'loss_account_id'),)
cash_box_line_pool = self.pool.get('account.cashbox.line')
super(account_cash_statement, self).button_cancel(cr, uid, ids, context=context) for obj in self.browse(cr, uid, ids, context=context):
for st in self.browse(cr, uid, ids, context): if obj.difference == 0.0:
for end in st.ending_details_ids: continue
cash_box_line_pool.write(cr, uid, [end.id], {'number': 0})
return True for item_label, item_account in TABLES:
if getattr(obj.journal_id, item_account):
raise osv.except_osv(_('Error!'),
_('There is no %s Account on the journal %s.') % (item_label, obj.journal_id.name,))
is_profit = obj.difference < 0.0
account = getattr(obj.journal_id, TABLES[is_profit][1])
values = {
'statement_id' : obj.id,
'journal_id' : obj.journal_id.id,
'account_id' : account.id,
'amount' : obj.difference,
'name' : 'Exceptional %s' % TABLES[is_profit][0],
}
absl_proxy.create(cr, uid, values, context=context)
return self.write(cr, uid, ids, {'closing_date': time.strftime("%Y-%m-%d %H:%M:%S")}, context=context)
account_cash_statement() account_cash_statement()
class account_journal(osv.osv):
_inherit = 'account.journal'
def _default_cashbox_line_ids(self, cr, uid, context=None):
# Return a list of coins in Euros.
result = [
dict(pieces=value) for value in [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500]
]
return result
_columns = {
'cashbox_line_ids' : fields.one2many('account.journal.cashbox.line', 'journal_id', 'CashBox'),
}
_defaults = {
'cashbox_line_ids' : _default_cashbox_line_ids,
}
account_journal()
class account_journal_cashbox_line(osv.osv):
_name = 'account.journal.cashbox.line'
_rec_name = 'pieces'
_columns = {
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
'journal_id' : fields.many2one('account.journal', 'Journal', required=True, select=1),
}
_order = 'pieces asc'
account_journal_cashbox_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -14,7 +14,7 @@
action="action_account_period_tree" action="action_account_period_tree"
id="menu_action_account_period_close_tree" id="menu_action_account_period_close_tree"
parent="account.menu_account_end_year_treatments" parent="account.menu_account_end_year_treatments"
sequence="0" groups="base.group_extended"/> sequence="0"/>
</data> </data>
</openerp> </openerp>

View File

@ -3,45 +3,40 @@
<record id="view_account_configuration_installer" model="ir.ui.view"> <record id="view_account_configuration_installer" model="ir.ui.view">
<field name="name">account.installer.form</field> <field name="name">account.installer.form</field>
<field name="model">account.installer</field> <field name="model">account.installer</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.res_config_installer"/> <field name="inherit_id" ref="base.res_config_installer"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<data> <form position="attributes" version="7.0">
<form position="attributes">
<attribute name="string">Accounting Application Configuration</attribute> <attribute name="string">Accounting Application Configuration</attribute>
</form> </form>
<separator string="title" position="attributes"> <footer position="replace">
<attribute name="string">Configure Your Chart of Accounts</attribute> <footer>
</separator> <button name="action_next" type="object" string="Continue" class="oe_highlight"/>
<xpath expr="//label[@string='description']" position="attributes"> </footer>
<attribute name="string">The default Chart of Accounts is matching your country selection. If no certified Chart of Accounts exists for your specified country, a generic one can be installed and will be selected by default.</attribute> </footer>
</xpath> <separator string="title" position="replace">
<xpath expr="//button[@string='Install Modules']" position="attributes"> <p class="oe_grey">
<attribute name="string">Configure</attribute> Select a configuration package to setup automatically your
</xpath> taxes and chart of accounts.
<xpath expr="//separator[@string=&quot;vsep&quot;]" position="attributes"> </p>
<attribute name="rowspan">23</attribute> <group>
<attribute name="string"/> <field name="charts" class="oe_inline"/>
</xpath>
<group colspan="8" position="inside">
<group colspan="4" width="600">
<field name="charts"/>
<group colspan="4" groups="account.group_account_user">
<separator col="4" colspan="4" string="Configure Fiscal Year"/>
<field name="has_default_company" invisible="1" />
<field name="company_id" colspan="4" widget="selection" attrs="{'invisible' : [('has_default_company', '=', True)]}"/><!-- we assume that this wizard will be run only by administrators and as this field may cause problem if hidden (because of the default company of the user removed from the selection because already configured), we simply choosed to remove the group "multi company" of it -->
<field name="date_start" on_change="on_change_start_date(date_start)"/>
<field name="date_stop"/>
<field name="period" colspan="4"/>
</group>
</group>
</group> </group>
</data> <group string="Configure your Fiscal Year" groups="account.group_account_user">
<field name="has_default_company" invisible="1" />
<field name="company_id" colspan="4" widget="selection" attrs="{'invisible' : [('has_default_company', '=', True)]}"/><!-- we assume that this wizard will be run only by administrators and as this field may cause problem if hidden (because of the default company of the user removed from the selection because already configured), we simply choosed to remove the group "multi company" of it -->
<label for="date_start" string="Date Range"/>
<div>
<field name="date_start" on_change="on_change_start_date(date_start)" class="oe_inline"/> -
<field name="date_stop" class="oe_inline"/>
</div>
<field name="period"/>
</group>
</separator>
</field> </field>
</record> </record>
<record id="action_account_configuration_installer" model="ir.actions.act_window"> <record id="action_account_configuration_installer" model="ir.actions.act_window">
<field name="name">Install your Chart of Accounts</field> <field name="name">Configure Accounting Data</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">account.installer</field> <field name="res_model">account.installer</field>
<field name="view_id" ref="view_account_configuration_installer"/> <field name="view_id" ref="view_account_configuration_installer"/>
@ -50,60 +45,11 @@
<field name="target">new</field> <field name="target">new</field>
</record> </record>
<record id="category_accounting_configuration" model="ir.actions.todo.category">
<field name="name">Accounting</field>
<field name="sequence">5</field>
</record>
<record id="account_configuration_installer_todo" model="ir.actions.todo"> <record id="account_configuration_installer_todo" model="ir.actions.todo">
<field name="action_id" ref="action_account_configuration_installer"/> <field name="action_id" ref="action_account_configuration_installer"/>
<field name="category_id" ref="category_accounting_configuration"/>
<field name="sequence">3</field> <field name="sequence">3</field>
<field name="type">automatic</field> <field name="type">automatic</field>
</record> </record>
<record id="action_view_financial_accounts_installer" model="ir.actions.act_window">
<field name="name">Review your Financial Accounts</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.account</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'config_invisible': False}</field>
</record>
<record id="view_financial_accounts_todo" model="ir.actions.todo">
<field name="action_id" ref="action_view_financial_accounts_installer" />
<field name="category_id" ref="category_accounting_configuration" />
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_user')])]" />
</record>
<record id="action_review_financial_journals_installer" model="ir.actions.act_window">
<field name="name">Review your Financial Journals</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.journal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help">Setup your accounting journals. For bank accounts, it's better to use the 'Setup Your Bank Accounts' tool that will automatically create the accounts and journals for you.</field>
</record>
<record id="review_financial_journals_todo" model="ir.actions.todo">
<field name="action_id" ref="action_review_financial_journals_installer" />
<field name="category_id" ref="category_accounting_configuration" />
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_user')])]" />
</record>
<record id="action_review_payment_terms_installer" model="ir.actions.act_window">
<field name="name">Review your Payment Terms</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">account.payment.term</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help">Payment terms define the conditions to pay a customer or supplier invoice in one or several payments. Customers periodic reminders will use the payment terms for each letter. Each customer or supplier can be assigned to one of these payment terms.</field>
</record>
<record id="review_payment_terms_todo" model="ir.actions.todo">
<field name="action_id" ref="action_review_payment_terms_installer" />
<field name="category_id" ref="category_accounting_configuration" />
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_user')])]" />
</record>
</data> </data>
</openerp> </openerp>

View File

@ -80,8 +80,11 @@ class account_invoice(osv.osv):
def _reconciled(self, cr, uid, ids, name, args, context=None): def _reconciled(self, cr, uid, ids, name, args, context=None):
res = {} res = {}
for id in ids: wf_service = netsvc.LocalService("workflow")
res[id] = self.test_paid(cr, uid, [id]) for inv in self.browse(cr, uid, ids, context=context):
res[inv.id] = self.test_paid(cr, uid, [inv.id])
if not res[inv.id] and inv.state == 'paid':
wf_service.trg_validate(uid, 'account.invoice', inv.id, 'open_test', cr)
return res return res
def _get_reference_type(self, cr, uid, context=None): def _get_reference_type(self, cr, uid, context=None):
@ -178,12 +181,14 @@ class account_invoice(osv.osv):
return invoice_ids return invoice_ids
_name = "account.invoice" _name = "account.invoice"
_inherit = ['mail.thread']
_description = 'Invoice' _description = 'Invoice'
_order = "id desc" _order = "id desc"
_columns = { _columns = {
'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}), 'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}),
'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}), 'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}),
'supplier_invoice_number': fields.char('Supplier Invoice Number', size=64, help="The reference of this invoice as provided by the supplier.", readonly=True, states={'draft':[('readonly',False)]}),
'type': fields.selection([ 'type': fields.selection([
('out_invoice','Customer Invoice'), ('out_invoice','Customer Invoice'),
('in_invoice','Supplier Invoice'), ('in_invoice','Supplier Invoice'),
@ -194,7 +199,7 @@ class account_invoice(osv.osv):
'number': fields.related('move_id','name', type='char', readonly=True, size=64, relation='account.move', store=True, string='Number'), 'number': fields.related('move_id','name', type='char', readonly=True, size=64, relation='account.move', store=True, string='Number'),
'internal_number': fields.char('Invoice Number', size=32, readonly=True, help="Unique number of the invoice, computed automatically when the invoice is created."), 'internal_number': fields.char('Invoice Number', size=32, readonly=True, help="Unique number of the invoice, computed automatically when the invoice is created."),
'reference': fields.char('Invoice Reference', size=64, help="The partner reference of this invoice."), 'reference': fields.char('Invoice Reference', size=64, help="The partner reference of this invoice."),
'reference_type': fields.selection(_get_reference_type, 'Reference Type', 'reference_type': fields.selection(_get_reference_type, 'Payment Reference',
required=True, readonly=True, states={'draft':[('readonly',False)]}), required=True, readonly=True, states={'draft':[('readonly',False)]}),
'comment': fields.text('Additional Information'), 'comment': fields.text('Additional Information'),
@ -204,20 +209,19 @@ class account_invoice(osv.osv):
('proforma2','Pro-forma'), ('proforma2','Pro-forma'),
('open','Open'), ('open','Open'),
('paid','Paid'), ('paid','Paid'),
('cancel','Cancelled') ('cancel','Cancelled'),
],'State', select=True, readonly=True, ],'Status', select=True, readonly=True,
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \ help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Invoice. \
\n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \ \n* The \'Pro-forma\' when invoice is in Pro-forma status,invoice does not have an invoice number. \
\n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \ \n* The \'Open\' status is used when user create invoice,a invoice number is generated.Its in open status till user does not pay invoice. \
\n* The \'Paid\' state is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \ \n* The \'Paid\' status is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \
\n* The \'Cancelled\' state is used when user cancel invoice.'), \n* The \'Cancelled\' status 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_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 "\ 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."), "of accounting entries. The payment term may compute several due dates, for example 50% now and 50% in one month, but if you want to force a due date, make sure that the payment term is not set on the invoice. If you keep the payment term and the due date empty, it means direct payment."),
'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}), 'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}),
'address_contact_id': fields.many2one('res.partner.address', 'Contact Address', readonly=True, states={'draft':[('readonly',False)]}),
'address_invoice_id': fields.many2one('res.partner.address', 'Invoice Address', readonly=True, required=True, states={'draft':[('readonly',False)]}),
'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]}, 'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]},
help="If you use payment terms, the due date will be computed automatically at the generation "\ 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. "\ "of accounting entries. If you keep the payment term and the due date empty, it means direct payment. "\
@ -253,7 +257,7 @@ class account_invoice(osv.osv):
'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}), '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)]}), '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)]}), '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', 'reconciled': fields.function(_reconciled, string='Paid/Reconciled', type='boolean',
store={ store={
'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ? 'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
@ -274,7 +278,7 @@ class account_invoice(osv.osv):
help="Remaining amount due."), help="Remaining amount due."),
'payment_ids': fields.function(_compute_lines, relation='account.move.line', type="many2many", string='Payments'), 'payment_ids': fields.function(_compute_lines, relation='account.move.line', type="many2many", string='Payments'),
'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}), 'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}),
'user_id': fields.many2one('res.users', 'Salesman', readonly=True, states={'draft':[('readonly',False)]}), 'user_id': fields.many2one('res.users', 'Salesperson', readonly=True, states={'draft':[('readonly',False)]}),
'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]}) 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]})
} }
_defaults = { _defaults = {
@ -287,11 +291,24 @@ class account_invoice(osv.osv):
'check_total': 0.0, 'check_total': 0.0,
'internal_number': False, 'internal_number': False,
'user_id': lambda s, cr, u, c: u, 'user_id': lambda s, cr, u, c: u,
'sent': False,
} }
_sql_constraints = [ _sql_constraints = [
('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'), ('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'),
] ]
def _find_partner(self, inv):
'''
Find the partner for which the accounting entries will be created
'''
#if the chosen partner is not a company and has a parent company, use the parent for the journal entries
#because you want to invoice 'Agrolait, accounting department' but the journal items are for 'Agrolait'
part = inv.partner_id
if part.parent_id and not part.is_company:
part = part.parent_id
return part
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False): def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
journal_obj = self.pool.get('account.journal') journal_obj = self.pool.get('account.journal')
if context is None: if context is None:
@ -305,7 +322,7 @@ class account_invoice(osv.osv):
if view_type == 'form': if view_type == 'form':
if partner['supplier'] and not partner['customer']: if partner['supplier'] and not partner['customer']:
view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.supplier.form')]) view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.supplier.form')])
else: elif partner['customer'] and not partner['supplier']:
view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.form')]) view_id = self.pool.get('ir.ui.view').search(cr,uid,[('name', '=', 'account.invoice.form')])
if view_id and isinstance(view_id, (list, tuple)): if view_id and isinstance(view_id, (list, tuple)):
view_id = view_id[0] view_id = view_id[0]
@ -318,7 +335,7 @@ class account_invoice(osv.osv):
res['fields'][field]['selection'] = journal_select res['fields'][field]['selection'] = journal_select
doc = etree.XML(res['arch']) doc = etree.XML(res['arch'])
if context.get('type', False): if context.get('type', False):
for node in doc.xpath("//field[@name='partner_bank_id']"): for node in doc.xpath("//field[@name='partner_bank_id']"):
if context['type'] == 'in_refund': if context['type'] == 'in_refund':
@ -326,7 +343,7 @@ class account_invoice(osv.osv):
elif context['type'] == 'out_refund': elif context['type'] == 'out_refund':
node.set('domain', "[('partner_id', '=', partner_id)]") node.set('domain', "[('partner_id', '=', partner_id)]")
res['arch'] = etree.tostring(doc) res['arch'] = etree.tostring(doc)
if view_type == 'search': if view_type == 'search':
if context.get('type', 'in_invoice') in ('out_invoice', 'out_refund'): if context.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
for node in doc.xpath("//group[@name='extended filter']"): for node in doc.xpath("//group[@name='extended filter']"):
@ -357,27 +374,73 @@ class account_invoice(osv.osv):
context = {} context = {}
try: try:
res = super(account_invoice, self).create(cr, uid, vals, context) res = super(account_invoice, self).create(cr, uid, vals, context)
for inv_id, name in self.name_get(cr, uid, [res], context=context): if res:
ctx = context.copy() self.create_send_note(cr, uid, [res], context=context)
if vals.get('type', 'in_invoice') in ('out_invoice', 'out_refund'):
ctx = self.get_log_context(cr, uid, context=ctx)
message = _("Invoice '%s' is waiting for validation.") % name
self.log(cr, uid, inv_id, message, context=ctx)
return res return res
except Exception, e: except Exception, e:
if '"journal_id" viol' in e.args[0]: if '"journal_id" viol' in e.args[0]:
raise orm.except_orm(_('Configuration Error!'), raise orm.except_orm(_('Configuration Error!'),
_('There is no Accounting Journal of type Sale/Purchase defined!')) _('There is no Sale/Purchase Journal(s) defined.'))
else: else:
raise orm.except_orm(_('Unknown Error'), str(e)) raise orm.except_orm(_('Unknown Error!'), str(e))
def invoice_print(self, cr, uid, ids, context=None):
'''
This function prints the invoice and mark it as sent, so that we can see more easily the next step of the workflow
'''
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
self.write(cr, uid, ids, {'sent': True}, context=context)
datas = {
'ids': ids,
'model': 'account.invoice',
'form': self.read(cr, uid, ids[0], context=context)
}
return {
'type': 'ir.actions.report.xml',
'report_name': 'account.invoice',
'datas': datas,
'nodestroy' : True
}
def action_invoice_sent(self, cr, uid, ids, context=None):
'''
This function opens a window to compose an email, with the edi invoice template message loaded by default
'''
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
ir_model_data = self.pool.get('ir.model.data')
try:
template_id = ir_model_data.get_object_reference(cr, uid, 'account', 'email_template_edi_invoice')[1]
except ValueError:
template_id = False
try:
compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
except ValueError:
compose_form_id = False
ctx = dict(context)
ctx.update({
'default_model': 'account.invoice',
'default_res_id': ids[0],
'default_use_template': bool(template_id),
'default_template_id': template_id,
'default_composition_mode': 'comment',
'mark_invoice_as_sent': True,
})
return {
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form_id, 'form')],
'view_id': compose_form_id,
'target': 'new',
'context': ctx,
}
def confirm_paid(self, cr, uid, ids, context=None): def confirm_paid(self, cr, uid, ids, context=None):
if context is None: if context is None:
context = {} context = {}
self.write(cr, uid, ids, {'state':'paid'}, context=context) self.write(cr, uid, ids, {'state':'paid'}, context=context)
for inv_id, name in self.name_get(cr, uid, ids, context=context): self.confirm_paid_send_note(cr, uid, ids, context=context)
message = _("Invoice '%s' is paid.") % name
self.log(cr, uid, inv_id, message)
return True return True
def unlink(self, cr, uid, ids, context=None): def unlink(self, cr, uid, ids, context=None):
@ -389,14 +452,12 @@ class account_invoice(osv.osv):
if t['state'] in ('draft', 'cancel') and t['internal_number']== False: if t['state'] in ('draft', 'cancel') and t['internal_number']== False:
unlink_ids.append(t['id']) unlink_ids.append(t['id'])
else: else:
raise osv.except_osv(_('Invalid action !'), _('You can not delete an invoice which is open or paid. We suggest you to refund it instead.')) raise osv.except_osv(_('Invalid Action!'), _('You can not delete an invoice which is not cancelled. You should refund it instead.'))
osv.osv.unlink(self, cr, uid, unlink_ids, context=context) osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
return True return True
def onchange_partner_id(self, cr, uid, ids, type, partner_id,\ def onchange_partner_id(self, cr, uid, ids, type, partner_id,\
date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False): date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
invoice_addr_id = False
contact_addr_id = False
partner_payment_term = False partner_payment_term = False
acc_id = False acc_id = False
bank_id = False bank_id = False
@ -406,12 +467,9 @@ class account_invoice(osv.osv):
if partner_id: if partner_id:
opt.insert(0, ('id', partner_id)) opt.insert(0, ('id', partner_id))
res = self.pool.get('res.partner').address_get(cr, uid, [partner_id], ['contact', 'invoice'])
contact_addr_id = res['contact']
invoice_addr_id = res['invoice']
p = self.pool.get('res.partner').browse(cr, uid, partner_id) p = self.pool.get('res.partner').browse(cr, uid, partner_id)
if company_id: if company_id:
if p.property_account_receivable.company_id.id != company_id and p.property_account_payable.company_id.id != company_id: if (p.property_account_receivable.company_id and (p.property_account_receivable.company_id.id != company_id)) and (p.property_account_payable.company_id and (p.property_account_payable.company_id.id != company_id)):
property_obj = self.pool.get('ir.property') property_obj = self.pool.get('ir.property')
rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)]) rec_pro_id = property_obj.search(cr,uid,[('name','=','property_account_receivable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)]) pay_pro_id = property_obj.search(cr,uid,[('name','=','property_account_payable'),('res_id','=','res.partner,'+str(partner_id)+''),('company_id','=',company_id)])
@ -424,8 +482,8 @@ class account_invoice(osv.osv):
rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
if not rec_res_id and not pay_res_id: if not rec_res_id and not pay_res_id:
raise osv.except_osv(_('Configuration Error !'), raise osv.except_osv(_('Configuration Error!'),
_('Can not find a chart of accounts for this company, you should create one.')) _('Cannot find a chart of accounts for this company, you should create one.'))
account_obj = self.pool.get('account.account') account_obj = self.pool.get('account.account')
rec_obj_acc = account_obj.browse(cr, uid, [rec_res_id]) rec_obj_acc = account_obj.browse(cr, uid, [rec_res_id])
pay_obj_acc = account_obj.browse(cr, uid, [pay_res_id]) pay_obj_acc = account_obj.browse(cr, uid, [pay_res_id])
@ -434,16 +492,15 @@ class account_invoice(osv.osv):
if type in ('out_invoice', 'out_refund'): if type in ('out_invoice', 'out_refund'):
acc_id = p.property_account_receivable.id acc_id = p.property_account_receivable.id
partner_payment_term = p.property_payment_term and p.property_payment_term.id or False
else: else:
acc_id = p.property_account_payable.id acc_id = p.property_account_payable.id
partner_payment_term = p.property_supplier_payment_term and p.property_supplier_payment_term.id or False
fiscal_position = p.property_account_position and p.property_account_position.id or False fiscal_position = p.property_account_position and p.property_account_position.id or False
partner_payment_term = p.property_payment_term and p.property_payment_term.id or False
if p.bank_ids: if p.bank_ids:
bank_id = p.bank_ids[0].id bank_id = p.bank_ids[0].id
result = {'value': { result = {'value': {
'address_contact_id': contact_addr_id,
'address_invoice_id': invoice_addr_id,
'account_id': acc_id, 'account_id': acc_id,
'payment_term': partner_payment_term, 'payment_term': partner_payment_term,
'fiscal_position': fiscal_position 'fiscal_position': fiscal_position
@ -471,28 +528,27 @@ class account_invoice(osv.osv):
if journal_id: if journal_id:
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id currency_id = journal.currency and journal.currency.id or journal.company_id.currency_id.id
company_id = journal.company_id.id
result = {'value': { result = {'value': {
'currency_id': currency_id, 'currency_id': currency_id,
'company_id': company_id,
} }
} }
return result return result
def onchange_payment_term_date_invoice(self, cr, uid, ids, payment_term_id, date_invoice): def onchange_payment_term_date_invoice(self, cr, uid, ids, payment_term_id, date_invoice):
if not payment_term_id: res = {}
return {}
res = {}
pt_obj = self.pool.get('account.payment.term')
if not date_invoice: if not date_invoice:
date_invoice = time.strftime('%Y-%m-%d') date_invoice = time.strftime('%Y-%m-%d')
if not payment_term_id:
pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice) return {'value':{'date_due': date_invoice}} #To make sure the invoice has a due date when no payment term
pterm_list = self.pool.get('account.payment.term').compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
if pterm_list: if pterm_list:
pterm_list = [line[0] for line in pterm_list] pterm_list = [line[0] for line in pterm_list]
pterm_list.sort() pterm_list.sort()
res = {'value':{'date_due': pterm_list[-1]}} res = {'value':{'date_due': pterm_list[-1]}}
else: else:
raise osv.except_osv(_('Data Insufficient !'), _('The payment term of supplier does not have a payment term line!')) raise osv.except_osv(_('Insufficient Data!'), _('The payment term of supplier does not have a payment term line.'))
return res return res
def onchange_invoice_line(self, cr, uid, ids, lines): def onchange_invoice_line(self, cr, uid, ids, lines):
@ -524,8 +580,8 @@ class account_invoice(osv.osv):
rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False rec_res_id = rec_line_data and rec_line_data[0].get('value_reference',False) and int(rec_line_data[0]['value_reference'].split(',')[1]) or False
pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False pay_res_id = pay_line_data and pay_line_data[0].get('value_reference',False) and int(pay_line_data[0]['value_reference'].split(',')[1]) or False
if not rec_res_id and not pay_res_id: if not rec_res_id and not pay_res_id:
raise osv.except_osv(_('Configuration Error !'), raise osv.except_osv(_('Configuration Error!'),
_('Can not find a chart of account, you should create one from the configuration of the accounting menu.')) _('Cannot find a chart of account, you should create one from Settings\Configuration\Accounting menu.'))
if type in ('out_invoice', 'out_refund'): if type in ('out_invoice', 'out_refund'):
acc_id = rec_res_id acc_id = rec_res_id
else: else:
@ -539,16 +595,16 @@ class account_invoice(osv.osv):
if line.account_id.company_id.id != company_id: if line.account_id.company_id.id != company_id:
result_id = account_obj.search(cr, uid, [('name','=',line.account_id.name),('company_id','=',company_id)]) result_id = account_obj.search(cr, uid, [('name','=',line.account_id.name),('company_id','=',company_id)])
if not result_id: if not result_id:
raise osv.except_osv(_('Configuration Error !'), raise osv.except_osv(_('Configuration Error!'),
_('Can not find a chart of account, you should create one from the configuration of the accounting menu.')) _('Cannot find a chart of account, you should create one from Settings\Configuration\Accounting menu.'))
inv_line_obj.write(cr, uid, [line.id], {'account_id': result_id[-1]}) inv_line_obj.write(cr, uid, [line.id], {'account_id': result_id[-1]})
else: else:
if invoice_line: if invoice_line:
for inv_line in invoice_line: for inv_line in invoice_line:
obj_l = account_obj.browse(cr, uid, inv_line[2]['account_id']) obj_l = account_obj.browse(cr, uid, inv_line[2]['account_id'])
if obj_l.company_id.id != company_id: if obj_l.company_id.id != company_id:
raise osv.except_osv(_('Configuration Error !'), raise osv.except_osv(_('Configuration Error!'),
_('Invoice line account company does not match with invoice company.')) _('Invoice line account\'s company and invoice\'s compnay does not match.'))
else: else:
continue continue
if company_id and type: if company_id and type:
@ -569,7 +625,7 @@ class account_invoice(osv.osv):
if r[1] == 'journal_id' and r[2] in journal_ids: if r[1] == 'journal_id' and r[2] in journal_ids:
val['journal_id'] = r[2] val['journal_id'] = r[2]
if not val.get('journal_id', False): if not val.get('journal_id', False):
raise osv.except_osv(_('Configuration Error !'), (_('Can\'t find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Financial Accounting\Accounts\Journals.') % (journal_type))) raise osv.except_osv(_('Configuration Error!'), (_('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Journals\Journals.') % (journal_type)))
dom = {'journal_id': [('id', 'in', journal_ids)]} dom = {'journal_id': [('id', 'in', journal_ids)]}
else: else:
journal_ids = obj_journal.search(cr, uid, []) journal_ids = obj_journal.search(cr, uid, [])
@ -618,6 +674,7 @@ class account_invoice(osv.osv):
'move_name':False, 'move_name':False,
'internal_number': False, 'internal_number': False,
'period_id': False, 'period_id': False,
'sent': False,
}) })
if 'date_invoice' not in default: if 'date_invoice' not in default:
default.update({ default.update({
@ -726,28 +783,31 @@ class account_invoice(osv.osv):
for tax in inv.tax_line: for tax in inv.tax_line:
if tax.manual: if tax.manual:
continue continue
key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id) key = (tax.tax_code_id.id, tax.base_code_id.id, tax.account_id.id, tax.account_analytic_id.id)
tax_key.append(key) tax_key.append(key)
if not key in compute_taxes: if not key in compute_taxes:
raise osv.except_osv(_('Warning !'), _('Global taxes defined, but they are not in invoice lines !')) raise osv.except_osv(_('Warning!'), _('Global taxes defined, but they are not in invoice lines !'))
base = compute_taxes[key]['base'] base = compute_taxes[key]['base']
if abs(base - tax.base) > inv.company_id.currency_id.rounding: if abs(base - tax.base) > inv.company_id.currency_id.rounding:
raise osv.except_osv(_('Warning !'), _('Tax base different!\nClick on compute to update the tax base.')) raise osv.except_osv(_('Warning!'), _('Tax base different!\nClick on compute to update the tax base.'))
for key in compute_taxes: for key in compute_taxes:
if not key in tax_key: if not key in tax_key:
raise osv.except_osv(_('Warning !'), _('Taxes are missing!\nClick on compute button.')) 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 = 0
total_currency = 0 total_currency = 0
cur_obj = self.pool.get('res.currency') cur_obj = self.pool.get('res.currency')
for i in invoice_move_lines: for i in invoice_move_lines:
if inv.currency_id.id != company_currency: 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['currency_id'] = inv.currency_id.id
i['amount_currency'] = i['price'] i['amount_currency'] = i['price']
i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id,
company_currency, i['price'], company_currency, i['price'],
context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}) context=context)
else: else:
i['amount_currency'] = False i['amount_currency'] = False
i['currency_id'] = False i['currency_id'] = False
@ -805,12 +865,12 @@ class account_invoice(osv.osv):
context = {} context = {}
for inv in self.browse(cr, uid, ids, context=context): for inv in self.browse(cr, uid, ids, context=context):
if not inv.journal_id.sequence_id: if not inv.journal_id.sequence_id:
raise osv.except_osv(_('Error !'), _('Please define sequence on the journal related to this invoice.')) raise osv.except_osv(_('Error!'), _('Please define sequence on the journal related to this invoice.'))
if not inv.invoice_line: if not inv.invoice_line:
raise osv.except_osv(_('No Invoice Lines !'), _('Please create some invoice lines.')) raise osv.except_osv(_('No Invoice Lines !'), _('Please create some invoice lines.'))
if inv.move_id: if inv.move_id:
continue continue
ctx = context.copy() ctx = context.copy()
ctx.update({'lang': inv.partner_id.lang}) ctx.update({'lang': inv.partner_id.lang})
if not inv.date_invoice: if not inv.date_invoice:
@ -824,8 +884,11 @@ class account_invoice(osv.osv):
self.check_tax_lines(cr, uid, inv, compute_taxes, ait_obj) self.check_tax_lines(cr, uid, inv, compute_taxes, ait_obj)
# I disabled the check_total feature # I disabled the check_total feature
#if inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0): group_check_total_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'group_supplier_inv_check_total')[1]
# raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe real total does not match the computed total.')) group_check_total = self.pool.get('res.groups').browse(cr, uid, group_check_total_id, context=context)
if group_check_total and uid in [x.id for x in group_check_total.users]:
if (inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding/2.0)):
raise osv.except_osv(_('Bad total !'), _('Please verify the price of the invoice !\nThe encoded total does not match the computed total.'))
if inv.payment_term: if inv.payment_term:
total_fixed = total_percent = 0 total_fixed = total_percent = 0
@ -836,7 +899,7 @@ class account_invoice(osv.osv):
total_percent += line.value_amount total_percent += line.value_amount
total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0) total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0)
if (total_fixed + total_percent) > 100: if (total_fixed + total_percent) > 100:
raise osv.except_osv(_('Error !'), _("Can not create the invoice !\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. The latest line of your payment term must be of type 'balance' to avoid rounding issues.")) raise osv.except_osv(_('Error!'), _("Cannot create the invoice.\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. In order to avoid rounding issues, the latest line of your payment term must be of type 'balance'."))
# one move line per tax line # one move line per tax line
iml += ait_obj.move_line_get(cr, uid, inv.id) iml += ait_obj.move_line_get(cr, uid, inv.id)
@ -857,7 +920,7 @@ class account_invoice(osv.osv):
# create one move line for the total and possibly adjust the other lines amount # create one move line for the total and possibly adjust the other lines amount
total = 0 total = 0
total_currency = 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 acc_id = inv.account_id.id
name = inv['name'] or '/' name = inv['name'] or '/'
@ -908,17 +971,18 @@ class account_invoice(osv.osv):
}) })
date = inv.date_invoice or time.strftime('%Y-%m-%d') date = inv.date_invoice or time.strftime('%Y-%m-%d')
part = inv.partner_id.id
line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, part, date, context=ctx)),iml) part = self._find_partner(inv)
line = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, part.id, date, context=ctx)),iml)
line = self.group_lines(cr, uid, iml, line, inv) line = self.group_lines(cr, uid, iml, line, inv)
journal_id = inv.journal_id.id journal_id = inv.journal_id.id
journal = journal_obj.browse(cr, uid, journal_id, context=ctx) journal = journal_obj.browse(cr, uid, journal_id, context=ctx)
if journal.centralisation: if journal.centralisation:
raise osv.except_osv(_('UserError'), raise osv.except_osv(_('User Error!'),
_('You cannot create an invoice on a centralised journal. Uncheck the centralised counterpart box in the related journal from the configuration menu.')) _('You cannot create an invoice on a centralized journal. Uncheck the centralized counterpart box in the related journal from the configuration menu.'))
line = self.finalize_invoice_move_lines(cr, uid, inv, line) line = self.finalize_invoice_move_lines(cr, uid, inv, line)
@ -939,17 +1003,21 @@ class account_invoice(osv.osv):
for i in line: for i in line:
i[2]['period_id'] = period_id i[2]['period_id'] = period_id
ctx.update(invoice=inv)
move_id = move_obj.create(cr, uid, move, context=ctx) move_id = move_obj.create(cr, uid, move, context=ctx)
new_move_name = move_obj.browse(cr, uid, move_id, context=ctx).name new_move_name = move_obj.browse(cr, uid, move_id, context=ctx).name
# make the invoice point to that move # make the invoice point to that move
self.write(cr, uid, [inv.id], {'move_id': move_id,'period_id':period_id, 'move_name':new_move_name}, context=ctx) self.write(cr, uid, [inv.id], {'move_id': move_id,'period_id':period_id, 'move_name':new_move_name}, context=ctx)
# Pass invoice in context in method post: used if you want to get the same # Pass invoice in context in method post: used if you want to get the same
# account move reference when creating the same invoice after a cancelled one: # account move reference when creating the same invoice after a cancelled one:
ctx.update({'invoice':inv})
move_obj.post(cr, uid, [move_id], context=ctx) move_obj.post(cr, uid, [move_id], context=ctx)
self._log_event(cr, uid, ids) self._log_event(cr, uid, ids)
return True return True
def invoice_validate(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state':'open'}, context=context)
return True
def line_get_convert(self, cr, uid, x, part, date, context=None): def line_get_convert(self, cr, uid, x, part, date, context=None):
return { return {
'date_maturity': x.get('date_maturity', False), 'date_maturity': x.get('date_maturity', False),
@ -1011,11 +1079,12 @@ class account_invoice(osv.osv):
if obj_inv.type in ('out_invoice', 'out_refund'): if obj_inv.type in ('out_invoice', 'out_refund'):
ctx = self.get_log_context(cr, uid, context=ctx) ctx = self.get_log_context(cr, uid, context=ctx)
message = _("Invoice '%s' is validated.") % name message = _("Invoice '%s' is validated.") % name
self.log(cr, uid, inv_id, message, context=ctx) self.message_post(cr, uid, [inv_id], body=message, context=context)
return True return True
def action_cancel(self, cr, uid, ids, *args): def action_cancel(self, cr, uid, ids, context=None):
context = {} # TODO: Use context from arguments if context is None:
context = {}
account_move_obj = self.pool.get('account.move') account_move_obj = self.pool.get('account.move')
invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids']) invoices = self.read(cr, uid, ids, ['move_id', 'payment_ids'])
move_ids = [] # ones that we will need to remove move_ids = [] # ones that we will need to remove
@ -1027,7 +1096,7 @@ class account_invoice(osv.osv):
pay_ids = account_move_line_obj.browse(cr, uid, i['payment_ids']) pay_ids = account_move_line_obj.browse(cr, uid, i['payment_ids'])
for move_line in pay_ids: for move_line in pay_ids:
if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids: if move_line.reconcile_partial_id and move_line.reconcile_partial_id.line_partial_ids:
raise osv.except_osv(_('Error !'), _('You can not cancel an invoice which is partially paid! You need to unreconcile related payment entries first!')) raise osv.except_osv(_('Error!'), _('You cannot cancel an invoice which is partially paid. You need to unreconcile related payment entries first.'))
# First, set the invoices as cancelled and detach the move ids # First, set the invoices as cancelled and detach the move ids
self.write(cr, uid, ids, {'state':'cancel', 'move_id':False}) self.write(cr, uid, ids, {'state':'cancel', 'move_id':False})
@ -1039,6 +1108,7 @@ class account_invoice(osv.osv):
# will be automatically deleted too # will be automatically deleted too
account_move_obj.unlink(cr, uid, move_ids, context=context) account_move_obj.unlink(cr, uid, move_ids, context=context)
self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice') self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice')
self.invoice_cancel_send_note(cr, uid, ids, context=context)
return True return True
################### ###################
@ -1060,10 +1130,10 @@ class account_invoice(osv.osv):
if not ids: if not ids:
return [] return []
types = { types = {
'out_invoice': 'CI: ', 'out_invoice': 'Invoice ',
'in_invoice': 'SI: ', 'in_invoice': 'Sup. Invoice ',
'out_refund': 'OR: ', 'out_refund': 'Refund ',
'in_refund': 'SR: ', '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')] 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')]
@ -1092,7 +1162,7 @@ class account_invoice(osv.osv):
return map(lambda x: (0,0,x), lines) return map(lambda x: (0,0,x), lines)
def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None): 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', 'address_contact_id', 'address_invoice_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', 'user_id', 'fiscal_position'])
obj_invoice_line = self.pool.get('account.invoice.line') obj_invoice_line = self.pool.get('account.invoice.line')
obj_invoice_tax = self.pool.get('account.invoice.tax') obj_invoice_tax = self.pool.get('account.invoice.tax')
obj_journal = self.pool.get('account.journal') obj_journal = self.pool.get('account.journal')
@ -1140,8 +1210,9 @@ class account_invoice(osv.osv):
'name': description, 'name': description,
}) })
# take the id part of the tuple returned for many2one fields # take the id part of the tuple returned for many2one fields
for field in ('address_contact_id', 'address_invoice_id', 'partner_id', for field in ('partner_id', 'company_id',
'account_id', 'currency_id', 'payment_term', 'journal_id'): 'account_id', 'currency_id', 'payment_term', 'journal_id',
'user_id', 'fiscal_position'):
invoice[field] = invoice[field] and invoice[field][0] invoice[field] = invoice[field] and invoice[field][0]
# create the new invoice # create the new invoice
new_ids.append(self.create(cr, uid, invoice)) new_ids.append(self.create(cr, uid, invoice))
@ -1152,7 +1223,7 @@ class account_invoice(osv.osv):
if context is None: if context is None:
context = {} context = {}
#TODO check if we can use different period for payment and the writeoff line #TODO check if we can use different period for payment and the writeoff line
assert len(ids)==1, "Can only pay one invoice at a time" assert len(ids)==1, "Can only pay one invoice at a time."
invoice = self.browse(cr, uid, ids[0], context=context) invoice = self.browse(cr, uid, ids[0], context=context)
src_account_id = invoice.account_id.id src_account_id = invoice.account_id.id
# Take the seq as name for move # Take the seq as name for move
@ -1184,12 +1255,15 @@ class account_invoice(osv.osv):
ref = invoice.reference ref = invoice.reference
else: else:
ref = self._convert_ref(cr, uid, invoice.number) ref = self._convert_ref(cr, uid, invoice.number)
partner = invoice.partner_id
if partner.parent_id and not partner.is_company:
partner = partner.parent_id
# Pay attention to the sign for both debit/credit AND amount_currency # Pay attention to the sign for both debit/credit AND amount_currency
l1 = { l1 = {
'debit': direction * pay_amount>0 and direction * pay_amount, 'debit': direction * pay_amount>0 and direction * pay_amount,
'credit': direction * pay_amount<0 and - direction * pay_amount, 'credit': direction * pay_amount<0 and - direction * pay_amount,
'account_id': src_account_id, 'account_id': src_account_id,
'partner_id': invoice.partner_id.id, 'partner_id': partner.id,
'ref':ref, 'ref':ref,
'date': date, 'date': date,
'currency_id':currency_id, 'currency_id':currency_id,
@ -1200,7 +1274,7 @@ class account_invoice(osv.osv):
'debit': direction * pay_amount<0 and - direction * pay_amount, 'debit': direction * pay_amount<0 and - direction * pay_amount,
'credit': direction * pay_amount>0 and direction * pay_amount, 'credit': direction * pay_amount>0 and direction * pay_amount,
'account_id': pay_account_id, 'account_id': pay_account_id,
'partner_id': invoice.partner_id.id, 'partner_id': partner.id,
'ref':ref, 'ref':ref,
'date': date, 'date': date,
'currency_id':currency_id, 'currency_id':currency_id,
@ -1238,16 +1312,44 @@ class account_invoice(osv.osv):
else: else:
code = invoice.currency_id.symbol code = invoice.currency_id.symbol
# TODO: use currency's formatting function # TODO: use currency's formatting function
msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining)") % \ msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining).") % \
(name, pay_amount, code, invoice.amount_total, code, total, code) (name, pay_amount, code, invoice.amount_total, code, total, code)
self.log(cr, uid, inv_id, msg) 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) 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 # Update the stored value (fields.function), so we write to trigger recompute
self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context) self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context)
return True return True
account_invoice() # -----------------------------------------
# OpenChatter notifications and need_action
# -----------------------------------------
def _get_document_type(self, type):
type_dict = {
# 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_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)),
subtype="account.mt_invoice_new", 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_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)),
subtype="account.mt_invoice_paid", 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_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)),
context=context)
class account_invoice_line(osv.osv): class account_invoice_line(osv.osv):
@ -1257,7 +1359,7 @@ class account_invoice_line(osv.osv):
cur_obj = self.pool.get('res.currency') cur_obj = self.pool.get('res.currency')
for line in self.browse(cr, uid, ids): for line in self.browse(cr, uid, ids):
price = line.price_unit * (1-(line.discount or 0.0)/100.0) price = line.price_unit * (1-(line.discount or 0.0)/100.0)
taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, address_id=line.invoice_id.address_invoice_id, partner=line.invoice_id.partner_id) taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, partner=line.invoice_id.partner_id)
res[line.id] = taxes['total'] res[line.id] = taxes['total']
if line.invoice_id: if line.invoice_id:
cur = line.invoice_id.currency_id cur = line.invoice_id.currency_id
@ -1277,7 +1379,7 @@ class account_invoice_line(osv.osv):
taxes = l[2].get('invoice_line_tax_id') taxes = l[2].get('invoice_line_tax_id')
if len(taxes[0]) >= 3 and taxes[0][2]: if len(taxes[0]) >= 3 and taxes[0][2]:
taxes = tax_obj.browse(cr, uid, list(taxes[0][2])) taxes = tax_obj.browse(cr, uid, list(taxes[0][2]))
for tax in tax_obj.compute_all(cr, uid, taxes, p,l[2].get('quantity'), context.get('address_invoice_id', False), l[2].get('product_id', False), context.get('partner_id', False))['taxes']: for tax in tax_obj.compute_all(cr, uid, taxes, p,l[2].get('quantity'), l[2].get('product_id', False), context.get('partner_id', False))['taxes']:
t = t - tax['amount'] t = t - tax['amount']
return t return t
return 0 return 0
@ -1285,27 +1387,36 @@ class account_invoice_line(osv.osv):
_name = "account.invoice.line" _name = "account.invoice.line"
_description = "Invoice Line" _description = "Invoice Line"
_columns = { _columns = {
'name': fields.char('Description', size=256, required=True), 'name': fields.text('Description', required=True),
'origin': fields.char('Origin', size=256, help="Reference of the document that produced this invoice."), 'origin': fields.char('Source Document', size=256, help="Reference of the document that produced this invoice."),
'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."),
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True), 'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null', select=True),
'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), 'product_id': fields.many2one('product.product', 'Product', ondelete='set null', select=True),
'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."),
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')), 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float", 'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float",
digits_compute= dp.get_precision('Account'), store=True), digits_compute= dp.get_precision('Account'), store=True),
'quantity': fields.float('Quantity', required=True), 'quantity': fields.float('Quantity', digits_compute= dp.get_precision('Product Unit of Measure'), required=True),
'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Account')), 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]), 'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]),
'note': fields.text('Notes'),
'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), '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) 'partner_id': fields.related('invoice_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True)
} }
def _default_account_id(self, cr, uid, context=None):
# XXX this gets the default account for the user's company,
# it should get the default account for the invoice's company
# however, the invoice's company does not reach this point
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 = { _defaults = {
'quantity': 1, 'quantity': 1,
'discount': 0.0, 'discount': 0.0,
'price_unit': _price_unit_default, '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): def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
@ -1322,12 +1433,12 @@ class account_invoice_line(osv.osv):
res['arch'] = etree.tostring(doc) res['arch'] = etree.tostring(doc)
return res return res
def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, currency_id=False, context=None, company_id=None): 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):
if context is None: if context is None:
context = {} context = {}
company_id = company_id if company_id != None else context.get('company_id',False) company_id = company_id if company_id != None else context.get('company_id',False)
context = dict(context) context = dict(context)
context.update({'company_id': company_id}) context.update({'company_id': company_id, 'force_company': company_id})
if not partner_id: if not partner_id:
raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") ) raise osv.except_osv(_('No Partner Defined !'),_("You must first select a partner !") )
if not product: if not product:
@ -1368,13 +1479,11 @@ class account_invoice_line(osv.osv):
result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id}) result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
result['name'] = res.partner_ref result['name'] = res.partner_ref
domain = {} result['uos_id'] = uom_id or res.uom_id.id
result['uos_id'] = res.uom_id.id or uom or False if res.description:
result['note'] = res.description result['name'] += '\n'+res.description
if result['uos_id']:
res2 = res.uom_id.category_id.id domain = {'uos_id':[('category_id','=',res.uom_id.category_id.id)]}
if res2:
domain = {'uos_id':[('category_id','=',res2 )]}
res_final = {'value':result, 'domain':domain} res_final = {'value':result, 'domain':domain}
@ -1390,33 +1499,32 @@ class account_invoice_line(osv.osv):
new_price = res_final['value']['price_unit'] * currency.rate new_price = res_final['value']['price_unit'] * currency.rate
res_final['value']['price_unit'] = new_price res_final['value']['price_unit'] = new_price
if uom: if result['uos_id'] != res.uom_id.id:
uom = self.pool.get('product.uom').browse(cr, uid, uom, context=context) selected_uom = self.pool.get('product.uom_id').browse(cr, uid, result['uos_id'], context=context)
if res.uom_id.category_id.id == uom.category_id.id: if res.uom_id.category_id.id == selected_uom.category_id.id:
new_price = res_final['value']['price_unit'] * uom.factor_inv new_price = res_final['value']['price_unit'] * uom_id.factor_inv
res_final['value']['price_unit'] = new_price res_final['value']['price_unit'] = new_price
return res_final return res_final
def uos_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, currency_id=False, context=None, company_id=None): def uos_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None):
if context is None: if context is None:
context = {} context = {}
company_id = company_id if company_id != None else context.get('company_id',False) company_id = company_id if company_id != None else context.get('company_id',False)
context = dict(context) context = dict(context)
context.update({'company_id': company_id}) context.update({'company_id': company_id})
warning = {} warning = {}
res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context=context) res = self.product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, currency_id, context=context)
if 'uos_id' in res['value']:
del res['value']['uos_id']
if not uom: if not uom:
res['value']['price_unit'] = 0.0 res['value']['price_unit'] = 0.0
if product and uom: if product and uom:
prod = self.pool.get('product.product').browse(cr, uid, product, context=context) 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) 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: if prod.uom_id.category_id.id != prod_uom.category_id.id:
warning = { warning = {
'title': _('Warning!'), 'title': _('Warning!'),
'message': _('You selected an Unit of Measure which is not compatible with the product.') '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 {'value': res['value'], 'warning': warning}
return res return res
@ -1437,7 +1545,7 @@ class account_invoice_line(osv.osv):
tax_code_found= False tax_code_found= False
for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id,
(line.price_unit * (1.0 - (line['discount'] or 0.0) / 100.0)), (line.price_unit * (1.0 - (line['discount'] or 0.0) / 100.0)),
line.quantity, inv.address_invoice_id.id, line.product_id, line.quantity, line.product_id,
inv.partner_id)['taxes']: inv.partner_id)['taxes']:
if inv.type in ('out_invoice', 'in_invoice'): if inv.type in ('out_invoice', 'in_invoice'):
@ -1464,7 +1572,7 @@ class account_invoice_line(osv.osv):
def move_line_get_item(self, cr, uid, line, context=None): def move_line_get_item(self, cr, uid, line, context=None):
return { return {
'type':'src', 'type':'src',
'name': line.name[:64], 'name': line.name.split('\n')[0][:64],
'price_unit':line.price_unit, 'price_unit':line.price_unit,
'quantity':line.quantity, 'quantity':line.quantity,
'price':line.price_subtotal, 'price':line.price_subtotal,
@ -1480,16 +1588,19 @@ class account_invoice_line(osv.osv):
def onchange_account_id(self, cr, uid, ids, product_id, partner_id, inv_type, fposition_id, account_id): def onchange_account_id(self, cr, uid, ids, product_id, partner_id, inv_type, fposition_id, account_id):
if not account_id: if not account_id:
return {} return {}
taxes = self.pool.get('account.account').browse(cr, uid, account_id).tax_ids unique_tax_ids = []
fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes) account = self.pool.get('account.account').browse(cr, uid, account_id)
if not product_id:
product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type, taxes = account.tax_ids
partner_id=partner_id, fposition_id=fposition_id) unique_tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes)
unique_tax_ids = set(tax_ids) else:
if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']: product_change_result = self.product_id_change(cr, uid, ids, product_id, False, type=inv_type,
unique_tax_ids |= set(product_change_result['value']['invoice_line_tax_id']) partner_id=partner_id, fposition_id=fposition_id,
return {'value':{'invoice_line_tax_id': list(unique_tax_ids)}} company_id=account.company_id.id)
if product_change_result and 'value' in product_change_result and 'invoice_line_tax_id' in product_change_result['value']:
unique_tax_ids = product_change_result['value']['invoice_line_tax_id']
return {'value':{'invoice_line_tax_id': unique_tax_ids}}
account_invoice_line() account_invoice_line()
@ -1518,6 +1629,7 @@ class account_invoice_tax(osv.osv):
'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True), 'invoice_id': fields.many2one('account.invoice', 'Invoice Line', ondelete='cascade', select=True),
'name': fields.char('Tax Description', size=64, required=True), 'name': fields.char('Tax Description', size=64, required=True),
'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]), 'account_id': fields.many2one('account.account', 'Tax Account', required=True, domain=[('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]),
'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic account'),
'base': fields.float('Base', digits_compute=dp.get_precision('Account')), 'base': fields.float('Base', digits_compute=dp.get_precision('Account')),
'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
'manual': fields.boolean('Manual'), 'manual': fields.boolean('Manual'),
@ -1572,15 +1684,14 @@ class account_invoice_tax(osv.osv):
company_currency = inv.company_id.currency_id.id company_currency = inv.company_id.currency_id.id
for line in inv.invoice_line: for line in inv.invoice_line:
for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, inv.address_invoice_id.id, line.product_id, inv.partner_id)['taxes']: for tax in tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, (line.price_unit* (1-(line.discount or 0.0)/100.0)), line.quantity, line.product_id, inv.partner_id)['taxes']:
tax['price_unit'] = cur_obj.round(cr, uid, cur, tax['price_unit'])
val={} val={}
val['invoice_id'] = inv.id val['invoice_id'] = inv.id
val['name'] = tax['name'] val['name'] = tax['name']
val['amount'] = tax['amount'] val['amount'] = tax['amount']
val['manual'] = False val['manual'] = False
val['sequence'] = tax['sequence'] val['sequence'] = tax['sequence']
val['base'] = tax['price_unit'] * line['quantity'] val['base'] = cur_obj.round(cr, uid, cur, tax['price_unit'] * line['quantity'])
if inv.type in ('out_invoice','in_invoice'): if inv.type in ('out_invoice','in_invoice'):
val['base_code_id'] = tax['base_code_id'] val['base_code_id'] = tax['base_code_id']
@ -1588,14 +1699,16 @@ class account_invoice_tax(osv.osv):
val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False) val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False) val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['account_id'] = tax['account_collected_id'] or line.account_id.id val['account_id'] = tax['account_collected_id'] or line.account_id.id
val['account_analytic_id'] = tax['account_analytic_collected_id']
else: else:
val['base_code_id'] = tax['ref_base_code_id'] val['base_code_id'] = tax['ref_base_code_id']
val['tax_code_id'] = tax['ref_tax_code_id'] val['tax_code_id'] = tax['ref_tax_code_id']
val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False) val['base_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['base'] * tax['ref_base_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False) val['tax_amount'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, val['amount'] * tax['ref_tax_sign'], context={'date': inv.date_invoice or time.strftime('%Y-%m-%d')}, round=False)
val['account_id'] = tax['account_paid_id'] or line.account_id.id val['account_id'] = tax['account_paid_id'] or line.account_id.id
val['account_analytic_id'] = tax['account_analytic_paid_id']
key = (val['tax_code_id'], val['base_code_id'], val['account_id']) key = (val['tax_code_id'], val['base_code_id'], val['account_id'], val['account_analytic_id'])
if not key in tax_grouped: if not key in tax_grouped:
tax_grouped[key] = val tax_grouped[key] = val
else: else:
@ -1627,12 +1740,11 @@ class account_invoice_tax(osv.osv):
'price': t['amount'] or 0.0, 'price': t['amount'] or 0.0,
'account_id': t['account_id'], 'account_id': t['account_id'],
'tax_code_id': t['tax_code_id'], 'tax_code_id': t['tax_code_id'],
'tax_amount': t['tax_amount'] 'tax_amount': t['tax_amount'],
'account_analytic_id': t['account_analytic_id'],
}) })
return res return res
account_invoice_tax()
class res_partner(osv.osv): class res_partner(osv.osv):
""" Inherits partner and adds invoice information in the partner form """ """ Inherits partner and adds invoice information in the partner form """
@ -1646,6 +1758,14 @@ class res_partner(osv.osv):
default.update({'invoice_ids' : []}) default.update({'invoice_ids' : []})
return super(res_partner, self).copy(cr, uid, id, default, context) return super(res_partner, self).copy(cr, uid, id, default, context)
res_partner()
class mail_compose_message(osv.osv):
_inherit = 'mail.compose.message'
def send_mail(self, cr, uid, ids, context=None):
context = context or {}
if context.get('default_model') == 'account.invoice' and context.get('default_res_id') and context.get('mark_invoice_as_sent'):
self.pool.get('account.invoice').write(cr, uid, [context['default_res_id']], {'sent': True}, context=context)
return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,13 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<!--
Invoices <!-- Invoices -->
-->
<record id="view_invoice_line_calendar" model="ir.ui.view"> <record id="view_invoice_line_calendar" model="ir.ui.view">
<field name="name">account.invoice.calendar</field> <field name="name">account.invoice.calendar</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">calendar</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<calendar string="Invoices" color="journal_id" date_start="date_invoice"> <calendar string="Invoices" color="journal_id" date_start="date_invoice">
<field name="partner_id"/> <field name="partner_id"/>
@ -19,7 +17,6 @@
<record model="ir.ui.view" id="view_invoice_graph"> <record model="ir.ui.view" id="view_invoice_graph">
<field name="name">account.invoice.graph</field> <field name="name">account.invoice.graph</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">graph</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<graph string="Invoices" type="bar"> <graph string="Invoices" type="bar">
<field name="partner_id"/> <field name="partner_id"/>
@ -31,15 +28,14 @@
<record id="view_invoice_line_tree" model="ir.ui.view"> <record id="view_invoice_line_tree" model="ir.ui.view">
<field name="name">account.invoice.line.tree</field> <field name="name">account.invoice.line.tree</field>
<field name="model">account.invoice.line</field> <field name="model">account.invoice.line</field>
<field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Invoice Line"> <tree string="Invoice Line">
<field name="name"/> <field name="name"/>
<field name="account_id" groups="account.group_account_user"/> <field name="account_id" groups="account.group_account_user"/>
<field name="quantity"/> <field name="quantity"/>
<field name="uos_id"/> <field name="uos_id" groups="product.group_uom"/>
<field name="price_unit"/> <field name="price_unit"/>
<field name="discount" groups="base.group_extended"/> <field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="price_subtotal"/> <field name="price_subtotal"/>
</tree> </tree>
</field> </field>
@ -48,25 +44,29 @@
<record id="view_invoice_line_form" model="ir.ui.view"> <record id="view_invoice_line_form" model="ir.ui.view">
<field name="name">account.invoice.line.form</field> <field name="name">account.invoice.line.form</field>
<field name="model">account.invoice.line</field> <field name="model">account.invoice.line</field>
<field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Invoice Line"> <form string="Invoice Line" version="7.0">
<field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, context, parent.company_id)"/> <group>
<field colspan="2" name="name"/> <group>
<label string="Quantity :" align="1.0"/> <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
<group colspan="1" col="2"> <label for="quantity"/>
<field name="quantity" nolabel="1"/> <div>
<field name="uos_id" on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, context, parent.company_id)" nolabel="1"/> <field name="quantity" class="oe_inline"/>
<field name="uos_id" class="oe_inline" groups="product.group_uom"
on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
</div>
<field name="price_unit"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
</group>
<group>
<field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]" name="account_id" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)" groups="account.group_account_user"/>
<field name="invoice_line_tax_id" context="{'type':parent.type}" domain="[('parent_id','=',False),('company_id', '=', parent.company_id)]" widget="many2many_tags"/>
<field domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
</group>
</group> </group>
<field name="price_unit"/> <label for="name"/>
<field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]" name="account_id" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> <field name="name"/>
<field name="discount" groups="base.group_extended"/>
<field domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
<separator string="Notes" colspan="4"/>
<field colspan="4" name="note" nolabel="1"/>
<separator colspan="4" string="Taxes"/>
<field colspan="4" name="invoice_line_tax_id" context="{'type':parent.type}" domain="[('parent_id','=',False),('company_id', '=', parent.company_id)]" nolabel="1"/>
</form> </form>
</field> </field>
</record> </record>
@ -74,7 +74,6 @@
<record id="view_invoice_tax_tree" model="ir.ui.view"> <record id="view_invoice_tax_tree" model="ir.ui.view">
<field name="name">account.invoice.tax.tree</field> <field name="name">account.invoice.tax.tree</field>
<field name="model">account.invoice.tax</field> <field name="model">account.invoice.tax</field>
<field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Manual Invoice Taxes"> <tree string="Manual Invoice Taxes">
<field name="sequence"/> <field name="sequence"/>
@ -90,22 +89,24 @@
<record id="view_invoice_tax_form" model="ir.ui.view"> <record id="view_invoice_tax_form" model="ir.ui.view">
<field name="name">account.invoice.tax.form</field> <field name="name">account.invoice.tax.form</field>
<field name="model">account.invoice.tax</field> <field name="model">account.invoice.tax</field>
<field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Manual Invoice Taxes"> <form string="Manual Invoice Taxes" version="7.0">
<field name="name"/> <group col="4">
<field name="sequence"/> <field name="name"/>
<field name="account_id"/> <field name="sequence"/>
<field name="manual"/> <field name="account_id" groups="account.group_account_user"/>
<field name="amount"/> <field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id)]" groups="analytic.group_analytic_accounting"/>
<field name="base" readonly="0"/> <field name="manual"/>
<separator colspan="4" string="Tax codes"/> <field name="amount"/>
<field name="base_code_id"/> <field name="base" readonly="0"/>
<field name="base_amount"/> <separator colspan="4" string="Tax Codes"/>
<field name="tax_code_id"/> <field name="base_code_id"/>
<field name="tax_amount"/> <field name="base_amount"/>
<field name="factor_base" invisible="True"/> <field name="tax_code_id"/>
<field name="factor_tax" invisible="True"/> <field name="tax_amount"/>
<field name="factor_base" invisible="True"/>
<field name="factor_tax" invisible="True"/>
</group>
</form> </form>
</field> </field>
</record> </record>
@ -113,12 +114,11 @@
<record id="invoice_tree" model="ir.ui.view"> <record id="invoice_tree" model="ir.ui.view">
<field name="name">account.invoice.tree</field> <field name="name">account.invoice.tree</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree colors="blue:state == 'draft';black:state in ('proforma','proforma2','open');gray:state == 'cancel'" string="Invoice"> <tree colors="blue:state == 'draft';black:state in ('proforma','proforma2','open');gray:state == 'cancel'" string="Invoice">
<field name="partner_id" groups="base.group_user"/>
<field name="date_invoice"/> <field name="date_invoice"/>
<field name="number"/> <field name="number"/>
<field name="partner_id" groups="base.group_user"/>
<field name="reference" invisible="1"/> <field name="reference" invisible="1"/>
<field name="name" invisible="1"/> <field name="name" invisible="1"/>
<field name="journal_id" invisible="1"/> <field name="journal_id" invisible="1"/>
@ -127,13 +127,11 @@
<field name="user_id"/> <field name="user_id"/>
<field name="date_due"/> <field name="date_due"/>
<field name="origin"/> <field name="origin"/>
<field name="currency_id"/> <field name="currency_id" groups="base.group_multi_currency"/>
<field name="residual" sum="Residual Amount"/> <field name="residual" sum="Residual Amount"/>
<field name="amount_untaxed" sum="Untaxed Amount"/> <field name="amount_untaxed" sum="Untaxed Amount"/>
<field name="amount_total" sum="Total Amount"/> <field name="amount_total" sum="Total Amount"/>
<field name="state"/> <field name="state"/>
<button name="invoice_open" states="draft,proforma2" string="Approve" icon="terp-camera_test"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -141,52 +139,97 @@
<record id="invoice_supplier_form" model="ir.ui.view"> <record id="invoice_supplier_form" model="ir.ui.view">
<field name="name">account.invoice.supplier.form</field> <field name="name">account.invoice.supplier.form</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">form</field>
<field name="priority">2</field> <field name="priority">2</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Supplier Invoice"> <form string="Supplier Invoice" version="7.0">
<group col="8" colspan="4"> <header>
<field name="journal_id" on_change="onchange_journal_id(journal_id)" widget="selection"/> <button name="invoice_open" states="draft,proforma2" string="Validate" class="oe_highlight" groups="account.group_account_invoice"/>
<field name="number" readonly="1"/> <button name="%(action_account_invoice_refund)d" type='action' string='Ask Refund' states='open,paid' groups="account.group_account_invoice"/>
<field name="type" invisible="1"/> <button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" groups="base.group_no_one"/>
<field name="currency_id" width="50"/> <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" groups="account.group_account_invoice"/>
<button name="%(action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" groups="account.group_account_user"/> <button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
<newline/> <field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
<field string="Supplier" name="partner_id" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}" options='{"quick_create": false}' domain="[('supplier', '=', True)]"/> </header>
<field domain="[('partner_id','=',partner_id)]" name="address_invoice_id" context="{'default_partner_id': partner_id}" options='{"quick_create": false}'/> <sheet string="Supplier Invoice">
<field name="fiscal_position" groups="base.group_extended" widget="selection"/> <div class="oe_title">
<newline/> <h1>
<field name="date_invoice"/> <label string="Draft Invoice" attrs="{'invisible': ['|',('state','&lt;&gt;','draft'), ('type','&lt;&gt;','in_invoice')]}"/>
<field name="period_id" domain="[('state', '=', 'draft')]" groups="account.group_account_user" widget="selection"/> <label string="Draft Refund" attrs="{'invisible': ['|',('state','&lt;&gt;','draft'), ('type','&lt;&gt;','in_refund')]}"/>
<group colspan="2" col="1" groups="account.group_account_user"> <label string="Invoice" attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','&lt;&gt;','in_invoice')]}"/>
<label align="0.0" string="(keep empty to use the current period)"/> <label string="Refund" attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','&lt;&gt;','in_refund')]}"/>
<field name="number" class="oe_inline" attrs="{'invisible': [('state', '=', 'draft')]}"/>
</h1>
</div>
<field name="type" invisible="1"/>
<group>
<group>
<field string="Supplier" name="partner_id"
on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)"
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"
domain="[('supplier', '=', True)]"/>
<field name="fiscal_position" widget="selection"/>
<field name="origin"/>
<field name="supplier_invoice_number"/>
<label for="reference_type"/>
<div>
<field name="reference_type" class="oe_inline oe_edit_only"/>
<field name="reference" class="oe_inline"/>
</div>
</group>
<group>
<field name="date_invoice"/>
<field name="date_due"/>
<field domain="[('company_id', '=', company_id), ('type', '=', 'payable')]"
name="account_id" groups="account.group_account_user"/>
<field name="journal_id" groups="account.group_account_user"
on_change="onchange_journal_id(journal_id, context)" widget="selection"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="check_total" groups="account.group_supplier_inv_check_total"/>
</group> </group>
</group> </group>
<notebook colspan="4"> <notebook>
<page string="Invoice"> <page string="Invoice">
<field domain="[('company_id', '=', company_id), ('type', '=', 'payable')]" name="account_id" groups="account.group_account_user"/> <field context="{'partner_id': partner_id, 'price_type': context.get('price_type') or False, 'type': type}" name="invoice_line">
<field name="reference_type" nolabel="1" size="0"/> <tree string="Invoice lines" editable="bottom">
<field name="reference" nolabel="1"/> <field name="product_id"
<field name="date_due"/> on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
<field colspan="4" context="{'address_invoice_id': address_invoice_id, 'partner_id': partner_id, 'price_type': 'price_type' in dir() and price_type or False, 'type': type}" name="invoice_line" nolabel="1"> <field name="name"/>
<tree string="Invoice lines"> <field name="company_id" groups="base.group_multi_company" readonly="1"/>
<field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.address_invoice_id, parent.currency_id, context, parent.company_id)"/> <field name="account_id" groups="account.group_account_user"
<field domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]" name="account_id" on_change="onchange_account_id(product_id,parent.partner_id,parent.type,parent.fiscal_position,account_id)"/> domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '!=', 'view')]"
<field name="invoice_line_tax_id" view_mode="2" context="{'type':parent.type}" domain="[('parent_id','=',False)]"/> on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/>
<field domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/> <field name="account_analytic_id" groups="analytic.group_analytic_accounting"
domain="[('type','!=','view'), ('company_id', '=', parent.company_id)]"/>
<field name="quantity"/> <field name="quantity"/>
<field name="uos_id" groups="product.group_uom"
on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
<field name="price_unit"/> <field name="price_unit"/>
<!-- Removed if subtotal is set --> <field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="invoice_line_tax_id" widget="many2many_tags" context="{'type':parent.type}"
domain="[('parent_id','=',False),('company_id', '=', parent.company_id)]"/>
<field name="price_subtotal"/> <field name="price_subtotal"/>
<field invisible="True" name="name"/>
<field invisible="True" name="uos_id"/>
</tree> </tree>
</field> </field>
<group col="1" colspan="2"> <group class="oe_subtotal_footer oe_right">
<field name="tax_line" nolabel="1"> <field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<div>
<label for="amount_tax"/>
<button name="button_reset_taxes" states="draft,proforma2"
string="(update)" class="oe_link oe_edit_only"
type="object" help="Recompute taxes and total"/>
</div>
<field name="amount_tax" nolabel="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="amount_total" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="residual" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="reconciled" invisible="1"/>
</group>
<div style="width: 50%%">
<field name="tax_line">
<tree editable="bottom" string="Taxes"> <tree editable="bottom" string="Taxes">
<field name="name"/> <field name="name"/>
<field name="account_id" groups="account.group_account_invoice"/> <field name="account_id" groups="account.group_account_invoice"/>
<field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id)]" groups="analytic.group_analytic_accounting"/>
<field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/> <field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/>
<field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/> <field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/>
@ -196,55 +239,48 @@
<field name="factor_tax" invisible="True"/> <field name="factor_tax" invisible="True"/>
</tree> </tree>
</field> </field>
</group> </div>
<group col="4" colspan="2"> <div class="oe_clear">
<button colspan="2" name="button_reset_taxes" states="draft" string="Compute Taxes" type="object" icon="terp-stock_format-scientific" help="This action will erase taxes"/> <label for="comment"/>
<field name="amount_untaxed"/> </div>
<label string="" colspan="2"/> <field name="comment"/>
<field name="amount_tax"/> </page>
<field name="reconciled"/> <page string="Other Info">
<field name="amount_total"/> <group>
<field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/> <group>
<field name="residual"/> <field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/>
<group col="6" colspan="4"> <field name="user_id"/>
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" icon="gtk-cancel" groups="base.group_no_one"/> <field name="name" invisible="1"/>
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="terp-stock_effects-object-colorize"/> <field name="payment_term" widget="selection"/>
<button name="%(action_account_invoice_refund)d" type='action' string='Refund' states='open,paid' icon="gtk-execute"/> </group>
<button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" icon="gtk-convert" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/> <group>
<button name="invoice_open" states="draft,proforma2" string="Approve" icon="terp-camera_test"/> <field name="move_id" groups="account.group_account_user"/>
<field name="period_id" domain="[('state', '=', 'draft')]" groups="account.group_account_user" widget="selection"/>
<field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/>
</group> </group>
</group> </group>
</page> </page>
<page string="Other Info"> <page string="Payments">
<field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/> <field name="payment_ids">
<field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/>
<newline/>
<field name="payment_term" widget="selection"/>
<field name="name"/>
<newline/>
<field name="origin" groups="base.group_extended"/>
<field domain="[('partner_id','=',partner_id)]" name="address_contact_id" groups="base.group_extended"/>
<field name="user_id"/>
<field name="move_id" groups="account.group_account_user"/>
<separator colspan="4" string="Additional Information"/>
<field colspan="4" name="comment" nolabel="1"/>
</page>
<page string="Payments" groups="base.group_extended">
<field name="payment_ids" colspan="4" nolabel="1" >
<tree string="Payments"> <tree string="Payments">
<field name="date" string="Payment Date"/> <field name="date" string="Payment Date"/>
<field name="move_id"/> <field name="move_id"/>
<field name="ref"/> <field name="ref"/>
<field name="name" groups="base.group_extended"/> <field name="name"/>
<field name="journal_id"/> <field name="journal_id"/>
<field name="debit"/> <field name="debit"/>
<field name="credit"/> <field name="credit"/>
<field name="amount_currency" groups="base.group_extended"/> <field name="amount_currency"/>
<field name="currency_id" groups="base.group_extended"/> <field name="currency_id" groups="base.group_multi_currency"/>
</tree> </tree>
</field> </field>
</page> </page>
</notebook> </notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form> </form>
</field> </field>
</record> </record>
@ -252,83 +288,137 @@
<record id="invoice_form" model="ir.ui.view"> <record id="invoice_form" model="ir.ui.view">
<field name="name">account.invoice.form</field> <field name="name">account.invoice.form</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Invoice"> <form string="Invoice" version="7.0">
<group colspan="4" col="8"> <header>
<field name="journal_id" groups="base.group_user" on_change="onchange_journal_id(journal_id, context)" widget="selection"/> <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight" groups="base.group_user"/>
<field name="number"/> <button name="invoice_print" string="Print" type="object" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight" groups="base.group_user"/>
<button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}" groups="base.group_user"/>
<button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}" groups="base.group_user"/>
<button name="invoice_open" states="draft" string="Validate" class="oe_highlight" groups="base.group_user"/>
<button name="invoice_open" states="proforma2" string="Validate" groups="base.group_user"/>
<button name="invoice_proforma2" states="draft" string="PRO-FORMA" groups="account.group_proforma_invoices"/>
<button name="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='open,proforma2,paid' groups="base.group_user"/>
<button name="invoice_cancel" states="draft,proforma2,open" string="Cancel" groups="base.group_no_one"/>
<button name="action_cancel_draft" states="cancel" string="Reset to Draft" type="object" groups="base.group_user"/>
<button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
<!--button name="%(account_invoices)d" string="Print Invoice" type="action" states="open,paid,proforma,sale,proforma2"/-->
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
</header>
<sheet string="Invoice">
<h1>
<label string="Draft Invoice " attrs="{'invisible': ['|',('state','not in',('draft',)), ('type','&lt;&gt;','out_invoice')]}"/>
<label string="Draft Refund " attrs="{'invisible': ['|',('state','not in',('draft',)), ('type','&lt;&gt;','out_refund')]}"/>
<label string="Pro Forma Invoice " attrs="{'invisible': [('state','not in',('proforma','proforma2'))]}"/>
<label string="Invoice " attrs="{'invisible': ['|',('state','in',('draft','proforma','proforma2')), ('type','&lt;&gt;','out_invoice')]}"/>
<label string="Refund " attrs="{'invisible': ['|',('state','in',('draft','proforma','proforma2')), ('type','&lt;&gt;','out_refund')]}"/>
<field name="number" readonly="1" class="oe_inline"/>
</h1>
<field name="type" invisible="1"/> <field name="type" invisible="1"/>
<field name="currency_id" width="50"/> <group>
<button name="%(action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" groups="account.group_account_user"/> <group>
<newline/> <field string="Customer" name="partner_id"
<field string="Customer" name="partner_id" on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)" groups="base.group_user" context="{'search_default_customer': 1}" options='{"quick_create": false}' domain="[('customer', '=', True)]"/> on_change="onchange_partner_id(type,partner_id,date_invoice,payment_term, partner_bank_id,company_id)"
<field domain="[('partner_id','=',partner_id)]" name="address_invoice_id" context="{'default_partner_id': partner_id}" options='{"quick_create": false}'/> groups="base.group_user" context="{'search_default_customer':1, 'show_address': 1}"
<field name="fiscal_position" groups="base.group_extended" widget="selection" options='{"quick_create": false}'/> options='{"always_reload": True}'/>
<newline/> <field name="fiscal_position" widget="selection" />
<field name="date_invoice"/> </group>
<field name="period_id" domain="[('state', '=', 'draft')]" groups="account.group_account_user" widget="selection"/> <group>
<field name="payment_term" widget="selection"/> <field name="date_invoice"/>
<newline/> <field name="journal_id" groups="account.group_account_user"
<field domain="[('company_id', '=', company_id),('type','=', 'receivable')]" name="account_id" groups="account.group_account_user"/> on_change="onchange_journal_id(journal_id, context)" widget="selection"/>
<field name="name" groups="base.group_extended"/> <field domain="[('company_id', '=', company_id),('type','=', 'receivable')]"
name="account_id" groups="account.group_account_user"/>
<label for="currency_id" groups="base.group_multi_currency"/>
<div groups="base.group_multi_currency">
<field name="currency_id" class="oe_inline"/>
<!-- note fp: I don't think we need this feature ?
<button name="%(action_account_change_currency)d" type="action"
icon="terp-stock_effects-object-colorize"
attrs="{'invisible':[('state','!=','draft')]}"
groups="account.group_account_user"/> -->
</div>
</group>
</group> </group>
<field name="sent" invisible="1"/>
<notebook colspan="4"> <notebook colspan="4">
<page string="Invoice"> <page string="Invoice Lines">
<field colspan="4" name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}"/> <field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}">
<group col="1" colspan="2"> <tree string="Invoice Lines" editable="bottom">
<field name="tax_line" nolabel="1"> <field name="product_id"
<tree editable="bottom" string="Taxes"> on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
<field name="name"/> <field name="name"/>
<field name="account_id" groups="account.group_account_invoice"/> <field name="company_id" groups="base.group_multi_company" readonly="1"/>
<field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/> <field name="account_id" groups="account.group_account_user"
<field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/> domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '!=', 'view')]"
<field invisible="True" name="base_amount"/> on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/>
<field invisible="True" name="tax_amount"/> <field name="account_analytic_id" groups="analytic.group_analytic_accounting"
<field name="factor_base" invisible="True"/> domain="[('type','!=','view'), ('company_id', '=', parent.company_id)]"/>
<field name="factor_tax" invisible="True"/> <field name="quantity"/>
</tree> <field name="uos_id" groups="product.group_uom"
</field> on_change="uos_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
<field name="price_unit"/>
<field name="discount" groups="sale.group_discount_per_so_line"/>
<field name="invoice_line_tax_id" widget="many2many_tags" context="{'type':parent.type}"
domain="[('parent_id','=',False),('company_id', '=', parent.company_id)]"/>
<field name="price_subtotal"/>
</tree>
</field>
<group class="oe_subtotal_footer oe_right">
<field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<div>
<label for="amount_tax"/>
<button name="button_reset_taxes" states="draft,proforma2"
string="(update)" class="oe_link oe_edit_only"
type="object" help="Recompute taxes and total"/>
</div>
<field name="amount_tax" nolabel="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="amount_total" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="residual" groups="account.group_account_user" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="reconciled" invisible="1"/>
</group> </group>
<group col="4" colspan="2"> <group>
<group colspan="2" col="1"> <field name="payment_term" class="oe_inline"/>
<button name="button_reset_taxes" states="draft,proforma2" string="Compute Taxes" type="object" groups="base.group_user" icon="terp-stock_format-scientific" help="This action will erase taxes"/>
</group>
<field name="amount_untaxed"/>
<label string="" colspan="2"/>
<field name="amount_tax"/>
<field name="reconciled"/>
<field name="amount_total"/>
<field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
<field name="residual"/>
<group col="8" colspan="4" groups="base.group_user">
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" icon="gtk-cancel" groups="base.group_no_one"/>
<button name="action_cancel_draft" states="cancel" string="Reset to Draft" type="object" icon="terp-stock_effects-object-colorize"/>
<button name='%(action_account_state_open)d' type='action' string='Re-Open' groups="account.group_account_invoice" attrs="{'invisible':['|', ('state','&lt;&gt;','paid'), ('reconciled', '=', True)]}" icon="gtk-convert" help="This button only appears when the state of the invoice is 'paid' (showing that it has been fully reconciled) and auto-computed boolean 'reconciled' is False (depicting that it's not the case anymore). In other words, the invoice has been dereconciled and it does not fit anymore the 'paid' state. You should press this button to re-open it and let it continue its normal process after having resolved the eventual exceptions it may have created."/>
<button name="%(action_account_invoice_refund)d" type='action' string='Refund' states='open,paid' icon="gtk-execute"/>
<button name="invoice_proforma2" states="draft" string="PRO-FORMA" icon="terp-gtk-media-pause" groups="account.group_account_user"/>
<button name="invoice_open" states="draft,proforma2" string="Validate" icon="gtk-go-forward"/>
<button name="%(account_invoices)d" string="Print Invoice" type="action" icon="gtk-print" states="open,paid,proforma,sale,proforma2"/>
</group>
</group> </group>
<div class="oe_clear">
<label for="comment"/>
</div>
<field name="comment" class="oe_inline" placeholder="Additional notes..."/>
</page> </page>
<page string="Other Info"> <page string="Other Info">
<field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/> <group col="4">
<newline/> <group>
<field name="date_due"/> <field name="company_id" on_change="onchange_company_id(company_id,partner_id,type,invoice_line,currency_id)" widget="selection" groups="base.group_multi_company"/>
<field name="user_id"/> <field name="user_id" groups="base.group_user"/>
<newline/> <field domain="[('partner_id.ref_companies', 'in', [company_id])]" name="partner_bank_id"/>
<field domain="[('partner_id.ref_companies', 'in', [company_id])]" name="partner_bank_id" <field name="period_id" domain="[('state', '=', 'draft')]"
groups="base.group_extended"/> groups="account.group_account_manager"
<field name="origin"/> string="Accounting Period"
<field colspan="4" domain="[('partner_id','=',partner_id)]" name="address_contact_id" placeholder="force period"/>
groups="base.group_extended"/> <field name="date_due"/>
<field name="move_id" groups="account.group_account_user"/> </group>
<separator colspan="4" string="Additional Information"/> <group>
<field colspan="4" name="comment" nolabel="1"/> <field name="origin" groups="base.group_user"/>
<field name="name" string="Customer Reference"/>
<field name="move_id" groups="account.group_account_user"/>
</group>
</group>
<field name="tax_line">
<tree editable="bottom" string="Taxes">
<field name="name"/>
<field name="account_id" groups="account.group_account_user"/>
<field name="base" on_change="base_change(base,parent.currency_id,parent.company_id,parent.date_invoice)" readonly="1"/>
<field name="amount" on_change="amount_change(amount,parent.currency_id,parent.company_id,parent.date_invoice)"/>
<field invisible="True" name="base_amount"/>
<field invisible="True" name="tax_amount"/>
<field name="factor_base" invisible="True"/>
<field name="factor_tax" invisible="True"/>
</tree>
</field>
</page> </page>
<page string="Payments"> <page string="Payments" groups="base.group_user">
<field name="payment_ids" colspan="4" nolabel="1"> <field name="payment_ids">
<tree string="Payments"> <tree string="Payments">
<field name="date"/> <field name="date"/>
<field name="move_id"/> <field name="move_id"/>
@ -337,12 +427,17 @@
<field name="journal_id" groups="base.group_user"/> <field name="journal_id" groups="base.group_user"/>
<field name="debit"/> <field name="debit"/>
<field name="credit"/> <field name="credit"/>
<field name="amount_currency"/> <field name="amount_currency" groups="base.group_multi_currency"/>
<field name="currency_id"/> <field name="currency_id" groups="base.group_multi_currency"/>
</tree> </tree>
</field> </field>
</page> </page>
</notebook> </notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div>
</form> </form>
</field> </field>
</record> </record>
@ -350,37 +445,23 @@
<record id="view_account_invoice_filter" model="ir.ui.view"> <record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account.invoice.select</field> <field name="name">account.invoice.select</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="type">search</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Invoice"> <search string="Search Invoice">
<group> <field name="number" string="Invoice" filter_domain="['|','|', ('number','ilike',self), ('origin','ilike',self), ('supplier_invoice_number', 'ilike', self)]"/>
<filter name="draft" icon="terp-document-new" string="Draft" domain="[('state','=','draft')]" help="Draft Invoices"/> <filter name="draft" icon="terp-document-new" string="Draft" domain="[('state','=','draft')]" help="Draft Invoices"/>
<filter name="proforma" icon="terp-gtk-media-pause" string="Proforma" domain="[('state','=','proforma2')]" help="Proforma Invoices"/> <filter name="proforma" icon="terp-gtk-media-pause" string="Proforma" domain="[('state','=','proforma2')]" help="Proforma Invoices" groups="account.group_proforma_invoices"/>
<filter name="invoices" icon="terp-dolar" string="Invoices" domain="[('state','not in',['draft','cancel'])]" help="Proforma/Open/Paid Invoices"/> <filter name="invoices" icon="terp-dolar" string="Invoices" domain="[('state','not in',['draft','cancel'])]" help="Proforma/Open/Paid Invoices"/>
<separator orientation="vertical"/> <filter name="unpaid" icon="terp-dolar_ok!" string="Unpaid" domain="[('state','=','open')]" help="Unpaid Invoices"/>
<filter name="unpaid" icon="terp-dolar_ok!" string="Unpaid" domain="[('state','=','open')]" help="Unpaid Invoices"/> <separator/>
<separator orientation="vertical"/> <filter domain="[('user_id','=',uid)]" help="My Invoices" icon="terp-personal"/>
<field name="number" <field name="partner_id"/>
string="Reference" <field name="user_id" string="Salesperson"/>
filter_domain="['|', ('number','ilike',self),('origin','ilike',self)]"/> <field name="period_id" string="Period"/>
<field name="partner_id"/>
<field name="user_id" widget="selection" string="Salesman">
<filter domain="[('user_id','=',uid)]" help="My invoices" icon="terp-personal" />
</field>
</group>
<newline/>
<group>
<field name="journal_id" widget="selection"/>
<field name="period_id" string="Period"/>
</group>
<newline/>
<group expand="0" string="Group By..."> <group expand="0" string="Group By...">
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/> <filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/> <filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<separator orientation="vertical"/>
<filter string="Journal" icon="terp-folder-orange" domain="[]" context="{'group_by':'journal_id'}"/> <filter string="Journal" icon="terp-folder-orange" domain="[]" context="{'group_by':'journal_id'}"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/> <filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
<separator orientation="vertical"/>
<filter string="Period" icon="terp-go-month" domain="[]" context="{'group_by':'period_id'}"/> <filter string="Period" icon="terp-go-month" domain="[]" context="{'group_by':'period_id'}"/>
<filter string="Invoice Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_invoice'}"/> <filter string="Invoice Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_invoice'}"/>
<filter string="Due Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_due'}"/> <filter string="Due Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_due'}"/>
@ -432,7 +513,19 @@
<field name="domain">[('type','=','out_invoice')]</field> <field name="domain">[('type','=','out_invoice')]</field>
<field name="context">{'default_type':'out_invoice', 'type':'out_invoice', 'journal_type': 'sale'}</field> <field name="context">{'default_type':'out_invoice', 'type':'out_invoice', 'journal_type': 'sale'}</field>
<field name="search_view_id" ref="view_account_invoice_filter"/> <field name="search_view_id" ref="view_account_invoice_filter"/>
<field name="help">With Customer Invoices you can create and manage sales invoices issued to your customers. OpenERP can also generate draft invoices automatically from sales orders or deliveries. You should only confirm them before sending them to your customers.</field> <field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a customer invoice.
</p><p>
OpenERP's electronic invoicing allows to ease and fasten the
collection of customer payments. Your customer receives the
invoice by email and he can pay online and/or import it
in his own system.
</p><p>
The discussions with your customer are automatically displayed at
the bottom of each invoice.
</p>
</field>
</record> </record>
@ -460,7 +553,15 @@
<field name="domain">[('type','=','in_invoice')]</field> <field name="domain">[('type','=','in_invoice')]</field>
<field name="context">{'default_type': 'in_invoice', 'type': 'in_invoice', 'journal_type': 'purchase'}</field> <field name="context">{'default_type': 'in_invoice', 'type': 'in_invoice', 'journal_type': 'purchase'}</field>
<field name="search_view_id" ref="view_account_invoice_filter"/> <field name="search_view_id" ref="view_account_invoice_filter"/>
<field name="help">With Supplier Invoices you can enter and manage invoices issued by your suppliers. OpenERP can also generate draft invoices automatically from purchase orders or receipts. This way, you can control the invoice from your supplier according to what you purchased or received.</field> <field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to record a new supplier invoice.
</p><p>
You can control the invoice from your supplier according to
what you purchased or received. OpenERP can also generate
draft invoices automatically from purchase orders or receipts.
</p>
</field>
</record> </record>
<menuitem action="action_invoice_tree2" id="menu_action_invoice_tree2" parent="menu_finance_payables"/> <menuitem action="action_invoice_tree2" id="menu_action_invoice_tree2" parent="menu_finance_payables"/>
@ -473,7 +574,17 @@
<field name="domain">[('type','=','out_refund')]</field> <field name="domain">[('type','=','out_refund')]</field>
<field name="context">{'default_type':'out_refund', 'type':'out_refund', 'journal_type': 'sale_refund'}</field> <field name="context">{'default_type':'out_refund', 'type':'out_refund', 'journal_type': 'sale_refund'}</field>
<field name="search_view_id" ref="view_account_invoice_filter"/> <field name="search_view_id" ref="view_account_invoice_filter"/>
<field name="help">With Customer Refunds you can manage the credit notes for your customers. A refund is a document that credits an invoice completely or partially. You can easily generate refunds and reconcile them directly from the invoice form.</field> <field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a customer refund.
</p><p>
A refund is a document that credits an invoice completely or
partially.
</p><p>
Instead of manually creating a customer refund, you
can generate it directly from the related customer invoice.
</p>
</field>
</record> </record>
<record id="action_invoice_tree3_view1" model="ir.actions.act_window.view"> <record id="action_invoice_tree3_view1" model="ir.actions.act_window.view">
@ -499,7 +610,14 @@
<field name="domain">[('type','=','in_refund')]</field> <field name="domain">[('type','=','in_refund')]</field>
<field name="context">{'default_type': 'in_refund', 'type': 'in_refund', 'journal_type': 'purchase_refund'}</field> <field name="context">{'default_type': 'in_refund', 'type': 'in_refund', 'journal_type': 'purchase_refund'}</field>
<field name="search_view_id" ref="view_account_invoice_filter"/> <field name="search_view_id" ref="view_account_invoice_filter"/>
<field name="help">With Supplier Refunds you can manage the credit notes you receive from your suppliers. A refund is a document that credits an invoice completely or partially. You can easily generate refunds and reconcile them directly from the invoice form.</field> <field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to register a refund you received from a supplier.
</p><p>
Instead of creating the supplier refund manually, you can generate
refunds and reconcile them directly from the related supplier invoice.
</p>
</field>
</record> </record>
<menuitem action="action_invoice_tree4" id="menu_action_invoice_tree4" parent="menu_finance_payables"/> <menuitem action="action_invoice_tree4" id="menu_action_invoice_tree4" parent="menu_finance_payables"/>

View File

@ -27,7 +27,7 @@
<field name="action">action_date_assign() <field name="action">action_date_assign()
action_move_create() action_move_create()
action_number() action_number()
write({'state':'open'})</field> invoice_validate()</field>
<field name="kind">function</field> <field name="kind">function</field>
</record> </record>
<record model="workflow.activity" id="act_open_test"> <record model="workflow.activity" id="act_open_test">

View File

@ -2,10 +2,12 @@
<openerp> <openerp>
<data> <data>
<menuitem icon="terp-account" id="menu_finance" name="Accounting" sequence="13" <!-- Top menu item -->
<menuitem name="Invoicing"
id="menu_finance"
groups="group_account_user,group_account_manager,group_account_invoice" groups="group_account_user,group_account_manager,group_account_invoice"
web_icon="images/accounting.png" sequence="50"/>
web_icon_hover="images/accounting-hover.png"/>
<menuitem id="menu_finance_receivables" name="Customers" parent="menu_finance" sequence="2"/> <menuitem id="menu_finance_receivables" name="Customers" parent="menu_finance" sequence="2"/>
<menuitem id="menu_finance_payables" name="Suppliers" parent="menu_finance" sequence="3"/> <menuitem id="menu_finance_payables" name="Suppliers" parent="menu_finance" sequence="3"/>
<menuitem id="menu_finance_bank_and_cash" name="Bank and Cash" parent="menu_finance" sequence="4" <menuitem id="menu_finance_bank_and_cash" name="Bank and Cash" parent="menu_finance" sequence="4"
@ -28,23 +30,21 @@
<menuitem id="menu_analytic" parent="menu_analytic_accounting" name="Accounts" groups="analytic.group_analytic_accounting"/> <menuitem id="menu_analytic" parent="menu_analytic_accounting" name="Accounts" groups="analytic.group_analytic_accounting"/>
<menuitem id="menu_journals" sequence="15" name="Journals" parent="menu_finance_configuration" groups="group_account_manager"/> <menuitem id="menu_journals" sequence="15" name="Journals" parent="menu_finance_configuration" groups="group_account_manager"/>
<menuitem id="menu_configuration_misc" name="Miscellaneous" parent="menu_finance_configuration" sequence="55"/> <menuitem id="menu_configuration_misc" name="Miscellaneous" parent="menu_finance_configuration" sequence="55"/>
<menuitem id="base.menu_action_currency_form" parent="menu_configuration_misc" sequence="20" groups="base.group_no_one"/> <menuitem id="base.menu_action_currency_form" name="Currencies" parent="menu_configuration_misc" sequence="20" groups="base.group_no_one"/>
<menuitem id="menu_finance_generic_reporting" name="Generic Reporting" parent="menu_finance_reports" sequence="100"/> <menuitem id="menu_finance_generic_reporting" name="Generic Reporting" parent="menu_finance_reports" sequence="100"/>
<menuitem id="menu_finance_entries" name="Journal Entries" parent="menu_finance" sequence="5" groups="group_account_user,group_account_manager"/> <menuitem id="menu_finance_entries" name="Journal Entries" parent="menu_finance" sequence="5" groups="group_account_user,group_account_manager"/>
<menuitem id="menu_account_reports" name="Financial Reports" parent="menu_finance_configuration" sequence="30" /> <menuitem id="menu_account_reports" name="Financial Reports" parent="menu_finance_configuration" sequence="30" />
<menuitem id="account.menu_finance_recurrent_entries" name="Recurring Entries" <menuitem id="account.menu_finance_recurrent_entries" name="Recurring Entries"
parent="menu_finance_periodical_processing" sequence="15" parent="menu_finance_periodical_processing" sequence="15"/>
groups="base.group_extended"/>
<menuitem id="menu_account_end_year_treatments" <menuitem id="menu_account_end_year_treatments"
name="End of Period" parent="menu_finance_periodical_processing" name="End of Period" parent="menu_finance_periodical_processing"
sequence="25"/> sequence="25"/>
<menuitem id="menu_finance_periodical_processing_billing" name="Billing" parent="menu_finance_periodical_processing" sequence="35"/> <menuitem id="menu_finance_periodical_processing_billing" name="Billing" parent="menu_finance_periodical_processing" sequence="35"/>
<menuitem id="menu_finance_statistic_report_statement" name="Statistic Reports" parent="menu_finance_reporting" sequence="300"/>
<menuitem id="next_id_22" name="Partners" parent="menu_finance_generic_reporting" sequence="1"/> <menuitem id="next_id_22" name="Partners" parent="menu_finance_generic_reporting" sequence="1"/>
<menuitem id="menu_multi_currency" name="Multi-Currencies" parent="menu_finance_generic_reporting" sequence="10"/> <menuitem id="menu_multi_currency" name="Multi-Currencies" parent="menu_finance_generic_reporting" sequence="10" groups="base.group_multi_currency"/>
<menuitem <menuitem
parent="account.menu_finance_legal_statement" parent="account.menu_finance_legal_statement"
id="final_accounting_reports" id="final_accounting_reports"

View File

@ -19,6 +19,7 @@
# #
############################################################################## ##############################################################################
import sys
import time import time
from datetime import datetime from datetime import datetime
from operator import itemgetter from operator import itemgetter
@ -94,7 +95,7 @@ class account_move_line(osv.osv):
if initial_bal and not context.get('periods', False) and not where_move_lines_by_date: if initial_bal and not context.get('periods', False) and not where_move_lines_by_date:
#we didn't pass any filter in the context, and the initial balance can't be computed using only the fiscalyear otherwise entries will be summed twice #we didn't pass any filter in the context, and the initial balance can't be computed using only the fiscalyear otherwise entries will be summed twice
#so we have to invalidate this query #so we have to invalidate this query
raise osv.except_osv(_('Warning !'),_("You haven't supplied enough argument to compute the initial balance, please select a period and journal in the context.")) raise osv.except_osv(_('Warning!'),_("You have not supplied enough arguments to compute the initial balance, please select a period and a journal in the context."))
if context.get('journal_ids', False): if context.get('journal_ids', False):
@ -165,28 +166,35 @@ class account_move_line(osv.osv):
del data[f] del data[f]
return data return data
def _prepare_analytic_line(self, cr, uid, obj_line, context=None):
"""
Prepare the values given at the create() of account.analytic.line upon the validation of a journal item having
an analytic account. This method is intended to be extended in other modules.
:param obj_line: browse record of the account.move.line that triggered the analytic line creation
"""
return {'name': obj_line.name,
'date': obj_line.date,
'account_id': obj_line.analytic_account_id.id,
'unit_amount': obj_line.quantity,
'product_id': obj_line.product_id and obj_line.product_id.id or False,
'product_uom_id': obj_line.product_uom_id and obj_line.product_uom_id.id or False,
'amount': (obj_line.credit or 0.0) - (obj_line.debit or 0.0),
'general_account_id': obj_line.account_id.id,
'journal_id': obj_line.journal_id.analytic_journal_id.id,
'ref': obj_line.ref,
'move_id': obj_line.id,
'user_id': uid,
}
def create_analytic_lines(self, cr, uid, ids, context=None): def create_analytic_lines(self, cr, uid, ids, context=None):
acc_ana_line_obj = self.pool.get('account.analytic.line') acc_ana_line_obj = self.pool.get('account.analytic.line')
for obj_line in self.browse(cr, uid, ids, context=context): for obj_line in self.browse(cr, uid, ids, context=context):
if obj_line.analytic_account_id: if obj_line.analytic_account_id:
if not obj_line.journal_id.analytic_journal_id: if not obj_line.journal_id.analytic_journal_id:
raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (obj_line.journal_id.name, )) raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (obj_line.journal_id.name, ))
amt = (obj_line.credit or 0.0) - (obj_line.debit or 0.0) vals_line = self._prepare_analytic_line(cr, uid, obj_line, context=context)
vals_lines = { acc_ana_line_obj.create(cr, uid, vals_line)
'name': obj_line.name,
'date': obj_line.date,
'account_id': obj_line.analytic_account_id.id,
'unit_amount': obj_line.quantity,
'product_id': obj_line.product_id and obj_line.product_id.id or False,
'product_uom_id': obj_line.product_uom_id and obj_line.product_uom_id.id or False,
'amount': amt,
'general_account_id': obj_line.account_id.id,
'journal_id': obj_line.journal_id.analytic_journal_id.id,
'ref': obj_line.ref,
'move_id': obj_line.id,
'user_id': uid
}
acc_ana_line_obj.create(cr, uid, vals_lines)
return True return True
def _default_get_move_form_hook(self, cursor, user, data): def _default_get_move_form_hook(self, cursor, user, data):
@ -207,15 +215,16 @@ class account_move_line(osv.osv):
if type(period_id) == str: if type(period_id) == str:
ids = period_obj.search(cr, uid, [('name', 'ilike', period_id)]) ids = period_obj.search(cr, uid, [('name', 'ilike', period_id)])
context.update({ context.update({
'period_id': ids[0] 'period_id': ids and ids[0] or False
}) })
return context return context
def _default_get(self, cr, uid, fields, context=None): def _default_get(self, cr, uid, fields, context=None):
#default_get should only do the following:
# -propose the next amount in debit/credit in order to balance the move
# -propose the next account from the journal (default debit/credit account) accordingly
if context is None: if context is None:
context = {} context = {}
if not context.get('journal_id', False) and context.get('search_default_journal_id', False):
context['journal_id'] = context.get('search_default_journal_id')
account_obj = self.pool.get('account.account') account_obj = self.pool.get('account.account')
period_obj = self.pool.get('account.period') period_obj = self.pool.get('account.period')
journal_obj = self.pool.get('account.journal') journal_obj = self.pool.get('account.journal')
@ -224,131 +233,71 @@ class account_move_line(osv.osv):
fiscal_pos_obj = self.pool.get('account.fiscal.position') fiscal_pos_obj = self.pool.get('account.fiscal.position')
partner_obj = self.pool.get('res.partner') partner_obj = self.pool.get('res.partner')
currency_obj = self.pool.get('res.currency') currency_obj = self.pool.get('res.currency')
if not context.get('journal_id', False):
context['journal_id'] = context.get('search_default_journal_id', False)
if not context.get('period_id', False):
context['period_id'] = context.get('search_default_period_id', False)
context = self.convert_to_period(cr, uid, context) context = self.convert_to_period(cr, uid, context)
# Compute simple values # Compute simple values
data = super(account_move_line, self).default_get(cr, uid, fields, context=context) data = super(account_move_line, self).default_get(cr, uid, fields, context=context)
# Starts: Manual entry from account.move form if context.get('journal_id'):
if context.get('lines'): total = 0.0
total_new = context.get('balance', 0.00) #in account.move form view, it is not possible to compute total debit and credit using
if context['journal']: #a browse record. So we must use the context to pass the whole one2many field and compute the total
journal_data = journal_obj.browse(cr, uid, context['journal'], context=context) if context.get('line_id'):
if journal_data.type == 'purchase': for move_line_dict in move_obj.resolve_2many_commands(cr, uid, 'line_id', context.get('line_id'), context=context):
if total_new > 0: data['name'] = data.get('name') or move_line_dict.get('name')
account = journal_data.default_credit_account_id data['partner_id'] = data.get('partner_id') or move_line_dict.get('partner_id')
else: total += move_line_dict.get('debit', 0.0) - move_line_dict.get('credit', 0.0)
account = journal_data.default_debit_account_id elif context.get('period_id'):
else: #find the date and the ID of the last unbalanced account.move encoded by the current user in that journal and period
if total_new > 0: move_id = False
account = journal_data.default_credit_account_id cr.execute('''SELECT move_id, date FROM account_move_line
else: WHERE journal_id = %s AND period_id = %s AND create_uid = %s AND state = %s
account = journal_data.default_debit_account_id ORDER BY id DESC limit 1''', (context['journal_id'], context['period_id'], uid, 'draft'))
if account and ((not fields) or ('debit' in fields) or ('credit' in fields)) and 'partner_id' in data and (data['partner_id']):
part = partner_obj.browse(cr, uid, data['partner_id'], context=context)
account = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, account.id)
account = account_obj.browse(cr, uid, account, context=context)
data['account_id'] = account.id
s = -total_new
data['debit'] = s > 0 and s or 0.0
data['credit'] = s < 0 and -s or 0.0
data = self._default_get_move_form_hook(cr, uid, data)
return data
# Ends: Manual entry from account.move form
if not 'move_id' in fields: #we are not in manual entry
return data
# Compute the current move
move_id = False
partner_id = False
if context.get('journal_id', False) and context.get('period_id', False):
if 'move_id' in fields:
cr.execute('SELECT move_id \
FROM \
account_move_line \
WHERE \
journal_id = %s and period_id = %s AND create_uid = %s AND state = %s \
ORDER BY id DESC limit 1',
(context['journal_id'], context['period_id'], uid, 'draft'))
res = cr.fetchone() res = cr.fetchone()
move_id = (res and res[0]) or False move_id = res and res[0] or False
if not move_id: data['date'] = res and res[1] or period_obj.browse(cr, uid, context['period_id'], context=context).date_start
return data data['move_id'] = move_id
else: if move_id:
data['move_id'] = move_id #if there exist some unbalanced accounting entries that match the journal and the period,
if 'date' in fields: #we propose to continue the same move by copying the ref, the name, the partner...
cr.execute('SELECT date \ move = move_obj.browse(cr, uid, move_id, context=context)
FROM \ data.setdefault('name', move.line_id[-1].name)
account_move_line \ for l in move.line_id:
WHERE \ data['partner_id'] = data.get('partner_id') or l.partner_id.id
journal_id = %s AND period_id = %s AND create_uid = %s \ data['ref'] = data.get('ref') or l.ref
ORDER BY id DESC', total += (l.debit or 0.0) - (l.credit or 0.0)
(context['journal_id'], context['period_id'], uid))
res = cr.fetchone()
if res:
data['date'] = res[0]
else:
period = period_obj.browse(cr, uid, context['period_id'],
context=context)
data['date'] = period.date_start
if not move_id:
return data
total = 0
ref_id = False
move = move_obj.browse(cr, uid, move_id, context=context)
if 'name' in fields:
data.setdefault('name', move.line_id[-1].name)
acc1 = False
for l in move.line_id:
acc1 = l.account_id
partner_id = partner_id or l.partner_id.id
ref_id = ref_id or l.ref
total += (l.debit or 0.0) - (l.credit or 0.0)
if 'ref' in fields: #compute the total of current move
data['ref'] = ref_id data['debit'] = total < 0 and -total or 0.0
if 'partner_id' in fields: data['credit'] = total > 0 and total or 0.0
data['partner_id'] = partner_id #pick the good account on the journal accordingly if the next proposed line will be a debit or a credit
journal_data = journal_obj.browse(cr, uid, context['journal_id'], context=context)
if move.journal_id.type == 'purchase': account = total > 0 and journal_data.default_credit_account_id or journal_data.default_debit_account_id
if total > 0: #map the account using the fiscal position of the partner, if needed
account = move.journal_id.default_credit_account_id part = data.get('partner_id') and partner_obj.browse(cr, uid, data['partner_id'], context=context) or False
else: if account and data.get('partner_id'):
account = move.journal_id.default_debit_account_id account = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, account.id)
else: account = account_obj.browse(cr, uid, account, context=context)
if total > 0: data['account_id'] = account and account.id or False
account = move.journal_id.default_credit_account_id #compute the amount in secondary currency of the account, if needed
else: if account and account.currency_id:
account = move.journal_id.default_debit_account_id data['currency_id'] = account.currency_id.id
part = partner_id and partner_obj.browse(cr, uid, partner_id) or False #set the context for the multi currency change
# part = False is acceptable for fiscal position. compute_ctx = context.copy()
account = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, account.id) compute_ctx.update({
if account: #the following 2 parameters are used to choose the currency rate, in case where the account
account = account_obj.browse(cr, uid, account, context=context) #doesn't work with an outgoing currency rate method 'at date' but 'average'
'res.currency.compute.account': account,
if account and ((not fields) or ('debit' in fields) or ('credit' in fields)): 'res.currency.compute.account_invert': True,
data['account_id'] = account.id })
# Propose the price VAT excluded, the VAT will be added when confirming line if data.get('date'):
if account.tax_ids: compute_ctx.update({'date': data['date']})
taxes = fiscal_pos_obj.map_tax(cr, uid, part and part.property_account_position or False, account.tax_ids) data['amount_currency'] = currency_obj.compute(cr, uid, account.company_id.currency_id.id, data['currency_id'], -total, context=compute_ctx)
tax = tax_obj.browse(cr, uid, taxes) data = self._default_get_move_form_hook(cr, uid, data)
for t in tax_obj.compute_inv(cr, uid, tax, total, 1):
total -= t['amount']
s = -total
data['debit'] = s > 0 and s or 0.0
data['credit'] = s < 0 and -s or 0.0
if account and account.currency_id:
data['currency_id'] = account.currency_id.id
acc = account
if s>0:
acc = acc1
compute_ctx = context.copy()
compute_ctx.update({
'res.currency.compute.account': acc,
'res.currency.compute.account_invert': True,
})
v = currency_obj.compute(cr, uid, account.company_id.currency_id.id, data['currency_id'], s, context=compute_ctx)
data['amount_currency'] = v
return data return data
def on_create_write(self, cr, uid, id, context=None): def on_create_write(self, cr, uid, id, context=None):
@ -471,33 +420,43 @@ class account_move_line(osv.osv):
result.append(line.id) result.append(line.id)
return result return result
def _get_reconcile(self, cr, uid, ids,name, unknow_none, context=None):
res = dict.fromkeys(ids, False)
for line in self.browse(cr, uid, ids, context=context):
if line.reconcile_id:
res[line.id] = str(line.reconcile_id.name)
elif line.reconcile_partial_id:
res[line.id] = str(line.reconcile_partial_id.name)
return res
_columns = { _columns = {
'name': fields.char('Name', size=64, required=True), 'name': fields.char('Name', size=64, required=True),
'quantity': fields.float('Quantity', digits=(16,2), help="The optional quantity expressed by this line, eg: number of product sold. The quantity is not a legal requirement but is very useful for some reports."), 'quantity': fields.float('Quantity', digits=(16,2), help="The optional quantity expressed by this line, eg: number of product sold. The quantity is not a legal requirement but is very useful for some reports."),
'product_uom_id': fields.many2one('product.uom', 'UoM'), 'product_uom_id': fields.many2one('product.uom', 'Unit of Measure'),
'product_id': fields.many2one('product.product', 'Product'), 'product_id': fields.many2one('product.product', 'Product'),
'debit': fields.float('Debit', digits_compute=dp.get_precision('Account')), 'debit': fields.float('Debit', digits_compute=dp.get_precision('Account')),
'credit': fields.float('Credit', digits_compute=dp.get_precision('Account')), 'credit': fields.float('Credit', digits_compute=dp.get_precision('Account')),
'account_id': fields.many2one('account.account', 'Account', required=True, ondelete="cascade", domain=[('type','<>','view'), ('type', '<>', 'closed')], select=2), 'account_id': fields.many2one('account.account', 'Account', required=True, ondelete="cascade", domain=[('type','<>','view'), ('type', '<>', 'closed')], select=2),
'move_id': fields.many2one('account.move', 'Move', ondelete="cascade", help="The move of this entry line.", select=2, required=True), 'move_id': fields.many2one('account.move', 'Journal Entry', ondelete="cascade", help="The move of this entry line.", select=2, required=True),
'narration': fields.related('move_id','narration', type='text', relation='account.move', string='Internal Note'), 'narration': fields.related('move_id','narration', type='text', relation='account.move', string='Internal Note'),
'ref': fields.related('move_id', 'ref', string='Reference', type='char', size=64, store=True), 'ref': fields.related('move_id', 'ref', string='Reference', type='char', size=64, store=True),
'statement_id': fields.many2one('account.bank.statement', 'Statement', help="The bank statement used for bank reconciliation", select=1), 'statement_id': fields.many2one('account.bank.statement', 'Statement', help="The bank statement used for bank reconciliation", select=1),
'reconcile_id': fields.many2one('account.move.reconcile', 'Reconcile', readonly=True, ondelete='set null', select=2), 'reconcile_id': fields.many2one('account.move.reconcile', 'Reconcile', readonly=True, ondelete='set null', select=2),
'reconcile_partial_id': fields.many2one('account.move.reconcile', 'Partial Reconcile', readonly=True, ondelete='set null', select=2), 'reconcile_partial_id': fields.many2one('account.move.reconcile', 'Partial Reconcile', readonly=True, ondelete='set null', select=2),
'reconcile': fields.function(_get_reconcile, type='char', string='Reconcile Ref'),
'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')), 'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')),
'amount_residual_currency': fields.function(_amount_residual, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in its currency (maybe different of the company currency)."), 'amount_residual_currency': fields.function(_amount_residual, string='Residual Amount in Currency', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in its currency (maybe different of the company currency)."),
'amount_residual': fields.function(_amount_residual, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in the company currency."), 'amount_residual': fields.function(_amount_residual, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in the company currency."),
'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."), 'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."),
'journal_id': fields.related('move_id', 'journal_id', string='Journal', type='many2one', relation='account.journal', required=True, select=True, readonly=True, 'journal_id': fields.related('move_id', 'journal_id', string='Journal', type='many2one', relation='account.journal', required=True, select=True,
store = { store = {
'account.move': (_get_move_lines, ['journal_id'], 20) 'account.move': (_get_move_lines, ['journal_id'], 20)
}), }),
'period_id': fields.related('move_id', 'period_id', string='Period', type='many2one', relation='account.period', required=True, select=True, readonly=True, 'period_id': fields.related('move_id', 'period_id', string='Period', type='many2one', relation='account.period', required=True, select=True,
store = { store = {
'account.move': (_get_move_lines, ['period_id'], 20) 'account.move': (_get_move_lines, ['period_id'], 20)
}), }),
'blocked': fields.boolean('Litigation', help="You can check this box to mark this journal item as a litigation with the associated partner"), 'blocked': fields.boolean('No Follow-up', help="You can check this box to mark this journal item as a litigation with the associated partner"),
'partner_id': fields.many2one('res.partner', 'Partner', select=1, ondelete='restrict'), 'partner_id': fields.many2one('res.partner', 'Partner', select=1, ondelete='restrict'),
'date_maturity': fields.date('Due date', select=True ,help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."), 'date_maturity': fields.date('Due date', select=True ,help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
'date': fields.related('move_id','date', string='Effective date', type='date', required=True, select=True, 'date': fields.related('move_id','date', string='Effective date', type='date', required=True, select=True,
@ -508,8 +467,7 @@ class account_move_line(osv.osv):
'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'), 'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'),
'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation'),('currency','Currency Adjustment')], 'Centralisation', size=8), 'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation'),('currency','Currency Adjustment')], 'Centralisation', size=8),
'balance': fields.function(_balance, fnct_search=_balance_search, string='Balance'), 'balance': fields.function(_balance, fnct_search=_balance_search, string='Balance'),
'state': fields.selection([('draft','Unbalanced'), ('valid','Valid')], 'State', readonly=True, 'state': fields.selection([('draft','Unbalanced'), ('valid','Balanced')], 'Status', readonly=True),
help='When new move line is created the state will be \'Draft\'.\n* When all the payments are done it will be in \'Valid\' state.'),
'tax_code_id': fields.many2one('account.tax.code', 'Tax Account', help="The Account can either be a base tax code or a tax code account."), 'tax_code_id': fields.many2one('account.tax.code', 'Tax Account', help="The Account can either be a base tax code or a tax code account."),
'tax_amount': fields.float('Tax/Base Amount', digits_compute=dp.get_precision('Account'), select=True, help="If the Tax account is a tax code account, this field will contain the taxed amount.If the tax account is base tax code, "\ 'tax_amount': fields.float('Tax/Base Amount', digits_compute=dp.get_precision('Account'), select=True, help="If the Tax account is a tax code account, this field will contain the taxed amount.If the tax account is base tax code, "\
"this field will contain the basic amount(without tax)."), "this field will contain the basic amount(without tax)."),
@ -517,7 +475,8 @@ class account_move_line(osv.osv):
type='many2one', relation='account.invoice', fnct_search=_invoice_search), type='many2one', relation='account.invoice', fnct_search=_invoice_search),
'account_tax_id':fields.many2one('account.tax', 'Tax'), 'account_tax_id':fields.many2one('account.tax', 'Tax'),
'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'),
'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) 'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company',
string='Company', store=True, readonly=True)
} }
def _get_date(self, cr, uid, context=None): def _get_date(self, cr, uid, context=None):
@ -525,7 +484,7 @@ class account_move_line(osv.osv):
context or {} context or {}
period_obj = self.pool.get('account.period') period_obj = self.pool.get('account.period')
dt = time.strftime('%Y-%m-%d') dt = time.strftime('%Y-%m-%d')
if ('journal_id' in context) and ('period_id' in context): if context.get('journal_id') and context.get('period_id'):
cr.execute('SELECT date FROM account_move_line ' \ cr.execute('SELECT date FROM account_move_line ' \
'WHERE journal_id = %s AND period_id = %s ' \ 'WHERE journal_id = %s AND period_id = %s ' \
'ORDER BY id DESC limit 1', 'ORDER BY id DESC limit 1',
@ -546,6 +505,38 @@ class account_move_line(osv.osv):
cur = self.pool.get('account.journal').browse(cr, uid, context['journal_id']).currency cur = self.pool.get('account.journal').browse(cr, uid, context['journal_id']).currency
return cur and cur.id or False return cur and cur.id or False
def _get_period(self, cr, uid, context=None):
"""
Return default account period value
"""
context = context or {}
if context.get('period_id', False):
return context['period_id']
account_period_obj = self.pool.get('account.period')
ids = account_period_obj.find(cr, uid, context=context)
period_id = False
if ids:
period_id = ids[0]
return period_id
def _get_journal(self, cr, uid, context=None):
"""
Return journal based on the journal type
"""
context = context or {}
if context.get('journal_id', False):
return context['journal_id']
journal_id = False
journal_pool = self.pool.get('account.journal')
if context.get('journal_type', False):
jids = journal_pool.search(cr, uid, [('type','=', context.get('journal_type'))])
if not jids:
raise osv.except_osv(_('Configuration Error!'), _('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration/Journals/Journals.') % context.get('journal_type'))
journal_id = jids[0]
return journal_id
_defaults = { _defaults = {
'blocked': False, 'blocked': False,
'centralisation': 'normal', 'centralisation': 'normal',
@ -553,11 +544,12 @@ class account_move_line(osv.osv):
'date_created': fields.date.context_today, 'date_created': fields.date.context_today,
'state': 'draft', 'state': 'draft',
'currency_id': _get_currency, 'currency_id': _get_currency,
'journal_id': lambda self, cr, uid, c: c.get('journal_id', False), 'journal_id': _get_journal,
'credit': 0.0, 'credit': 0.0,
'debit': 0.0, 'debit': 0.0,
'amount_currency': 0.0,
'account_id': lambda self, cr, uid, c: c.get('account_id', False), 'account_id': lambda self, cr, uid, c: c.get('account_id', False),
'period_id': lambda self, cr, uid, c: c.get('period_id', False), 'period_id': _get_period,
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.move.line', context=c) 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.move.line', context=c)
} }
_order = "date desc, id desc" _order = "date desc, id desc"
@ -576,14 +568,14 @@ class account_move_line(osv.osv):
lines = self.browse(cr, uid, ids, context=context) lines = self.browse(cr, uid, ids, context=context)
for l in lines: for l in lines:
if l.account_id.type == 'view': if l.account_id.type == 'view':
raise osv.except_osv(_('Error :'), _('You can not create journal items on a "view" account %s %s') % (l.account_id.code, l.account_id.name)) return False
return True return True
def _check_no_closed(self, cr, uid, ids, context=None): def _check_no_closed(self, cr, uid, ids, context=None):
lines = self.browse(cr, uid, ids, context=context) lines = self.browse(cr, uid, ids, context=context)
for l in lines: for l in lines:
if l.account_id.type == 'closed': if l.account_id.type == 'closed':
raise osv.except_osv(_('Error :'), _('You can not create journal items on a closed account %s %s') % (l.account_id.code, l.account_id.name)) raise osv.except_osv(_('Error!'), _('You cannot create journal items on a closed account %s %s.') % (l.account_id.code, l.account_id.name))
return True return True
def _check_company_id(self, cr, uid, ids, context=None): def _check_company_id(self, cr, uid, ids, context=None):
@ -607,12 +599,34 @@ class account_move_line(osv.osv):
return False return False
return True return True
def _check_currency_and_amount(self, cr, uid, ids, context=None):
for l in self.browse(cr, uid, ids, context=context):
if (l.amount_currency and not l.currency_id):
return False
return True
def _check_currency_amount(self, cr, uid, ids, context=None):
for l in self.browse(cr, uid, ids, context=context):
if l.amount_currency:
if (l.amount_currency > 0.0 and l.credit > 0.0) or (l.amount_currency < 0.0 and l.debit > 0.0):
return False
return True
def _check_currency_company(self, cr, uid, ids, context=None):
for l in self.browse(cr, uid, ids, context=context):
if l.currency_id.id == l.company_id.currency_id.id:
return False
return True
_constraints = [ _constraints = [
(_check_no_view, 'You can not create journal items on an account of type view.', ['account_id']), (_check_no_view, 'You cannot create journal items on an account of type view.', ['account_id']),
(_check_no_closed, 'You can not create journal items on closed account.', ['account_id']), (_check_no_closed, 'You cannot create journal items on closed account.', ['account_id']),
(_check_company_id, 'Company must be the same for its related account and period.', ['company_id']), (_check_company_id, 'Account and Period must belong to the same company.', ['company_id']),
(_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']), (_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']),
(_check_currency, 'The selected account of your Journal Entry forces to provide a secondary currency. You should remove the secondary currency on the account or select a multi-currency view on the journal.', ['currency_id']), (_check_currency, 'The selected account of your Journal Entry forces to provide a secondary currency. You should remove the secondary currency on the account or select a multi-currency view on the journal.', ['currency_id']),
(_check_currency_and_amount, "You cannot create journal items with a secondary currency without recording both 'currency' and 'amount currency' field.", ['currency_id','amount_currency']),
(_check_currency_amount, 'The amount expressed in the secondary currency must be positif when journal item are debit and negatif when journal item are credit.', ['amount_currency']),
(_check_currency_company, "You cannot provide a secondary currency if it is the same than the company one." , ['currency_id']),
] ]
#TODO: ONCHANGE_ACCOUNT_ID: set account_tax_id #TODO: ONCHANGE_ACCOUNT_ID: set account_tax_id
@ -640,6 +654,12 @@ class account_move_line(osv.osv):
} }
return result return result
def onchange_account_id(self, cr, uid, ids, account_id, context=None):
res = {'value': {}}
if account_id:
res['value']['account_tax_id'] = [x.id for x in self.pool.get('account.account').browse(cr, uid, account_id, context=context).tax_ids]
return res
def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, date=False, journal=False): def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, date=False, journal=False):
partner_obj = self.pool.get('res.partner') partner_obj = self.pool.get('res.partner')
payment_term_obj = self.pool.get('account.payment.term') payment_term_obj = self.pool.get('account.payment.term')
@ -652,17 +672,24 @@ class account_move_line(osv.osv):
return {'value':val} return {'value':val}
if not date: if not date:
date = datetime.now().strftime('%Y-%m-%d') date = datetime.now().strftime('%Y-%m-%d')
jt = False
if journal:
jt = journal_obj.browse(cr, uid, journal).type
part = partner_obj.browse(cr, uid, partner_id) part = partner_obj.browse(cr, uid, partner_id)
if part.property_payment_term: payment_term_id = False
res = payment_term_obj.compute(cr, uid, part.property_payment_term.id, 100, date) if jt and jt in ('purchase', 'purchase_refund') and part.property_supplier_payment_term:
payment_term_id = part.property_supplier_payment_term.id
elif jt and part.property_payment_term:
payment_term_id = part.property_payment_term.id
if payment_term_id:
res = payment_term_obj.compute(cr, uid, payment_term_id, 100, date)
if res: if res:
val['date_maturity'] = res[0][0] val['date_maturity'] = res[0][0]
if not account_id: if not account_id:
id1 = part.property_account_payable.id id1 = part.property_account_payable.id
id2 = part.property_account_receivable.id id2 = part.property_account_receivable.id
if journal: if jt:
jt = journal_obj.browse(cr, uid, journal).type
if jt in ('sale', 'purchase_refund'): if jt in ('sale', 'purchase_refund'):
val['account_id'] = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, id2) val['account_id'] = fiscal_pos_obj.map_account(cr, uid, part and part.property_account_position or False, id2)
elif jt in ('purchase', 'sale_refund'): elif jt in ('purchase', 'sale_refund'):
@ -702,7 +729,9 @@ class account_move_line(osv.osv):
context = {} context = {}
if context and context.get('next_partner_only', False): if context and context.get('next_partner_only', False):
if not context.get('partner_id', False): if not context.get('partner_id', False):
partner = self.get_next_partner_only(cr, uid, offset, context) partner = self.list_partners_to_reconcile(cr, uid, context=context)
if partner:
partner = partner[0]
else: else:
partner = context.get('partner_id', False) partner = context.get('partner_id', False)
if not partner: if not partner:
@ -710,26 +739,26 @@ class account_move_line(osv.osv):
args.append(('partner_id', '=', partner[0])) args.append(('partner_id', '=', partner[0]))
return super(account_move_line, self).search(cr, uid, args, offset, limit, order, context, count) return super(account_move_line, self).search(cr, uid, args, offset, limit, order, context, count)
def get_next_partner_only(self, cr, uid, offset=0, context=None): def list_partners_to_reconcile(self, cr, uid, context=None):
cr.execute( cr.execute(
""" """
SELECT p.id SELECT partner_id
FROM res_partner p FROM (
RIGHT JOIN ( SELECT l.partner_id, p.last_reconciliation_date, SUM(l.debit) AS debit, SUM(l.credit) AS credit
SELECT l.partner_id AS partner_id, SUM(l.debit) AS debit, SUM(l.credit) AS credit
FROM account_move_line l FROM account_move_line l
LEFT JOIN account_account a ON (a.id = l.account_id) RIGHT JOIN account_account a ON (a.id = l.account_id)
LEFT JOIN res_partner p ON (l.partner_id = p.id) RIGHT JOIN res_partner p ON (l.partner_id = p.id)
WHERE a.reconcile IS TRUE WHERE a.reconcile IS TRUE
AND l.reconcile_id IS NULL AND l.reconcile_id IS NULL
AND (p.last_reconciliation_date IS NULL OR l.date > p.last_reconciliation_date) AND (p.last_reconciliation_date IS NULL OR l.date > p.last_reconciliation_date)
AND l.state <> 'draft' AND l.state <> 'draft'
GROUP BY l.partner_id GROUP BY l.partner_id, p.last_reconciliation_date
) AS s ON (p.id = s.partner_id) ) AS s
WHERE debit > 0 AND credit > 0 WHERE debit > 0 AND credit > 0
ORDER BY p.last_reconciliation_date LIMIT 1 OFFSET %s""", (offset, ) ORDER BY last_reconciliation_date""")
) ids = cr.fetchall()
return cr.fetchone() ids = len(ids) and [x[0] for x in ids] or []
return self.pool.get('res.partner').name_get(cr, uid, ids, context=context)
def reconcile_partial(self, cr, uid, ids, type='auto', context=None, writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False): def reconcile_partial(self, cr, uid, ids, type='auto', context=None, writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False):
move_rec_obj = self.pool.get('account.move.reconcile') move_rec_obj = self.pool.get('account.move.reconcile')
@ -742,7 +771,7 @@ class account_move_line(osv.osv):
context = {} context = {}
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
if company_list and not line.company_id.id in company_list: if company_list and not line.company_id.id in company_list:
raise osv.except_osv(_('Warning !'), _('To reconcile the entries company should be the same for all entries')) raise osv.except_osv(_('Warning!'), _('To reconcile the entries company should be the same for all entries.'))
company_list.append(line.company_id.id) company_list.append(line.company_id.id)
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
@ -751,7 +780,7 @@ class account_move_line(osv.osv):
else: else:
currency_id = line.company_id.currency_id currency_id = line.company_id.currency_id
if line.reconcile_id: if line.reconcile_id:
raise osv.except_osv(_('Warning'), _('Already Reconciled!')) raise osv.except_osv(_('Warning!'), _('Already reconciled.'))
if line.reconcile_partial_id: if line.reconcile_partial_id:
for line2 in line.reconcile_partial_id.line_partial_ids: for line2 in line.reconcile_partial_id.line_partial_ids:
if not line2.reconcile_id: if not line2.reconcile_id:
@ -795,11 +824,11 @@ class account_move_line(osv.osv):
company_list = [] company_list = []
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
if company_list and not line.company_id.id in company_list: if company_list and not line.company_id.id in company_list:
raise osv.except_osv(_('Warning !'), _('To reconcile the entries company should be the same for all entries')) raise osv.except_osv(_('Warning!'), _('To reconcile the entries company should be the same for all entries.'))
company_list.append(line.company_id.id) company_list.append(line.company_id.id)
for line in unrec_lines: for line in unrec_lines:
if line.state <> 'valid': if line.state <> 'valid':
raise osv.except_osv(_('Error'), raise osv.except_osv(_('Error!'),
_('Entry "%s" is not valid !') % line.name) _('Entry "%s" is not valid !') % line.name)
credit += line['credit'] credit += line['credit']
debit += line['debit'] debit += line['debit']
@ -822,15 +851,20 @@ class account_move_line(osv.osv):
r = cr.fetchall() r = cr.fetchall()
#TODO: move this check to a constraint in the account_move_reconcile object #TODO: move this check to a constraint in the account_move_reconcile object
if not unrec_lines: if not unrec_lines:
raise osv.except_osv(_('Error'), _('Entry is already reconciled')) raise osv.except_osv(_('Error!'), _('Entry is already reconciled.'))
account = account_obj.browse(cr, uid, account_id, context=context) account = account_obj.browse(cr, uid, account_id, context=context)
if r[0][1] != None: if r[0][1] != None:
raise osv.except_osv(_('Error'), _('Some entries are already reconciled !')) raise osv.except_osv(_('Error!'), _('Some entries are already reconciled.'))
if (not currency_obj.is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \ if context.get('fy_closing'):
# We don't want to generate any write-off when being called from the
# wizard used to close a fiscal year (and it doesn't give us any
# writeoff_acc_id).
pass
elif (not currency_obj.is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \
(account.currency_id and (not currency_obj.is_zero(cr, uid, account.currency_id, currency))): (account.currency_id and (not currency_obj.is_zero(cr, uid, account.currency_id, currency))):
if not writeoff_acc_id: if not writeoff_acc_id:
raise osv.except_osv(_('Warning'), _('You have to provide an account for the write off/exchange difference entry !')) raise osv.except_osv(_('Warning!'), _('You have to provide an account for the write off/exchange difference entry.'))
if writeoff > 0: if writeoff > 0:
debit = writeoff debit = writeoff
credit = 0.0 credit = 0.0
@ -909,8 +943,8 @@ class account_move_line(osv.osv):
if lines and lines[0]: if lines and lines[0]:
partner_id = lines[0].partner_id and lines[0].partner_id.id or False partner_id = lines[0].partner_id and lines[0].partner_id.id or False
if partner_id and context and context.get('stop_reconcile', False): if partner_id and not partner_obj.has_something_to_reconcile(cr, uid, partner_id, context=context):
partner_obj.write(cr, uid, [partner_id], {'last_reconciliation_date': time.strftime('%Y-%m-%d %H:%M:%S')}) partner_obj.mark_as_reconciled(cr, uid, [partner_id], context=context)
return r_id return r_id
def view_header_get(self, cr, user, view_id, view_type, context=None): def view_header_get(self, cr, user, view_id, view_type, context=None):
@ -925,6 +959,8 @@ class account_move_line(osv.osv):
return res return res
if (not context.get('journal_id', False)) or (not context.get('period_id', False)): if (not context.get('journal_id', False)) or (not context.get('period_id', False)):
return False return False
if context.get('search_default_journal_id', False):
context['journal_id'] = context.get('search_default_journal_id')
cr.execute('SELECT code FROM account_journal WHERE id = %s', (context['journal_id'], )) cr.execute('SELECT code FROM account_journal WHERE id = %s', (context['journal_id'], ))
j = cr.fetchone()[0] or '' j = cr.fetchone()[0] or ''
cr.execute('SELECT code FROM account_period WHERE id = %s', (context['period_id'], )) cr.execute('SELECT code FROM account_period WHERE id = %s', (context['period_id'], ))
@ -960,130 +996,6 @@ class account_move_line(osv.osv):
'context':context, 'context':context,
} }
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
journal_pool = self.pool.get('account.journal')
if context is None:
context = {}
result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
if view_type != 'tree':
#Remove the toolbar from the form view
if view_type == 'form':
if result.get('toolbar', False):
result['toolbar']['action'] = []
#Restrict the list of journal view in search view
if view_type == 'search' and result['fields'].get('journal_id', False):
result['fields']['journal_id']['selection'] = journal_pool.name_search(cr, uid, '', [], context=context)
ctx = context.copy()
#we add the refunds journal in the selection field of journal
if context.get('journal_type', False) == 'sale':
ctx.update({'journal_type': 'sale_refund'})
result['fields']['journal_id']['selection'] += journal_pool.name_search(cr, uid, '', [], context=ctx)
elif context.get('journal_type', False) == 'purchase':
ctx.update({'journal_type': 'purchase_refund'})
result['fields']['journal_id']['selection'] += journal_pool.name_search(cr, uid, '', [], context=ctx)
return result
if context.get('view_mode', False):
return result
fld = []
fields = {}
flds = []
title = _("Accounting Entries") #self.view_header_get(cr, uid, view_id, view_type, context)
ids = journal_pool.search(cr, uid, [])
journals = journal_pool.browse(cr, uid, ids, context=context)
all_journal = [None]
common_fields = {}
total = len(journals)
for journal in journals:
all_journal.append(journal.id)
for field in journal.view_id.columns_id:
if not field.field in fields:
fields[field.field] = [journal.id]
fld.append((field.field, field.sequence))
flds.append(field.field)
common_fields[field.field] = 1
else:
fields.get(field.field).append(journal.id)
common_fields[field.field] = common_fields[field.field] + 1
fld.append(('period_id', 3))
fld.append(('journal_id', 10))
flds.append('period_id')
flds.append('journal_id')
fields['period_id'] = all_journal
fields['journal_id'] = all_journal
fld = sorted(fld, key=itemgetter(1))
widths = {
'statement_id': 50,
'state': 60,
'tax_code_id': 50,
'move_id': 40,
}
document = etree.Element('tree', string=title, editable="top",
refresh="5", on_write="on_create_write",
colors="red:state=='draft';black:state=='valid'")
fields_get = self.fields_get(cr, uid, flds, context)
for field, _seq in fld:
if common_fields.get(field) == total:
fields.get(field).append(None)
# if field=='state':
# state = 'colors="red:state==\'draft\'"'
f = etree.SubElement(document, 'field', name=field)
if field == 'debit':
f.set('sum', _("Total debit"))
elif field == 'credit':
f.set('sum', _("Total credit"))
elif field == 'move_id':
f.set('required', 'False')
elif field == 'account_tax_id':
f.set('domain', "[('parent_id', '=' ,False)]")
f.set('context', "{'journal_id': journal_id}")
elif field == 'account_id' and journal.id:
f.set('domain', "[('journal_id', '=', journal_id),('type','!=','view'), ('type','!=','closed')]")
f.set('on_change', 'onchange_account_id(account_id, partner_id)')
elif field == 'partner_id':
f.set('on_change', 'onchange_partner_id(move_id, partner_id, account_id, debit, credit, date, journal_id)')
elif field == 'journal_id':
f.set('context', "{'journal_id': journal_id}")
elif field == 'statement_id':
f.set('domain', "[('state', '!=', 'confirm'),('journal_id.type', '=', 'bank')]")
f.set('invisible', 'True')
elif field == 'date':
f.set('on_change', 'onchange_date(date)')
elif field == 'analytic_account_id':
# Currently it is not working due to being executed by superclass's fields_view_get
# f.set('groups', 'analytic.group_analytic_accounting')
pass
if field in ('amount_currency', 'currency_id'):
f.set('on_change', 'onchange_currency(account_id, amount_currency, currency_id, date, journal_id)')
f.set('attrs', "{'readonly': [('state', '=', 'valid')]}")
if field in widths:
f.set('width', str(widths[field]))
if field in ('journal_id',):
f.set("invisible", "context.get('journal_id', False)")
elif field in ('period_id',):
f.set("invisible", "context.get('period_id', False)")
orm.setup_modifiers(f, fields_get[field], context=context,
in_tree_view=True)
result['arch'] = etree.tostring(document, pretty_print=True)
result['fields'] = fields_get
return result
def _check_moves(self, cr, uid, context=None): def _check_moves(self, cr, uid, context=None):
# use the first move ever created for this journal and period # use the first move ever created for this journal and period
if context is None: if context is None:
@ -1092,12 +1004,12 @@ class account_move_line(osv.osv):
res = cr.fetchone() res = cr.fetchone()
if res: if res:
if res[1] != 'draft': if res[1] != 'draft':
raise osv.except_osv(_('UserError'), raise osv.except_osv(_('User Error!'),
_('The account move (%s) for centralisation ' \ _('The account move (%s) for centralisation ' \
'has been confirmed!') % res[2]) 'has been confirmed.') % res[2])
return res return res
def _remove_move_reconcile(self, cr, uid, move_ids=[], context=None): def _remove_move_reconcile(self, cr, uid, move_ids=None, opening_reconciliation=False, context=None):
# Function remove move rencocile ids related with moves # Function remove move rencocile ids related with moves
obj_move_line = self.pool.get('account.move.line') obj_move_line = self.pool.get('account.move.line')
obj_move_rec = self.pool.get('account.move.reconcile') obj_move_rec = self.pool.get('account.move.reconcile')
@ -1112,6 +1024,8 @@ class account_move_line(osv.osv):
unlink_ids += rec_ids unlink_ids += rec_ids
unlink_ids += part_rec_ids unlink_ids += part_rec_ids
if unlink_ids: if unlink_ids:
if opening_reconciliation:
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
obj_move_rec.unlink(cr, uid, unlink_ids) obj_move_rec.unlink(cr, uid, unlink_ids)
return True return True
@ -1141,9 +1055,9 @@ class account_move_line(osv.osv):
if isinstance(ids, (int, long)): if isinstance(ids, (int, long)):
ids = [ids] ids = [ids]
if vals.get('account_tax_id', False): if vals.get('account_tax_id', False):
raise osv.except_osv(_('Unable to change tax !'), _('You can not change the tax, you should remove and recreate lines !')) raise osv.except_osv(_('Unable to change tax!'), _('You cannot change the tax, you should remove and recreate lines.'))
if ('account_id' in vals) and not account_obj.read(cr, uid, vals['account_id'], ['active'])['active']: if ('account_id' in vals) and not account_obj.read(cr, uid, vals['account_id'], ['active'])['active']:
raise osv.except_osv(_('Bad account!'), _('You can not use an inactive account!')) raise osv.except_osv(_('Bad Account!'), _('You cannot use an inactive account.'))
if update_check: if update_check:
if ('account_id' in vals) or ('journal_id' in vals) or ('period_id' in vals) or ('move_id' in vals) or ('debit' in vals) or ('credit' in vals) or ('date' in vals): if ('account_id' in vals) or ('journal_id' in vals) or ('period_id' in vals) or ('move_id' in vals) or ('debit' in vals) or ('credit' in vals) or ('date' in vals):
self._update_check(cr, uid, ids, context) self._update_check(cr, uid, ids, context)
@ -1186,12 +1100,12 @@ class account_move_line(osv.osv):
jour_period_obj = self.pool.get('account.journal.period') jour_period_obj = self.pool.get('account.journal.period')
cr.execute('SELECT state FROM account_journal_period WHERE journal_id = %s AND period_id = %s', (journal_id, period_id)) cr.execute('SELECT state FROM account_journal_period WHERE journal_id = %s AND period_id = %s', (journal_id, period_id))
result = cr.fetchall() result = cr.fetchall()
journal = journal_obj.browse(cr, uid, journal_id, context=context)
period = period_obj.browse(cr, uid, period_id, context=context)
for (state,) in result: for (state,) in result:
if state == 'done': if state == 'done':
raise osv.except_osv(_('Error !'), _('You can not add/modify entries in a closed journal.')) raise osv.except_osv(_('Error !'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
if not result: if not result:
journal = journal_obj.browse(cr, uid, journal_id, context=context)
period = period_obj.browse(cr, uid, period_id, context=context)
jour_period_obj.create(cr, uid, { jour_period_obj.create(cr, uid, {
'name': (journal.code or journal.name)+':'+(period.name or ''), 'name': (journal.code or journal.name)+':'+(period.name or ''),
'journal_id': journal.id, 'journal_id': journal.id,
@ -1204,9 +1118,9 @@ class account_move_line(osv.osv):
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
err_msg = _('Move name (id): %s (%s)') % (line.move_id.name, str(line.move_id.id)) err_msg = _('Move name (id): %s (%s)') % (line.move_id.name, str(line.move_id.id))
if line.move_id.state <> 'draft' and (not line.journal_id.entry_posted): if line.move_id.state <> 'draft' and (not line.journal_id.entry_posted):
raise osv.except_osv(_('Error !'), _('You can not do this modification on a confirmed entry! You can just change some non legal fields or you must unconfirm the journal entry first! \n%s') % err_msg) raise osv.except_osv(_('Error!'), _('You cannot do this modification on a confirmed entry. You can just change some non legal fields or you must unconfirm the journal entry first.\n%s.') % err_msg)
if line.reconcile_id: if line.reconcile_id:
raise osv.except_osv(_('Error !'), _('You can not do this modification on a reconciled entry! You can just change some non legal fields or you must unreconcile first!\n%s') % err_msg) raise osv.except_osv(_('Error!'), _('You cannot do this modification on a reconciled entry. You can just change some non legal fields or you must unreconcile first.\n%s.') % err_msg)
t = (line.journal_id.id, line.period_id.id) t = (line.journal_id.id, line.period_id.id)
if t not in done: if t not in done:
self._update_journal_check(cr, uid, line.journal_id.id, line.period_id.id, context) self._update_journal_check(cr, uid, line.journal_id.id, line.period_id.id, context)
@ -1226,26 +1140,29 @@ class account_move_line(osv.osv):
if company_id: if company_id:
vals['company_id'] = company_id[0] vals['company_id'] = company_id[0]
if ('account_id' in vals) and not account_obj.read(cr, uid, vals['account_id'], ['active'])['active']: if ('account_id' in vals) and not account_obj.read(cr, uid, vals['account_id'], ['active'])['active']:
raise osv.except_osv(_('Bad account!'), _('You can not use an inactive account!')) raise osv.except_osv(_('Bad Account!'), _('You cannot use an inactive account.'))
if 'journal_id' in vals: if 'journal_id' in vals and vals['journal_id']:
context['journal_id'] = vals['journal_id'] context['journal_id'] = vals['journal_id']
if 'period_id' in vals: if 'period_id' in vals and vals['period_id']:
context['period_id'] = vals['period_id'] context['period_id'] = vals['period_id']
if ('journal_id' not in context) and ('move_id' in vals) and vals['move_id']: if ('journal_id' not in context) and ('move_id' in vals) and vals['move_id']:
m = move_obj.browse(cr, uid, vals['move_id']) m = move_obj.browse(cr, uid, vals['move_id'])
context['journal_id'] = m.journal_id.id context['journal_id'] = m.journal_id.id
context['period_id'] = m.period_id.id context['period_id'] = m.period_id.id
#we need to treat the case where a value is given in the context for period_id as a string #we need to treat the case where a value is given in the context for period_id as a string
if 'period_id' not in context or not isinstance(context.get('period_id', ''), (int, long)): if 'period_id' in context and not isinstance(context.get('period_id', ''), (int, long)):
period_candidate_ids = self.pool.get('account.period').name_search(cr, uid, name=context.get('period_id','')) period_candidate_ids = self.pool.get('account.period').name_search(cr, uid, name=context.get('period_id',''))
if len(period_candidate_ids) != 1: if len(period_candidate_ids) != 1:
raise osv.except_osv(_('Encoding error'), _('No period found or more than one period found for the given date.')) raise osv.except_osv(_('Error!'), _('No period found or more than one period found for the given date.'))
context['period_id'] = period_candidate_ids[0][0] context['period_id'] = period_candidate_ids[0][0]
if not context.get('journal_id', False) and context.get('search_default_journal_id', False): if not context.get('journal_id', False) and context.get('search_default_journal_id', False):
context['journal_id'] = context.get('search_default_journal_id') context['journal_id'] = context.get('search_default_journal_id')
self._update_journal_check(cr, uid, context['journal_id'], context['period_id'], context) self._update_journal_check(cr, uid, context['journal_id'], context['period_id'], context)
move_id = vals.get('move_id', False) move_id = vals.get('move_id', False)
journal = journal_obj.browse(cr, uid, context['journal_id'], context=context) journal = journal_obj.browse(cr, uid, context['journal_id'], context=context)
vals['journal_id'] = vals.get('journal_id') or context.get('journal_id')
vals['period_id'] = vals.get('period_id') or context.get('period_id')
vals['date'] = vals.get('date') or context.get('date')
if not move_id: if not move_id:
if journal.centralisation: if journal.centralisation:
#Check for centralisation #Check for centralisation
@ -1265,7 +1182,7 @@ class account_move_line(osv.osv):
move_id = move_obj.create(cr, uid, v, context) move_id = move_obj.create(cr, uid, v, context)
vals['move_id'] = move_id vals['move_id'] = move_id
else: else:
raise osv.except_osv(_('No piece number !'), _('Can not create an automatic sequence for this piece!\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')) raise osv.except_osv(_('No piece number !'), _('Cannot create an automatic sequence for this piece.\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.'))
ok = not (journal.type_control_ids or journal.account_control_ids) ok = not (journal.type_control_ids or journal.account_control_ids)
if ('account_id' in vals): if ('account_id' in vals):
account = account_obj.browse(cr, uid, vals['account_id'], context=context) account = account_obj.browse(cr, uid, vals['account_id'], context=context)
@ -1290,7 +1207,7 @@ class account_move_line(osv.osv):
vals['amount_currency'] = cur_obj.compute(cr, uid, account.company_id.currency_id.id, vals['amount_currency'] = cur_obj.compute(cr, uid, account.company_id.currency_id.id,
account.currency_id.id, vals.get('debit', 0.0)-vals.get('credit', 0.0), context=ctx) account.currency_id.id, vals.get('debit', 0.0)-vals.get('credit', 0.0), context=ctx)
if not ok: if not ok:
raise osv.except_osv(_('Bad account !'), _('You can not use this general account in this journal, check the tab \'Entry Controls\' on the related journal !')) raise osv.except_osv(_('Bad Account!'), _('You cannot use this general account in this journal, check the tab \'Entry Controls\' on the related journal.'))
if vals.get('analytic_account_id',False): if vals.get('analytic_account_id',False):
if journal.analytic_journal_id: if journal.analytic_journal_id:
@ -1349,7 +1266,7 @@ class account_move_line(osv.osv):
} }
if data['tax_code_id']: if data['tax_code_id']:
self.create(cr, uid, data, context) self.create(cr, uid, data, context)
#create the VAT movement #create the Tax movement
data = { data = {
'move_id': vals['move_id'], 'move_id': vals['move_id'],
'name': tools.ustr(vals['name'] or '') + ' ' + tools.ustr(tax['name'] or ''), 'name': tools.ustr(vals['name'] or '') + ' ' + tools.ustr(tax['name'] or ''),
@ -1373,6 +1290,19 @@ class account_move_line(osv.osv):
move_obj.button_validate(cr,uid, [vals['move_id']], context) move_obj.button_validate(cr,uid, [vals['move_id']], context)
return result return result
def list_periods(self, cr, uid, context=None):
ids = self.pool.get('account.period').search(cr,uid,[])
return self.pool.get('account.period').name_get(cr, uid, ids, context=context)
def list_journals(self, cr, uid, context=None):
ng = dict(self.pool.get('account.journal').name_search(cr,uid,'',[]))
ids = ng.keys()
result = []
for journal in self.pool.get('account.journal').browse(cr, uid, ids, context=context):
result.append((journal.id,ng[journal.id],journal.type,
bool(journal.currency),bool(journal.analytic_journal_id)))
return result
account_move_line() account_move_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,8 +7,8 @@
wiz = wizards.browse(cr, uid, ref('account.account_configuration_installer_todo')) wiz = wizards.browse(cr, uid, ref('account.account_configuration_installer_todo'))
part = self.pool.get('res.partner').browse(cr, uid, ref('base.main_partner')) part = self.pool.get('res.partner').browse(cr, uid, ref('base.main_partner'))
# if we know the country and the wizard has not yet been executed, we do it # if we know the country and the wizard has not yet been executed, we do it
if (part.country.id) and (wiz.state=='open'): if (part.country_id.id) and (wiz.state=='open'):
mod = 'l10n_'+part.country.code.lower() mod = 'l10n_'+part.country_id.code.lower()
ids = modules.search(cr, uid, [ ('name','=',mod) ], context=context) ids = modules.search(cr, uid, [ ('name','=',mod) ], context=context)
if ids: if ids:
wizards.write(cr, uid, [ref('account.account_configuration_installer_todo')], { wizards.write(cr, uid, [ref('account.account_configuration_installer_todo')], {

View File

@ -20,8 +20,9 @@
rml="account/report/account_print_invoice.rml" rml="account/report/account_print_invoice.rml"
string="Invoices" string="Invoices"
attachment="(object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')" attachment="(object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')"
attachment_use="True"
usage="default" usage="default"
multi="True"/> />
<report id="account_transfers" model="account.transfer" name="account.transfer" string="Transfers" xml="account/report/transfer.xml" xsl="account/report/transfer.xsl"/> <report id="account_transfers" model="account.transfer" name="account.transfer" string="Transfers" xml="account/report/transfer.xml" xsl="account/report/transfer.xsl"/>
<report auto="False" id="account_intracom" menu="False" model="account.move.line" name="account.intracom" string="IntraCom"/> <report auto="False" id="account_intracom" menu="False" model="account.move.line" name="account.intracom" string="IntraCom"/>
@ -40,13 +41,5 @@
groups="group_account_user,group_account_manager" groups="group_account_user,group_account_manager"
parent="account.menu_finance_generic_reporting" sequence="3"/> parent="account.menu_finance_generic_reporting" sequence="3"/>
<report id="account_account_balance_landscape"
string="Account balance"
model="account.account"
name="account.account.balance.landscape"
rml="account/report/account_balance_landscape.rml"
auto="False"
menu="False"/>
</data> </data>
</openerp> </openerp>

View File

@ -5,14 +5,12 @@
<record id="test_invoice_1" model="account.invoice"> <record id="test_invoice_1" model="account.invoice">
<field name="currency_id" ref="base.EUR"/> <field name="currency_id" ref="base.EUR"/>
<field name="company_id" ref="base.main_company"/> <field name="company_id" ref="base.main_company"/>
<field name="address_invoice_id" ref="base.res_partner_address_tang"/> <field name="partner_id" ref="base.res_partner_1"/>
<field name="partner_id" ref="base.res_partner_asus"/>
<field name="journal_id" ref="account.sales_journal"/> <field name="journal_id" ref="account.sales_journal"/>
<field name="state">draft</field> <field name="state">draft</field>
<field name="type">out_invoice</field> <field name="type">out_invoice</field>
<field name="account_id" ref="account.a_recv"/> <field name="account_id" ref="account.a_recv"/>
<field name="name">Test invoice 1</field> <field name="name">Test invoice 1</field>
<field name="address_contact_id" ref="base.res_partner_address_tang"/>
</record> </record>
<record id="test_tax_line" model="account.invoice.tax"> <record id="test_tax_line" model="account.invoice.tax">
<field name="name">Test Tax</field> <field name="name">Test Tax</field>

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +1,33 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<record id="action_aged_receivable" model="ir.actions.act_window">
<field name="name">Receivable Accounts</field> <record id="action_company_analysis_tree" model="ir.actions.act_window">
<field name="res_model">report.account.receivable</field> <field name="name">Company Analysis</field>
<field name="res_model">account.entries.report</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">graph,tree</field> <field name="view_mode">tree,graph</field>
<field name="domain">[('type','=','receivable')]</field> <field name="context">{'group_by':['user_type'], 'group_by_no_leaf':1}</field>
<field name="view_id" ref="account.view_account_entries_report_tree"/>
<field name="domain">[('year','=',time.strftime('%Y'))]</field>
</record> </record>
<record id="action_aged_income" model="ir.actions.act_window">
<field name="name">Income Accounts</field>
<field name="res_model">report.account.receivable</field>
<field name="view_type">form</field>
<field name="view_mode">graph,tree</field>
<field name="domain">[('type','=','income')]</field>
</record>
<record id="action_company_analysis_tree" model="ir.actions.act_window">
<field name="name">Company Analysis</field>
<field name="res_model">account.entries.report</field>
<field name="view_type">form</field>
<field name="view_mode">tree,graph</field>
<field name="context">{'group_by':['user_type'], 'group_by_no_leaf':1}</field>
<field name="view_id" ref="account.view_account_entries_report_tree"/>
<field name="domain">[('year','=',time.strftime('%Y'))]</field>
</record>
<record id="action_treasory_graph" model="ir.actions.act_window">
<field name="name">Treasury</field>
<field name="res_model">account.account</field>
<field name="view_type">form</field>
<field name="view_mode">graph,tree</field>
<field name="domain">[('type','=','liquidity')]</field>
<field name="context">{'default_type': 'liquidity'}</field>
<field name="view_id" ref="account.view_treasory_graph"/>
</record>
<record id="board_account_form" model="ir.ui.view"> <record id="board_account_form" model="ir.ui.view">
<field name="name">board.account.form</field> <field name="name">board.account.form</field>
<field name="model">board.board</field> <field name="model">board.board</field>
<field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Account Board"> <form string="Account Board" version="7.0">
<board style="2-1"> <board style="2-1">
<column> <column>
<action name="%(account.action_invoice_tree1)d" creatable="true" string="Draft Customer Invoices" domain="[('state','in',('draft','proforma2')), ('type','=','out_invoice')]"/>
<action name="%(action_company_analysis_tree)d" string="Company Analysis"/> <action name="%(action_company_analysis_tree)d" string="Company Analysis"/>
</column> </column>
<column>
<action name="%(action_treasory_graph)d" string="Treasury"/> <!--groups="account.group_account_manager,account.group_account_user"-->
</column>
</board> </board>
</form> </form>
</field> </field>
</record> </record>
<record id="open_board_account" model="ir.actions.act_window"> <record id="open_board_account" model="ir.actions.act_window">
<field name="name">Accounting Dashboard</field> <field name="name">Accounting</field>
<field name="res_model">board.board</field> <field name="res_model">board.board</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
@ -61,10 +35,12 @@
<field name="view_id" ref="board_account_form"/> <field name="view_id" ref="board_account_form"/>
</record> </record>
<menuitem id="menu_dashboard_acc" name="Accounting" sequence="30" parent="base.menu_reporting_dashboard" groups="group_account_user,group_account_manager"/> <menuitem id="menu_board_account"
<menuitem action="open_board_account" icon="terp-graph" id="menu_board_account" parent="menu_dashboard_acc" sequence="1"/> action="open_board_account"
<menuitem icon="terp-account" id="account.menu_finance" name="Accounting" sequence="14" action="open_board_account"/> icon="terp-graph"
parent="base.menu_reporting_dashboard"
groups="group_account_user,group_account_manager"
sequence="45"/>
</data> </data>
</openerp> </openerp>

View File

@ -24,24 +24,27 @@ from osv import fields, osv
class res_company(osv.osv): class res_company(osv.osv):
_inherit = "res.company" _inherit = "res.company"
_columns = { _columns = {
'expects_chart_of_accounts': fields.boolean('Expects a Chart of Accounts'),
'tax_calculation_rounding_method': fields.selection([
('round_per_line', 'Round per Line'),
('round_globally', 'Round Globally'),
], '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."),
'paypal_account': fields.char("Paypal Account", size=128, help="Paypal username (usually email) for receiving online payments."), 'paypal_account': fields.char("Paypal Account", size=128, help="Paypal username (usually email) for receiving online payments."),
'overdue_msg': fields.text('Overdue Payments Message', translate=True), 'overdue_msg': fields.text('Overdue Payments Message', translate=True),
'property_reserve_and_surplus_account': fields.property(
'account.account',
type='many2one',
relation='account.account',
string="Reserve and Profit/Loss Account",
view_load=True,
domain="[('type', '=', 'other')]",
help="This account is used for transferring Profit/Loss (If It is Profit: Amount will be added, Loss : Amount will be deducted.), as calculated in Profit & Loss Report"),
} }
_defaults = { _defaults = {
'overdue_msg': '''Our records indicate that the following payments are still due. If the amount 'expects_chart_of_accounts': True,
has already been paid, please disregard this notice. However, if you have any 'tax_calculation_rounding_method': 'round_per_line',
queries regarding your account, please contact us. 'overdue_msg': '''Dear Sir/Madam,
Thank you in advance.
''' Our records indicate that some payments on your account are still due. Please find details below.
If the amount has already been paid, please disregard this notice. Otherwise, please forward us the total amount stated below.
If you have any queries regarding your account, Please contact us.
Thank you in advance for your cooperation.
Best Regards,'''
} }
res_company() res_company()

View File

@ -5,7 +5,6 @@
<field name="name">res.company.form.inherit</field> <field name="name">res.company.form.inherit</field>
<field name="inherit_id" ref="base.view_company_form"/> <field name="inherit_id" ref="base.view_company_form"/>
<field name="model">res.company</field> <field name="model">res.company</field>
<field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<notebook position="inside"> <notebook position="inside">
<page string="Overdue Payments" position="inside"> <page string="Overdue Payments" position="inside">
@ -16,18 +15,5 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_company_inherit_1_form">
<field name="name">res.company.form.inherit</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="model">res.company</field>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="property_reserve_and_surplus_account" colspan="2"/>
<field name="paypal_account" />
</field>
</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -10,17 +10,33 @@
<!-- <!--
Payment term Payment term
--> -->
<record id="account_payment_term" model="account.payment.term"> <record id="account_payment_term_immediate" model="account.payment.term">
<field name="name">30 Days End of Month</field> <field name="name">Immediate Payment</field>
<field name="note">30 Days End of Month</field> <field name="note">Immediate Payment</field>
</record> </record>
<record id="account_payment_term_line" model="account.payment.term.line">
<field name="name">30 Days End of Month</field> <record id="account_payment_term_line_immediate" model="account.payment.term.line">
<field name="name">Immediate Payment</field>
<field name="value">balance</field> <field name="value">balance</field>
<field eval="30" name="days"/> <field eval="0" name="days"/>
<field eval="-1" name="days2"/> <field eval="0" name="days2"/>
<field eval="account_payment_term" name="payment_id"/> <field eval="account_payment_term_immediate" name="payment_id"/>
</record> </record>
<record id="account_payment_term_15days" model="account.payment.term">
<field name="name">15 Days</field>
<field name="note">15 Days</field>
</record>
<record id="account_payment_term_line_15days" model="account.payment.term.line">
<field name="name">15 Days</field>
<field name="value">balance</field>
<field eval="15" name="days"/>
<field eval="0" name="days2"/>
<field eval="account_payment_term_15days" name="payment_id"/>
</record>
<record forcecreate="True" id="decimal_payment" model="decimal.precision"> <record forcecreate="True" id="decimal_payment" model="decimal.precision">
<field name="name">Payment Term</field> <field name="name">Payment Term</field>
<field name="digits">6</field> <field name="digits">6</field>
@ -30,6 +46,7 @@
<field name="name">30 Net Days</field> <field name="name">30 Net Days</field>
<field name="note">30 Net Days</field> <field name="note">30 Net Days</field>
</record> </record>
<record id="account_payment_term_line_net" model="account.payment.term.line"> <record id="account_payment_term_line_net" model="account.payment.term.line">
<field name="name">30 Net Days</field> <field name="name">30 Net Days</field>
<field name="value">balance</field> <field name="value">balance</field>
@ -37,434 +54,7 @@
<field eval="0" name="days2"/> <field eval="0" name="days2"/>
<field eval="account_payment_term_net" name="payment_id"/> <field eval="account_payment_term_net" name="payment_id"/>
</record> </record>
<record id="account_payment_term_advance" model="account.payment.term">
<field name="name">30% Advance End 30 Days</field>
<field name="note">30% Advance End 30 Days</field>
</record>
<record id="account_payment_term_line_advance1" model="account.payment.term.line">
<field name="name">30% Advance</field>
<field name="value">procent</field>
<field eval="3" name="sequence"/>
<field eval="0.300000" name="value_amount"/>
<field eval="0" name="days"/>
<field eval="0" name="days2"/>
<field eval="account_payment_term_advance" name="payment_id"/>
</record>
<record id="account_payment_term_line_advance2" model="account.payment.term.line">
<field name="name">Remaining Balance</field>
<field name="value">balance</field>
<field eval="30" name="days"/>
<field eval="-1" name="days2"/>
<field eval="account_payment_term_advance" name="payment_id"/>
</record>
<!--
Account Journal View
-->
<record id="account_journal_bank_view" model="account.journal.view">
<field name="name">Bank/Cash Journal View</field>
</record>
<record id="bank_col1" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Date</field>
<field name="field">date</field>
<field eval="True" name="required"/>
<field eval="3" name="sequence"/>
</record>
<record id="bank_col2" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Journal Entry</field>
<field name="field">move_id</field>
<field eval="False" name="required"/>
<field eval="1" name="sequence"/>
</record>
<record id="bank_col7" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Name</field>
<field name="field">name</field>
<field eval="7" name="sequence"/>
<field eval="True" name="required"/>
</record>
<record id="bank_col4" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Statement</field>
<field name="field">statement_id</field>
<field eval="4" name="sequence"/>
</record>
<record id="bank_col6" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Partner</field>
<field name="field">partner_id</field>
<field eval="5" name="sequence"/>
</record>
<record id="bank_col5" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Account</field>
<field name="field">account_id</field>
<field eval="True" name="required"/>
<field eval="6" name="sequence"/>
</record>
<record id="bank_col9" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Debit</field>
<field name="field">debit</field>
<field eval="11" name="sequence"/>
</record>
<record id="bank_col10" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Credit</field>
<field name="field">credit</field>
<field eval="12" name="sequence"/>
</record>
<record id="bank_col3" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Ref</field>
<field name="field">ref</field>
<field eval="2" name="sequence"/>
</record>
<record id="bank_col23" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">State</field>
<field name="field">state</field>
<field eval="19" name="sequence"/>
</record>
<record id="bank_col20" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view"/>
<field name="name">Reconcile</field>
<field name="field">reconcile_id</field>
<field eval="20" name="sequence"/>
</record>
<record id="account_journal_bank_view_multi" model="account.journal.view">
<field name="name">Bank/Cash Journal (Multi-Currency) View</field>
</record>
<record id="bank_col1_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Date</field>
<field name="field">date</field>
<field eval="True" name="required"/>
<field eval="3" name="sequence"/>
</record>
<record id="bank_col2_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Journal Entry</field>
<field name="field">move_id</field>
<field eval="False" name="required"/>
<field eval="1" name="sequence"/>
</record>
<record id="bank_col7_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Name</field>
<field name="field">name</field>
<field eval="7" name="sequence"/>
<field eval="True" name="required"/>
</record>
<record id="bank_col4_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Statement</field>
<field name="field">statement_id</field>
<field eval="4" name="sequence"/>
</record>
<record id="bank_col6_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Partner</field>
<field name="field">partner_id</field>
<field eval="5" name="sequence"/>
</record>
<record id="bank_col5_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Account</field>
<field name="field">account_id</field>
<field eval="True" name="required"/>
<field eval="6" name="sequence"/>
</record>
<record id="bank_col17_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Currency Amt.</field>
<field name="field">amount_currency</field>
<field eval="9" name="sequence"/>
</record>
<record id="bank_col18_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Currency</field>
<field name="field">currency_id</field>
<field eval="10" name="sequence"/>
</record>
<record id="bank_col9_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Debit</field>
<field name="field">debit</field>
<field eval="11" name="sequence"/>
</record>
<record id="bank_col10_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Credit</field>
<field name="field">credit</field>
<field eval="12" name="sequence"/>
</record>
<record id="bank_col3_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Ref</field>
<field name="field">ref</field>
<field eval="2" name="sequence"/>
</record>
<record id="bank_col23_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">State</field>
<field name="field">state</field>
<field eval="19" name="sequence"/>
</record>
<record id="bank_col20_multi" model="account.journal.column">
<field name="view_id" ref="account_journal_bank_view_multi"/>
<field name="name">Reconcile</field>
<field name="field">reconcile_id</field>
<field eval="20" name="sequence"/>
</record>
<record id="account_journal_view" model="account.journal.view">
<field name="name">Journal View</field>
</record>
<record id="journal_col1" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Date</field>
<field name="field">date</field>
<field eval="True" name="required"/>
<field eval="3" name="sequence"/>
</record>
<record id="journal_col2" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Journal Entry</field>
<field name="field">move_id</field>
<field eval="False" name="required"/>
<field eval="1" name="sequence"/>
</record>
<record id="journal_col3" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Ref</field>
<field name="field">ref</field>
<field eval="2" name="sequence"/>
</record>
<record id="journal_col5" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Partner</field>
<field name="field">partner_id</field>
<field eval="5" name="sequence"/>
</record>
<record id="journal_col4" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Account</field>
<field name="field">account_id</field>
<field eval="True" name="required"/>
<field eval="6" name="sequence"/>
</record>
<record id="journal_col6" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Name</field>
<field name="field">name</field>
<field eval="7" name="sequence"/>
<field eval="True" name="required"/>
</record>
<record id="journal_col8" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Debit</field>
<field name="field">debit</field>
<field eval="11" name="sequence"/>
</record>
<record id="journal_col9" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Credit</field>
<field name="field">credit</field>
<field eval="12" name="sequence"/>
</record>
<record id="journal_col11" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">Analytic Account</field>
<field name="field">analytic_account_id</field>
<field eval="14" name="sequence"/>
</record>
<record id="journal_col24" model="account.journal.column">
<field name="view_id" ref="account_journal_view"/>
<field name="name">State</field>
<field name="field">state</field>
<field eval="19" name="sequence"/>
</record>
<record id="account_sp_journal_view" model="account.journal.view">
<field name="name">Sale/Purchase Journal View</field>
</record>
<record id="sp_journal_col1" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Date</field>
<field name="field">date</field>
<field eval="True" name="required"/>
<field eval="3" name="sequence"/>
</record>
<record id="sp_journal_col2" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Journal Entry</field>
<field name="field">move_id</field>
<field eval="False" name="required"/>
<field eval="1" name="sequence"/>
</record>
<record id="sp_journal_col3" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Ref</field>
<field name="field">ref</field>
<field eval="2" name="sequence"/>
</record>
<record id="sp_journal_col4" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Account</field>
<field name="field">account_id</field>
<field eval="True" name="required"/>
<field eval="6" name="sequence"/>
</record>
<record id="sp_journal_col5" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Partner</field>
<field name="field">partner_id</field>
<field eval="5" name="sequence"/>
</record>
<record id="sp_journal_col6" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Name</field>
<field name="field">name</field>
<field eval="7" name="sequence"/>
<field eval="True" name="required"/>
</record>
<record id="sp_journal_col7" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Due Date</field>
<field name="field">date_maturity</field>
<field eval="8" name="sequence"/>
</record>
<record id="sp_journal_col8" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Debit</field>
<field name="field">debit</field>
<field eval="11" name="sequence"/>
</record>
<record id="sp_journal_col9" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Credit</field>
<field name="field">credit</field>
<field eval="12" name="sequence"/>
</record>
<record id="sp_journal_col10" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Tax</field>
<field name="field">account_tax_id</field>
<field eval="13" name="sequence"/>
</record>
<record id="sp_journal_col11" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Analytic Account</field>
<field name="field">analytic_account_id</field>
<field eval="14" name="sequence"/>
</record>
<record id="sp_journal_col24" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">State</field>
<field name="field">state</field>
<field eval="19" name="sequence"/>
</record>
<record id="sp_journal_col20" model="account.journal.column">
<field name="view_id" ref="account_sp_journal_view"/>
<field name="name">Reconcile</field>
<field name="field">reconcile_id</field>
<field eval="20" name="sequence"/>
</record>
<record id="account_sp_refund_journal_view" model="account.journal.view">
<field name="name">Sale/Purchase Refund Journal View</field>
</record>
<record id="sp_refund_journal_col1" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Date</field>
<field name="field">date</field>
<field eval="True" name="required"/>
<field eval="3" name="sequence"/>
</record>
<record id="sp_refund_journal_col2" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Journal Entry</field>
<field name="field">move_id</field>
<field eval="False" name="required"/>
<field eval="1" name="sequence"/>
</record>
<record id="sp_refund_journal_col3" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Ref</field>
<field name="field">ref</field>
<field eval="2" name="sequence"/>
</record>
<record id="sp_refund_journal_col4" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Account</field>
<field name="field">account_id</field>
<field eval="True" name="required"/>
<field eval="6" name="sequence"/>
</record>
<record id="sp_refund_journal_col5" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Partner</field>
<field name="field">partner_id</field>
<field eval="5" name="sequence"/>
</record>
<record id="sp_refund_journal_col6" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Name</field>
<field name="field">name</field>
<field eval="7" name="sequence"/>
<field eval="True" name="required"/>
</record>
<record id="sp_refund_journal_col7" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Due Date</field>
<field name="field">date_maturity</field>
<field eval="8" name="sequence"/>
</record>
<record id="sp_refund_journal_col8" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Debit</field>
<field name="field">debit</field>
<field eval="11" name="sequence"/>
</record>
<record id="sp_refund_journal_col9" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Credit</field>
<field name="field">credit</field>
<field eval="12" name="sequence"/>
</record>
<record id="sp_refund_journal_col10" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Tax</field>
<field name="field">account_tax_id</field>
<field eval="13" name="sequence"/>
</record>
<record id="sp_refund_journal_col11" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Analytic Account</field>
<field name="field">analytic_account_id</field>
<field eval="14" name="sequence"/>
</record>
<record id="sp_refund_journal_col24" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">State</field>
<field name="field">state</field>
<field eval="19" name="sequence"/>
</record>
<record id="sp_refund_journal_col20" model="account.journal.column">
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="name">Reconcile</field>
<field name="field">reconcile_id</field>
<field eval="20" name="sequence"/>
</record>
<!-- <!--
Account Journal Sequences Account Journal Sequences
--> -->
@ -518,7 +108,6 @@
<!-- <!--
Account Statement Sequences Account Statement Sequences
--> -->
<record id="sequence_reconcile" model="ir.sequence.type"> <record id="sequence_reconcile" model="ir.sequence.type">
<field name="name">Account Reconcile</field> <field name="name">Account Reconcile</field>
<field name="code">account.reconcile</field> <field name="code">account.reconcile</field>
@ -554,21 +143,6 @@
<field eval="1" name="number_next"/> <field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/> <field eval="1" name="number_increment"/>
</record> </record>
<!--
Sequence for analytic account
-->
<record id="seq_type_analytic_account" model="ir.sequence.type">
<field name="name">Analytic account</field>
<field name="code">account.analytic.account</field>
</record>
<record id="seq_analytic_account" model="ir.sequence">
<field name="name">Analytic account sequence</field>
<field name="code">account.analytic.account</field>
<field eval="3" name="padding"/>
<field eval="2708" name="number_next"/>
</record>
<!-- <!--
Invoice requests (deprecated) Invoice requests (deprecated)
--> -->
@ -577,7 +151,14 @@
<field name="object">account.invoice</field> <field name="object">account.invoice</field>
</record> </record>
<!-- mail: subtypes -->
<record id="mt_invoice_new" model="mail.message.subtype">
<field name="name">created</field>
<field name="res_model">account.invoice</field>
</record>
<record id="mt_invoice_paid" model="mail.message.subtype">
<field name="name">paid</field>
<field name="res_model">account.invoice</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data noupdate="1"> <data noupdate="1">
<!-- Types --> <!-- Types -->
@ -44,7 +45,6 @@
<record id="conf_chart0" model="account.account.template"> <record id="conf_chart0" model="account.account.template">
<field name="code">0</field> <field name="code">0</field>
<field name="name">Configurable Account Chart</field> <field name="name">Configurable Account Chart</field>
<field eval="0" name="parent_id"/>
<field name="type">view</field> <field name="type">view</field>
<field name="user_type" ref="data_account_type_view"/> <field name="user_type" ref="data_account_type_view"/>
</record> </record>
@ -381,7 +381,6 @@
<field name="property_account_income_categ" ref="conf_a_sale"/> <field name="property_account_income_categ" ref="conf_a_sale"/>
<field name="property_account_income_opening" ref="conf_o_income"/> <field name="property_account_income_opening" ref="conf_o_income"/>
<field name="property_account_expense_opening" ref="conf_o_expense"/> <field name="property_account_expense_opening" ref="conf_o_expense"/>
<field name="property_reserve_and_surplus_account" ref="conf_a_reserve_and_surplus"/>
<field name="complete_tax_set" eval="False"/> <field name="complete_tax_set" eval="False"/>
</record> </record>
@ -548,9 +547,8 @@
</record> </record>
<record id="action_wizard_multi_chart_todo" model="ir.actions.todo"> <record id="action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="name">Generate Chart of Accounts from a Chart Template</field> <field name="name">Set Your Accounting Options</field>
<field name="action_id" ref="account.action_wizard_multi_chart"/> <field name="action_id" ref="account.action_wizard_multi_chart"/>
<field name="category_id" ref="account.category_accounting_configuration"/>
<field name="type">automatic</field> <field name="type">automatic</field>
</record> </record>

View File

@ -127,9 +127,60 @@
<field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/> <field eval="time.strftime('%Y')+'-12-31'" name="date_stop"/>
<field name="company_id" ref="base.main_company"/> <field name="company_id" ref="base.main_company"/>
</record> </record>
<!-- Payment Term -->
<record id="account_payment_term" model="account.payment.term">
<field name="name">30 Days End of Month</field>
<field name="note">30 Days End of Month</field>
</record>
<record id="account_payment_term_line" model="account.payment.term.line">
<field name="name">30 Days End of Month</field>
<field name="value">balance</field>
<field eval="30" name="days"/>
<field eval="-1" name="days2"/>
<field eval="account_payment_term" name="payment_id"/>
</record>
<record id="account_payment_term_advance" model="account.payment.term">
<field name="name">30% Advance End 30 Days</field>
<field name="note">30% Advance End 30 Days</field>
</record>
<record id="account_payment_term_line_advance1" model="account.payment.term.line">
<field name="name">30% Advance</field>
<field name="value">procent</field>
<field eval="3" name="sequence"/>
<field eval="0.300000" name="value_amount"/>
<field eval="0" name="days"/>
<field eval="0" name="days2"/>
<field eval="account_payment_term_advance" name="payment_id"/>
</record>
<record id="account_payment_term_line_advance2" model="account.payment.term.line">
<field name="name">Remaining Balance</field>
<field name="value">balance</field>
<field eval="30" name="days"/>
<field eval="-1" name="days2"/>
<field eval="account_payment_term_advance" name="payment_id"/>
</record>
<record id="base.user_demo" model="res.users"> <record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('account.group_account_user'))]"/> <field name="groups_id" eval="[(4,ref('account.group_account_user'))]"/>
</record> </record>
<!-- Add payment term on some demo partners -->
<record id="base.res_partner_2" model="res.partner">
<field name="property_payment_term" ref="account_payment_term_net"/>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="property_payment_term" ref="account_payment_term"/>
<field name="property_supplier_payment_term" ref="account_payment_term"/>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="property_supplier_payment_term" ref="account_payment_term_net"/>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="property_supplier_payment_term" ref="account_payment_term"/>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1,50 +1,48 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<openerp> <openerp>
<data noupdate="1"> <data noupdate="1">
<record id="demo_invoice_0" model="account.invoice"> <record id="demo_invoice_0" model="account.invoice">
<field name="date_due" eval="time.strftime('%Y')+'-01-30'"/> <field name="date_due" eval="time.strftime('%Y')+'-01-30'"/>
<field name="payment_term" ref="account.account_payment_term"/> <field name="payment_term" ref="account.account_payment_term"/>
<field name="journal_id" ref="account.expenses_journal"/> <field name="journal_id" ref="account.expenses_journal"/>
<field name="currency_id" ref="base.EUR"/> <field name="currency_id" ref="base.EUR"/>
<field name="address_invoice_id" ref="base.res_partner_address_wong"/> <field name="user_id" ref="base.user_demo"/>
<field name="user_id" ref="base.user_demo"/> <field name="reference_type">none</field>
<field name="address_contact_id" ref="base.res_partner_address_wong"/> <field name="company_id" ref="base.main_company"/>
<field name="reference_type">none</field> <field name="state">draft</field>
<field name="company_id" ref="base.main_company"/> <field name="type">in_invoice</field>
<field name="state">draft</field> <field name="account_id" ref="account.a_pay"/>
<field name="type">in_invoice</field> <field eval="0" name="reconciled"/>
<field name="account_id" ref="account.a_pay"/> <field name="date_invoice" eval="time.strftime('%Y')+'-01-01'"/>
<field eval="0" name="reconciled"/> <field eval="14.0" name="amount_untaxed"/>
<field name="date_invoice" eval="time.strftime('%Y')+'-01-01'"/> <field eval="14.0" name="amount_total"/>
<field eval="14.0" name="amount_untaxed"/> <field name="partner_id" ref="base.res_partner_17"/>
<field eval="14.0" name="amount_total"/> </record>
<field name="partner_id" ref="base.res_partner_maxtor"/> <record id="demo_invoice_0_line_rpanrearpanelshe0" model="account.invoice.line">
</record> <field name="invoice_id" ref="demo_invoice_0"/>
<record id="demo_invoice_0_line_rpanrearpanelshe0" model="account.invoice.line"> <field name="account_id" ref="account.a_expense"/>
<field name="invoice_id" ref="demo_invoice_0"/> <field name="uos_id" ref="product.product_uom_unit"/>
<field name="account_id" ref="account.a_expense"/> <field name="price_unit" eval="10.0" />
<field name="uos_id" ref="product.product_uom_unit"/> <field name="price_subtotal" eval="10.0" />
<field name="price_unit" eval="10.0" /> <field name="company_id" ref="base.main_company"/>
<field name="price_subtotal" eval="10.0" /> <field name="invoice_line_tax_id" eval="[(6,0,[])]"/>
<field name="company_id" ref="base.main_company"/> <field name="product_id" ref="product.product_product_39"/>
<field name="invoice_line_tax_id" eval="[(6,0,[])]"/> <field name="quantity" eval="1.0" />
<field name="product_id" ref="product.product_product_rearpanelarm0"/> <field name="partner_id" ref="base.res_partner_16"/>
<field name="quantity" eval="1.0" /> <field name="name">Toner Cartridge</field>
<field name="partner_id" ref="base.res_partner_maxtor"/> </record>
<field name="name">[RPAN100] Rear Panel SHE100</field> <record id="demo_invoice_0_line_rckrackcm0" model="account.invoice.line">
</record> <field name="invoice_id" ref="demo_invoice_0"/>
<record id="demo_invoice_0_line_rckrackcm0" model="account.invoice.line"> <field name="account_id" ref="account.a_expense"/>
<field name="invoice_id" ref="demo_invoice_0"/> <field name="uos_id" ref="product.product_uom_unit"/>
<field name="account_id" ref="account.a_expense"/> <field name="price_unit" eval="4.0"/>
<field name="uos_id" ref="product.product_uom_unit"/> <field name="price_subtotal" eval="4.0"/>
<field name="price_unit" eval="4.0"/> <field name="company_id" ref="base.main_company"/>
<field name="price_subtotal" eval="4.0"/> <field name="invoice_line_tax_id" eval="[(6,0,[])]"/>
<field name="company_id" ref="base.main_company"/> <field name="product_id" ref="product.product_product_43"/>
<field name="invoice_line_tax_id" eval="[(6,0,[])]"/> <field name="quantity" eval="1.0" />
<field name="product_id" ref="product.product_product_shelf1"/> <field name="partner_id" ref="base.res_partner_17"/>
<field name="quantity" eval="1.0" /> <field name="name">Zed+ Antivirus</field>
<field name="partner_id" ref="base.res_partner_maxtor"/> </record>
<field name="name">[RCK200] Rack 200cm</field> </data>
</record>
</data>
</openerp> </openerp>

View File

@ -19,7 +19,6 @@
<record id="chart0" model="account.account"> <record id="chart0" model="account.account">
<field name="code">X0</field> <field name="code">X0</field>
<field name="name">Chart For Automated Tests</field> <field name="name">Chart For Automated Tests</field>
<field eval="0" name="parent_id"/>
<field name="type">view</field> <field name="type">view</field>
<field name="user_type" ref="data_account_type_view"/> <field name="user_type" ref="data_account_type_view"/>
</record> </record>
@ -123,6 +122,14 @@
<field name="type">other</field> <field name="type">other</field>
<field name="user_type" ref="data_account_type_income"/> <field name="user_type" ref="data_account_type_income"/>
</record> </record>
<record id="usd_bnk" model="account.account">
<field name="code">X11007</field>
<field name="name">USD Bank Account - (test)</field>
<field ref="cas" name="parent_id"/>
<field name="type">liquidity</field>
<field name="user_type" ref="data_account_type_asset"/>
<field name="currency_id" ref="base.USD"/>
</record>
<record model="account.account" id="liabilities_view"> <record model="account.account" id="liabilities_view">
<field name="name">Liabilities - (test)</field> <field name="name">Liabilities - (test)</field>
@ -297,14 +304,6 @@
<field name="company_id" ref="base.main_company"/> <field name="company_id" ref="base.main_company"/>
</record> </record>
<record forcecreate="True" id="property_reserve_and_surplus_account" model="ir.property">
<field name="name">property_account_receivable</field>
<field name="fields_id" search="[('model','=','res.company'),('name','=','property_reserve_and_surplus_account')]"/>
<field eval="'account.account,'+str(rsa)" name="value"/>
<field name="company_id" ref="base.main_company"/>
</record>
<!-- <!--
Account Journal Account Journal
--> -->
@ -313,7 +312,6 @@
<field name="name">Sales Journal - (test)</field> <field name="name">Sales Journal - (test)</field>
<field name="code">TSAJ</field> <field name="code">TSAJ</field>
<field name="type">sale</field> <field name="type">sale</field>
<field name="view_id" ref="account_sp_journal_view"/>
<field name="sequence_id" ref="sequence_sale_journal"/> <field name="sequence_id" ref="sequence_sale_journal"/>
<field model="account.account" name="default_credit_account_id" ref="a_sale"/> <field model="account.account" name="default_credit_account_id" ref="a_sale"/>
<field model="account.account" name="default_debit_account_id" ref="a_sale"/> <field model="account.account" name="default_debit_account_id" ref="a_sale"/>
@ -324,7 +322,6 @@
<field name="name">Sales Credit Note Journal - (test)</field> <field name="name">Sales Credit Note Journal - (test)</field>
<field name="code">TSCNJ</field> <field name="code">TSCNJ</field>
<field name="type">sale_refund</field> <field name="type">sale_refund</field>
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="sequence_id" ref="sequence_refund_sales_journal"/> <field name="sequence_id" ref="sequence_refund_sales_journal"/>
<field model="account.account" name="default_credit_account_id" ref="a_sale"/> <field model="account.account" name="default_credit_account_id" ref="a_sale"/>
<field model="account.account" name="default_debit_account_id" ref="a_sale"/> <field model="account.account" name="default_debit_account_id" ref="a_sale"/>
@ -336,7 +333,6 @@
<field name="name">Expenses Journal - (test)</field> <field name="name">Expenses Journal - (test)</field>
<field name="code">TEXJ</field> <field name="code">TEXJ</field>
<field name="type">purchase</field> <field name="type">purchase</field>
<field name="view_id" ref="account_sp_journal_view"/>
<field name="sequence_id" ref="sequence_purchase_journal"/> <field name="sequence_id" ref="sequence_purchase_journal"/>
<field model="account.account" name="default_debit_account_id" ref="a_expense"/> <field model="account.account" name="default_debit_account_id" ref="a_expense"/>
<field model="account.account" name="default_credit_account_id" ref="a_expense"/> <field model="account.account" name="default_credit_account_id" ref="a_expense"/>
@ -347,7 +343,6 @@
<field name="name">Expenses Credit Notes Journal - (test)</field> <field name="name">Expenses Credit Notes Journal - (test)</field>
<field name="code">TECNJ</field> <field name="code">TECNJ</field>
<field name="type">purchase_refund</field> <field name="type">purchase_refund</field>
<field name="view_id" ref="account_sp_refund_journal_view"/>
<field name="sequence_id" ref="sequence_refund_purchase_journal"/> <field name="sequence_id" ref="sequence_refund_purchase_journal"/>
<field model="account.account" name="default_debit_account_id" ref="a_expense"/> <field model="account.account" name="default_debit_account_id" ref="a_expense"/>
<field model="account.account" name="default_credit_account_id" ref="a_expense"/> <field model="account.account" name="default_credit_account_id" ref="a_expense"/>
@ -359,10 +354,9 @@
<field name="name">Bank Journal - (test)</field> <field name="name">Bank Journal - (test)</field>
<field name="code">TBNK</field> <field name="code">TBNK</field>
<field name="type">bank</field> <field name="type">bank</field>
<field name="view_id" ref="account_journal_bank_view"/>
<field name="sequence_id" ref="sequence_bank_journal"/> <field name="sequence_id" ref="sequence_bank_journal"/>
<field model="account.account" name="default_debit_account_id" ref="cash"/> <field model="account.account" name="default_debit_account_id" ref="bnk"/>
<field model="account.account" name="default_credit_account_id" ref="cash"/> <field model="account.account" name="default_credit_account_id" ref="bnk"/>
<field name="analytic_journal_id" ref="sit"/> <field name="analytic_journal_id" ref="sit"/>
<field name="user_id" ref="base.user_root"/> <field name="user_id" ref="base.user_root"/>
</record> </record>
@ -370,7 +364,6 @@
<field name="name">Checks Journal - (test)</field> <field name="name">Checks Journal - (test)</field>
<field name="code">TCHK</field> <field name="code">TCHK</field>
<field name="type">bank</field> <field name="type">bank</field>
<field name="view_id" ref="account_journal_bank_view"/>
<field name="sequence_id" ref="sequence_check_journal"/> <field name="sequence_id" ref="sequence_check_journal"/>
<field model="account.account" name="default_debit_account_id" ref="cash"/> <field model="account.account" name="default_debit_account_id" ref="cash"/>
<field model="account.account" name="default_credit_account_id" ref="cash"/> <field model="account.account" name="default_credit_account_id" ref="cash"/>
@ -381,7 +374,16 @@
<field name="name">Cash Journal - (test)</field> <field name="name">Cash Journal - (test)</field>
<field name="code">TCSH</field> <field name="code">TCSH</field>
<field name="type">cash</field> <field name="type">cash</field>
<field name="view_id" ref="account_journal_bank_view"/> <field name="profit_account_id" model="account.account" ref="rsa" />
<field name="loss_account_id" model="account.account" ref="rsa" />
<field name="internal_account_id" model="account.account" ref="rsa" />
<field name="with_last_closing_balance" eval="True" />
<!--
Usually, cash payment methods requires a control at opening and closing.
Bot for demo data, it's better to avoid the control step so that people
that test OpenERP arrive directly in the touchscreen UI.
-->
<field name="cash_control" eval="False"/>
<field name="sequence_id" ref="sequence_cash_journal"/> <field name="sequence_id" ref="sequence_cash_journal"/>
<field model="account.account" name="default_debit_account_id" ref="cash"/> <field model="account.account" name="default_debit_account_id" ref="cash"/>
<field model="account.account" name="default_credit_account_id" ref="cash"/> <field model="account.account" name="default_credit_account_id" ref="cash"/>
@ -392,7 +394,6 @@
<field name="name">Miscellaneous Journal - (test)</field> <field name="name">Miscellaneous Journal - (test)</field>
<field name="code">TMIS</field> <field name="code">TMIS</field>
<field name="type">general</field> <field name="type">general</field>
<field name="view_id" ref="account_journal_view"/>
<field name="sequence_id" ref="sequence_miscellaneous_journal"/> <field name="sequence_id" ref="sequence_miscellaneous_journal"/>
<field name="analytic_journal_id" ref="sit"/> <field name="analytic_journal_id" ref="sit"/>
<field name="user_id" ref="base.user_root"/> <field name="user_id" ref="base.user_root"/>
@ -401,13 +402,21 @@
<field name="name">Opening Entries Journal - (test)</field> <field name="name">Opening Entries Journal - (test)</field>
<field name="code">TOEJ</field> <field name="code">TOEJ</field>
<field name="type">situation</field> <field name="type">situation</field>
<field name="view_id" ref="account_journal_view"/>
<field name="sequence_id" ref="sequence_opening_journal"/> <field name="sequence_id" ref="sequence_opening_journal"/>
<field model="account.account" name="default_debit_account_id" ref="o_income"/> <field model="account.account" name="default_debit_account_id" ref="o_income"/>
<field model="account.account" name="default_credit_account_id" ref="o_expense"/> <field model="account.account" name="default_credit_account_id" ref="o_expense"/>
<field eval="True" name="centralisation"/> <field eval="True" name="centralisation"/>
<field name="user_id" ref="base.user_root"/> <field name="user_id" ref="base.user_root"/>
</record> </record>
<record id="bank_journal_usd" model="account.journal">
<field name="name">USD Bank Journal - (test)</field>
<field name="code">TUBK</field>
<field name="type">bank</field>
<field model="account.account" name="default_debit_account_id" ref="usd_bnk"/>
<field model="account.account" name="default_credit_account_id" ref="usd_bnk"/>
<field name="currency" ref="base.USD"/>
</record>
<!-- <!--
Product income and expense accounts, default parameters Product income and expense accounts, default parameters
--> -->

View File

@ -2,7 +2,7 @@
############################################################################## ##############################################################################
# #
# OpenERP, Open Source Business Applications # OpenERP, Open Source Business Applications
# Copyright (c) 2011 OpenERP S.A. <http://openerp.com> # Copyright (c) 2011-2012 OpenERP S.A. <http://openerp.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
@ -19,7 +19,7 @@
# #
############################################################################## ##############################################################################
from osv import fields, osv, orm from openerp.osv import osv
from edi import EDIMixin from edi import EDIMixin
INVOICE_LINE_EDI_STRUCT = { INVOICE_LINE_EDI_STRUCT = {
@ -30,7 +30,6 @@ INVOICE_LINE_EDI_STRUCT = {
'price_unit': True, 'price_unit': True,
'quantity': True, 'quantity': True,
'discount': True, 'discount': True,
'note': True,
# fields used for web preview only - discarded on import # fields used for web preview only - discarded on import
'price_subtotal': True, 'price_subtotal': True,
@ -75,7 +74,7 @@ class account_invoice(osv.osv, EDIMixin):
"""Exports a supplier or customer invoice""" """Exports a supplier or customer invoice"""
edi_struct = dict(edi_struct or INVOICE_EDI_STRUCT) edi_struct = dict(edi_struct or INVOICE_EDI_STRUCT)
res_company = self.pool.get('res.company') res_company = self.pool.get('res.company')
res_partner_address = self.pool.get('res.partner.address') res_partner = self.pool.get('res.partner')
edi_doc_list = [] edi_doc_list = []
for invoice in records: for invoice in records:
# generate the main report # generate the main report
@ -84,8 +83,7 @@ class account_invoice(osv.osv, EDIMixin):
edi_doc.update({ edi_doc.update({
'company_address': res_company.edi_export_address(cr, uid, invoice.company_id, context=context), 'company_address': res_company.edi_export_address(cr, uid, invoice.company_id, context=context),
'company_paypal_account': invoice.company_id.paypal_account, 'company_paypal_account': invoice.company_id.paypal_account,
'partner_address': res_partner_address.edi_export(cr, uid, [invoice.address_invoice_id], context=context)[0], 'partner_address': res_partner.edi_export(cr, uid, [invoice.partner_id], context=context)[0],
'currency': self.pool.get('res.currency').edi_export(cr, uid, [invoice.currency_id], context=context)[0], 'currency': self.pool.get('res.currency').edi_export(cr, uid, [invoice.currency_id], context=context)[0],
'partner_ref': invoice.reference or False, 'partner_ref': invoice.reference or False,
}) })
@ -102,8 +100,8 @@ class account_invoice(osv.osv, EDIMixin):
return tax_account return tax_account
def _edi_invoice_account(self, cr, uid, partner_id, invoice_type, context=None): def _edi_invoice_account(self, cr, uid, partner_id, invoice_type, context=None):
partner_pool = self.pool.get('res.partner') res_partner = self.pool.get('res.partner')
partner = partner_pool.browse(cr, uid, partner_id, context=context) partner = res_partner.browse(cr, uid, partner_id, context=context)
if invoice_type in ('out_invoice', 'out_refund'): if invoice_type in ('out_invoice', 'out_refund'):
invoice_account = partner.property_account_receivable invoice_account = partner.property_account_receivable
else: else:
@ -125,36 +123,33 @@ class account_invoice(osv.osv, EDIMixin):
# the desired company among the user's allowed companies # the desired company among the user's allowed companies
self._edi_requires_attributes(('company_id','company_address','type'), edi_document) self._edi_requires_attributes(('company_id','company_address','type'), edi_document)
res_partner_address = self.pool.get('res.partner.address')
res_partner = self.pool.get('res.partner') res_partner = self.pool.get('res.partner')
# imported company = new partner xid, company_name = edi_document.pop('company_id')
src_company_id, src_company_name = edi_document.pop('company_id') # Retrofit address info into a unified partner info (changed in v7 - used to keep them separate)
partner_id = self.edi_import_relation(cr, uid, 'res.partner', src_company_name, company_address_edi = edi_document.pop('company_address')
src_company_id, context=context) company_address_edi['name'] = company_name
invoice_type = edi_document['type'] company_address_edi['is_company'] = True
partner_value = {} company_address_edi['__import_model'] = 'res.partner'
if invoice_type in ('out_invoice', 'out_refund'): company_address_edi['__id'] = xid # override address ID, as of v7 they should be the same anyway
partner_value.update({'customer': True}) if company_address_edi.get('logo'):
if invoice_type in ('in_invoice', 'in_refund'): company_address_edi['image'] = company_address_edi.pop('logo')
partner_value.update({'supplier': True})
res_partner.write(cr, uid, [partner_id], partner_value, context=context)
# imported company_address = new partner address invoice_type = edi_document['type']
address_info = edi_document.pop('company_address') if invoice_type.startswith('out_'):
address_info['partner_id'] = (src_company_id, src_company_name) company_address_edi['customer'] = True
address_info['type'] = 'invoice' else:
address_id = res_partner_address.edi_import(cr, uid, address_info, context=context) company_address_edi['supplier'] = True
partner_id = res_partner.edi_import(cr, uid, company_address_edi, context=context)
# modify edi_document to refer to new partner # modify edi_document to refer to new partner
partner_address = res_partner_address.browse(cr, uid, address_id, context=context) partner = res_partner.browse(cr, uid, partner_id, context=context)
edi_document['partner_id'] = (src_company_id, src_company_name) partner_edi_m2o = self.edi_m2o(cr, uid, partner, context=context)
edi_document.pop('partner_address', False) # ignored edi_document['partner_id'] = partner_edi_m2o
edi_document['address_invoice_id'] = self.edi_m2o(cr, uid, partner_address, context=context) edi_document.pop('partner_address', None) # ignored, that's supposed to be our own address!
return partner_id return partner_id
def edi_import(self, cr, uid, edi_document, context=None): def edi_import(self, cr, uid, edi_document, context=None):
""" During import, invoices will import the company that is provided in the invoice as """ During import, invoices will import the company that is provided in the invoice as
a new partner (e.g. supplier company for a customer invoice will be come a supplier a new partner (e.g. supplier company for a customer invoice will be come a supplier
@ -193,7 +188,7 @@ class account_invoice(osv.osv, EDIMixin):
invoice_type = invoice_type.startswith('in_') and invoice_type.replace('in_','out_') or invoice_type.replace('out_','in_') invoice_type = invoice_type.startswith('in_') and invoice_type.replace('in_','out_') or invoice_type.replace('out_','in_')
edi_document['type'] = invoice_type edi_document['type'] = invoice_type
#import company as a new partner # import company as a new partner
partner_id = self._edi_import_company(cr, uid, edi_document, context=context) partner_id = self._edi_import_company(cr, uid, edi_document, context=context)
# Set Account # Set Account

View File

@ -1,17 +1,6 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<openerp> <openerp>
<data> <data>
<!-- EDI Export + Send email Action -->
<record id="ir_actions_server_edi_invoice" model="ir.actions.server">
<field name="code">if (object.type in ('out_invoice', 'out_refund')) and not object.partner_id.opt_out: object.edi_export_and_email(template_ext_id='account.email_template_edi_invoice', context=context)</field>
<field eval="6" name="sequence"/>
<field name="state">code</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="account.model_account_invoice"/>
<field name="condition">True</field>
<field name="name">Auto-email confirmed invoices</field>
</record>
<!-- EDI related Email Templates menu --> <!-- EDI related Email Templates menu -->
<record model="ir.actions.act_window" id="action_email_templates"> <record model="ir.actions.act_window" id="action_email_templates">
<field name="name">Email Templates</field> <field name="name">Email Templates</field>
@ -27,28 +16,26 @@
</data> </data>
<!-- Mail template and workflow bindings are done in a NOUPDATE block <!-- Mail template are declared in a NOUPDATE block
so users can freely customize/delete them --> so users can freely customize/delete them -->
<data noupdate="1"> <data noupdate="1">
<!-- bind the mailing server action to invoice open activity -->
<record id="account.act_open" model="workflow.activity">
<field name="action_id" ref="ir_actions_server_edi_invoice"/>
</record>
<!--Email template --> <!--Email template -->
<record id="email_template_edi_invoice" model="email.template"> <record id="email_template_edi_invoice" model="email.template">
<field name="name">Automated Invoice Notification Mail</field> <field name="name">Invoice - Send by Email</field>
<field name="email_from">${object.user_id.user_email or object.company_id.email or 'noreply@localhost'}</field> <field name="email_from">${object.user_id.email or object.company_id.email or 'noreply@localhost'}</field>
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field> <field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field>
<field name="email_to">${object.address_invoice_id.email or ''}</field> <field name="email_recipients">${object.partner_id.id}</field>
<field name="model_id" ref="account.model_account_invoice"/> <field name="model_id" ref="account.model_account_invoice"/>
<field name="auto_delete" eval="True"/> <field name="auto_delete" eval="True"/>
<field name="report_template" ref="account_invoices"/>
<field name="report_name">Invoice_${(object.number or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''}</field>
<field name="lang">${object.partner_id.lang}</field>
<field name="body_html"><![CDATA[ <field name="body_html"><![CDATA[
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); "> <div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; ">
<p>Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},</p> <p>Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},</p>
<p>A new invoice is available for ${object.partner_id.name}: </p> <p>A new invoice is available for you: </p>
<p style="border-left: 1px solid #8e0000; margin-left: 30px;"> <p style="border-left: 1px solid #8e0000; margin-left: 30px;">
&nbsp;&nbsp;<strong>REFERENCES</strong><br /> &nbsp;&nbsp;<strong>REFERENCES</strong><br />
@ -58,21 +45,17 @@
% if object.origin: % if object.origin:
&nbsp;&nbsp;Order reference: ${object.origin}<br /> &nbsp;&nbsp;Order reference: ${object.origin}<br />
% endif % endif
&nbsp;&nbsp;Your contact: <a href="mailto:${object.user_id.user_email or ''}?subject=Invoice%20${object.number}">${object.user_id.name}</a> % if object.user_id:
&nbsp;&nbsp;Your contact: <a href="mailto:${object.user_id.email or ''}?subject=Invoice%20${object.number}">${object.user_id.name}</a>
% endif
</p> </p>
<p> % if object.company_id.paypal_account and object.type in ('out_invoice'):
You can view the invoice document, download it and pay online using the following link:
</p>
<a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #FFF; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-color: #8E0000; border-radius: 5px 5px; background-repeat: repeat no-repeat;"
href="${ctx.get('edi_web_url_view') or ''}">View Invoice</a>
% if object.company_id.paypal_account and object.type in ('out_invoice', 'in_refund'):
<% <%
comp_name = quote(object.company_id.name) comp_name = quote(object.company_id.name)
inv_number = quote(object.number) inv_number = quote(object.number)
paypal_account = quote(object.company_id.paypal_account) paypal_account = quote(object.company_id.paypal_account)
inv_amount = quote(str(object.amount_total)) inv_amount = quote(str(object.residual))
cur_name = quote(object.currency_id.name) cur_name = quote(object.currency_id.name)
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=%s&amp;item_name=%s%%20Invoice%%20%s&amp;" \ paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=%s&amp;item_name=%s%%20Invoice%%20%s&amp;" \
"invoice=%s&amp;amount=%s&amp;currency_code=%s&amp;button_subtype=services&amp;no_note=1&amp;bn=OpenERP_Invoice_PayNow_%s" % \ "invoice=%s&amp;amount=%s&amp;currency_code=%s&amp;button_subtype=services&amp;no_note=1&amp;bn=OpenERP_Invoice_PayNow_%s" % \
@ -91,7 +74,7 @@
<br/> <br/>
<br/> <br/>
<div style="width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;"> <div style="width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;">
<h3 style="margin: 0px; padding: 2px 14px; font-size: 12px; color: #FFF;"> <h3 style="margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;">
<strong style="text-transform:uppercase;">${object.company_id.name}</strong></h3> <strong style="text-transform:uppercase;">${object.company_id.name}</strong></h3>
</div> </div>
<div style="width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;"> <div style="width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;">
@ -123,64 +106,6 @@
</div> </div>
</div> </div>
]]></field> ]]></field>
<field name="body_text"><![CDATA[
Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},
A new invoice is available for ${object.partner_id.name}:
| Invoice number: *${object.number}*
| Invoice total: *${object.amount_total} ${object.currency_id.name}*
| Invoice date: ${object.date_invoice}
% if object.origin:
| Order reference: ${object.origin}
% endif
| Your contact: ${object.user_id.name} ${object.user_id.user_email and '<%s>'%(object.user_id.user_email) or ''}
You can view the invoice document, download it and pay online using the following link:
${ctx.get('edi_web_url_view') or 'n/a'}
% if object.company_id.paypal_account and object.type in ('out_invoice', 'in_refund'):
<%
comp_name = quote(object.company_id.name)
inv_number = quote(object.number)
paypal_account = quote(object.company_id.paypal_account)
inv_amount = quote(str(object.amount_total))
cur_name = quote(object.currency_id.name)
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Invoice%%20%s"\
"&invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1&bn=OpenERP_Invoice_PayNow_%s" % \
(paypal_account,comp_name,inv_number,inv_number,inv_amount,cur_name,cur_name)
%>
It is also possible to directly pay with Paypal:
${paypal_url}
% endif
If you have any question, do not hesitate to contact us.
Thank you for choosing ${object.company_id.name}!
--
${object.user_id.name} ${object.user_id.user_email and '<%s>'%(object.user_id.user_email) or ''}
${object.company_id.name}
% if object.company_id.street:
${object.company_id.street or ''}
% endif
% if object.company_id.street2:
${object.company_id.street2}
% endif
% if object.company_id.city or object.company_id.zip:
${object.company_id.zip or ''} ${object.company_id.city or ''}
% endif
% if object.company_id.country_id:
${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}
% endif
% if object.company_id.phone:
Phone: ${object.company_id.phone}
% endif
% if object.company_id.website:
${object.company_id.website or ''}
% endif
]]></field>
</record> </record>
</data> </data>
</openerp> </openerp>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10955
addons/account/i18n/es_DO.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

11268
addons/account/i18n/es_UY.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

12740
addons/account/i18n/ja.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More