[MERGE]merge with trunk

bzr revid: kbh@tinyerp.com-20121204061729-tl6loso2kr6imc2t
This commit is contained in:
Khushboo Bhatt (Open ERP) 2012-12-04 11:47:29 +05:30
commit a865423e0f
7769 changed files with 2174778 additions and 1615206 deletions

View File

@ -63,6 +63,8 @@ for a particular financial year and for preparation of vouchers there is a modul
'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',
@ -71,7 +73,6 @@ for a particular financial year and for preparation of vouchers there is a modul
'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',
@ -85,14 +86,12 @@ for a particular financial year and for preparation of vouchers there is a modul
'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',
@ -126,6 +125,16 @@ for a particular financial year and for preparation of vouchers there is a modul
'res_config_view.xml', 'res_config_view.xml',
'account_pre_install.yml' 'account_pre_install.yml'
], ],
'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': [
'demo/account_demo.xml', 'demo/account_demo.xml',
'project/project_demo.xml', 'project/project_demo.xml',
@ -151,6 +160,5 @@ for a particular financial year and for preparation of vouchers there is a modul
], ],
'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:

View File

@ -30,6 +30,8 @@ from osv import fields, osv
import decimal_precision as dp import decimal_precision as dp
from tools.translate import _ from tools.translate import _
from tools.float_utils import float_round from tools.float_utils import float_round
from openerp import SUPERUSER_ID
import tools
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -109,7 +111,7 @@ class account_payment_term_line(osv.osv):
'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \ 'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \
"If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."), "If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."),
'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."), 'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."),
'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True), 'payment_id': fields.many2one('account.payment.term', 'Payment Term', required=True, select=True, ondelete='cascade'),
} }
_defaults = { _defaults = {
'value': 'balance', 'value': 'balance',
@ -153,6 +155,7 @@ class account_account_type(osv.osv):
return res return res
def _save_report_type(self, cr, uid, account_type_id, field_name, field_value, arg, context=None): def _save_report_type(self, cr, uid, account_type_id, field_name, field_value, arg, context=None):
field_value = field_value or 'none'
obj_data = self.pool.get('ir.model.data') obj_data = self.pool.get('ir.model.data')
obj_financial_report = self.pool.get('account.financial.report') obj_financial_report = self.pool.get('account.financial.report')
#unlink if it exists somewhere in the financial reports related to BS or PL #unlink if it exists somewhere in the financial reports related to BS or PL
@ -179,7 +182,7 @@ class account_account_type(osv.osv):
'Balance' will generally be used for cash accounts. 'Balance' will generally be used for cash accounts.
'Detail' will copy each existing journal item of the previous year, even the reconciled ones. 'Detail' will copy each existing journal item of the previous year, even the reconciled ones.
'Unreconciled' will copy only the journal items that were unreconciled on the first day of the new fiscal year."""), 'Unreconciled' will copy only the journal items that were unreconciled on the first day of the new fiscal year."""),
'report_type': fields.function(_get_current_report_type, fnct_inv=_save_report_type, type='selection', string='P&L / BS Category', 'report_type': fields.function(_get_current_report_type, fnct_inv=_save_report_type, type='selection', string='P&L / BS Category', store=True,
selection= [('none','/'), selection= [('none','/'),
('income', _('Profit & Loss (Income account)')), ('income', _('Profit & Loss (Income account)')),
('expense', _('Profit & Loss (Expense account)')), ('expense', _('Profit & Loss (Expense account)')),
@ -225,7 +228,7 @@ class account_account(osv.osv):
while pos < len(args): while pos < len(args):
if args[pos][0] == 'code' and args[pos][1] in ('like', 'ilike') and args[pos][2]: if args[pos][0] == 'code' and args[pos][1] in ('like', 'ilike') and args[pos][2]:
args[pos] = ('code', '=like', str(args[pos][2].replace('%', ''))+'%') args[pos] = ('code', '=like', tools.ustr(args[pos][2].replace('%', ''))+'%')
if args[pos][0] == 'journal_id': if args[pos][0] == 'journal_id':
if not args[pos][2]: if not args[pos][2]:
del args[pos] del args[pos]
@ -297,7 +300,6 @@ class account_account(osv.osv):
if aml_query.strip(): if aml_query.strip():
wheres.append(aml_query.strip()) wheres.append(aml_query.strip())
filters = " AND ".join(wheres) filters = " AND ".join(wheres)
_logger.debug('Filters: %s',(filters))
# IN might not work ideally in case there are too many # IN might not work ideally in case there are too many
# children_and_consolidated, in that case join on a # children_and_consolidated, in that case join on a
# values() e.g.: # values() e.g.:
@ -313,7 +315,6 @@ class account_account(osv.osv):
" GROUP BY l.account_id") " GROUP BY l.account_id")
params = (tuple(children_and_consolidated),) + query_params params = (tuple(children_and_consolidated),) + query_params
cr.execute(request, params) cr.execute(request, params)
_logger.debug('Status: %s',(cr.statusmessage))
for row in cr.dictfetchall(): for row in cr.dictfetchall():
accounts[row['id']] = row accounts[row['id']] = row
@ -540,10 +541,18 @@ class account_account(osv.osv):
return False return False
return True return True
def _check_company_account(self, cr, uid, ids, context=None):
for account in self.browse(cr, uid, ids, context=context):
if account.parent_id:
if account.company_id != account.parent_id.company_id:
return False
return True
_constraints = [ _constraints = [
(_check_recursion, 'Error!\nYou cannot create recursive accounts.', ['parent_id']), (_check_recursion, 'Error!\nYou cannot create recursive accounts.', ['parent_id']),
(_check_type, 'Configuration Error!\nYou cannot define children to an account with internal type different of "View".', ['type']), (_check_type, 'Configuration Error!\nYou cannot define children to an account with internal type different of "View".', ['type']),
(_check_account_type, 'Configuration Error!\nYou cannot select an account type with a deferral method different of "Unreconciled" for accounts with internal type "Payable/Receivable".', ['user_type','type']), (_check_account_type, 'Configuration Error!\nYou cannot select an account type with a deferral method different of "Unreconciled" for accounts with internal type "Payable/Receivable".', ['user_type','type']),
(_check_company_account, 'Error!\nYou cannot create an account which has parent account of different company.', ['parent_id']),
] ]
_sql_constraints = [ _sql_constraints = [
('code_company_uniq', 'unique (code,company_id)', 'The code of the account must be unique per company !') ('code_company_uniq', 'unique (code,company_id)', 'The code of the account must be unique per company !')
@ -593,13 +602,13 @@ class account_account(osv.osv):
res.append((record['id'], name)) res.append((record['id'], name))
return res return res
def copy(self, cr, uid, id, default={}, context=None, done_list=[], local=False): def copy(self, cr, uid, id, default=None, context=None, done_list=None, local=False):
default = {} if default is None else default.copy()
if done_list is None:
done_list = []
account = self.browse(cr, uid, id, context=context) account = self.browse(cr, uid, id, context=context)
new_child_ids = [] new_child_ids = []
if not default: default.update(code=_("%s (copy)") % (account['code'] or ''))
default = {}
default = default.copy()
default['code'] = (account['code'] or '') + '(copy)'
if not local: if not local:
done_list = [] done_list = []
if account.id in done_list: if account.id in done_list:
@ -632,8 +641,7 @@ class account_account(osv.osv):
return True return True
def _check_allow_type_change(self, cr, uid, ids, new_type, context=None): def _check_allow_type_change(self, cr, uid, ids, new_type, context=None):
group1 = ['payable', 'receivable', 'other'] restricted_groups = ['consolidation','view']
group2 = ['consolidation','view']
line_obj = self.pool.get('account.move.line') line_obj = self.pool.get('account.move.line')
for account in self.browse(cr, uid, ids, context=context): for account in self.browse(cr, uid, ids, context=context):
old_type = account.type old_type = account.type
@ -641,14 +649,25 @@ class account_account(osv.osv):
if line_obj.search(cr, uid, [('account_id', 'in', account_ids)]): if line_obj.search(cr, uid, [('account_id', 'in', account_ids)]):
#Check for 'Closed' type #Check for 'Closed' type
if old_type == 'closed' and new_type !='closed': if old_type == 'closed' and new_type !='closed':
raise osv.except_osv(_('Warning!'), _("You cannot change the type of account from 'Closed' to any other type which contains journal items!")) raise osv.except_osv(_('Warning !'), _("You cannot change the type of account from 'Closed' to any other type as it contains journal items!"))
#Check for change From group1 to group2 and vice versa # Forbid to change an account type for restricted_groups as it contains journal items (or if one of its children does)
if (old_type in group1 and new_type in group2) or (old_type in group2 and new_type in group1): if (new_type in restricted_groups):
raise osv.except_osv(_('Warning!'), _("You cannot change the type of account from '%s' to '%s' type as it contains journal items!") % (old_type,new_type,)) raise osv.except_osv(_('Warning !'), _("You cannot change the type of account to '%s' type as it contains journal items!") % (new_type,))
return True
# For legal reason (forbiden to modify journal entries which belongs to a closed fy or period), Forbid to modify
# the code of an account if journal entries have been already posted on this account. This cannot be simply
# 'configurable' since it can lead to a lack of confidence in OpenERP and this is what we want to change.
def _check_allow_code_change(self, cr, uid, ids, context=None):
line_obj = self.pool.get('account.move.line')
for account in self.browse(cr, uid, ids, context=context):
account_ids = self.search(cr, uid, [('id', 'child_of', [account.id])], context=context)
if line_obj.search(cr, uid, [('account_id', 'in', account_ids)], context=context):
raise osv.except_osv(_('Warning !'), _("You cannot change the code of account which contains journal items!"))
return True return True
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
if context is None: if context is None:
context = {} context = {}
if not ids: if not ids:
@ -668,6 +687,8 @@ class account_account(osv.osv):
self._check_moves(cr, uid, ids, "write", context=context) self._check_moves(cr, uid, ids, "write", context=context)
if 'type' in vals.keys(): if 'type' in vals.keys():
self._check_allow_type_change(cr, uid, ids, vals['type'], context=context) self._check_allow_type_change(cr, uid, ids, vals['type'], context=context)
if 'code' in vals.keys():
self._check_allow_code_change(cr, uid, ids, context=context)
return super(account_account, self).write(cr, uid, ids, vals, context=context) return super(account_account, self).write(cr, uid, ids, vals, context=context)
def unlink(self, cr, uid, ids, context=None): def unlink(self, cr, uid, ids, context=None):
@ -676,44 +697,6 @@ class account_account(osv.osv):
account_account() account_account()
class account_journal_view(osv.osv):
_name = "account.journal.view"
_description = "Journal View"
_columns = {
'name': fields.char('Journal View', size=64, required=True),
'columns_id': fields.one2many('account.journal.column', 'view_id', 'Columns')
}
_order = "name"
account_journal_view()
class account_journal_column(osv.osv):
def _col_get(self, cr, user, context=None):
result = []
cols = self.pool.get('account.move.line')._columns
for col in cols:
if col in ('period_id', 'journal_id'):
continue
result.append( (col, cols[col].string) )
result.sort()
return result
_name = "account.journal.column"
_description = "Journal Column"
_columns = {
'name': fields.char('Column Name', size=64, required=True),
'field': fields.selection(_col_get, 'Field Name', required=True, size=32),
'view_id': fields.many2one('account.journal.view', 'Journal View', select=True),
'sequence': fields.integer('Sequence', help="Gives the sequence order to journal column.", readonly=True),
'required': fields.boolean('Required'),
'readonly': fields.boolean('Readonly'),
}
_order = "view_id, sequence"
account_journal_column()
class account_journal(osv.osv): class account_journal(osv.osv):
_name = "account.journal" _name = "account.journal"
_description = "Journal" _description = "Journal"
@ -729,7 +712,6 @@ class account_journal(osv.osv):
" Select 'Opening/Closing Situation' for entries generated for new fiscal years."), " Select 'Opening/Closing Situation' for entries generated for new fiscal years."),
'type_control_ids': fields.many2many('account.account.type', 'account_journal_type_rel', 'journal_id','type_id', 'Type Controls', domain=[('code','<>','view'), ('code', '<>', 'closed')]), 'type_control_ids': fields.many2many('account.account.type', 'account_journal_type_rel', 'journal_id','type_id', 'Type Controls', domain=[('code','<>','view'), ('code', '<>', 'closed')]),
'account_control_ids': fields.many2many('account.account', 'account_account_type_rel', 'journal_id','account_id', 'Account', domain=[('type','<>','view'), ('type', '<>', 'closed')]), 'account_control_ids': fields.many2many('account.account', 'account_account_type_rel', 'journal_id','account_id', 'Account', domain=[('type','<>','view'), ('type', '<>', 'closed')]),
'view_id': fields.many2one('account.journal.view', 'Display Mode', required=True, help="Gives the view used when writing or browsing entries in this journal. The view tells OpenERP which fields should be visible, required or readonly and in which order. You can create your own view for a faster encoding in each journal."),
'default_credit_account_id': fields.many2one('account.account', 'Default Credit Account', domain="[('type','!=','view')]", help="It acts as a default account for credit amount"), 'default_credit_account_id': fields.many2one('account.account', 'Default Credit Account', domain="[('type','!=','view')]", help="It acts as a default account for credit amount"),
'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account', domain="[('type','!=','view')]", help="It acts as a default account for debit amount"), 'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account', domain="[('type','!=','view')]", help="It acts as a default account for debit amount"),
'centralisation': fields.boolean('Centralised Counterpart', help="Check this box to determine that each entry of this journal won't create a new counterpart but will share the same counterpart. This is used in fiscal year closing."), 'centralisation': fields.boolean('Centralised Counterpart', help="Check this box to determine that each entry of this journal won't create a new counterpart but will share the same counterpart. This is used in fiscal year closing."),
@ -746,9 +728,11 @@ class account_journal(osv.osv):
'profit_account_id' : fields.many2one('account.account', 'Profit Account'), 'profit_account_id' : fields.many2one('account.account', 'Profit Account'),
'loss_account_id' : fields.many2one('account.account', 'Loss Account'), 'loss_account_id' : fields.many2one('account.account', 'Loss Account'),
'internal_account_id' : fields.many2one('account.account', 'Internal Transfers Account', select=1), 'internal_account_id' : fields.many2one('account.account', 'Internal Transfers Account', select=1),
'cash_control' : fields.boolean('Cash Control', help='If you want the journal should be control at opening/closing, check this option'),
} }
_defaults = { _defaults = {
'cash_control' : False,
'with_last_closing_balance' : False, 'with_last_closing_balance' : False,
'user_id': lambda self, cr, uid, context: uid, 'user_id': lambda self, cr, uid, context: uid,
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id, 'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
@ -773,14 +757,15 @@ class account_journal(osv.osv):
(_check_currency, 'Configuration error!\nThe currency chosen should be shared by the default accounts too.', ['currency','default_debit_account_id','default_credit_account_id']), (_check_currency, 'Configuration error!\nThe currency chosen should be shared by the default accounts too.', ['currency','default_debit_account_id','default_credit_account_id']),
] ]
def copy(self, cr, uid, id, default={}, context=None, done_list=[], local=False): def copy(self, cr, uid, id, default=None, context=None, done_list=None, local=False):
default = {} if default is None else default.copy()
if done_list is None:
done_list = []
journal = self.browse(cr, uid, id, context=context) journal = self.browse(cr, uid, id, context=context)
if not default: default.update(
default = {} code=_("%s (copy)") % (journal['code'] or ''),
default = default.copy() name=_("%s (copy)") % (journal['name'] or ''),
default['code'] = (journal['code'] or '') + '(copy)' sequence_id=False)
default['name'] = (journal['name'] or '') + '(copy)'
default['sequence_id'] = False
return super(account_journal, self).copy(cr, uid, id, default, context=context) return super(account_journal, self).copy(cr, uid, id, default, context=context)
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
@ -817,7 +802,7 @@ class account_journal(osv.osv):
if not 'sequence_id' in vals or not vals['sequence_id']: if not 'sequence_id' in vals or not vals['sequence_id']:
# if we have the right to create a journal, we should be able to # if we have the right to create a journal, we should be able to
# create it's sequence. # create it's sequence.
vals.update({'sequence_id': self.create_sequence(cr, 1, vals, context)}) vals.update({'sequence_id': self.create_sequence(cr, SUPERUSER_ID, vals, context)})
return super(account_journal, self).create(cr, uid, vals, context) return super(account_journal, self).create(cr, uid, vals, context)
def name_get(self, cr, user, ids, context=None): def name_get(self, cr, user, ids, context=None):
@ -832,6 +817,10 @@ class account_journal(osv.osv):
@return: Returns a list of tupples containing id, name @return: Returns a list of tupples containing id, name
""" """
if not ids:
return []
if isinstance(ids, (int, long)):
ids = [ids]
result = self.browse(cr, user, ids, context=context) result = self.browse(cr, user, ids, context=context)
res = [] res = []
for rs in result: for rs in result:
@ -858,37 +847,6 @@ class account_journal(osv.osv):
return self.name_get(cr, user, ids, context=context) return self.name_get(cr, user, ids, context=context)
def onchange_type(self, cr, uid, ids, type, currency, context=None):
obj_data = self.pool.get('ir.model.data')
user_pool = self.pool.get('res.users')
type_map = {
'sale':'account_sp_journal_view',
'sale_refund':'account_sp_refund_journal_view',
'purchase':'account_sp_journal_view',
'purchase_refund':'account_sp_refund_journal_view',
'cash':'account_journal_bank_view',
'bank':'account_journal_bank_view',
'general':'account_journal_view',
'situation':'account_journal_view'
}
res = {}
view_id = type_map.get(type, 'account_journal_view')
user = user_pool.browse(cr, uid, uid)
if type in ('cash', 'bank') and currency and user.company_id.currency_id.id != currency:
view_id = 'account_journal_bank_view_multi'
data_id = obj_data.search(cr, uid, [('model','=','account.journal.view'), ('name','=',view_id)])
data = obj_data.browse(cr, uid, data_id[0], context=context)
res.update({
'centralisation':type == 'situation',
'view_id':data.res_id,
})
return {
'value':res
}
account_journal() account_journal()
class account_fiscalyear(osv.osv): class account_fiscalyear(osv.osv):
@ -999,7 +957,7 @@ class account_period(osv.osv):
'date_stop': fields.date('End of Period', required=True, states={'done':[('readonly',True)]}), 'date_stop': fields.date('End of Period', required=True, states={'done':[('readonly',True)]}),
'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True), 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True),
'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True, 'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True,
help='When monthly periods are created. The state is \'Draft\'. At the end of monthly period it is in \'Done\' state.'), help='When monthly periods are created. The status is \'Draft\'. At the end of monthly period it is in \'Done\' status.'),
'company_id': fields.related('fiscalyear_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) 'company_id': fields.related('fiscalyear_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True)
} }
_defaults = { _defaults = {
@ -1126,7 +1084,7 @@ class account_journal_period(osv.osv):
'icon': fields.function(_icon_get, string='Icon', type='char', size=32), 'icon': fields.function(_icon_get, string='Icon', type='char', size=32),
'active': fields.boolean('Active', required=True, help="If the active field is set to False, it will allow you to hide the journal period without removing it."), 'active': fields.boolean('Active', required=True, help="If the active field is set to False, it will allow you to hide the journal period without removing it."),
'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'Status', required=True, readonly=True, 'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'Status', required=True, readonly=True,
help='When journal period is created. The state is \'Draft\'. If a report is printed it comes to \'Printed\' state. When all transactions are done, it comes in \'Done\' state.'), help='When journal period is created. The status is \'Draft\'. If a report is printed it comes to \'Printed\' status. When all transactions are done, it comes in \'Done\' status.'),
'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'), 'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'),
'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) 'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True)
} }
@ -1169,7 +1127,8 @@ class account_fiscalyear(osv.osv):
'end_journal_period_id':fields.many2one('account.journal.period','End of Year Entries Journal', readonly=True), 'end_journal_period_id':fields.many2one('account.journal.period','End of Year Entries Journal', readonly=True),
} }
def copy(self, cr, uid, id, default={}, context=None): def copy(self, cr, uid, id, default=None, context=None):
default = {} if default is None else default.copy()
default.update({ default.update({
'period_ids': [], 'period_ids': [],
'end_journal_period_id': False 'end_journal_period_id': False
@ -1273,7 +1232,7 @@ class account_move(osv.osv):
'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}), 'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}),
'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}),
'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'Status', required=True, readonly=True, 'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'Status', required=True, readonly=True,
help='All manually created new journal entries are usually in the state \'Unposted\', but you can set the option to skip that state on the related journal. In that case, they will behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' state.'), help='All manually created new journal entries are usually in the status \'Unposted\', but you can set the option to skip that status on the related journal. In that case, they will behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' status.'),
'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}), 'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}),
'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'), 'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'),
'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True), 'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True),
@ -1367,13 +1326,6 @@ class account_move(osv.osv):
'WHERE id IN %s', ('draft', tuple(ids),)) 'WHERE id IN %s', ('draft', tuple(ids),))
return True return True
def onchange_line_id(self, cr, uid, ids, line_ids, context=None):
balance = 0.0
for line in line_ids:
if line[2]:
balance += (line[2]['debit'] or 0.00)- (line[2]['credit'] or 0.00)
return {'value': {'balance': balance}}
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
if context is None: if context is None:
context = {} context = {}
@ -1394,7 +1346,7 @@ class account_move(osv.osv):
if not l[0]: if not l[0]:
l[2].update({ l[2].update({
'reconcile_id':False, 'reconcile_id':False,
'reconcil_partial_id':False, 'reconcile_partial_id':False,
'analytic_lines':False, 'analytic_lines':False,
'invoice':False, 'invoice':False,
'ref':False, 'ref':False,
@ -1422,15 +1374,18 @@ class account_move(osv.osv):
if 'line_id' in vals: if 'line_id' in vals:
c = context.copy() c = context.copy()
c['novalidate'] = True c['novalidate'] = True
c['period_id'] = vals['period_id'] if 'period_id' in vals else self._get_period(cr, uid, context)
c['journal_id'] = vals['journal_id']
if 'date' in vals: c['date'] = vals['date']
result = super(account_move, self).create(cr, uid, vals, c) result = super(account_move, self).create(cr, uid, vals, c)
self.validate(cr, uid, [result], context) self.validate(cr, uid, [result], context)
else: else:
result = super(account_move, self).create(cr, uid, vals, context) result = super(account_move, self).create(cr, uid, vals, context)
return result return result
def copy(self, cr, uid, id, default={}, context=None): def copy(self, cr, uid, id, default=None, context=None):
if context is None: default = {} if default is None else default.copy()
context = {} context = {} if context is None else context.copy()
default.update({ default.update({
'state':'draft', 'state':'draft',
'name':'/', 'name':'/',
@ -1450,6 +1405,11 @@ class account_move(osv.osv):
raise osv.except_osv(_('User Error!'), raise osv.except_osv(_('User Error!'),
_('You cannot delete a posted journal entry "%s".') % \ _('You cannot delete a posted journal entry "%s".') % \
move['name']) move['name'])
for line in move.line_id:
if line.invoice:
raise osv.except_osv(_('User Error!'),
_("Move cannot be deleted if linked to an invoice. (Invoice: %s - Move ID:%s)") % \
(line.invoice.number,move.name))
line_ids = map(lambda x: x.id, move.line_id) line_ids = map(lambda x: x.id, move.line_id)
context['journal_id'] = move.journal_id.id context['journal_id'] = move.journal_id.id
context['period_id'] = move.period_id.id context['period_id'] = move.period_id.id
@ -1658,11 +1618,41 @@ class account_move_reconcile(osv.osv):
'line_id': fields.one2many('account.move.line', 'reconcile_id', 'Entry Lines'), 'line_id': fields.one2many('account.move.line', 'reconcile_id', 'Entry Lines'),
'line_partial_ids': fields.one2many('account.move.line', 'reconcile_partial_id', 'Partial Entry lines'), 'line_partial_ids': fields.one2many('account.move.line', 'reconcile_partial_id', 'Partial Entry lines'),
'create_date': fields.date('Creation date', readonly=True), 'create_date': fields.date('Creation date', readonly=True),
'opening_reconciliation': fields.boolean('Opening Entries Reconciliation', help="Is this reconciliation produced by the opening of a new fiscal year ?."),
} }
_defaults = { _defaults = {
'name': lambda self,cr,uid,ctx=None: self.pool.get('ir.sequence').get(cr, uid, 'account.reconcile', context=ctx) or '/', 'name': lambda self,cr,uid,ctx=None: self.pool.get('ir.sequence').get(cr, uid, 'account.reconcile', context=ctx) or '/',
} }
# You cannot unlink a reconciliation if it is a opening_reconciliation one,
# you should use the generate opening entries wizard for that
def unlink(self, cr, uid, ids, context=None):
for move_rec in self.browse(cr, uid, ids, context=context):
if move_rec.opening_reconciliation:
raise osv.except_osv(_('Error!'), _('You cannot unreconcile journal items if they has been generated by the \
opening/closing fiscal year process.'))
return super(account_move_reconcile, self).unlink(cr, uid, ids, context=context)
# Look in the line_id and line_partial_ids to ensure the partner is the same or empty
# on all lines. We allow that only for opening/closing period
def _check_same_partner(self, cr, uid, ids, context=None):
for reconcile in self.browse(cr, uid, ids, context=context):
move_lines = []
if not reconcile.opening_reconciliation:
if reconcile.line_id:
first_partner = reconcile.line_id[0].partner_id.id
move_lines = reconcile.line_id
elif reconcile.line_partial_ids:
first_partner = reconcile.line_partial_ids[0].partner_id.id
move_lines = reconcile.line_partial_ids
if any([line.partner_id.id != first_partner for line in move_lines]):
return False
return True
_constraints = [
(_check_same_partner, 'You can only reconcile journal items with the same partner.', ['line_id']),
]
def reconcile_partial_check(self, cr, uid, ids, type='auto', context=None): def reconcile_partial_check(self, cr, uid, ids, type='auto', context=None):
total = 0.0 total = 0.0
for rec in self.browse(cr, uid, ids, context=context): for rec in self.browse(cr, uid, ids, context=context):
@ -1856,7 +1846,7 @@ class account_tax(osv.osv):
def get_precision_tax(): def get_precision_tax():
def change_digit_tax(cr): def change_digit_tax(cr):
res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, 1, 'Account') res = pooler.get_pool(cr.dbname).get('decimal.precision').precision_get(cr, SUPERUSER_ID, 'Account')
return (16, res+2) return (16, res+2)
return change_digit_tax return change_digit_tax
@ -1899,7 +1889,7 @@ class account_tax(osv.osv):
'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."), 'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"), 'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"),
'company_id': fields.many2one('res.company', 'Company', required=True), 'company_id': fields.many2one('res.company', 'Company', required=True),
'description': fields.char('Tax Code',size=32), 'description': fields.char('Tax Code'),
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."), 'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Application', required=True) 'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Application', required=True)
@ -2260,7 +2250,10 @@ class account_model(osv.osv):
_defaults = { _defaults = {
'legend': lambda self, cr, uid, context:_('You can specify year, month and date in the name of the model using the following labels:\n\n%(year)s: To Specify Year \n%(month)s: To Specify Month \n%(date)s: Current Date\n\ne.g. My model on %(date)s'), 'legend': lambda self, cr, uid, context:_('You can specify year, month and date in the name of the model using the following labels:\n\n%(year)s: To Specify Year \n%(month)s: To Specify Month \n%(date)s: Current Date\n\ne.g. My model on %(date)s'),
} }
def generate(self, cr, uid, ids, datas={}, context=None):
def generate(self, cr, uid, ids, data=None, context=None):
if data is None:
data = {}
move_ids = [] move_ids = []
entry = {} entry = {}
account_move_obj = self.pool.get('account.move') account_move_obj = self.pool.get('account.move')
@ -2271,8 +2264,8 @@ class account_model(osv.osv):
if context is None: if context is None:
context = {} context = {}
if datas.get('date', False): if data.get('date', False):
context.update({'date': datas['date']}) context.update({'date': data['date']})
move_date = context.get('date', time.strftime('%Y-%m-%d')) move_date = context.get('date', time.strftime('%Y-%m-%d'))
move_date = datetime.strptime(move_date,"%Y-%m-%d") move_date = datetime.strptime(move_date,"%Y-%m-%d")
@ -2334,6 +2327,16 @@ class account_model(osv.osv):
return move_ids return move_ids
def onchange_journal_id(self, cr, uid, ids, journal_id, context=None):
company_id = False
if journal_id:
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
if journal.company_id.id:
company_id = journal.company_id.id
return {'value': {'company_id': company_id}}
account_model() account_model()
class account_model_line(osv.osv): class account_model_line(osv.osv):
@ -2448,10 +2451,10 @@ class account_subscription_line(osv.osv):
all_moves = [] all_moves = []
obj_model = self.pool.get('account.model') obj_model = self.pool.get('account.model')
for line in self.browse(cr, uid, ids, context=context): for line in self.browse(cr, uid, ids, context=context):
datas = { data = {
'date': line.date, 'date': line.date,
} }
move_ids = obj_model.generate(cr, uid, [line.subscription_id.model_id.id], datas, context) move_ids = obj_model.generate(cr, uid, [line.subscription_id.model_id.id], data, context)
tocheck[line.subscription_id.id] = True tocheck[line.subscription_id.id] = True
self.write(cr, uid, [line.id], {'move_id':move_ids[0]}) self.write(cr, uid, [line.id], {'move_id':move_ids[0]})
all_moves.extend(move_ids) all_moves.extend(move_ids)
@ -2499,7 +2502,7 @@ class account_account_template(osv.osv):
'reconcile': fields.boolean('Allow Reconciliation', help="Check this option if you want the user to reconcile entries in this account."), 'reconcile': fields.boolean('Allow Reconciliation', help="Check this option if you want the user to reconcile entries in this account."),
'shortcut': fields.char('Shortcut', size=12), 'shortcut': fields.char('Shortcut', size=12),
'note': fields.text('Note'), 'note': fields.text('Note'),
'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade'), 'parent_id': fields.many2one('account.account.template', 'Parent Account Template', ondelete='cascade', domain=[('type','=','view')]),
'child_parent_ids':fields.one2many('account.account.template', 'parent_id', 'Children'), 'child_parent_ids':fields.one2many('account.account.template', 'parent_id', 'Children'),
'tax_ids': fields.many2many('account.tax.template', 'account_account_template_tax_rel', 'account_id', 'tax_id', 'Default Taxes'), 'tax_ids': fields.many2many('account.tax.template', 'account_account_template_tax_rel', 'account_id', 'tax_id', 'Default Taxes'),
'nocreate': fields.boolean('Optional create', help="If checked, the new chart of accounts will not contain this by default."), 'nocreate': fields.boolean('Optional create', help="If checked, the new chart of accounts will not contain this by default."),
@ -2512,20 +2515,9 @@ class account_account_template(osv.osv):
'nocreate': False, 'nocreate': False,
} }
def _check_type(self, cr, uid, ids, context=None):
if context is None:
context = {}
accounts = self.browse(cr, uid, ids, context=context)
for account in accounts:
if account.parent_id and account.parent_id.type != 'view':
return False
return True
_check_recursion = check_cycle _check_recursion = check_cycle
_constraints = [ _constraints = [
(_check_recursion, 'Error!\nYou cannot create recursive account templates.', ['parent_id']), (_check_recursion, 'Error!\nYou cannot create recursive account templates.', ['parent_id']),
(_check_type, 'Configuration Error!\nYou cannot define children to an account that has internal type other than "View".', ['type']),
] ]
def name_get(self, cr, uid, ids, context=None): def name_get(self, cr, uid, ids, context=None):
@ -2757,7 +2749,6 @@ class account_chart_template(osv.osv):
'property_account_income_categ': fields.many2one('account.account.template', 'Income Category Account'), 'property_account_income_categ': fields.many2one('account.account.template', 'Income Category Account'),
'property_account_expense': fields.many2one('account.account.template', 'Expense Account on Product Template'), 'property_account_expense': fields.many2one('account.account.template', 'Expense Account on Product Template'),
'property_account_income': fields.many2one('account.account.template', 'Income Account on Product Template'), 'property_account_income': fields.many2one('account.account.template', 'Income Account on Product Template'),
'property_reserve_and_surplus_account': fields.many2one('account.account.template', 'Reserve and Profit/Loss Account', domain=[('type', '=', 'payable')], help='This Account is used for transferring Profit/Loss(If It is Profit: Amount will be added, Loss: Amount will be deducted.), Which is calculated from Profilt & Loss Report'),
'property_account_income_opening': fields.many2one('account.account.template', 'Opening Entries Income Account'), 'property_account_income_opening': fields.many2one('account.account.template', 'Opening Entries Income Account'),
'property_account_expense_opening': fields.many2one('account.account.template', 'Opening Entries Expense Account'), 'property_account_expense_opening': fields.many2one('account.account.template', 'Opening Entries Expense Account'),
} }
@ -2806,7 +2797,7 @@ class account_tax_template(osv.osv):
'ref_base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."), 'ref_base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."), 'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
'include_base_amount': fields.boolean('Include in Base Amount', help="Set if the amount of tax must be included in the base amount before computing the next taxes."), 'include_base_amount': fields.boolean('Include in Base Amount', help="Set if the amount of tax must be included in the base amount before computing the next taxes."),
'description': fields.char('Internal Name', size=32), 'description': fields.char('Internal Name'),
'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Use In', required=True,), 'type_tax_use': fields.selection([('sale','Sale'),('purchase','Purchase'),('all','All')], 'Tax Use In', required=True,),
'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."), 'price_include': fields.boolean('Tax Included in Price', help="Check this if the price you use on the product and invoices includes this tax."),
} }
@ -2995,6 +2986,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
_columns = { _columns = {
'company_id':fields.many2one('res.company', 'Company', required=True), 'company_id':fields.many2one('res.company', 'Company', required=True),
'currency_id': fields.many2one('res.currency', 'Currency', help="Currency as per company's country."),
'only_one_chart_template': fields.boolean('Only One Chart Template Available'), 'only_one_chart_template': fields.boolean('Only One Chart Template Available'),
'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True), 'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True),
'bank_accounts_id': fields.one2many('account.bank.accounts.wizard', 'bank_account_id', 'Cash and Banks', required=True), 'bank_accounts_id': fields.one2many('account.bank.accounts.wizard', 'bank_account_id', 'Cash and Banks', required=True),
@ -3005,6 +2997,13 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'purchase_tax_rate': fields.float('Purchase Tax(%)'), 'purchase_tax_rate': fields.float('Purchase Tax(%)'),
'complete_tax_set': fields.boolean('Complete Set of Taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'), 'complete_tax_set': fields.boolean('Complete Set of Taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'),
} }
def onchange_company_id(self, cr, uid, ids, company_id, context=None):
currency_id = False
if company_id:
currency_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.id
return {'value': {'currency_id': currency_id}}
def onchange_tax_rate(self, cr, uid, ids, rate=False, context=None): def onchange_tax_rate(self, cr, uid, ids, rate=False, context=None):
return {'value': {'purchase_tax_rate': rate or False}} return {'value': {'purchase_tax_rate': rate or False}}
@ -3035,6 +3034,13 @@ class wizard_multi_charts_accounts(osv.osv_memory):
res.update({'bank_accounts_id': [{'acc_name': _('Cash'), 'account_type': 'cash'},{'acc_name': _('Bank'), 'account_type': 'bank'}]}) res.update({'bank_accounts_id': [{'acc_name': _('Cash'), 'account_type': 'cash'},{'acc_name': _('Bank'), 'account_type': 'bank'}]})
if 'company_id' in fields: if 'company_id' in fields:
res.update({'company_id': self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0].company_id.id}) res.update({'company_id': self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0].company_id.id})
if 'currency_id' in fields:
company_id = res.get('company_id') or False
if company_id:
company_obj = self.pool.get('res.company')
country_id = company_obj.browse(cr, uid, company_id, context=context).country_id.id
currency_id = company_obj.on_change_country(cr, uid, company_id, country_id, context=context)['value']['currency_id']
res.update({'currency_id': currency_id})
ids = self.pool.get('account.chart.template').search(cr, uid, [('visible', '=', True)], context=context) ids = self.pool.get('account.chart.template').search(cr, uid, [('visible', '=', True)], context=context)
if ids: if ids:
@ -3125,16 +3131,6 @@ class wizard_multi_charts_accounts(osv.osv_memory):
default_account = acc_template_ref.get(template.property_account_income_opening.id) default_account = acc_template_ref.get(template.property_account_income_opening.id)
return default_account return default_account
def _get_view_id(journal_type):
# Get the journal views
if journal_type in ('general', 'situation'):
data = obj_data.get_object_reference(cr, uid, 'account', 'account_journal_view')
elif journal_type in ('sale_refund', 'purchase_refund'):
data = obj_data.get_object_reference(cr, uid, 'account', 'account_sp_refund_journal_view')
else:
data = obj_data.get_object_reference(cr, uid, 'account', 'account_sp_journal_view')
return data and data[1] or False
journal_names = { journal_names = {
'sale': _('Sales Journal'), 'sale': _('Sales Journal'),
'purchase': _('Purchase Journal'), 'purchase': _('Purchase Journal'),
@ -3164,7 +3160,6 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'code': journal_codes[journal_type], 'code': journal_codes[journal_type],
'company_id': company_id, 'company_id': company_id,
'centralisation': journal_type == 'situation', 'centralisation': journal_type == 'situation',
'view_id': _get_view_id(journal_type),
'analytic_journal_id': _get_analytic_journal(journal_type), 'analytic_journal_id': _get_analytic_journal(journal_type),
'default_credit_account_id': _get_default_account(journal_type, 'credit'), 'default_credit_account_id': _get_default_account(journal_type, 'credit'),
'default_debit_account_id': _get_default_account(journal_type, 'debit'), 'default_debit_account_id': _get_default_account(journal_type, 'debit'),
@ -3190,7 +3185,6 @@ class wizard_multi_charts_accounts(osv.osv_memory):
('property_account_income_categ','product.category','account.account'), ('property_account_income_categ','product.category','account.account'),
('property_account_expense','product.template','account.account'), ('property_account_expense','product.template','account.account'),
('property_account_income','product.template','account.account'), ('property_account_income','product.template','account.account'),
('property_reserve_and_surplus_account','res.company','account.account')
] ]
template = self.pool.get('account.chart.template').browse(cr, uid, chart_template_id, context=context) template = self.pool.get('account.chart.template').browse(cr, uid, chart_template_id, context=context)
for record in todo_list: for record in todo_list:
@ -3213,7 +3207,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
property_obj.create(cr, uid, vals, context=context) property_obj.create(cr, uid, vals, context=context)
return True return True
def _install_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, acc_ref={}, taxes_ref={}, tax_code_ref={}, context=None): def _install_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, acc_ref=None, taxes_ref=None, tax_code_ref=None, context=None):
''' '''
This function recursively loads the template objects and create the real objects from them. This function recursively loads the template objects and create the real objects from them.
@ -3231,6 +3225,12 @@ class wizard_multi_charts_accounts(osv.osv_memory):
* a last identical containing the mapping of tax code templates and tax codes * a last identical containing the mapping of tax code templates and tax codes
:rtype: tuple(dict, dict, dict) :rtype: tuple(dict, dict, dict)
''' '''
if acc_ref is None:
acc_ref = {}
if taxes_ref is None:
taxes_ref = {}
if tax_code_ref is None:
tax_code_ref = {}
template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context) template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context)
if template.parent_id: if template.parent_id:
tmp1, tmp2, tmp3 = self._install_template(cr, uid, template.parent_id.id, company_id, code_digits=code_digits, acc_ref=acc_ref, taxes_ref=taxes_ref, tax_code_ref=tax_code_ref, context=context) tmp1, tmp2, tmp3 = self._install_template(cr, uid, template.parent_id.id, company_id, code_digits=code_digits, acc_ref=acc_ref, taxes_ref=taxes_ref, tax_code_ref=tax_code_ref, context=context)
@ -3243,7 +3243,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
tax_code_ref.update(tmp3) tax_code_ref.update(tmp3)
return acc_ref, taxes_ref, tax_code_ref return acc_ref, taxes_ref, tax_code_ref
def _load_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, account_ref={}, taxes_ref={}, tax_code_ref={}, context=None): def _load_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, account_ref=None, taxes_ref=None, tax_code_ref=None, context=None):
''' '''
This function generates all the objects from the templates This function generates all the objects from the templates
@ -3261,6 +3261,12 @@ class wizard_multi_charts_accounts(osv.osv_memory):
* a last identical containing the mapping of tax code templates and tax codes * a last identical containing the mapping of tax code templates and tax codes
:rtype: tuple(dict, dict, dict) :rtype: tuple(dict, dict, dict)
''' '''
if account_ref is None:
account_ref = {}
if taxes_ref is None:
taxes_ref = {}
if tax_code_ref is None:
tax_code_ref = {}
template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context) template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context)
obj_tax_code_template = self.pool.get('account.tax.code.template') obj_tax_code_template = self.pool.get('account.tax.code.template')
obj_acc_tax = self.pool.get('account.tax') obj_acc_tax = self.pool.get('account.tax')
@ -3339,19 +3345,18 @@ class wizard_multi_charts_accounts(osv.osv_memory):
ir_values_obj = self.pool.get('ir.values') ir_values_obj = self.pool.get('ir.values')
obj_wizard = self.browse(cr, uid, ids[0]) obj_wizard = self.browse(cr, uid, ids[0])
company_id = obj_wizard.company_id.id company_id = obj_wizard.company_id.id
self.pool.get('res.company').write(cr, uid, [company_id], {'currency_id': obj_wizard.currency_id.id})
# If the floats for sale/purchase rates have been filled, create templates from them # If the floats for sale/purchase rates have been filled, create templates from them
self._create_tax_templates_from_rates(cr, uid, obj_wizard, company_id, context=context) self._create_tax_templates_from_rates(cr, uid, obj_wizard, company_id, context=context)
# Install all the templates objects and generate the real objects # Install all the templates objects and generate the real objects
acc_template_ref, taxes_ref, tax_code_ref = self._install_template(cr, uid, obj_wizard.chart_template_id.id, company_id, code_digits=obj_wizard.code_digits, obj_wizard=obj_wizard, context=context) acc_template_ref, taxes_ref, tax_code_ref = self._install_template(cr, uid, obj_wizard.chart_template_id.id, company_id, code_digits=obj_wizard.code_digits, obj_wizard=obj_wizard, context=context)
# write values of default taxes for product # write values of default taxes for product as super user
if obj_wizard.sale_tax and taxes_ref: if obj_wizard.sale_tax and taxes_ref:
ir_values_obj.set(cr, uid, key='default', key2=False, name="taxes_id", company=company_id, ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "taxes_id", [taxes_ref[obj_wizard.sale_tax.id]], for_all_users=True, company_id=company_id)
models =[('product.product',False)], value=[taxes_ref[obj_wizard.sale_tax.id]])
if obj_wizard.purchase_tax and taxes_ref: if obj_wizard.purchase_tax and taxes_ref:
ir_values_obj.set(cr, uid, key='default', key2=False, name="supplier_taxes_id", company=company_id, ir_values_obj.set_default(cr, SUPERUSER_ID, 'product.product', "supplier_taxes_id", [taxes_ref[obj_wizard.purchase_tax.id]], for_all_users=True, company_id=company_id)
models =[('product.product',False)], value=[taxes_ref[obj_wizard.purchase_tax.id]])
# Create Bank journals # Create Bank journals
self._create_bank_journals_from_o2m(cr, uid, obj_wizard, company_id, acc_template_ref, context=context) self._create_bank_journals_from_o2m(cr, uid, obj_wizard, company_id, acc_template_ref, context=context)
@ -3371,11 +3376,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
''' '''
obj_data = self.pool.get('ir.model.data') obj_data = self.pool.get('ir.model.data')
obj_journal = self.pool.get('account.journal') obj_journal = self.pool.get('account.journal')
# Get the id of journal views
tmp = obj_data.get_object_reference(cr, uid, 'account', 'account_journal_bank_view_multi')
view_id_cur = tmp and tmp[1] or False
tmp = obj_data.get_object_reference(cr, uid, 'account', 'account_journal_bank_view')
view_id_cash = tmp and tmp[1] or False
# we need to loop again to find next number for journal code # we need to loop again to find next number for journal code
# because we can't rely on the value current_num as, # because we can't rely on the value current_num as,
@ -3401,10 +3402,8 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'default_debit_account_id': default_account_id, 'default_debit_account_id': default_account_id,
} }
if line['currency_id']: if line['currency_id']:
vals['view_id'] = view_id_cur
vals['currency'] = line['currency_id'] vals['currency'] = line['currency_id']
else:
vals['view_id'] = view_id_cash
return vals return vals
def _prepare_bank_account(self, cr, uid, line, new_code, acc_template_ref, ref_acc_bank, company_id, context=None): def _prepare_bank_account(self, cr, uid, line, new_code, acc_template_ref, ref_acc_bank, company_id, context=None):

