##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
_name = "account.payment.term"
_description = "Payment Term"
_columns = {
- 'name': fields.char('Payment Term', size=32, translate=True, required=True),
+ 'name': fields.char('Payment Term', size=64, translate=True, required=True),
'active': fields.boolean('Active'),
'note': fields.text('Description', translate=True),
'line_ids': fields.one2many('account.payment.term.line', 'payment_id', 'Terms'),
'sequence': fields.integer('Sequence', required=True, help="The sequence field is used to order the payment term lines from the lowest sequences to the higher ones"),
'value': fields.selection([('procent','Percent'),('balance','Balance'),('fixed','Fixed Amount')], 'Value',required=True),
'value_amount': fields.float('Value Amount'),
- '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."),
'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),
}
_name = "account.account"
_description = "Account"
_parent_store = True
+ _parent_order = 'length(code),code'
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
args[pos] = ('id','in',ids1)
pos+=1
- if context and context.has_key('consolidate_childs'): #add concolidated childs of accounts
+ if context and context.has_key('consolidate_childs'): #add consolidated childs of accounts
ids = super(account_account,self).search(cr, uid, args, offset, limit,
order, context=context, count=count)
for consolidate_child in self.browse(cr, uid, context['account_id']).child_consol_ids:
def _get_children_and_consol(self, cr, uid, ids, context={}):
#this function search for all the children and all consolidated children (recursively) of the given account ids
- res = self.search(cr, uid, [('parent_id', 'child_of', ids)])
- for id in res:
- this = self.browse(cr, uid, id, context)
- for child in this.child_consol_ids:
- if child.id not in res:
- res.append(child.id)
- if len(res) != len(ids):
- return self._get_children_and_consol(cr, uid, res, context)
- return res
+ ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)], context=context)
+ ids3 = []
+ for rec in self.browse(cr, uid, ids2, context=context):
+ for child in rec.child_consol_ids:
+ ids3.append(child.id)
+ if ids3:
+ ids3 = self._get_children_and_consol(cr, uid, ids3, context)
+ return ids2+ids3
def __compute(self, cr, uid, ids, field_names, arg, context={}, query=''):
#compute the balance/debit/credit accordingly to the value of field_name for the given account ids
mapping = {
- 'balance': "COALESCE(SUM(l.debit) - SUM(l.credit), 0) as balance ",
+ 'balance': "COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance ",
'debit': "COALESCE(SUM(l.debit), 0) as debit ",
'credit': "COALESCE(SUM(l.credit), 0) as credit "
}
'check_history': fields.boolean('Display History',
help="Check this box if you want to print all entries when printing the General Ledger, "\
"otherwise it will only print its balance."),
- 'merge_invoice': fields.boolean('Merge Invoice Entries',help="Check this box if you want that all lines of "\
- "a customer or supplier invoice using this account are created in one line only"),
}
def _default_company(self, cr, uid, context={}):
'active': fields.boolean('Active'),
'view_id': fields.many2one('account.journal.view', 'View', required=True, help="Gives the view used when writing or browsing entries in this journal. The view tell Open ERP 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'),
- 'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account'),
- 'centralisation': fields.boolean('Centralised counterpart', help="Check this box if you want that each entry doesn't create a counterpart but share the same counterpart for each entry of this journal."),
+ 'default_credit_account_id': fields.many2one('account.account', 'Default Credit Account', domain="[('type','!=','view')]"),
+ 'default_debit_account_id': fields.many2one('account.account', 'Default Debit Account', domain="[('type','!=','view')]"),
+ 'centralisation': fields.boolean('Centralised counterpart', help="Check this box if you want that each entry doesn't create a counterpart but share the same counterpart for each entry of this journal. This is used in fiscal year closing."),
'update_posted': fields.boolean('Allow Cancelling Entries'),
+ 'group_invoice_lines': fields.boolean('Group invoice lines', help="If this box is cheked, the system will try to group the accouting lines when generating them from invoices."),
'sequence_id': fields.many2one('ir.sequence', 'Entry Sequence', help="The sequence gives the display order for a list of journals", required=True),
'user_id': fields.many2one('res.users', 'User', help="The responsible user of this journal"),
'groups_id': fields.many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', 'Groups'),
'currency': fields.many2one('res.currency', 'Currency', help='The currency used to enter statement'),
'entry_posted': fields.boolean('Skip \'Draft\' State for Created Entries', help='Check this box if you don\'t want that new account moves pass through the \'draft\' state and goes direclty to the \'posted state\' without any manual validation.'),
'company_id': fields.related('default_credit_account_id','company_id',type='many2one', relation="res.company", string="Company"),
+ 'fy_seq_id': fields.one2many('fiscalyear.seq', 'journal_id', 'Sequences'),
}
_defaults = {
_columns = {
'name': fields.char('Fiscal Year', size=64, required=True),
'code': fields.char('Code', size=6, required=True),
+ 'company_id': fields.many2one('res.company', 'Company',
+ help="Keep empty if the fiscal year belongs to several companies."),
'date_start': fields.date('Start date', required=True),
'date_stop': fields.date('End date', required=True),
'period_ids': fields.one2many('account.period', 'fiscalyear_id', 'Periods'),
_columns = {
'name': fields.char('Period Name', size=64, required=True),
'code': fields.char('Code', size=12),
+ 'special': fields.boolean('Opening/Closing Period', size=12,
+ help="These periods can overlap."),
'date_start': fields.date('Start 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),
}
_order = "date_start"
- def _check_duration(self,cr,uid,ids):
+ def _check_duration(self,cr,uid,ids,context={}):
obj_period=self.browse(cr,uid,ids[0])
if obj_period.date_stop < obj_period.date_start:
return False
return True
- def _check_year_limit(self,cr,uid,ids):
- obj_period=self.browse(cr,uid,ids[0])
- if obj_period.fiscalyear_id.date_stop < obj_period.date_stop or obj_period.fiscalyear_id.date_stop < obj_period.date_start or obj_period.fiscalyear_id.date_start > obj_period.date_start or obj_period.fiscalyear_id.date_start > obj_period.date_stop:
- return False
+ def _check_year_limit(self,cr,uid,ids,context={}):
+ for obj_period in self.browse(cr,uid,ids):
+ if obj_period.special:
+ continue
+ if obj_period.fiscalyear_id.date_stop < obj_period.date_stop or obj_period.fiscalyear_id.date_stop < obj_period.date_start or obj_period.fiscalyear_id.date_start > obj_period.date_start or obj_period.fiscalyear_id.date_start > obj_period.date_stop:
+ return False
+
+ pids = self.search(cr, uid, [('date_stop','>=',obj_period.date_start),('date_start','<=',obj_period.date_stop),('special','=',False),('id','<>',obj_period.id)])
+ for period in self.browse(cr, uid, pids):
+ if period.fiscalyear_id.company_id.id==obj_period.fiscalyear_id.company_id.id:
+ return False
return True
_constraints = [
(_check_duration, 'Error ! The date duration of the Period(s) is invalid. ', ['date_stop']),
- (_check_year_limit, 'Error ! The date duration of the Period(s) should be within the limit of the Fiscal year. ', ['date_stop'])
+ (_check_year_limit, 'Invalid period ! Some periods overlap or the date duration is not in the limit of the fiscal year. ', ['date_stop'])
]
def next(self, cr, uid, period, step, context={}):
_inherit = "account.fiscalyear"
_description = "Fiscal Year"
_columns = {
- 'start_journal_period_id':fields.many2one('account.journal.period','New Entries Journal'),
'end_journal_period_id':fields.many2one('account.journal.period','End of Year Entries Journal', readonly=True),
}
'to_check': fields.boolean('To Be Verified'),
'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner"),
'amount': fields.function(_amount_compute, method=True, string='Amount', digits=(16,2)),
+ 'date': fields.date('Date', required=True),
'type': fields.selection([
('pay_voucher','Cash Payment'),
('bank_pay_voucher','Bank Payment'),
'state': lambda *a: 'draft',
'period_id': _get_period,
'type' : lambda *a : 'journal_voucher',
+ 'date': lambda *a:time.strftime('%Y-%m-%d'),
}
def _check_centralisation(self, cursor, user, ids):
context['journal_id'] = move.journal_id.id
context['period_id'] = move.period_id.id
self.pool.get('account.move.line')._update_check(cr, uid, line_ids, context)
+ self.pool.get('account.move.line').unlink(cr, uid, line_ids, context=context)
toremove.append(move.id)
result = super(account_move, self).unlink(cr, uid, toremove, context)
return result
for move in self.browse(cr, uid, ids, context):
#unlink analytic lines on move_lines
for obj_line in move.line_id:
- for obj in obj_line.analytic_lines:
+ for obj in obj_line.analytic_lines:
self.pool.get('account.analytic.line').unlink(cr,uid,obj.id)
journal = move.journal_id
res[record.id] = round(_rec_get(record), 2)
return res
+ def _sum_year(self, cr, uid, ids, name, args, context):
+ if 'fiscalyear_id' in context and context['fiscalyear_id']:
+ fiscalyear_id = context['fiscalyear_id']
+ else:
+ fiscalyear_id = self.pool.get('account.fiscalyear').find(cr, uid, exception=False)
+ where = ''
+ if fiscalyear_id:
+ pids = map(lambda x: str(x.id), self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id).period_ids)
+ if pids:
+ where = ' and period_id in (' + (','.join(pids))+')'
+ return self._sum(cr, uid, ids, name, args, context,
+ where=where)
+
def _sum_period(self, cr, uid, ids, name, args, context):
if 'period_id' in context and context['period_id']:
period_id = context['period_id']
'name': fields.char('Tax Case Name', size=64, required=True),
'code': fields.char('Case Code', size=64),
'info': fields.text('Description'),
- 'sum': fields.function(_sum, method=True, string="Year Sum"),
+ 'sum': fields.function(_sum_year, method=True, string="Year Sum"),
'sum_period': fields.function(_sum_period, method=True, string="Period Sum"),
'parent_id': fields.many2one('account.tax.code', 'Parent Code', select=True),
'child_ids': fields.one2many('account.tax.code', 'parent_id', 'Childs Codes'),
'sequence': fields.integer('Sequence', required=True, help="The sequence field is used to order the taxes lines from the lowest sequences to the higher ones. The order is important if you have a tax that have several tax childs. In this case, the evaluation order is important."),
'amount': fields.float('Amount', required=True, digits=(14,4)),
'active': fields.boolean('Active'),
- 'type': fields.selection( [('percent','Percent'), ('fixed','Fixed'), ('none','None'), ('code','Python Code')], 'Tax Type', required=True),
- 'applicable_type': fields.selection( [('true','True'), ('code','Python Code')], 'Applicable Type', required=True),
+ 'type': fields.selection( [('percent','Percent'), ('fixed','Fixed'), ('none','None'), ('code','Python Code'),('balance','Balance')], 'Tax Type', required=True,
+ help="The computation method for the tax amount."),
+ 'applicable_type': fields.selection( [('true','True'), ('code','Python Code')], 'Applicable Type', required=True,
+ help="If not applicable (computed through a Python code), the tax do not appears on the invoice."),
'domain':fields.char('Domain', size=32, help="This field is only used if you develop your own module allowing developpers to create specific taxes in a custom domain."),
'account_collected_id':fields.many2one('account.account', 'Invoice Tax Account'),
'account_paid_id':fields.many2one('account.account', 'Refund Tax Account'),
#
'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="Use this code for the VAT declaration."),
'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="Use this code for the VAT declaration."),
- 'base_sign': fields.float('Base Code Sign', help="Usualy 1 or -1."),
- 'tax_sign': fields.float('Tax Code Sign', help="Usualy 1 or -1."),
+ 'base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
+ 'tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
# Same fields for refund invoices
'ref_base_code_id': fields.many2one('account.tax.code', 'Refund Base Code', help="Use this code for the VAT declaration."),
'ref_tax_code_id': fields.many2one('account.tax.code', 'Refund Tax Code', help="Use this code for the VAT declaration."),
- 'ref_base_sign': fields.float('Base Code Sign', help="Usualy 1 or -1."),
- 'ref_tax_sign': fields.float('Tax Code Sign', help="Usualy 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."),
'include_base_amount': fields.boolean('Include in base amount', help="Indicate 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),
'description': fields.char('Internal Name',size=32),
exec tax.python_compute in localdict
amount = localdict['result']
data['amount'] = amount
+ elif tax.type=='balance':
+ data['amount'] = cur_price_unit - reduce(lambda x,y: y.get('amount',0.0)+x, res, 0.0)
+ data['balance'] = cur_price_unit
+
amount2 = data['amount']
if len(tax.child_ids):
if tax.child_depend:
- del res[-1]
+ latest = res.pop()
amount = amount2
child_tax = self._unit_compute(cr, uid, tax.child_ids, amount, address_id, product, partner)
res.extend(child_tax)
+ if tax.child_depend:
+ for r in res:
+ for name in ('base','ref_base'):
+ if latest[name+'_code_id'] and latest[name+'_sign'] and not r[name+'_code_id']:
+ r[name+'_code_id'] = latest[name+'_code_id']
+ r[name+'_sign'] = latest[name+'_sign']
+ r['price_unit'] = latest['price_unit']
+ latest[name+'_code_id'] = False
+ for name in ('tax','ref_tax'):
+ if latest[name+'_code_id'] and latest[name+'_sign'] and not r[name+'_code_id']:
+ r[name+'_code_id'] = latest[name+'_code_id']
+ r[name+'_sign'] = latest[name+'_sign']
+ r['amount'] = data['amount']
+ latest[name+'_code_id'] = False
if tax.include_base_amount:
cur_price_unit+=amount2
return res
one tax for each tax id in IDS and their childs
"""
res = self._unit_compute(cr, uid, taxes, price_unit, address_id, product, partner)
+ total = 0.0
for r in res:
- r['amount'] *= quantity
+ if r.get('balance',False):
+ r['amount'] = round(r['balance'] * quantity, 2) - total
+ else:
+ r['amount'] = round(r['amount'] * quantity, 2)
+ total += r['amount']
+
return res
def _unit_compute_inv(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None):
localdict = {'price_unit':cur_price_unit, 'address':address, 'product':product, 'partner':partner}
exec tax.python_compute_inv in localdict
amount = localdict['result']
+ elif tax.type=='balance':
+ data['amount'] = cur_price_unit - reduce(lambda x,y: y.get('amount',0.0)+x, res, 0.0)
+ data['balance'] = cur_price_unit
+
if tax.include_base_amount:
cur_price_unit -= amount
one tax for each tax id in IDS and their childs
"""
res = self._unit_compute_inv(cr, uid, taxes, price_unit, address_id, product, partner=None)
+ total = 0.0
for r in res:
- r['amount'] *= quantity
+ if r.get('balance',False):
+ r['amount'] = round(r['balance'] * quantity, 2) - total
+ else:
+ r['amount'] = round(r['amount'] * quantity, 2)
+ total += r['amount']
return res
account_tax()
ids=module_obj.search(cr, uid, [('category_id', '=', 'Account Charts'), ('state', '<>', 'installed')])
res=[(m.id, m.shortdesc) for m in module_obj.browse(cr, uid, ids)]
res.append((-1, 'None'))
- res.sort(lambda x,y: cmp(x[1],y[1]))
+ res.sort(key=lambda x: x[1])
return res
_columns = {
'target':'new',
}
- def install_account_chart(self, cr, uid,ids, context=None):
+ def install_account_chart(self, cr, uid, ids, context=None):
for res in self.read(cr,uid,ids):
- id = res['charts']
- def install(id):
+ chart_id = res['charts']
+ if chart_id > 0:
mod_obj = self.pool.get('ir.module.module')
- mod_obj.write(cr , uid, [id] ,{'state' : 'to install'})
- mod_obj.download(cr, uid, [id], context=context)
- cr.commit()
- cr.execute("select m.id as id from ir_module_module_dependency d inner join ir_module_module m on (m.name=d.name) where d.module_id=%s and m.state='uninstalled'",(id,))
- ret = cr.fetchall()
- if len(ret):
- for r in ret:
- install(r[0])
- else:
- mod_obj.write(cr , uid, [id] ,{'state' : 'to install'})
- mod_obj.download(cr, uid, [id], context=context)
- cr.commit()
- if id>0:
- install(id)
+ mod_obj.button_install(cr, uid, [chart_id], context=context)
cr.commit()
db, pool = pooler.restart_pool(cr.dbname, update_module=True)
account_tax_template()
+# Fiscal Position Templates
+
+class account_fiscal_position_template(osv.osv):
+ _name = 'account.fiscal.position.template'
+ _description = 'Template for Fiscal Position'
+
+ _columns = {
+ 'name': fields.char('Fiscal Position Template', size=64, translate=True, required=True),
+ 'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True),
+ 'account_ids': fields.one2many('account.fiscal.position.account.template', 'position_id', 'Accounts Mapping'),
+ 'tax_ids': fields.one2many('account.fiscal.position.tax.template', 'position_id', 'Taxes Mapping')
+ }
+
+account_fiscal_position_template()
+
+class account_fiscal_position_tax_template(osv.osv):
+ _name = 'account.fiscal.position.tax.template'
+ _description = 'Fiscal Position Template Taxes Mapping'
+ _rec_name = 'position_id'
+
+ _columns = {
+ 'position_id': fields.many2one('account.fiscal.position.template', 'Fiscal Position', required=True, ondelete='cascade'),
+ 'tax_src_id': fields.many2one('account.tax.template', 'Tax Source', required=True),
+ 'tax_dest_id': fields.many2one('account.tax.template', 'Replacement Tax')
+ }
+
+account_fiscal_position_tax_template()
+
+class account_fiscal_position_account_template(osv.osv):
+ _name = 'account.fiscal.position.account.template'
+ _description = 'Fiscal Position Template Accounts Mapping'
+ _rec_name = 'position_id'
+ _columns = {
+ 'position_id': fields.many2one('account.fiscal.position.template', 'Fiscal Position', required=True, ondelete='cascade'),
+ 'account_src_id': fields.many2one('account.account.template', 'Account Source', domain=[('type','<>','view')], required=True),
+ 'account_dest_id': fields.many2one('account.account.template', 'Account Destination', domain=[('type','<>','view')], required=True)
+ }
+
+account_fiscal_position_account_template()
+
# Multi charts of Accounts wizard
class wizard_multi_charts_accounts(osv.osv_memory):
obj_acc_tax = self.pool.get('account.tax')
obj_journal = self.pool.get('account.journal')
obj_acc_template = self.pool.get('account.account.template')
+ obj_fiscal_position_template = self.pool.get('account.fiscal.position.template')
+ obj_fiscal_position = self.pool.get('account.fiscal.position')
# Creating Account
obj_acc_root = obj_multi.chart_template_id.account_root_id
vals_journal['code'] = _('SAJ')
if obj_multi.chart_template_id.property_account_receivable:
- vals_journal['default_credit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_receivable.id]
- vals_journal['default_debit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_receivable.id]
+ vals_journal['default_credit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_income_categ.id]
+ vals_journal['default_debit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_income_categ.id]
obj_journal.create(cr,uid,vals_journal)
vals_journal['code']=_('EXJ')
if obj_multi.chart_template_id.property_account_payable:
- vals_journal['default_credit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_payable.id]
- vals_journal['default_debit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_payable.id]
+ vals_journal['default_credit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_expense_categ.id]
+ vals_journal['default_debit_account_id'] = acc_template_ref[obj_multi.chart_template_id.property_account_expense_categ.id]
obj_journal.create(cr,uid,vals_journal)
vals={
'name': line.acc_no.bank and line.acc_no.bank.name+' '+tmp or tmp,
'currency_id': line.currency_id and line.currency_id.id or False,
- 'code': str(int(ref_acc_bank.code.ljust(dig,'0')) + current_num),
+ 'code': str(ref_acc_bank.code.ljust(dig,'0') + str(current_num)),
'type': 'other',
'user_type': account_template.user_type and account_template.user_type.id or False,
'reconcile': True,
#create the property
property_obj.create(cr, uid, vals)
+ fp_ids = obj_fiscal_position_template.search(cr, uid,[('chart_template_id', '=', obj_multi.chart_template_id.id)])
+
+ if fp_ids:
+ for position in obj_fiscal_position_template.browse(cr, uid, fp_ids):
+
+ vals_fp = {
+ 'company_id' : company_id,
+ 'name' : position.name,
+ }
+ new_fp = obj_fiscal_position.create(cr, uid, vals_fp)
+
+ obj_tax_fp = self.pool.get('account.fiscal.position.tax')
+ obj_ac_fp = self.pool.get('account.fiscal.position.account')
+
+ for tax in position.tax_ids:
+ vals_tax = {
+ 'tax_src_id' : tax_template_ref[tax.tax_src_id.id],
+ 'tax_dest_id' : tax_template_ref[tax.tax_dest_id.id],
+ 'position_id' : new_fp,
+ }
+ obj_tax_fp.create(cr, uid, vals_tax)
+
+ for acc in position.account_ids:
+ vals_acc = {
+ 'account_src_id' : acc_template_ref[acc.account_src_id.id],
+ 'account_dest_id' : acc_template_ref[acc.account_dest_id.id],
+ 'position_id' : new_fp,
+ }
+ obj_ac_fp.create(cr, uid, vals_acc)
+
return {
'view_type': 'form',
"view_mode": 'form',