View File

@ -39,7 +39,6 @@ class account_analytic_line(osv.osv):
} }
_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'
@ -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,13 +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 _prepare_name_get(self, cr, uid, bank_type_obj, bank_obj, context=None): def _prepare_name_get(self, cr, uid, bank_dicts, context=None):
"""Add ability to have %(currency_name)s in the format_layout of """Add ability to have %(currency_name)s in the format_layout of res.partner.bank.type"""
res.partner.bank.type""" currency_ids = list(set(data['currency_id'][0] for data in bank_dicts if data.get('currency_id')))
bank_obj._data[bank_obj.id]['currency_name'] = bank_obj.currency_id and bank_obj.currency_id.name or '' currencies = self.pool.get('res.currency').browse(cr, uid, currency_ids, context=context)
return super(bank, self)._prepare_name_get(cr, uid, bank_type_obj, bank_obj, context=context) currency_name = dict((currency.id, currency.name) for currency in currencies)
def post_write(self, cr, uid, ids, context={}): 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]
@ -85,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:
@ -108,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

@ -61,7 +61,7 @@ class account_bank_statement(osv.osv):
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
@ -123,8 +123,8 @@ class account_bank_statement(osv.osv):
('open','Open'), # used by cash statements ('open','Open'), # used by cash statements
('confirm', 'Closed')], ('confirm', 'Closed')],
'Status', 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.'),
@ -304,14 +304,14 @@ class account_bank_statement(osv.osv):
'date': st_line.date, 'date': st_line.date,
'ref': st_line.ref, 'ref': st_line.ref,
'move_id': move_id, 'move_id': move_id,
'partner_id': partner_id, 'partner_id': par_id,
'account_id': acc_id, 'account_id': acc_id,
'credit': credit, 'credit': credit,
'debit': debit, 'debit': debit,
'statement_id': st_line.statement_id.id, 'statement_id': st_line.statement_id.id,
'journal_id': st_line.statement_id.journal_id.id, 'journal_id': st_line.statement_id.journal_id.id,
'period_id': st_line.statement_id.period_id.id, 'period_id': st_line.statement_id.period_id.id,
'currency_id': cur_id, 'currency_id': amount_currency and cur_id,
'amount_currency': amount_currency, 'amount_currency': amount_currency,
'analytic_account_id': analytic_id, 'analytic_account_id': analytic_id,
} }
@ -430,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.message_append_note(cr, uid, [st.id], body=_('Statement %s is confirmed, journal items are created.') % (st_number,), context=context) self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st_number,), context=context)
return self.write(cr, uid, ids, {'state':'confirm'}, context=context) 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):
@ -447,20 +447,24 @@ class account_bank_statement(osv.osv):
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): def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
cr.execute('SELECT balance_end_real \ res = False
FROM account_bank_statement \ if journal_id:
WHERE journal_id = %s AND NOT state = %s \ cr.execute('SELECT balance_end_real \
ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft')) FROM account_bank_statement \
res = cr.fetchone() 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 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):
if not journal_id:
return {}
balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context) balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context) journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['company_id', 'currency'], 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)
@ -482,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

@ -15,7 +15,7 @@
<group name="accounting" col="2" colspan="2" attrs="{'invisible': [('company_id','=', False)]}"> <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>
@ -28,7 +28,7 @@
<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>

View File

@ -78,7 +78,7 @@ class account_cash_statement(osv.osv):
""" """
res = {} res = {}
for statement in self.browse(cr, uid, ids, context=context): for statement in self.browse(cr, uid, ids, context=context):
if statement.journal_id.type not in ('cash',): if (statement.journal_id.type not in ('cash',)) or (not statement.journal_id.cash_control):
continue continue
start = end = 0 start = end = 0
for line in statement.details_ids: for line in statement.details_ids:
@ -194,12 +194,27 @@ class account_cash_statement(osv.osv):
journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context) journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
if journal and (journal.type == 'cash') and not vals.get('details_ids'): if journal and (journal.type == 'cash') and not vals.get('details_ids'):
vals['details_ids'] = [] vals['details_ids'] = []
last_pieces = None
if journal.with_last_closing_balance == True:
domain = [('journal_id', '=', journal.id),
('state', '=', 'confirm')]
last_bank_statement_ids = self.search(cr, uid, domain, limit=1, order='create_date desc', context=context)
if last_bank_statement_ids:
last_bank_statement = self.browse(cr, uid, last_bank_statement_ids[0], context=context)
last_pieces = dict(
(line.pieces, line.number_closing) for line in last_bank_statement.details_ids
)
for value in journal.cashbox_line_ids: for value in journal.cashbox_line_ids:
nested_values = { nested_values = {
'number_closing' : 0, 'number_closing' : 0,
'number_opening' : 0, 'number_opening' : last_pieces.get(value.pieces, 0) if isinstance(last_pieces, dict) else 0,
'pieces' : value.pieces 'pieces' : value.pieces
} }
vals['details_ids'].append([0, False, nested_values]) vals['details_ids'].append([0, False, nested_values])
res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context) res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
@ -274,13 +289,13 @@ class account_cash_statement(osv.osv):
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)
absl_proxy = self.pool.get('account.bank.statement.line') absl_proxy = self.pool.get('account.bank.statement.line')
TABLES = (('Profit', 'profit_account_id'), ('Loss', 'loss_account_id'),) TABLES = ((_('Profit'), 'profit_account_id'), (_('Loss'), 'loss_account_id'),)
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
if obj.difference == 0.0: if obj.difference == 0.0:
continue continue
for item_label, item_account in TALBES: for item_label, item_account in TABLES:
if getattr(obj.journal_id, item_account): if getattr(obj.journal_id, item_account):
raise osv.except_osv(_('Error!'), raise osv.except_osv(_('Error!'),
_('There is no %s Account on the journal %s.') % (item_label, obj.journal_id.name,)) _('There is no %s Account on the journal %s.') % (item_label, obj.journal_id.name,))

View File

@ -14,8 +14,12 @@
</footer> </footer>
</footer> </footer>
<separator string="title" position="replace"> <separator string="title" position="replace">
<p class="oe_grey">
Select a configuration package to setup automatically your
taxes and chart of accounts.
</p>
<group> <group>
<field name="charts"/> <field name="charts" class="oe_inline"/>
</group> </group>
<group string="Configure your Fiscal Year" groups="account.group_account_user"> <group string="Configure your Fiscal Year" groups="account.group_account_user">
<field name="has_default_company" invisible="1" /> <field name="has_default_company" invisible="1" />
@ -32,7 +36,7 @@
</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">Configure 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"/>

View File

@ -185,6 +185,7 @@ class account_invoice(osv.osv):
_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'),
@ -206,15 +207,15 @@ class account_invoice(osv.osv):
('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."), '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. If you keep the payment term and the due date empty, it means direct payment. The payment term may compute several due dates, for example 50% now, 50% in one month."),
'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}), 'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}),
@ -253,7 +254,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 ?
@ -390,23 +391,34 @@ class account_invoice(osv.osv):
''' '''
This function opens a window to compose an email, with the edi invoice template message loaded by default This function opens a window to compose an email, with the edi invoice template message loaded by default
''' '''
mod_obj = self.pool.get('ir.model.data') assert len(ids) == 1, 'This option should only be used for a single id at a time.'
template = mod_obj.get_object_reference(cr, uid, 'account', 'email_template_edi_invoice') ir_model_data = self.pool.get('ir.model.data')
template_id = template and template[1] or False try:
res = mod_obj.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form') template_id = ir_model_data.get_object_reference(cr, uid, 'account', 'email_template_edi_invoice')[1]
res_id = res and res[1] or False except ValueError:
ctx = dict(context, active_model='account.invoice', active_id=ids[0]) template_id = False
ctx.update({'mail.compose.template_id': template_id}) 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 { return {
'view_type': 'form', 'type': 'ir.actions.act_window',
'view_mode': 'form', 'view_type': 'form',
'res_model': 'mail.compose.message', 'view_mode': 'form',
'views': [(res_id, 'form')], 'res_model': 'mail.compose.message',
'view_id': res_id, 'views': [(compose_form_id, 'form')],
'type': 'ir.actions.act_window', 'view_id': compose_form_id,
'target': 'new', 'target': 'new',
'context': ctx, 'context': ctx,
'nodestroy': True,
} }
def confirm_paid(self, cr, uid, ids, context=None): def confirm_paid(self, cr, uid, ids, context=None):
@ -425,7 +437,7 @@ 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 cannot delete an invoice which is open or paid. You should 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
@ -445,7 +457,7 @@ class account_invoice(osv.osv):
invoice_addr_id = res['invoice'] 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)])
@ -503,18 +515,20 @@ 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):
res = {} res = {}
if not payment_term_id:
return res
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:
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) 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]
@ -767,17 +781,20 @@ class account_invoice(osv.osv):
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
@ -854,8 +871,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
@ -887,7 +907,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 '/'
@ -938,9 +958,14 @@ 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) #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
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)
@ -969,13 +994,13 @@ 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
@ -1045,11 +1070,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.message_append_note(cr, uid, [inv_id], body=message, context=context) 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
@ -1095,10 +1121,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')]
@ -1219,12 +1245,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,
@ -1235,7 +1264,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,
@ -1275,7 +1304,7 @@ class account_invoice(osv.osv):
# 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.message_append_note(cr, uid, [inv_id], body=msg, context=context) self.message_post(cr, uid, [inv_id], body=msg, context=context)
self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context) 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
@ -1288,26 +1317,29 @@ class account_invoice(osv.osv):
def _get_document_type(self, type): def _get_document_type(self, type):
type_dict = { type_dict = {
'out_invoice': 'Customer invoice', # Translation markers will have no effect at runtime, only used to properly flag export
'in_invoice': 'Supplier invoice', 'out_invoice': _('Customer invoice'),
'out_refund': 'Customer Refund', 'in_invoice': _('Supplier invoice'),
'in_refund': 'Supplier Refund', 'out_refund': _('Customer Refund'),
'in_refund': _('Supplier Refund'),
} }
return type_dict.get(type, 'Invoice') return type_dict.get(type, 'Invoice')
def create_send_note(self, cr, uid, ids, context=None): def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id],body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)), 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): def confirm_paid_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)), 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): def invoice_cancel_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context): for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)), context=context) self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)),
context=context)
account_invoice()
class account_invoice_line(osv.osv): class account_invoice_line(osv.osv):
@ -1346,10 +1378,11 @@ class account_invoice_line(osv.osv):
_description = "Invoice Line" _description = "Invoice Line"
_columns = { _columns = {
'name': fields.text('Description', required=True), 'name': fields.text('Description', required=True),
'origin': fields.char('Source', 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('Product Price')), '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",
@ -1361,10 +1394,19 @@ class account_invoice_line(osv.osv):
'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), '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):
@ -1386,7 +1428,7 @@ class account_invoice_line(osv.osv):
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:
@ -1473,10 +1515,11 @@ class account_invoice_line(osv.osv):
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': _('The selected unit of measure is not compatible with the unit of measure of 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
@ -1540,16 +1583,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()
@ -1634,14 +1680,13 @@ class account_invoice_tax(osv.osv):
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, 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']
@ -1695,8 +1740,6 @@ class account_invoice_tax(osv.osv):
}) })
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 """
@ -1710,16 +1753,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_message(osv.osv): class mail_compose_message(osv.osv):
_name = 'mail.message' _inherit = 'mail.compose.message'
_inherit = 'mail.message'
def _postprocess_sent_message(self, cr, uid, message, context=None): def send_mail(self, cr, uid, ids, context=None):
if message.model == 'account.invoice': context = context or {}
self.pool.get('account.invoice').write(cr, uid, [message.res_id], {'sent':True}, context=context) if context.get('default_model') == 'account.invoice' and context.get('default_res_id') and context.get('mark_invoice_as_sent'):
return super(mail_message, self)._postprocess_sent_message(cr, uid, message=message, context=context) 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)
mail_message()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -61,7 +61,7 @@
<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 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 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), ('parent_id', '!=', False)]" name="account_analytic_id" groups="analytic.group_analytic_accounting"/> <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"/> <field name="company_id" groups="base.group_multi_company" readonly="1"/>
</group> </group>
</group> </group>
@ -95,7 +95,7 @@
<field name="name"/> <field name="name"/>
<field name="sequence"/> <field name="sequence"/>
<field name="account_id" groups="account.group_account_user"/> <field name="account_id" groups="account.group_account_user"/>
<field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting"/> <field name="account_analytic_id" domain="[('type','&lt;&gt;','view'), ('company_id', '=', parent.company_id)]" groups="analytic.group_analytic_accounting"/>
<field name="manual"/> <field name="manual"/>
<field name="amount"/> <field name="amount"/>
<field name="base" readonly="0"/> <field name="base" readonly="0"/>
@ -127,7 +127,7 @@
<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"/>
@ -143,13 +143,11 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Supplier Invoice" version="7.0"> <form string="Supplier Invoice" version="7.0">
<header> <header>
<span groups="base.group_user"> <button name="invoice_open" states="draft,proforma2" string="Validate" class="oe_highlight" groups="account.group_account_invoice"/>
<button name="invoice_open" states="draft,proforma2" string="Validate" class="oe_highlight"/> <button name="%(action_account_invoice_refund)d" type='action' string='Ask Refund' states='open,paid' groups="account.group_account_invoice"/>
<button name="%(action_account_invoice_refund)d" type='action' string='Ask Refund' states='open,paid' />
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" groups="base.group_no_one"/> <button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" groups="base.group_no_one"/>
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object"/> <button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" groups="account.group_account_invoice"/>
<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='%(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."/>
</span>
<field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
</header> </header>
<sheet string="Supplier Invoice"> <sheet string="Supplier Invoice">
@ -171,11 +169,12 @@
domain="[('supplier', '=', True)]"/> domain="[('supplier', '=', True)]"/>
<field name="fiscal_position" widget="selection"/> <field name="fiscal_position" widget="selection"/>
<field name="origin"/> <field name="origin"/>
<label for="reference_type"/> <field name="supplier_invoice_number"/>
<div> <label for="reference_type"/>
<div>
<field name="reference_type" class="oe_inline oe_edit_only"/> <field name="reference_type" class="oe_inline oe_edit_only"/>
<field name="reference" class="oe_inline"/> <field name="reference" class="oe_inline"/>
</div> </div>
</group> </group>
<group> <group>
<field name="date_invoice"/> <field name="date_invoice"/>
@ -184,38 +183,45 @@
name="account_id" groups="account.group_account_user"/> name="account_id" groups="account.group_account_user"/>
<field name="journal_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"/> on_change="onchange_journal_id(journal_id, context)" widget="selection"/>
<field name="currency_id"/> <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> <notebook>
<page string="Invoice"> <page string="Invoice">
<field context="{'partner_id': partner_id, 'price_type': 'price_type' in dir() and price_type or False, 'type': type}" name="invoice_line"> <field context="{'partner_id': partner_id, 'price_type': context.get('price_type') or False, 'type': type}" name="invoice_line">
<tree string="Invoice lines" editable="bottom"> <tree string="Invoice lines" editable="bottom">
<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)"/> <field name="product_id"
<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="base.group_account_user"/> 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="invoice_line_tax_id" view_mode="2" context="{'type':parent.type}" domain="[('parent_id','=',False)]"/> <field name="name"/>
<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"/>
<field name="account_id" groups="account.group_account_user"
domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '!=', 'view')]"
on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/>
<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"/>
<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 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)" invisible="1"/>
<!-- Removed if subtotal is set -->
<field name="name" invisible="1"/>
<field name="uos_id" invisible="1"/>
</tree> </tree>
</field> </field>
<group class="oe_subtotal_footer oe_right"> <group class="oe_subtotal_footer oe_right">
<field name="amount_untaxed"/> <field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<div> <div>
<label for="amount_tax"/> <label for="amount_tax"/>
<button name="button_reset_taxes" states="draft,proforma2" <button name="button_reset_taxes" states="draft,proforma2"
string="(update)" class="oe_link oe_edit_only" string="(update)" class="oe_link oe_edit_only"
type="object" help="Recompute taxes and total"/> type="object" help="Recompute taxes and total"/>
</div> </div>
<field name="amount_tax" nolabel="1"/> <field name="amount_tax" nolabel="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="amount_total" class="oe_subtotal_footer_separator"/> <field name="amount_total" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="residual"/> <field name="residual" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="reconciled" invisible="1"/> <field name="reconciled" invisible="1"/>
</group> </group>
<div style="width: 50%%"> <div style="width: 50%%">
@ -223,7 +229,7 @@
<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), ('parent_id', '!=', False)]" groups="analytic.group_analytic_accounting"/> <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)"/>
@ -265,15 +271,15 @@
<field name="debit"/> <field name="debit"/>
<field name="credit"/> <field name="credit"/>
<field name="amount_currency"/> <field name="amount_currency"/>
<field name="currency_id"/> <field name="currency_id" groups="base.group_multi_currency"/>
</tree> </tree>
</field> </field>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers"/> <field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div> </div>
</form> </form>
</field> </field>
@ -285,20 +291,18 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Invoice" version="7.0"> <form string="Invoice" version="7.0">
<header> <header>
<span groups="base.group_user"> <button name="action_invoice_sent" type="object" string="Send by Email" 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','=',True), ('state', '!=', 'open')]}" class="oe_highlight"/> <button name="invoice_print" string="Print" type="object" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight" groups="base.group_user"/>
<button name="invoice_print" string="Print Invoice" type="object" attrs="{'invisible':['|',('sent','=',True), ('state', '!=', 'open')]}" class="oe_highlight"/> <button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}" groups="base.group_user"/>
<button name="action_invoice_sent" type="object" string="Send by Email" attrs="{'invisible':['|',('sent','=',False), ('state', '!=', 'open')]}"/> <button name="invoice_print" string="Print Invoice" type="object" 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')]}"/> <button name="invoice_open" states="draft" string="Validate" class="oe_highlight" groups="base.group_user"/>
<button name="invoice_open" states="draft" string="Validate" class="oe_highlight"/> <button name="invoice_open" states="proforma2" string="Validate" groups="base.group_user"/>
<button name="invoice_open" states="proforma2" string="Validate"/> <button name="invoice_proforma2" states="draft" string="PRO-FORMA" groups="account.group_proforma_invoices"/>
<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="%(action_account_invoice_refund)d" type='action' string='Refund Invoice' states='paid'/> <button name="invoice_cancel" states="draft,proforma2,open" string="Cancel" groups="base.group_no_one"/>
<button name="invoice_cancel" states="draft,proforma2,sale,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_cancel_draft" states="cancel" string="Reset to Draft" type="object"/> <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='%(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"/-->
<!--button name="%(account_invoices)d" string="Print Invoice" type="action" states="open,paid,proforma,sale,proforma2"/-->
</span>
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/> <field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,paid" statusbar_colors='{"proforma":"blue","proforma2":"blue"}'/>
</header> </header>
<sheet string="Invoice"> <sheet string="Invoice">
@ -316,7 +320,7 @@
<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)" 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, 'show_address': 1}" groups="base.group_user" context="{'search_default_customer':1, 'show_address': 1}"
options='{"always_reload": true}'/> options='{"always_reload": True}'/>
<field name="fiscal_position" widget="selection" /> <field name="fiscal_position" widget="selection" />
</group> </group>
<group> <group>
@ -326,8 +330,8 @@
<field domain="[('company_id', '=', company_id),('type','=', 'receivable')]" <field domain="[('company_id', '=', company_id),('type','=', 'receivable')]"
name="account_id" groups="account.group_account_user"/> name="account_id" groups="account.group_account_user"/>
<label for="currency_id"/> <label for="currency_id" groups="base.group_multi_currency"/>
<div> <div groups="base.group_multi_currency">
<field name="currency_id" class="oe_inline"/> <field name="currency_id" class="oe_inline"/>
<!-- note fp: I don't think we need this feature ? <!-- note fp: I don't think we need this feature ?
<button name="%(action_account_change_currency)d" type="action" <button name="%(action_account_change_currency)d" type="action"
@ -342,31 +346,36 @@
<page string="Invoice Lines"> <page string="Invoice Lines">
<field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}"> <field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}">
<tree string="Invoice Lines" editable="bottom"> <tree string="Invoice Lines" editable="bottom">
<field name="invoice_line_tax_id" invisible="1"/> <field name="product_id"
<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)"/>
<field name="name"/> <field name="name"/>
<field name="company_id" groups="base.group_multi_company" readonly="1"/>
<field name="account_id" groups="account.group_account_user" <field name="account_id" groups="account.group_account_user"
domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]" domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '!=', 'view')]"
on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/>
<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" <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)"/> 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"/>
<field name="discount" groups="sale.group_discount_per_so_line"/> <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"/>
</tree> </tree>
</field> </field>
<group class="oe_subtotal_footer oe_right"> <group class="oe_subtotal_footer oe_right">
<field name="amount_untaxed"/> <field name="amount_untaxed" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<div> <div>
<label for="amount_tax"/> <label for="amount_tax"/>
<button name="button_reset_taxes" states="draft,proforma2" <button name="button_reset_taxes" states="draft,proforma2"
string="(update)" class="oe_link oe_edit_only" string="(update)" class="oe_link oe_edit_only"
type="object" help="Recompute taxes and total"/> type="object" help="Recompute taxes and total"/>
</div> </div>
<field name="amount_tax" nolabel="1"/> <field name="amount_tax" nolabel="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="amount_total" class="oe_subtotal_footer_separator"/> <field name="amount_total" class="oe_subtotal_footer_separator" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="residual" groups="account.group_account_user"/> <field name="residual" groups="account.group_account_user" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="reconciled" invisible="1"/> <field name="reconciled" invisible="1"/>
</group> </group>
<group> <group>
@ -418,16 +427,16 @@
<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> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/> <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_follower_ids" widget="mail_followers"/> <field name="message_ids" widget="mail_thread" placeholder="Share a note..."/>
</div> </div>
</form> </form>
</field> </field>
@ -438,7 +447,7 @@
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Invoice"> <search string="Search Invoice">
<field name="number" string="Invoice" filter_domain="['|', ('number','ilike',self),('origin','ilike',self)]"/> <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" groups="account.group_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"/>
@ -447,7 +456,6 @@
<filter domain="[('user_id','=',uid)]" help="My Invoices" icon="terp-personal"/> <filter domain="[('user_id','=',uid)]" help="My Invoices" icon="terp-personal"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="user_id" string="Salesperson"/> <field name="user_id" string="Salesperson"/>
<field name="journal_id"/>
<field name="period_id" string="Period"/> <field name="period_id" string="Period"/>
<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'}"/>

View File

@ -6,7 +6,7 @@
<menuitem name="Invoicing" <menuitem name="Invoicing"
id="menu_finance" id="menu_finance"
groups="group_account_user,group_account_manager,group_account_invoice" groups="group_account_user,group_account_manager,group_account_invoice"
sequence="100"/> sequence="50"/>
<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"/>
@ -30,7 +30,7 @@
<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" />
@ -44,7 +44,7 @@
<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="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

@ -166,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):
@ -208,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')
@ -225,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 Tax excluded, the Tax 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):
@ -472,6 +420,15 @@ 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."),
@ -480,21 +437,22 @@ class account_move_line(osv.osv):
'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'),
'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', 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)
}), }),
@ -509,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')], 'Status', 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)."),
@ -518,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):
@ -526,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',
@ -547,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',
@ -554,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"
@ -577,7 +568,7 @@ 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 cannot create journal items on “View” type 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):
@ -608,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 cannot 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 cannot create journal items on closed account.', ['account_id']), (_check_no_closed, 'You cannot create journal items on closed account.', ['account_id']),
(_check_company_id, 'Account and Period must belong to the same company.', ['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
@ -641,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')
@ -703,7 +722,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:
@ -711,26 +732,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')
@ -910,8 +931,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):
@ -926,6 +947,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'], ))
@ -961,127 +984,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 = []
flds = []
title = _("Accounting Entries") # self.view_header_get(cr, uid, view_id, view_type, context)
ids = journal_pool.search(cr, uid, [], context=context)
journals = journal_pool.browse(cr, uid, ids, context=context)
for journal in journals:
for field in journal.view_id.columns_id:
# sometimes, it's possible that a defined column is not loaded (the module containing
# this field is not loaded) when we make an update.
if field.field not in self._columns:
continue
if not field.field in flds:
fld.append((field.field, field.sequence))
flds.append(field.field)
default_columns = {
'period_id': 3,
'journal_id': 10,
'state': sys.maxint,
}
for d in default_columns:
if d not in flds:
fld.append((d, default_columns[d]))
flds.append(d)
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",
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:
# TODO add string to element
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:
@ -1095,7 +997,7 @@ class account_move_line(osv.osv):
'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')
@ -1110,6 +1012,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
@ -1184,12 +1088,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 cannot 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,
@ -1225,16 +1129,16 @@ class account_move_line(osv.osv):
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 cannot 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(_('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.'))
@ -1244,6 +1148,9 @@ class account_move_line(osv.osv):
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
@ -1371,6 +1278,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

@ -41,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>

File diff suppressed because it is too large Load Diff

View File

@ -12,16 +12,6 @@
<field name="domain">[('year','=',time.strftime('%Y'))]</field> <field name="domain">[('year','=',time.strftime('%Y'))]</field>
</record> </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>
@ -29,12 +19,8 @@
<form string="Account Board" version="7.0"> <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"/>
</column>
</board> </board>
</form> </form>
</field> </field>

View File

@ -32,14 +32,6 @@ class res_company(osv.osv):
help="If you select 'Round per Line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round Globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."), help="If you select 'Round per Line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round Globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
'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 = {

View File

@ -15,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="arch" type="xml">
<xpath expr="//group[@name='account_grp']" position="inside">
<field name="property_reserve_and_surplus_account"/>
<field name="tax_calculation_rounding_method"/>
<field name="paypal_account" placeholder="e.g. sales@openerp.com"/>
</xpath>
</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -59,412 +59,6 @@
<field eval="account_payment_term_advance" name="payment_id"/> <field eval="account_payment_term_advance" name="payment_id"/>
</record> </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">Status</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">Status</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">Status</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">Status</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">Status</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 +112,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,8 +147,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>
<!-- <!--
Invoice requests (deprecated) Invoice requests (deprecated)
--> -->
@ -564,7 +155,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

@ -45,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>
@ -382,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>

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,9 +19,8 @@
# #
############################################################################## ##############################################################################
from osv import fields, osv, orm from openerp.osv import osv
from edi import EDIMixin from edi import EDIMixin
from edi.models import edi
INVOICE_LINE_EDI_STRUCT = { INVOICE_LINE_EDI_STRUCT = {
'name': True, 'name': True,
@ -71,16 +70,6 @@ INVOICE_EDI_STRUCT = {
class account_invoice(osv.osv, EDIMixin): class account_invoice(osv.osv, EDIMixin):
_inherit = 'account.invoice' _inherit = 'account.invoice'
def action_invoice_sent(self, cr, uid, ids, context=None):
""""Override this method to add a link to mail"""
if context is None:
context = {}
invoice_objs = self.browse(cr, uid, ids, context=context)
edi_token = self.pool.get('edi.document').export_edi(cr, uid, invoice_objs, context = context)[0]
web_root_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
ctx = dict(context, edi_web_url_view=edi.EDI_VIEW_WEB_URL % (web_root_url, cr.dbname, edi_token))
return super(account_invoice, self).action_invoice_sent(cr, uid, ids, context=ctx)
def edi_export(self, cr, uid, records, edi_struct=None, context=None): def edi_export(self, cr, uid, records, edi_struct=None, context=None):
"""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)
@ -111,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:
@ -136,31 +125,30 @@ class account_invoice(osv.osv, EDIMixin):
self._edi_requires_attributes(('company_id','company_address','type'), edi_document) self._edi_requires_attributes(('company_id','company_address','type'), edi_document)
res_partner = self.pool.get('res.partner') res_partner = self.pool.get('res.partner')
src_company_id, src_company_name = edi_document.pop('company_id') xid, company_name = edi_document.pop('company_id')
# Retrofit address info into a unified partner info (changed in v7 - used to keep them separate)
company_address_edi = edi_document.pop('company_address')
company_address_edi['name'] = company_name
company_address_edi['is_company'] = True
company_address_edi['__import_model'] = 'res.partner'
company_address_edi['__id'] = xid # override address ID, as of v7 they should be the same anyway
if company_address_edi.get('logo'):
company_address_edi['image'] = company_address_edi.pop('logo')
invoice_type = edi_document['type'] invoice_type = edi_document['type']
partner_value = {} if invoice_type.startswith('out_'):
if invoice_type in ('out_invoice', 'out_refund'): company_address_edi['customer'] = True
partner_value.update({'customer': True}) else:
if invoice_type in ('in_invoice', 'in_refund'): company_address_edi['supplier'] = True
partner_value.update({'supplier': True}) partner_id = res_partner.edi_import(cr, uid, company_address_edi, context=context)
# imported company_address = new partner address
address_info = edi_document.pop('company_address')
if 'name' not in address_info:
address_info['name'] = src_company_name
address_info['type'] = 'invoice'
address_info.update(partner_value)
address_id = res_partner.edi_import(cr, uid, address_info, context=context)
# modify edi_document to refer to new partner # modify edi_document to refer to new partner
partner_address = res_partner.browse(cr, uid, address_id, context=context) partner = res_partner.browse(cr, uid, partner_id, context=context)
address_edi_m2o = self.edi_m2o(cr, uid, partner_address, context=context) partner_edi_m2o = self.edi_m2o(cr, uid, partner, context=context)
edi_document['partner_id'] = address_edi_m2o edi_document['partner_id'] = partner_edi_m2o
edi_document.pop('partner_address', False) # ignored edi_document.pop('partner_address', None) # ignored, that's supposed to be our own address!
return address_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
@ -200,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,25 @@
</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.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.partner_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="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: rgb(255, 255, 255); ">
<p>Hello${object.partner_id.name and ' ' or ''}${object.partner_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 +44,17 @@
% if object.origin: % if object.origin:
&nbsp;&nbsp;Order reference: ${object.origin}<br /> &nbsp;&nbsp;Order reference: ${object.origin}<br />
% endif % endif
% 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> &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>
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'): % 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" % \
@ -123,64 +105,6 @@
</div> </div>
</div> </div>
]]></field> ]]></field>
<field name="body_text"><![CDATA[
Hello${object.partner_id.name and ' ' or ''}${object.partner_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.email and '<%s>'%(object.user_id.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.email and '<%s>'%(object.user_id.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

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

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

View File

@ -45,12 +45,12 @@ class account_installer(osv.osv_memory):
sorted(((m.name, m.shortdesc) sorted(((m.name, m.shortdesc)
for m in modules.browse(cr, uid, ids, context=context)), for m in modules.browse(cr, uid, ids, context=context)),
key=itemgetter(1))) key=itemgetter(1)))
charts.insert(0, ('configurable', 'Generic Chart Of Accounts')) charts.insert(0, ('configurable', _('Custom')))
return charts return charts
_columns = { _columns = {
# Accounting # Accounting
'charts': fields.selection(_get_charts, 'Chart of Accounts', 'charts': fields.selection(_get_charts, 'Accounting Package',
required=True, required=True,
help="Installs localized accounting charts to match as closely as " help="Installs localized accounting charts to match as closely as "
"possible the accounting needs of your company based on your " "possible the accounting needs of your company based on your "
@ -119,15 +119,6 @@ class account_installer(osv.osv_memory):
self.execute_simple(cr, uid, ids, context) self.execute_simple(cr, uid, ids, context)
super(account_installer, self).execute(cr, uid, ids, context=context) super(account_installer, self).execute(cr, uid, ids, context=context)
def action_next(self, cr, uid, ids, context=None):
next = self.execute(cr, uid, ids, context=context)
for installer in self.browse(cr, uid, ids, context=context):
if installer.charts == 'l10n_be':
return {'type': 'ir.actions.act_window_close'}
else :
if next : return next
return self.next(cr, uid, ids, context=context)
def execute_simple(self, cr, uid, ids, context=None): def execute_simple(self, cr, uid, ids, context=None):
if context is None: if context is None:
context = {} context = {}

View File

@ -20,8 +20,8 @@
############################################################################## ##############################################################################
from operator import itemgetter from operator import itemgetter
from osv import fields, osv from osv import fields, osv
import time
class account_fiscal_position(osv.osv): class account_fiscal_position(osv.osv):
_name = 'account.fiscal.position' _name = 'account.fiscal.position'
@ -44,17 +44,17 @@ class account_fiscal_position(osv.osv):
return [] return []
if not fposition_id: if not fposition_id:
return map(lambda x: x.id, taxes) return map(lambda x: x.id, taxes)
result = [] result = set()
for t in taxes: for t in taxes:
ok = False ok = False
for tax in fposition_id.tax_ids: for tax in fposition_id.tax_ids:
if tax.tax_src_id.id == t.id: if tax.tax_src_id.id == t.id:
if tax.tax_dest_id: if tax.tax_dest_id:
result.append(tax.tax_dest_id.id) result.add(tax.tax_dest_id.id)
ok=True ok=True
if not ok: if not ok:
result.append(t.id) result.add(t.id)
return result return list(result)
def map_account(self, cr, uid, fposition_id, account_id, context=None): def map_account(self, cr, uid, fposition_id, account_id, context=None):
if not fposition_id: if not fposition_id:
@ -77,6 +77,12 @@ class account_fiscal_position_tax(osv.osv):
'tax_dest_id': fields.many2one('account.tax', 'Replacement Tax') 'tax_dest_id': fields.many2one('account.tax', 'Replacement Tax')
} }
_sql_constraints = [
('tax_src_dest_uniq',
'unique (position_id,tax_src_id,tax_dest_id)',
'A tax fiscal position could be defined only once time on same taxes.')
]
account_fiscal_position_tax() account_fiscal_position_tax()
class account_fiscal_position_account(osv.osv): class account_fiscal_position_account(osv.osv):
@ -89,6 +95,12 @@ class account_fiscal_position_account(osv.osv):
'account_dest_id': fields.many2one('account.account', 'Account Destination', domain=[('type','<>','view')], required=True) 'account_dest_id': fields.many2one('account.account', 'Account Destination', domain=[('type','<>','view')], required=True)
} }
_sql_constraints = [
('account_src_dest_uniq',
'unique (position_id,account_src_id,account_dest_id)',
'An account fiscal position could be defined only once time on same accounts.')
]
account_fiscal_position_account() account_fiscal_position_account()
class res_partner(osv.osv): class res_partner(osv.osv):
@ -145,6 +157,29 @@ class res_partner(osv.osv):
def _debit_search(self, cr, uid, obj, name, args, context=None): def _debit_search(self, cr, uid, obj, name, args, context=None):
return self._asset_difference_search(cr, uid, obj, name, 'payable', args, context=context) return self._asset_difference_search(cr, uid, obj, name, 'payable', args, context=context)
def has_something_to_reconcile(self, cr, uid, partner_id, context=None):
'''
at least a debit, a credit and a line older than the last reconciliation date of the partner
'''
cr.execute('''
SELECT l.partner_id, SUM(l.debit) AS debit, SUM(l.credit) AS credit
FROM account_move_line l
RIGHT JOIN account_account a ON (a.id = l.account_id)
RIGHT JOIN res_partner p ON (l.partner_id = p.id)
WHERE a.reconcile IS TRUE
AND p.id = %s
AND l.reconcile_id IS NULL
AND (p.last_reconciliation_date IS NULL OR l.date > p.last_reconciliation_date)
AND l.state <> 'draft'
GROUP BY l.partner_id''', (partner_id,))
res = cr.dictfetchone()
if res:
return bool(res['debit'] and res['credit'])
return False
def mark_as_reconciled(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'last_reconciliation_date': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
_columns = { _columns = {
'credit': fields.function(_credit_debit_get, 'credit': fields.function(_credit_debit_get,
fnct_search=_credit_search, string='Total Receivable', multi='dc', help="Total amount this customer owes you."), fnct_search=_credit_search, string='Total Receivable', multi='dc', help="Total amount this customer owes you."),
@ -174,7 +209,7 @@ class res_partner(osv.osv):
relation='account.fiscal.position', relation='account.fiscal.position',
string="Fiscal Position", string="Fiscal Position",
view_load=True, view_load=True,
help="The fiscal position will determine taxes and the accounts used for the partner.", help="The fiscal position will determine taxes and accounts used for the partner.",
), ),
'property_payment_term': fields.property( 'property_payment_term': fields.property(
'account.payment.term', 'account.payment.term',
@ -185,7 +220,7 @@ class res_partner(osv.osv):
help="This payment term will be used instead of the default one for the current partner"), help="This payment term will be used instead of the default one for the current partner"),
'ref_companies': fields.one2many('res.company', 'partner_id', 'ref_companies': fields.one2many('res.company', 'partner_id',
'Companies that refers to partner'), 'Companies that refers to partner'),
'last_reconciliation_date': fields.datetime('Latest Reconciliation Date', help='Date on which the partner accounting entries were reconciled last time') 'last_reconciliation_date': fields.datetime('Latest Reconciliation Date', help='Date on which the partner accounting entries were fully reconciled last time. It differs from the date of the last reconciliation made for this partner, as here we depict the fact that nothing more was to be reconciled at this date. This can be achieved in 2 ways: either the last debit/credit entry was reconciled, either the user pressed the button "Fully Reconciled" in the manual reconciliation process')
} }
res_partner() res_partner()

View File

@ -6,13 +6,13 @@
<field name="name">account.fiscal.position.form</field> <field name="name">account.fiscal.position.form</field>
<field name="model">account.fiscal.position</field> <field name="model">account.fiscal.position</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Fiscal Position"> <form string="Fiscal Position" version="7.0">
<group col="4"> <group col="4">
<field name="name"/> <field name="name"/>
<field name="active"/> <field name="active"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/> <field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group> </group>
<separator string="Mapping"/> <separator string="Taxes Mapping"/>
<field name="tax_ids" widget="one2many_list"> <field name="tax_ids" widget="one2many_list">
<tree string="Tax Mapping" editable="bottom"> <tree string="Tax Mapping" editable="bottom">
<field name="tax_src_id" domain="[('parent_id','=',False)]"/> <field name="tax_src_id" domain="[('parent_id','=',False)]"/>
@ -23,6 +23,7 @@
<field name="tax_dest_id" domain="[('parent_id','=',False)]"/> <field name="tax_dest_id" domain="[('parent_id','=',False)]"/>
</form> </form>
</field> </field>
<separator string="Accounts Mapping"/>
<field name="account_ids" widget="one2many_list"> <field name="account_ids" widget="one2many_list">
<tree string="Account Mapping" editable="bottom"> <tree string="Account Mapping" editable="bottom">
<field name="account_src_id"/> <field name="account_src_id"/>
@ -91,32 +92,7 @@
<field name="debit"/> <field name="debit"/>
</group> </group>
</group> </group>
<field name="bank_ids"> <field name="bank_ids" context="{'default_partner_id': active_id, 'form_view_ref': 'base.view_partner_bank_form'}">
<form string="Bank account" version="7.0">
<field name="state"/>
<field name="acc_number"/>
<group>
<group name="owner" string="Bank Account Owner">
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="owner_name"/>
<label for="street" string="Address"/>
<div>
<field name="street" placeholder="Street..."/>
<div>
<field name="zip" class="oe_inline" placeholder="ZIP"/>
<field name="city" class="oe_inline" placeholder="City"/>
</div>
<field name="state_id" placeholder="State" options='{"no_open": true}'/>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
</div>
</group>
<group name="bank" string="Information About the Bank">
<field name="bank" on_change="onchange_bank_id(bank)"/>
<field name="bank_name"/>
<field name="bank_bic" placeholder="e.g. GEBABEBB"/>
</group>
</group>
</form>
<tree string="Bank Details"> <tree string="Bank Details">
<field name="sequence" invisible="1"/> <field name="sequence" invisible="1"/>
<field name="acc_number"/> <field name="acc_number"/>
@ -138,7 +114,7 @@
context="{'search_default_partner_id':[active_id], 'default_partner_id': active_id}" context="{'search_default_partner_id':[active_id], 'default_partner_id': active_id}"
src_model="res.partner" src_model="res.partner"
view_type="form" view_type="form"
view_mode="tree,form,graph,calendar"/> view_mode="tree,form"/>
</data> </data>
</openerp> </openerp>

View File

@ -30,14 +30,14 @@ class product_category(osv.osv):
relation='account.account', relation='account.account',
string="Income Account", string="Income Account",
view_load=True, view_load=True,
help="This account will be used for invoices to value sales for the current product category"), help="This account will be used for invoices to value sales."),
'property_account_expense_categ': fields.property( 'property_account_expense_categ': fields.property(
'account.account', 'account.account',
type='many2one', type='many2one',
relation='account.account', relation='account.account',
string="Expense Account", string="Expense Account",
view_load=True, view_load=True,
help="This account will be used for invoices to value expenses for the current product category"), help="This account will be used for invoices to value expenses."),
} }
product_category() product_category()
@ -60,14 +60,14 @@ class product_template(osv.osv):
relation='account.account', relation='account.account',
string="Income Account", string="Income Account",
view_load=True, view_load=True,
help="This account will be used for invoices instead of the default one to value sales for the current product"), help="This account will be used for invoices instead of the default one to value sales for the current product."),
'property_account_expense': fields.property( 'property_account_expense': fields.property(
'account.account', 'account.account',
type='many2one', type='many2one',
relation='account.account', relation='account.account',
string="Expense Account", string="Expense Account",
view_load=True, view_load=True,
help="This account will be used for invoices instead of the default one to value expenses for the current product"), help="This account will be used for invoices instead of the default one to value expenses for the current product."),
} }
product_template() product_template()

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