From 439d7a5a9083aea9f81b1c626f9699be15f705e6 Mon Sep 17 00:00:00 2001
From: bch <>
Date: Thu, 4 Jan 2007 09:45:50 +0000
Subject: [PATCH] ACCOUNT: * bank statment line now have a ref t othe
corresponding invoice. * account.py splitted for depedendy reason.
L10N_CH: debug
bzr revid: bch-cd59941716bff05a29b95739b303b6f1c2a859a8
---
addons/account/__init__.py | 3 +
addons/account/account.py | 636 ++---------------------
addons/account/account_analytic_line.py | 130 +++++
addons/account/account_bank_statement.py | 192 +++++++
addons/account/account_invoice_view.xml | 5 +-
addons/account/account_move_line.py | 466 +++++++++++++++++
addons/account/account_view.xml | 3 +-
addons/account/invoice.py | 36 +-
addons/account/project/project.py | 94 ----
addons/l10n_ch/dta/dta_wizard.py | 43 +-
10 files changed, 882 insertions(+), 726 deletions(-)
create mode 100644 addons/account/account_analytic_line.py
create mode 100644 addons/account/account_bank_statement.py
create mode 100644 addons/account/account_move_line.py
diff --git a/addons/account/__init__.py b/addons/account/__init__.py
index b62474360b1..43169f60587 100644
--- a/addons/account/__init__.py
+++ b/addons/account/__init__.py
@@ -29,6 +29,9 @@
import account
import project
import invoice
+import account_bank_statement
+import account_move_line
+import account_analytic_line
import transfer
import wizard
import report
diff --git a/addons/account/account.py b/addons/account/account.py
index c2c0476d7cb..45fc3eb5376 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -70,6 +70,31 @@ class account_payment_term(osv.osv):
result.append( (next_date.strftime('%Y-%m-%d'), amt) )
amount -= amt
return result
+
+ def get_discounts(self,cr,uid,id,base_date, context={}):
+ """
+ return the list of (date,percentage) ordered by date for the
+ payment term with the corresponding id. return [] if no cash
+ discount are defined. base_date is the date from where the
+ discounts are computed.
+ """
+
+ pt = self.browse(cr, uid, id, context)
+
+ if not pt.cash_discount_ids:
+ return []
+
+ res=[]
+ for d in pt.cash_discount_ids:
+ res.append(
+ ((mx.DateTime.strptime(base_date,'%Y-%m-%d') +\
+ RelativeDateTime(days=d.delay+1)).strftime("%Y-%m-%d"),
+ d.discount)
+ )
+
+ res.sort(cmp=lambda x,y: cmp(x[0],y[0]))
+ return res
+
account_payment_term()
class account_payment_term_line(osv.osv):
@@ -93,18 +118,6 @@ class account_payment_term_line(osv.osv):
account_payment_term_line()
-class account_cash_discount(osv.osv):
- _name = "account.cash.discount"
- _description = "Cash Discount" #A reduction in the price if payment is made within a stipulated period.
- _columns = {
- 'name': fields.char('Name', size=32),
- 'delay': fields.integer('Number of Days', required=True),
- 'discount': fields.float('Discount (%)',required=True),
- 'payment_id': fields.many2one('account.payment.term','Associated Payment Term'),
- }
-account_cash_discount()
-
-
class account_account_type(osv.osv):
_name = "account.account.type"
_description = "Account Type"
@@ -248,6 +261,21 @@ class account_account(osv.osv):
return res
account_account()
+
+class account_cash_discount(osv.osv):
+ _name = "account.cash.discount"
+ _description = "Cash Discount" #A reduction in the price if payment is made within a stipulated period.
+ _columns = {
+ 'name': fields.char('Name', size=32),
+ 'delay': fields.integer('Number of Days', required=True),
+ 'discount': fields.float('Discount (%)',digits=(16,6),required=True),
+ 'payment_id': fields.many2one('account.payment.term','Associated Payment Term'),
+ 'credit_account_id': fields.many2one('account.account', 'Credit Account'),
+ 'debit_account_id': fields.many2one('account.account', 'Debit Account'),
+ }
+account_cash_discount()
+
+
class account_journal_view(osv.osv):
_name = "account.journal.view"
_description = "Journal View"
@@ -698,157 +726,6 @@ class account_move_reconcile(osv.osv):
}
account_move_reconcile()
-#
-# use a sequence for names ?
-#
-class account_bank_statement(osv.osv):
- def _default_journal_id(self, cr, uid, context={}):
- if context.get('journal_id', False):
- return context['journal_id']
- return False
-
- def _default_balance_start(self, cr, uid, context={}):
- cr.execute('select id from account_bank_statement where journal_id=%d order by date desc limit 1', (1,))
- res = cr.fetchone()
- if res:
- return self.browse(cr, uid, [res[0]], context)[0].balance_end
- return 0.0
-
- def _end_balance(self, cr, uid, ids, prop, unknow_none, unknow_dict):
- res = {}
- statements = self.browse(cr, uid, ids)
- for statement in statements:
- res[statement.id] = statement.balance_start
- for line in statement.line_ids:
- res[statement.id] += line.amount
- for r in res:
- res[r] = round(res[r], 2)
- return res
-
- def _get_period(self, cr, uid, context={}):
- periods = self.pool.get('account.period').find(cr, uid)
- if periods:
- return periods[0]
- else:
- return False
-
- _order = "date desc"
- _name = "account.bank.statement"
- _description = "Bank Statement"
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'date': fields.date('Date', required=True, states={'confirm':[('readonly',True)]}),
- 'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'confirm':[('readonly',True)]}, domain=[('type','=','cash')], relate=True),
- 'period_id': fields.many2one('account.period', 'Period', required=True, states={'confirm':[('readonly',True)]}),
- 'balance_start': fields.float('Starting Balance', digits=(16,2), states={'confirm':[('readonly',True)]}),
- 'balance_end_real': fields.float('Ending Balance', digits=(16,2), states={'confirm':[('readonly',True)]}),
- 'balance_end': fields.function(_end_balance, method=True, string='Balance'),
- 'line_ids': fields.one2many('account.bank.statement.line', 'statement_id', 'Statement lines', states={'confirm':[('readonly',True)]}),
- 'move_line_ids': fields.one2many('account.move.line', 'statement_id', 'Entry lines', states={'confirm':[('readonly',True)]}),
- 'state': fields.selection([('draft','Draft'),('confirm','Confirm')], 'State', required=True, states={'confirm':[('readonly',True)]}, readonly="1"),
- #'partner_id': fields.many2one('res.partner', 'Partner', states={'confirm':[('readonly',True)]}),
- #'invoice_id': fields.many2one('account.invoice', 'Invoice', states={'confirm':[('readonly',True)]}),
- #write-off account
- #selection: partiel/total
- }
-
- _defaults = {
- 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement'),
- 'date': lambda *a: time.strftime('%Y-%m-%d'),
- 'state': lambda *a: 'draft',
- 'balance_start': _default_balance_start,
- 'journal_id': _default_journal_id,
- 'period_id': _get_period,
- }
- def button_confirm(self, cr, uid, ids, context={}):
- done = []
- for st in self.browse(cr, uid, ids, context):
- if not st.state=='draft':
- continue
- if not (abs(st.balance_end - st.balance_end_real) < 0.0001):
- raise osv.except_osv('Error !', 'The statement balance is incorrect !\nCheck that the ending balance equals the computed one.')
- if (not st.journal_id.default_credit_account_id) or (not st.journal_id.default_debit_account_id):
- raise osv.except_osv('Configration Error !', 'Please verify that an account is defined in the journal.')
- for move in st.line_ids:
- if not move.amount:
- continue
- self.pool.get('account.move.line').create(cr, uid, {
- 'name': move.name,
- 'date': move.date,
- 'partner_id': ((move.partner_id) and move.partner_id.id) or False,
- 'account_id': (move.account_id) and move.account_id.id,
- 'credit': ((move.amount>0) and move.amount) or 0.0,
- 'debit': ((move.amount<0) and -move.amount) or 0.0,
- 'statement_id': st.id,
- 'journal_id': st.journal_id.id,
- 'period_id': st.period_id.id,
- }, context=context)
- if not st.journal_id.centralisation:
- c = context.copy()
- c['journal_id'] = st.journal_id.id
- c['period_id'] = st.period_id.id
- fields = ['move_id','name','date','partner_id','account_id','credit','debit']
- default = self.pool.get('account.move.line').default_get(cr, uid, fields, context=c)
- default.update({
- 'statement_id': st.id,
- 'journal_id': st.journal_id.id,
- 'period_id': st.period_id.id,
- })
- self.pool.get('account.move.line').create(cr, uid, default, context=context)
- done.append(st.id)
- self.write(cr, uid, done, {'state':'confirm'}, context=context)
- return True
- def button_cancel(self, cr, uid, ids, context={}):
- done = []
- for st in self.browse(cr, uid, ids, context):
- if st.state=='draft':
- continue
- ids = [x.move_id.id for x in st.move_line_ids]
- self.pool.get('account.move').unlink(cr, uid, ids, context)
- done.append(st.id)
- self.write(cr, uid, done, {'state':'draft'}, context=context)
- return True
- def onchange_journal_id(self, cr, uid, id, journal_id, context={}):
- if not journal_id:
- return {}
- cr.execute('select balance_end_real from account_bank_statement where journal_id=%d order by date desc limit 1', (journal_id,))
- res = cr.fetchone()
- if res:
- return {'value': {'balance_start': res[0] or 0.0}}
- return {}
-account_bank_statement()
-
-class account_bank_statement_line(osv.osv):
- def onchange_partner_id(self, cr, uid, id, partner_id, type, context={}):
- if not partner_id:
- return {}
- part = self.pool.get('res.partner').browse(cr, uid, partner_id, context)
- if type=='supplier':
- account_id = part.property_account_payable[0]
- else:
- account_id = part.property_account_receivable[0]
- cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, account_id))
- balance = cr.fetchone()[0] or 0.0
- val = {'amount': balance, 'account_id':account_id}
- return {'value':val}
- _order = "date,name desc"
- _name = "account.bank.statement.line"
- _description = "Bank Statement Line"
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'date': fields.date('Date'),
- 'amount': fields.float('Amount'),
- 'type': fields.selection([('supplier','Supplier'),('customer','Customer'),('general','General')], 'Type', required=True),
- 'partner_id': fields.many2one('res.partner', 'Partner'),
- 'account_id': fields.many2one('account.account','Account', required=True),
- 'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True),
- }
- _defaults = {
- 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'),
- 'date': lambda *a: time.strftime('%Y-%m-%d'),
- 'type': lambda *a: 'general',
- }
-account_bank_statement_line()
#----------------------------------------------------------
@@ -903,439 +780,6 @@ class account_tax_code(osv.osv):
}
account_tax_code()
-class account_move_line(osv.osv):
- _name = "account.move.line"
- _description = "Entry lines"
-
- def default_get(self, cr, uid, fields, context={}):
- data = self._default_get(cr, uid, fields, context)
- for f in data.keys():
- if f not in fields:
- del data[f]
- return data
-
- def _default_get(self, cr, uid, fields, context={}):
- # Compute simple values
- data = super(account_move_line, self).default_get(cr, uid, fields, context)
-
- # Compute the current move
- move_id = False
- partner_id = False
- statement_acc_id = False
- if context.get('journal_id',False) and context.get('period_id',False):
- cr.execute('select move_id \
- from \
- account_move_line \
- where \
- journal_id=%d and period_id=%d and create_uid=%d and state=%s \
- order by id desc limit 1', (context['journal_id'], context['period_id'], uid, 'draft'))
- res = cr.fetchone()
- move_id = (res and res[0]) or False
- cr.execute('select date \
- from \
- account_move_line \
- where \
- journal_id=%d and period_id=%d and create_uid=%d order by id desc', (context['journal_id'], context['period_id'], uid))
- res = cr.fetchone()
- data['date'] = res and res[0] or time.strftime('%Y-%m-%d')
- cr.execute('select statement_id, account_id \
- from \
- account_move_line \
- where \
- journal_id=%d and period_id=%d and statement_id is not null and create_uid=%d order by id desc', (context['journal_id'], context['period_id'], uid))
- res = cr.fetchone()
- statement_id = res and res[0] or False
- statement_acc_id = res and res[1]
-
- if not move_id:
- return data
-
- data['move_id'] = move_id
-
- total = 0
- taxes = {}
- move = self.pool.get('account.move').browse(cr, uid, move_id, context)
- for l in move.line_id:
- partner_id = partner_id or l.partner_id.id
- total += (l.debit - l.credit)
- for tax in l.account_id.tax_ids:
- acc = (l.debit >0) and tax.account_paid_id.id or tax.account_collected_id.id
- taxes.setdefault((acc,tax.tax_code_id.id), False)
- taxes[(l.account_id.id,l.tax_code_id.id)] = True
- data.setdefault('name', l.name)
-
- data['partner_id'] = partner_id
-
- print taxes
- for t in taxes:
- if not taxes[t] and t[0]:
- s=0
- for l in move.line_id:
- for tax in l.account_id.tax_ids:
- taxes = self.pool.get('account.tax').compute(cr, uid, [tax.id], l.debit or l.credit, 1, False)
- key = (l.debit and 'account_paid_id') or 'account_collected_id'
- for t2 in taxes:
- if (t2[key] == t[0]) and (tax.tax_code_id.id==t[1]):
- if l.debit:
- s += t2['amount']
- else:
- s -= t2['amount']
- data['debit'] = s>0 and s or 0.0
- data['credit'] = s<0 and -s or 0.0
-
- data['tax_code_id'] = t[1]
-
- data['account_id'] = t[0]
-
- #
- # Compute line for tax T
- #
- return data
-
- #
- # Compute latest line
- #
- data['credit'] = total>0 and total
- data['debit'] = total<0 and -total
- if total>=0:
- data['account_id'] = move.journal_id.default_credit_account_id.id or False
- else:
- data['account_id'] = move.journal_id.default_debit_account_id.id or False
- if data['account_id']:
- account = self.pool.get('account.account').browse(cr, uid, data['account_id'])
- data['tax_code_id'] = self._default_get_tax(cr, uid, account )
- return data
-
- def _default_get_tax(self, cr, uid, account, debit=0, credit=0, context={}):
- if account.tax_ids:
- return account.tax_ids[0].base_code_id.id
- return False
-
- def _on_create_write(self, cr, uid, id, context={}):
- ml = self.browse(cr, uid, id, context)
- return map(lambda x: x.id, ml.move_id.line_id)
-
- def _balance(self, cr, uid, ids, prop, unknow_none, unknow_dict):
- res={}
- # TODO group the foreach in sql
- for id in ids:
- cr.execute('SELECT date,account_id FROM account_move_line WHERE id=%d', (id,))
- dt, acc = cr.fetchone()
- cr.execute('SELECT SUM(debit-credit) FROM account_move_line WHERE account_id=%d AND (date<%s OR (date=%s AND id<=%d)) and active', (acc,dt,dt,id))
- res[id] = cr.fetchone()[0]
- return res
-
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'quantity': fields.float('Quantity', digits=(16,2), help="The optionnal quantity expressed by this line, eg: number of product sold. The quantity is not a legal requirement but is very usefull for some reports."),
- 'debit': fields.float('Debit', digits=(16,2), states={'reconciled':[('readonly',True)]}),
- 'credit': fields.float('Credit', digits=(16,2), states={'reconciled':[('readonly',True)]}),
- 'account_id': fields.many2one('account.account', 'Account', required=True, ondelete="cascade", states={'reconciled':[('readonly',True)]}, domain=[('type','<>','view')]),
-
- 'move_id': fields.many2one('account.move', 'Entry', required=True, ondelete="cascade", states={'reconciled':[('readonly',True)]}, help="The entry of this entry line.", select=True),
-
- 'ref': fields.char('Ref.', size=32),
- 'statement_id': fields.many2one('account.bank.statement', 'Statement', help="The bank statement used for bank reconciliation", select=True),
- 'reconcile_id': fields.many2one('account.move.reconcile', 'Reconcile', readonly=True, ondelete='set null', select=True),
- 'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optionnal other currency if it is a multi-currency entry."),
- 'currency_id': fields.many2one('res.currency', 'Currency', help="The optionnal other currency if it is a multi-currency entry."),
-
- 'period_id': fields.many2one('account.period', 'Period', required=True),
- 'journal_id': fields.many2one('account.journal', 'Journal', required=True, relate=True),
- 'blocked': fields.boolean('Litigation', help="You can check this box to mark the entry line as a litigation with the associated partner"),
-
- 'partner_id': fields.many2one('res.partner', 'Partner Ref.', states={'reconciled':[('readonly',True)]}),
- 'date_maturity': fields.date('Maturity date', states={'reconciled':[('readonly',True)]}, help="This field is used for payable and receivable entries. You can put the limit date for the payment of this entry line."),
- 'date': fields.date('Effective date', required=True),
- 'date_created': fields.date('Creation date'),
- 'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'),
- 'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation')], 'Centralisation', size=6),
- 'balance': fields.function(_balance, method=True, string='Balance'),
- 'active': fields.boolean('Active'),
- 'state': fields.selection([('draft','Draft'), ('valid','Valid'), ('reconciled','Reconciled')], 'State', readonly=True),
- 'tax_code_id': fields.many2one('account.tax.code', 'Tax Account'),
- 'tax_amount': fields.float('Tax/Base Amount', digits=(16,2), select=True),
- }
- _defaults = {
- 'blocked': lambda *a: False,
- 'active': lambda *a: True,
- 'centralisation': lambda *a: 'normal',
- 'date_created': lambda *a: time.strftime('%Y-%m-%d'),
- 'state': lambda *a: 'draft',
- 'journal_id': lambda self, cr, uid, c: c.get('journal_id', False),
- 'period_id': lambda self, cr, uid, c: c.get('period_id', False),
- }
- _order = "date desc,id desc"
- _sql_constraints = [
- ('credit_debit1', 'CHECK (credit*debit=0)', 'Wrong credit or debit value in accounting entry !'),
- ('credit_debit2', 'CHECK (credit+debit>=0)', 'Wrong credit or debit value in accounting entry !'),
- ]
- def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, journal=False):
- if (not partner_id) or account_id:
- return {}
- part = self.pool.get('res.partner').browse(cr, uid, partner_id)
- id1 = part.property_account_payable[0]
- id2 = part.property_account_receivable[0]
- cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, id2))
- balance = cr.fetchone()[0] or 0.0
- val = {}
- if (not debit) and (not credit):
- if abs(balance)>0.01:
- val['credit'] = ((balance>0) and balance) or 0
- val['debit'] = ((balance<0) and -balance) or 0
- val['account_id'] = id2
- else:
- cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, id1))
- balance = cr.fetchone()[0] or 0.0
- val['credit'] = ((balance>0) and balance) or 0
- val['debit'] = ((balance<0) and -balance) or 0
- val['account_id'] = id1
- else:
- val['account_id'] = (debit>0) and id2 or id1
- if journal:
- jt = self.pool.get('account.journal').browse(cr, uid, journal).type
- if jt=='sale':
- val['account_id'] = id2
- elif jt=='purchase':
- val['account_id'] = id1
- return {'value':val}
-
- #
- # type: the type if reconciliation (no logic behind this field, for infà)
- #
- # writeoff; entry generated for the difference between the lines
- #
-
- def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context={}):
- id_set = ','.join(map(str, ids))
- lines = self.read(cr, uid, ids, context=context)
- unrec_lines = filter(lambda x: not x['reconcile_id'], lines)
- credit = debit = 0
- account_id = False
- partner_id = False
- for line in unrec_lines:
- credit += line['credit']
- debit += line['debit']
- account_id = line['account_id'][0]
- partner_id = (line['partner_id'] and line['partner_id'][0]) or False
- writeoff = debit - credit
- date = time.strftime('%Y-%m-%d')
-
- cr.execute('SELECT account_id,reconcile_id FROM account_move_line WHERE id IN ('+id_set+') GROUP BY account_id,reconcile_id')
- r = cr.fetchall()
-#TODO: move this check to a constraint in the account_move_reconcile object
- if len(r) != 1:
- raise Exception('Entries are not of the same account or already reconciled ! ')
- if r[0][1] != None:
- raise Exception('Some entries are already reconciled !')
- if writeoff != 0:
- if not writeoff_acc_id:
- raise osv.except_osv('Warning', 'You have to provide an account for the write off entry !')
- if writeoff > 0:
- debit = writeoff
- credit = 0.0
- self_credit = writeoff
- self_debit = 0.0
- else:
- debit = 0.0
- credit = -writeoff
- self_credit = 0.0
- self_debit = -writeoff
-
- writeoff_lines = [
- (0, 0, {'name':'Write-Off', 'debit':self_debit, 'credit':self_credit, 'account_id':account_id, 'date':date, 'partner_id':partner_id}),
- (0, 0, {'name':'Write-Off', 'debit':debit, 'credit':credit, 'account_id':writeoff_acc_id, 'date':date, 'partner_id':partner_id})
- ]
-
- name = 'Write-Off'
- if writeoff_journal_id:
- journal = self.pool.get('account.journal').browse(cr, uid, writeoff_journal_id)
- if journal.sequence_id:
- name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
-
- writeoff_move_id = self.pool.get('account.move').create(cr, uid, {
- 'name': name,
- 'period_id': writeoff_period_id,
- 'journal_id': writeoff_journal_id,
-
- 'state': 'draft',
- 'line_id': writeoff_lines
- })
-
- writeoff_line_ids = self.search(cr, uid, [('move_id', '=', writeoff_move_id), ('account_id', '=', account_id)])
- ids += writeoff_line_ids
-
- self.write(cr, uid, ids, {'state': 'reconciled'}, update_check=False)
- r_id = self.pool.get('account.move.reconcile').create(cr, uid, {
- 'name': date,
- 'type': type,
- 'line_id': map(lambda x: (4,x,False), ids)
- })
- # the id of the move.reconcile is written in the move.line (self) by the create method above
- # because of the way the line_id are defined: (4, x, False)
- wf_service = netsvc.LocalService("workflow")
- for id in ids:
- wf_service.trg_trigger(uid, 'account.move.line', id, cr)
- return r_id
-
- def view_header_get(self, cr, user, view_id, view_type, context):
- if (not context.get('journal_id', False)) or (not context.get('period_id', False)):
- return False
- cr.execute('select code from account_journal where id=%d', (context['journal_id'],))
- j = cr.fetchone()[0] or ''
- cr.execute('select code from account_period where id=%d', (context['period_id'],))
- p = cr.fetchone()[0] or ''
- if j or p:
- return j+':'+p
- return 'Journal'
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False):
- result = super(osv.osv, self).fields_view_get(cr, uid, view_id,view_type,context)
- if view_type=='tree' and 'journal_id' in context:
- title = self.view_header_get(cr, uid, view_id, view_type, context)
- journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id'])
-
- # if the journal view has a state field, color lines depending on
- # its value
- state = ''
- for field in journal.view_id.columns_id:
- if field.field=='state':
- state = ' colors="red:state==\'draft\'"'
-
- #xml = '''\n\n\t''' % (title, state)
- xml = '''\n\n\t''' % (title, state)
- fields = []
-
- widths = {
- 'ref': 50,
- 'statement_id': 50,
- 'state': 60,
- 'tax_code_id': 50,
- 'move_id': 40,
- }
- for field in journal.view_id.columns_id:
- fields.append(field.field)
- attrs = []
- if field.readonly:
- attrs.append('readonly="1"')
- if field.required:
- attrs.append('required="1"')
- else:
- attrs.append('required="0"')
- if field.field == 'partner_id':
- attrs.append('on_change="onchange_partner_id(move_id,partner_id,account_id,debit,credit,((\'journal_id\' in context) and context[\'journal_id\']) or {})"')
- if field.field in widths:
- attrs.append('width="'+str(widths[field.field])+'"')
- xml += '''\n''' % (field.field,' '.join(attrs))
-
- xml += ''''''
- result['arch'] = xml
- result['fields'] = self.fields_get(cr, uid, fields, context)
- return result
-
- def unlink(self, cr, uid, ids, context={}, check=True):
- self._update_check(cr, uid, ids, context)
- for line in self.browse(cr, uid, ids, context):
- context['journal_id']=line.journal_id.id
- context['period_id']=line.period_id.id
- result = super(account_move_line, self).unlink(cr, uid, [line.id], context=context)
- if check:
- self.pool.get('account.move').validate(cr, uid, [line.move_id.id], context=context)
- return result
-
- #
- # TO VERIFY: check if try to write journal of only one line ???
- #
- def write(self, cr, uid, ids, vals, context={}, check=True, update_check=True):
- if update_check:
- self._update_check(cr, uid, ids, context)
- result = super(osv.osv, self).write(cr, uid, ids, vals, context)
- if check:
- done = []
- for line in self.browse(cr, uid, ids):
- if line.move_id.id not in done:
- done.append(line.move_id.id)
- self.pool.get('account.move').validate(cr, uid, [line.move_id.id], context)
- return result
-
- def _update_journal_check(self, cr, uid, journal_id, period_id, context={}):
- cr.execute('select state from account_journal_period where journal_id=%d and period_id=%d', (journal_id, period_id))
- result = cr.fetchall()
- for (state,) in result:
- if state=='done':
- raise osv.except_osv('Error !', 'You can not add/modify entries in a closed journal.')
- if not result:
- journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context)
- period = self.pool.get('account.period').browse(cr, uid, period_id, context)
- self.pool.get('account.journal.period').create(cr, uid, {
- 'name': (journal.code or journal.name)+':'+(period.name or ''),
- 'journal_id': journal.id,
- 'period_id': period.id
- })
- return True
-
- def _update_check(self, cr, uid, ids, context={}):
- done = {}
- for line in self.browse(cr, uid, ids, context):
- if line.move_id.state<>'draft':
- raise osv.except_osv('Error !', 'You can not modify or delete a confirmed entry !')
- if line.reconcile_id:
- raise osv.except_osv('Error !', 'You can not modify or delete a reconciled entry !')
- t = (line.journal_id.id, line.period_id.id)
- if t not in done:
- self._update_journal_check(cr, uid, line.journal_id.id, line.period_id.id, context)
- done[t] = True
- return True
-
- def create(self, cr, uid, vals, context={}, check=True):
- if 'journal_id' in vals and 'journal_id' not in context:
- context['journal_id'] = vals['journal_id']
- if 'period_id' in vals and 'period_id' not in context:
- context['period_id'] = vals['period_id']
- if 'journal_id' not in context and 'move_id' in vals:
- m = self.pool.get('account.move').browse(cr, uid, vals['move_id'])
- context['journal_id'] = m.journal_id.id
- context['period_id'] = m.period_id.id
- self._update_journal_check(cr, uid, context['journal_id'], context['period_id'], context)
- move_id = vals.get('move_id', False)
- journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id'])
- if not move_id:
- if journal.centralisation:
- # use the first move ever created for this journal and period
- cr.execute('select id from account_move where journal_id=%d and period_id=%d order by id limit 1', (context['journal_id'],context['period_id']))
- res = cr.fetchone()
- if res:
- vals['move_id'] = res[0]
-
- if not vals.get('move_id', False):
- if journal.sequence_id:
- name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
- v = {
- 'name': name,
- 'period_id': context['period_id'],
- 'journal_id': context['journal_id']
- }
- move_id = self.pool.get('account.move').create(cr, uid, v, context)
- vals['move_id'] = move_id
- else:
- raise osv.except_osv('No piece number !', 'Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')
-
- if ('account_id' in vals) and journal.type_control_ids:
- type = self.pool.get('account.account').browse(cr, uid, vals['account_id']).type
- ok = False
- for t in journal.type_control_ids:
- if type==t.code:
- ok = True
- break
- if not ok:
- raise osv.except_osv('Bad account !', 'You can not use this general account in this journal !')
-
- result = super(osv.osv, self).create(cr, uid, vals, context)
- if check:
- self.pool.get('account.move').validate(cr, uid, [vals['move_id']], context)
- return result
-account_move_line()
-
class account_tax(osv.osv):
"""
A tax object.
diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py
new file mode 100644
index 00000000000..77e605c1d46
--- /dev/null
+++ b/addons/account/account_analytic_line.py
@@ -0,0 +1,130 @@
+
+##############################################################################
+#
+# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#
+# $Id$
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import time
+
+from osv import fields
+from osv import osv
+
+class account_analytic_line(osv.osv):
+ _name = 'account.analytic.line'
+ _columns = {
+ 'name' : fields.char('Description', size=128, required=True),
+ 'date' : fields.date('Date', required=True),
+ 'amount' : fields.float('Amount', required=True),
+ 'unit_amount' : fields.float('Quantity'),
+ 'product_uom_id' : fields.many2one('product.uom', 'UoM'),
+ 'product_id' : fields.many2one('product.product', 'Product'),
+ 'account_id' : fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='cascade', select=True),
+ 'general_account_id' : fields.many2one('account.account', 'General account', required=True, ondelete='cascade'),
+ 'move_id' : fields.many2one('account.move.line', 'General entry', ondelete='cascade', select=True),
+ 'journal_id' : fields.many2one('account.analytic.journal', 'Analytic journal', required=True, ondelete='cascade', select=True),
+ 'code' : fields.char('Code', size=8),
+ 'user_id' : fields.many2one('res.users', 'User',),
+ }
+
+ _defaults = {
+ 'date': lambda *a: time.strftime('%Y-%m-%d'),
+ }
+ _order = 'date'
+
+ def on_change_unit_amount(self, cr, uid, id, prod_id, unit_amount, unit=False, context={}):
+ if unit_amount and prod_id:
+ rate = 1
+ if unit:
+ uom_id = self.pool.get('product.uom')
+ hunit = uom_id.browse(cr, uid, unit)
+ rate = hunit.factor
+ uom_id = self.pool.get('product.product')
+ prod = uom_id.browse(cr, uid, prod_id)
+ a = prod.product_tmpl_id.property_account_expense
+ if not a:
+ a = prod.categ_id.property_account_expense_categ
+ return {'value' : {'amount' : -round(unit_amount * prod.standard_price * rate,2), 'general_account_id':a[0]}}
+ return {}
+
+account_analytic_line()
+
+
+class timesheet_invoice(osv.osv):
+ _name = "report.hr.timesheet.invoice.journal"
+ _description = "Analytic account costs and revenues"
+ _auto = False
+ _columns = {
+ 'name': fields.date('Month', readonly=True),
+ 'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True, relate=True, select=True),
+ 'journal_id': fields.many2one('account.analytic.journal', 'Journal', readonly=True),
+ 'quantity': fields.float('Quantities', readonly=True),
+ 'cost': fields.float('Credit', readonly=True),
+ 'revenue': fields.float('Debit', readonly=True)
+ }
+ _order = 'name desc, account_id'
+ def init(self, cr):
+ #cr.execute("""
+ #create or replace view report_hr_timesheet_invoice_journal as (
+ # select
+ # min(l.id) as id,
+ # substring(l.create_date for 7)||'-01' as name,
+ # sum(greatest(-l.amount,0)) as cost,
+ # sum(greatest(l.amount,0)) as revenue,
+ # sum(l.unit_amount*u.factor) as quantity,
+ # journal_id,
+ # account_id
+ # from account_analytic_line l
+ # left join product_uom u on (u.id=l.product_uom_id)
+ # group by
+ # substring(l.create_date for 7),
+ # journal_id,
+ # account_id
+ #)""")
+ cr.execute("""
+ create or replace view report_hr_timesheet_invoice_journal as (
+ select
+ min(l.id) as id,
+ substring(l.create_date for 7)||'-01' as name,
+ sum(
+ CASE WHEN -l.amount>0 THEN 0 ELSE -l.amount
+ END
+ ) as cost,
+ sum(
+ CASE WHEN l.amount>0 THEN l.amount ELSE 0
+ END
+ ) as revenue,
+ sum(l.unit_amount*u.factor) as quantity,
+ journal_id,
+ account_id
+ from account_analytic_line l
+ left join product_uom u on (u.id=l.product_uom_id)
+ group by
+ substring(l.create_date for 7),
+ journal_id,
+ account_id
+ )""")
+timesheet_invoice()
diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py
new file mode 100644
index 00000000000..ba6e4b231b8
--- /dev/null
+++ b/addons/account/account_bank_statement.py
@@ -0,0 +1,192 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#
+# $Id: account.py 1005 2005-07-25 08:41:42Z nicoe $
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+import time
+import netsvc
+from osv import fields, osv
+
+from tools.misc import currency
+
+import mx.DateTime
+from mx.DateTime import RelativeDateTime, now, DateTime, localtime
+
+#
+# use a sequence for names ?
+#
+class account_bank_statement(osv.osv):
+ def _default_journal_id(self, cr, uid, context={}):
+ if context.get('journal_id', False):
+ return context['journal_id']
+ return False
+
+ def _default_balance_start(self, cr, uid, context={}):
+ cr.execute('select id from account_bank_statement where journal_id=%d order by date desc limit 1', (1,))
+ res = cr.fetchone()
+ if res:
+ return self.browse(cr, uid, [res[0]], context)[0].balance_end
+ return 0.0
+
+ def _end_balance(self, cr, uid, ids, prop, unknow_none, unknow_dict):
+ res = {}
+ statements = self.browse(cr, uid, ids)
+ for statement in statements:
+ res[statement.id] = statement.balance_start
+ for line in statement.line_ids:
+ res[statement.id] += line.amount
+ for r in res:
+ res[r] = round(res[r], 2)
+ return res
+
+ def _get_period(self, cr, uid, context={}):
+ periods = self.pool.get('account.period').find(cr, uid)
+ if periods:
+ return periods[0]
+ else:
+ return False
+
+ _order = "date desc"
+ _name = "account.bank.statement"
+ _description = "Bank Statement"
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'date': fields.date('Date', required=True, states={'confirm':[('readonly',True)]}),
+ 'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'confirm':[('readonly',True)]}, domain=[('type','=','cash')], relate=True),
+ 'period_id': fields.many2one('account.period', 'Period', required=True, states={'confirm':[('readonly',True)]}),
+ 'balance_start': fields.float('Starting Balance', digits=(16,2), states={'confirm':[('readonly',True)]}),
+ 'balance_end_real': fields.float('Ending Balance', digits=(16,2), states={'confirm':[('readonly',True)]}),
+ 'balance_end': fields.function(_end_balance, method=True, string='Balance'),
+ 'line_ids': fields.one2many('account.bank.statement.line', 'statement_id', 'Statement lines', states={'confirm':[('readonly',True)]}),
+ 'move_line_ids': fields.one2many('account.move.line', 'statement_id', 'Entry lines', states={'confirm':[('readonly',True)]}),
+ 'state': fields.selection([('draft','Draft'),('confirm','Confirm')], 'State', required=True, states={'confirm':[('readonly',True)]}, readonly="1"),
+ }
+
+ _defaults = {
+ 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement'),
+ 'date': lambda *a: time.strftime('%Y-%m-%d'),
+ 'state': lambda *a: 'draft',
+ 'balance_start': _default_balance_start,
+ 'journal_id': _default_journal_id,
+ 'period_id': _get_period,
+ }
+ def button_confirm(self, cr, uid, ids, context={}):
+ done = []
+ for st in self.browse(cr, uid, ids, context):
+ if not st.state=='draft':
+ continue
+ if not (abs(st.balance_end - st.balance_end_real) < 0.0001):
+ raise osv.except_osv('Error !', 'The statement balance is incorrect !\nCheck that the ending balance equals the computed one.')
+ if (not st.journal_id.default_credit_account_id) or (not st.journal_id.default_debit_account_id):
+ raise osv.except_osv('Configration Error !', 'Please verify that an account is defined in the journal.')
+ for move in st.line_ids:
+ if not move.amount:
+ continue
+ self.pool.get('account.move.line').create(cr, uid, {
+ 'name': move.name,
+ 'date': move.date,
+ 'partner_id': ((move.partner_id) and move.partner_id.id) or False,
+ 'account_id': (move.account_id) and move.account_id.id,
+ 'credit': ((move.amount>0) and move.amount) or 0.0,
+ 'debit': ((move.amount<0) and -move.amount) or 0.0,
+ 'statement_id': st.id,
+ 'journal_id': st.journal_id.id,
+ 'period_id': st.period_id.id,
+ }, context=context)
+ if not st.journal_id.centralisation:
+ c = context.copy()
+ c['journal_id'] = st.journal_id.id
+ c['period_id'] = st.period_id.id
+ fields = ['move_id','name','date','partner_id','account_id','credit','debit']
+ default = self.pool.get('account.move.line').default_get(cr, uid, fields, context=c)
+ default.update({
+ 'statement_id': st.id,
+ 'journal_id': st.journal_id.id,
+ 'period_id': st.period_id.id,
+ })
+ self.pool.get('account.move.line').create(cr, uid, default, context=context)
+ done.append(st.id)
+ self.write(cr, uid, done, {'state':'confirm'}, context=context)
+ return True
+ def button_cancel(self, cr, uid, ids, context={}):
+ done = []
+ for st in self.browse(cr, uid, ids, context):
+ if st.state=='draft':
+ continue
+ ids = [x.move_id.id for x in st.move_line_ids]
+ self.pool.get('account.move').unlink(cr, uid, ids, context)
+ done.append(st.id)
+ self.write(cr, uid, done, {'state':'draft'}, context=context)
+ return True
+ def onchange_journal_id(self, cr, uid, id, journal_id, context={}):
+ if not journal_id:
+ return {}
+ cr.execute('select balance_end_real from account_bank_statement where journal_id=%d order by date desc limit 1', (journal_id,))
+ res = cr.fetchone()
+ if res:
+ return {'value': {'balance_start': res[0] or 0.0}}
+ return {}
+account_bank_statement()
+
+class account_bank_statement_line(osv.osv):
+ def onchange_partner_id(self, cr, uid, id, partner_id, type, context={}):
+ if not partner_id:
+ return {}
+ part = self.pool.get('res.partner').browse(cr, uid, partner_id, context)
+ if type=='supplier':
+ account_id = part.property_account_payable[0]
+ else:
+ account_id = part.property_account_receivable[0]
+ cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, account_id))
+ balance = cr.fetchone()[0] or 0.0
+ val = {'amount': balance, 'account_id':account_id}
+ return {'value':val}
+ _order = "date,name desc"
+ _name = "account.bank.statement.line"
+ _description = "Bank Statement Line"
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'date': fields.date('Date'),
+ 'amount': fields.float('Amount'),
+ 'type': fields.selection([('supplier','Supplier'),('customer','Customer'),('general','General')], 'Type', required=True),
+ 'partner_id': fields.many2one('res.partner', 'Partner'),
+ 'account_id': fields.many2one('account.account','Account', required=True),
+ 'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True),
+ 'invoice_id': fields.many2one('account.invoice', 'Invoice', states={'confirm':[('readonly',True)]}),
+
+
+ }
+ _defaults = {
+ 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'),
+ 'date': lambda *a: time.strftime('%Y-%m-%d'),
+ 'type': lambda *a: 'general',
+ }
+account_bank_statement_line()
+
+
+
+
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index abd0c2b16ce..8e94e7de722 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -105,11 +105,13 @@
-
+
+
+
@@ -138,6 +140,7 @@
+
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
new file mode 100644
index 00000000000..3e053d7b1fe
--- /dev/null
+++ b/addons/account/account_move_line.py
@@ -0,0 +1,466 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#
+# $Id: account.py 1005 2005-07-25 08:41:42Z nicoe $
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+import time
+import netsvc
+from osv import fields, osv
+
+
+class account_move_line(osv.osv):
+ _name = "account.move.line"
+ _description = "Entry lines"
+
+ def default_get(self, cr, uid, fields, context={}):
+ data = self._default_get(cr, uid, fields, context)
+ for f in data.keys():
+ if f not in fields:
+ del data[f]
+ return data
+
+ def _default_get(self, cr, uid, fields, context={}):
+ # Compute simple values
+ data = super(account_move_line, self).default_get(cr, uid, fields, context)
+
+ # Compute the current move
+ move_id = False
+ partner_id = False
+ statement_acc_id = False
+ if context.get('journal_id',False) and context.get('period_id',False):
+ cr.execute('select move_id \
+ from \
+ account_move_line \
+ where \
+ journal_id=%d and period_id=%d and create_uid=%d and state=%s \
+ order by id desc limit 1', (context['journal_id'], context['period_id'], uid, 'draft'))
+ res = cr.fetchone()
+ move_id = (res and res[0]) or False
+ cr.execute('select date \
+ from \
+ account_move_line \
+ where \
+ journal_id=%d and period_id=%d and create_uid=%d order by id desc', (context['journal_id'], context['period_id'], uid))
+ res = cr.fetchone()
+ data['date'] = res and res[0] or time.strftime('%Y-%m-%d')
+ cr.execute('select statement_id, account_id \
+ from \
+ account_move_line \
+ where \
+ journal_id=%d and period_id=%d and statement_id is not null and create_uid=%d order by id desc', (context['journal_id'], context['period_id'], uid))
+ res = cr.fetchone()
+ statement_id = res and res[0] or False
+ statement_acc_id = res and res[1]
+
+ if not move_id:
+ return data
+
+ data['move_id'] = move_id
+
+ total = 0
+ taxes = {}
+ move = self.pool.get('account.move').browse(cr, uid, move_id, context)
+ for l in move.line_id:
+ partner_id = partner_id or l.partner_id.id
+ total += (l.debit - l.credit)
+ for tax in l.account_id.tax_ids:
+ acc = (l.debit >0) and tax.account_paid_id.id or tax.account_collected_id.id
+ taxes.setdefault((acc,tax.tax_code_id.id), False)
+ taxes[(l.account_id.id,l.tax_code_id.id)] = True
+ data.setdefault('name', l.name)
+
+ data['partner_id'] = partner_id
+
+ print taxes
+ for t in taxes:
+ if not taxes[t] and t[0]:
+ s=0
+ for l in move.line_id:
+ for tax in l.account_id.tax_ids:
+ taxes = self.pool.get('account.tax').compute(cr, uid, [tax.id], l.debit or l.credit, 1, False)
+ key = (l.debit and 'account_paid_id') or 'account_collected_id'
+ for t2 in taxes:
+ if (t2[key] == t[0]) and (tax.tax_code_id.id==t[1]):
+ if l.debit:
+ s += t2['amount']
+ else:
+ s -= t2['amount']
+ data['debit'] = s>0 and s or 0.0
+ data['credit'] = s<0 and -s or 0.0
+
+ data['tax_code_id'] = t[1]
+
+ data['account_id'] = t[0]
+
+ #
+ # Compute line for tax T
+ #
+ return data
+
+ #
+ # Compute latest line
+ #
+ data['credit'] = total>0 and total
+ data['debit'] = total<0 and -total
+ if total>=0:
+ data['account_id'] = move.journal_id.default_credit_account_id.id or False
+ else:
+ data['account_id'] = move.journal_id.default_debit_account_id.id or False
+ if data['account_id']:
+ account = self.pool.get('account.account').browse(cr, uid, data['account_id'])
+ data['tax_code_id'] = self._default_get_tax(cr, uid, account )
+ return data
+
+ def _default_get_tax(self, cr, uid, account, debit=0, credit=0, context={}):
+ if account.tax_ids:
+ return account.tax_ids[0].base_code_id.id
+ return False
+
+ def _on_create_write(self, cr, uid, id, context={}):
+ ml = self.browse(cr, uid, id, context)
+ return map(lambda x: x.id, ml.move_id.line_id)
+
+ def _balance(self, cr, uid, ids, prop, unknow_none, unknow_dict):
+ res={}
+ # TODO group the foreach in sql
+ for id in ids:
+ cr.execute('SELECT date,account_id FROM account_move_line WHERE id=%d', (id,))
+ dt, acc = cr.fetchone()
+ cr.execute('SELECT SUM(debit-credit) FROM account_move_line WHERE account_id=%d AND (date<%s OR (date=%s AND id<=%d)) and active', (acc,dt,dt,id))
+ res[id] = cr.fetchone()[0]
+ return res
+
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'quantity': fields.float('Quantity', digits=(16,2), help="The optionnal quantity expressed by this line, eg: number of product sold. The quantity is not a legal requirement but is very usefull for some reports."),
+ 'debit': fields.float('Debit', digits=(16,2), states={'reconciled':[('readonly',True)]}),
+ 'credit': fields.float('Credit', digits=(16,2), states={'reconciled':[('readonly',True)]}),
+ 'account_id': fields.many2one('account.account', 'Account', required=True, ondelete="cascade", states={'reconciled':[('readonly',True)]}, domain=[('type','<>','view')]),
+
+ 'move_id': fields.many2one('account.move', 'Entry', required=True, ondelete="cascade", states={'reconciled':[('readonly',True)]}, help="The entry of this entry line.", select=True),
+
+ 'ref': fields.char('Ref.', size=32),
+ 'statement_id': fields.many2one('account.bank.statement', 'Statement', help="The bank statement used for bank reconciliation", select=True),
+ 'reconcile_id': fields.many2one('account.move.reconcile', 'Reconcile', readonly=True, ondelete='set null', select=True),
+ 'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optionnal other currency if it is a multi-currency entry."),
+ 'currency_id': fields.many2one('res.currency', 'Currency', help="The optionnal other currency if it is a multi-currency entry."),
+
+ 'period_id': fields.many2one('account.period', 'Period', required=True),
+ 'journal_id': fields.many2one('account.journal', 'Journal', required=True, relate=True),
+ 'blocked': fields.boolean('Litigation', help="You can check this box to mark the entry line as a litigation with the associated partner"),
+
+ 'partner_id': fields.many2one('res.partner', 'Partner Ref.', states={'reconciled':[('readonly',True)]}),
+ 'date_maturity': fields.date('Maturity date', states={'reconciled':[('readonly',True)]}, help="This field is used for payable and receivable entries. You can put the limit date for the payment of this entry line."),
+ 'date': fields.date('Effective date', required=True),
+ 'date_created': fields.date('Creation date'),
+ 'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'),
+ 'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation')], 'Centralisation', size=6),
+ 'balance': fields.function(_balance, method=True, string='Balance'),
+ 'active': fields.boolean('Active'),
+ 'state': fields.selection([('draft','Draft'), ('valid','Valid'), ('reconciled','Reconciled')], 'State', readonly=True),
+ 'tax_code_id': fields.many2one('account.tax.code', 'Tax Account'),
+ 'tax_amount': fields.float('Tax/Base Amount', digits=(16,2), select=True),
+ }
+ _defaults = {
+ 'blocked': lambda *a: False,
+ 'active': lambda *a: True,
+ 'centralisation': lambda *a: 'normal',
+ 'date_created': lambda *a: time.strftime('%Y-%m-%d'),
+ 'state': lambda *a: 'draft',
+ 'journal_id': lambda self, cr, uid, c: c.get('journal_id', False),
+ 'period_id': lambda self, cr, uid, c: c.get('period_id', False),
+ }
+ _order = "date desc,id desc"
+ _sql_constraints = [
+ ('credit_debit1', 'CHECK (credit*debit=0)', 'Wrong credit or debit value in accounting entry !'),
+ ('credit_debit2', 'CHECK (credit+debit>=0)', 'Wrong credit or debit value in accounting entry !'),
+ ]
+ def onchange_partner_id(self, cr, uid, ids, move_id, partner_id, account_id=None, debit=0, credit=0, journal=False):
+ if (not partner_id) or account_id:
+ return {}
+ part = self.pool.get('res.partner').browse(cr, uid, partner_id)
+ id1 = part.property_account_payable[0]
+ id2 = part.property_account_receivable[0]
+ cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, id2))
+ balance = cr.fetchone()[0] or 0.0
+ val = {}
+ if (not debit) and (not credit):
+ if abs(balance)>0.01:
+ val['credit'] = ((balance>0) and balance) or 0
+ val['debit'] = ((balance<0) and -balance) or 0
+ val['account_id'] = id2
+ else:
+ cr.execute('select sum(debit-credit) from account_move_line where (reconcile_id is null) and partner_id=%d and account_id=%d', (partner_id, id1))
+ balance = cr.fetchone()[0] or 0.0
+ val['credit'] = ((balance>0) and balance) or 0
+ val['debit'] = ((balance<0) and -balance) or 0
+ val['account_id'] = id1
+ else:
+ val['account_id'] = (debit>0) and id2 or id1
+ if journal:
+ jt = self.pool.get('account.journal').browse(cr, uid, journal).type
+ if jt=='sale':
+ val['account_id'] = id2
+ elif jt=='purchase':
+ val['account_id'] = id1
+ return {'value':val}
+
+ #
+ # type: the type if reconciliation (no logic behind this field, for infà)
+ #
+ # writeoff; entry generated for the difference between the lines
+ #
+
+ def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context={}):
+ id_set = ','.join(map(str, ids))
+ lines = self.read(cr, uid, ids, context=context)
+ unrec_lines = filter(lambda x: not x['reconcile_id'], lines)
+ credit = debit = 0
+ account_id = False
+ partner_id = False
+ for line in unrec_lines:
+ credit += line['credit']
+ debit += line['debit']
+ account_id = line['account_id'][0]
+ partner_id = (line['partner_id'] and line['partner_id'][0]) or False
+ writeoff = debit - credit
+ date = time.strftime('%Y-%m-%d')
+
+ cr.execute('SELECT account_id,reconcile_id FROM account_move_line WHERE id IN ('+id_set+') GROUP BY account_id,reconcile_id')
+ r = cr.fetchall()
+#TODO: move this check to a constraint in the account_move_reconcile object
+ if len(r) != 1:
+ raise Exception('Entries are not of the same account or already reconciled ! ')
+ if r[0][1] != None:
+ raise Exception('Some entries are already reconciled !')
+ if writeoff != 0:
+ if not writeoff_acc_id:
+ raise osv.except_osv('Warning', 'You have to provide an account for the write off entry !')
+ if writeoff > 0:
+ debit = writeoff
+ credit = 0.0
+ self_credit = writeoff
+ self_debit = 0.0
+ else:
+ debit = 0.0
+ credit = -writeoff
+ self_credit = 0.0
+ self_debit = -writeoff
+
+ writeoff_lines = [
+ (0, 0, {'name':'Write-Off', 'debit':self_debit, 'credit':self_credit, 'account_id':account_id, 'date':date, 'partner_id':partner_id}),
+ (0, 0, {'name':'Write-Off', 'debit':debit, 'credit':credit, 'account_id':writeoff_acc_id, 'date':date, 'partner_id':partner_id})
+ ]
+
+ name = 'Write-Off'
+ if writeoff_journal_id:
+ journal = self.pool.get('account.journal').browse(cr, uid, writeoff_journal_id)
+ if journal.sequence_id:
+ name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
+
+ writeoff_move_id = self.pool.get('account.move').create(cr, uid, {
+ 'name': name,
+ 'period_id': writeoff_period_id,
+ 'journal_id': writeoff_journal_id,
+
+ 'state': 'draft',
+ 'line_id': writeoff_lines
+ })
+
+ writeoff_line_ids = self.search(cr, uid, [('move_id', '=', writeoff_move_id), ('account_id', '=', account_id)])
+ ids += writeoff_line_ids
+
+ self.write(cr, uid, ids, {'state': 'reconciled'}, update_check=False)
+ r_id = self.pool.get('account.move.reconcile').create(cr, uid, {
+ 'name': date,
+ 'type': type,
+ 'line_id': map(lambda x: (4,x,False), ids)
+ })
+ # the id of the move.reconcile is written in the move.line (self) by the create method above
+ # because of the way the line_id are defined: (4, x, False)
+ wf_service = netsvc.LocalService("workflow")
+ for id in ids:
+ wf_service.trg_trigger(uid, 'account.move.line', id, cr)
+ return r_id
+
+ def view_header_get(self, cr, user, view_id, view_type, context):
+ if (not context.get('journal_id', False)) or (not context.get('period_id', False)):
+ return False
+ cr.execute('select code from account_journal where id=%d', (context['journal_id'],))
+ j = cr.fetchone()[0] or ''
+ cr.execute('select code from account_period where id=%d', (context['period_id'],))
+ p = cr.fetchone()[0] or ''
+ if j or p:
+ return j+':'+p
+ return 'Journal'
+
+ def fields_view_get(self, cr, uid, view_id=None, view_type='form', context={}, toolbar=False):
+ result = super(osv.osv, self).fields_view_get(cr, uid, view_id,view_type,context)
+ if view_type=='tree' and 'journal_id' in context:
+ title = self.view_header_get(cr, uid, view_id, view_type, context)
+ journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id'])
+
+ # if the journal view has a state field, color lines depending on
+ # its value
+ state = ''
+ for field in journal.view_id.columns_id:
+ if field.field=='state':
+ state = ' colors="red:state==\'draft\'"'
+
+ #xml = '''\n\n\t''' % (title, state)
+ xml = '''\n\n\t''' % (title, state)
+ fields = []
+
+ widths = {
+ 'ref': 50,
+ 'statement_id': 50,
+ 'state': 60,
+ 'tax_code_id': 50,
+ 'move_id': 40,
+ }
+ for field in journal.view_id.columns_id:
+ fields.append(field.field)
+ attrs = []
+ if field.readonly:
+ attrs.append('readonly="1"')
+ if field.required:
+ attrs.append('required="1"')
+ else:
+ attrs.append('required="0"')
+ if field.field == 'partner_id':
+ attrs.append('on_change="onchange_partner_id(move_id,partner_id,account_id,debit,credit,((\'journal_id\' in context) and context[\'journal_id\']) or {})"')
+ if field.field in widths:
+ attrs.append('width="'+str(widths[field.field])+'"')
+ xml += '''\n''' % (field.field,' '.join(attrs))
+
+ xml += ''''''
+ result['arch'] = xml
+ result['fields'] = self.fields_get(cr, uid, fields, context)
+ return result
+
+ def unlink(self, cr, uid, ids, context={}, check=True):
+ self._update_check(cr, uid, ids, context)
+ for line in self.browse(cr, uid, ids, context):
+ context['journal_id']=line.journal_id.id
+ context['period_id']=line.period_id.id
+ result = super(account_move_line, self).unlink(cr, uid, [line.id], context=context)
+ if check:
+ self.pool.get('account.move').validate(cr, uid, [line.move_id.id], context=context)
+ return result
+
+ #
+ # TO VERIFY: check if try to write journal of only one line ???
+ #
+ def write(self, cr, uid, ids, vals, context={}, check=True, update_check=True):
+ if update_check:
+ self._update_check(cr, uid, ids, context)
+ result = super(osv.osv, self).write(cr, uid, ids, vals, context)
+ if check:
+ done = []
+ for line in self.browse(cr, uid, ids):
+ if line.move_id.id not in done:
+ done.append(line.move_id.id)
+ self.pool.get('account.move').validate(cr, uid, [line.move_id.id], context)
+ return result
+
+ def _update_journal_check(self, cr, uid, journal_id, period_id, context={}):
+ cr.execute('select state from account_journal_period where journal_id=%d and period_id=%d', (journal_id, period_id))
+ result = cr.fetchall()
+ for (state,) in result:
+ if state=='done':
+ raise osv.except_osv('Error !', 'You can not add/modify entries in a closed journal.')
+ if not result:
+ journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context)
+ period = self.pool.get('account.period').browse(cr, uid, period_id, context)
+ self.pool.get('account.journal.period').create(cr, uid, {
+ 'name': (journal.code or journal.name)+':'+(period.name or ''),
+ 'journal_id': journal.id,
+ 'period_id': period.id
+ })
+ return True
+
+ def _update_check(self, cr, uid, ids, context={}):
+ done = {}
+ for line in self.browse(cr, uid, ids, context):
+ if line.move_id.state<>'draft':
+ raise osv.except_osv('Error !', 'You can not modify or delete a confirmed entry !')
+ if line.reconcile_id:
+ raise osv.except_osv('Error !', 'You can not modify or delete a reconciled entry !')
+ t = (line.journal_id.id, line.period_id.id)
+ if t not in done:
+ self._update_journal_check(cr, uid, line.journal_id.id, line.period_id.id, context)
+ done[t] = True
+ return True
+
+ def create(self, cr, uid, vals, context={}, check=True):
+ if 'journal_id' in vals and 'journal_id' not in context:
+ context['journal_id'] = vals['journal_id']
+ if 'period_id' in vals and 'period_id' not in context:
+ context['period_id'] = vals['period_id']
+ if 'journal_id' not in context and 'move_id' in vals:
+ m = self.pool.get('account.move').browse(cr, uid, vals['move_id'])
+ context['journal_id'] = m.journal_id.id
+ context['period_id'] = m.period_id.id
+ self._update_journal_check(cr, uid, context['journal_id'], context['period_id'], context)
+ move_id = vals.get('move_id', False)
+ journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id'])
+ if not move_id:
+ if journal.centralisation:
+ # use the first move ever created for this journal and period
+ cr.execute('select id from account_move where journal_id=%d and period_id=%d order by id limit 1', (context['journal_id'],context['period_id']))
+ res = cr.fetchone()
+ if res:
+ vals['move_id'] = res[0]
+
+ if not vals.get('move_id', False):
+ if journal.sequence_id:
+ name = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
+ v = {
+ 'name': name,
+ 'period_id': context['period_id'],
+ 'journal_id': context['journal_id']
+ }
+ move_id = self.pool.get('account.move').create(cr, uid, v, context)
+ vals['move_id'] = move_id
+ else:
+ raise osv.except_osv('No piece number !', 'Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')
+
+ if ('account_id' in vals) and journal.type_control_ids:
+ type = self.pool.get('account.account').browse(cr, uid, vals['account_id']).type
+ ok = False
+ for t in journal.type_control_ids:
+ if type==t.code:
+ ok = True
+ break
+ if not ok:
+ raise osv.except_osv('Bad account !', 'You can not use this general account in this journal !')
+
+ result = super(osv.osv, self).create(cr, uid, vals, context)
+ if check:
+ self.pool.get('account.move').validate(cr, uid, [vals['move_id']], context)
+ return result
+account_move_line()
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index 7a689cef425..c21e1df901f 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -398,7 +398,7 @@
-
+
@@ -407,6 +407,7 @@
+
diff --git a/addons/account/invoice.py b/addons/account/invoice.py
index aeff689ca77..7e90721ca99 100644
--- a/addons/account/invoice.py
+++ b/addons/account/invoice.py
@@ -107,6 +107,8 @@ class account_invoice(osv.osv):
'date_invoice': fields.date('Date Invoiced', required=True, states={'open':[('readonly',True)],'close':[('readonly',True)]}),
'date_due': fields.date('Due Date', states={'open':[('readonly',True)],'close':[('readonly',True)]}),
+ 'date_discount': fields.date('Discount Date', states={'open':[('readonly',True)],'close':[('readonly',True)]},
+ help='The date of the first cash discount'),
'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}, relate=True),
'address_contact_id': fields.many2one('res.partner.address', 'Contact Address', readonly=True, states={'draft':[('readonly',False)]}),
@@ -175,16 +177,32 @@ class account_invoice(osv.osv):
def onchange_currency_id(self, cr, uid, ids, curr_id):
return {}
- def onchange_payment_term(self, cr, uid, ids, payment_term):
- if not payment_term:
+ def onchange_payment_term(self, cr, uid, ids, payment_term_id):
+ if not payment_term_id:
return {}
- invoice= self.pool.get('account.invoice').browse(cr, uid, ids)[0]
- pterm_list= self.pool.get('account.payment.term').compute(cr, uid, payment_term, value=1, date_ref=invoice.date_invoice)
- if not pterm_list:
- return {}
- pterm_list = [line[0] for line in pterm_list]
- pterm_list.sort()
- return {'value':{'date_due': pterm_list[-1]}}
+ res={}
+ pt_obj= self.pool.get('account.payment.term')
+
+ if ids :
+ invoice= self.pool.get('account.invoice').browse(cr, uid, ids)[0]
+ date_invoice= invoice.date_invoice
+ else:
+ date_invoice= time.strftime('%Y-%m-%d')
+
+ pterm_list= pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
+
+ if pterm_list:
+ pterm_list = [line[0] for line in pterm_list]
+ pterm_list.sort()
+ res= {'value':{'date_due': pterm_list[-1]}}
+
+
+ disc_list= pt_obj.get_discounts(cr,uid,payment_term_id,date_invoice)
+ if disc_list :
+ res = res or {'value':{}}
+ res['value'].update({'date_discount': disc_list[0][0] })
+
+ return res
# go from canceled state to draft state
diff --git a/addons/account/project/project.py b/addons/account/project/project.py
index 929e40145ee..5af1aa708c5 100644
--- a/addons/account/project/project.py
+++ b/addons/account/project/project.py
@@ -174,99 +174,5 @@ class account_analytic_journal(osv.osv):
'type': lambda *a: 'general',
}
account_analytic_journal()
-
-class account_analytic_line(osv.osv):
- _name = 'account.analytic.line'
- _columns = {
- 'name' : fields.char('Description', size=128, required=True),
- 'date' : fields.date('Date', required=True),
- 'amount' : fields.float('Amount', required=True),
- 'unit_amount' : fields.float('Quantity'),
- 'product_uom_id' : fields.many2one('product.uom', 'UoM'),
- 'product_id' : fields.many2one('product.product', 'Product'),
- 'account_id' : fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='cascade', select=True),
- 'general_account_id' : fields.many2one('account.account', 'General account', required=True, ondelete='cascade'),
- 'move_id' : fields.many2one('account.move.line', 'General entry', ondelete='cascade', select=True),
- 'journal_id' : fields.many2one('account.analytic.journal', 'Analytic journal', required=True, ondelete='cascade', select=True),
- 'code' : fields.char('Code', size=8),
- 'user_id' : fields.many2one('res.users', 'User',),
- }
-
- _defaults = {
- 'date': lambda *a: time.strftime('%Y-%m-%d'),
- }
- _order = 'date'
-
- def on_change_unit_amount(self, cr, uid, id, prod_id, unit_amount, unit=False, context={}):
- if unit_amount and prod_id:
- rate = 1
- if unit:
- uom_id = self.pool.get('product.uom')
- hunit = uom_id.browse(cr, uid, unit)
- rate = hunit.factor
- uom_id = self.pool.get('product.product')
- prod = uom_id.browse(cr, uid, prod_id)
- a = prod.product_tmpl_id.property_account_expense
- if not a:
- a = prod.categ_id.property_account_expense_categ
- return {'value' : {'amount' : -round(unit_amount * prod.standard_price * rate,2), 'general_account_id':a[0]}}
- return {}
-account_analytic_line()
-
-class timesheet_invoice(osv.osv):
- _name = "report.hr.timesheet.invoice.journal"
- _description = "Analytic account costs and revenues"
- _auto = False
- _columns = {
- 'name': fields.date('Month', readonly=True),
- 'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True, relate=True, select=True),
- 'journal_id': fields.many2one('account.analytic.journal', 'Journal', readonly=True),
- 'quantity': fields.float('Quantities', readonly=True),
- 'cost': fields.float('Credit', readonly=True),
- 'revenue': fields.float('Debit', readonly=True)
- }
- _order = 'name desc, account_id'
- def init(self, cr):
- #cr.execute("""
- #create or replace view report_hr_timesheet_invoice_journal as (
- # select
- # min(l.id) as id,
- # substring(l.create_date for 7)||'-01' as name,
- # sum(greatest(-l.amount,0)) as cost,
- # sum(greatest(l.amount,0)) as revenue,
- # sum(l.unit_amount*u.factor) as quantity,
- # journal_id,
- # account_id
- # from account_analytic_line l
- # left join product_uom u on (u.id=l.product_uom_id)
- # group by
- # substring(l.create_date for 7),
- # journal_id,
- # account_id
- #)""")
- cr.execute("""
- create or replace view report_hr_timesheet_invoice_journal as (
- select
- min(l.id) as id,
- substring(l.create_date for 7)||'-01' as name,
- sum(
- CASE WHEN -l.amount>0 THEN 0 ELSE -l.amount
- END
- ) as cost,
- sum(
- CASE WHEN l.amount>0 THEN l.amount ELSE 0
- END
- ) as revenue,
- sum(l.unit_amount*u.factor) as quantity,
- journal_id,
- account_id
- from account_analytic_line l
- left join product_uom u on (u.id=l.product_uom_id)
- group by
- substring(l.create_date for 7),
- journal_id,
- account_id
- )""")
-timesheet_invoice()
diff --git a/addons/l10n_ch/dta/dta_wizard.py b/addons/l10n_ch/dta/dta_wizard.py
index a0a17fba3cb..6cab088c4cd 100644
--- a/addons/l10n_ch/dta/dta_wizard.py
+++ b/addons/l10n_ch/dta/dta_wizard.py
@@ -43,15 +43,6 @@ def _bank_get(self, cr, uid, context={}):
res = [(r['active'], r['name']) for r in res]
return res
-def _journal_get(self, cr, uid, context={}):
- pool= pooler.get_pool(cr.dbname)
- obj= pool.get('account.journal')
- ids= obj.search(cr, uid, [('type','=','cash')])
- res= obj.read(cr, uid, ids, ['active', 'name'], context)
- res= [(r['active'], r['name']) for r in res]
- return res
-
-
check_form = """
"""
+
check_fields = {
'dta_line_ids' : {
'string':'DTA lines',
@@ -76,9 +68,11 @@ check_fields = {
'journal' : {
'string':'Journal',
- 'type':'selection',
- 'selection':_journal_get,
+ 'type':'many2one',
+ 'relation':'account.journal',
+ 'domain':"[('type','=','cash')]",
'required': True,
+ 'help':'The journal used for the bank statement',
},
}
@@ -146,26 +140,25 @@ def _get_dta_lines(self,cr,uid,data,context):
if i.dta_state != '2bpaid' or i.state in ['draft','cancel','paid']:
continue
- discount_ids= i.payment_term and i.payment_term.cash_discount_ids and i.payment_term.cash_discount_ids
- discount= ""
cash_disc_date=""
- if discount_ids:
- for d in discount_ids: # TODO a mettre en fct dans l'objet payment term
- cash_disc_date= mx.DateTime.strptime(i.date_invoice,'%Y-%m-%d') +\
- RelativeDateTime(days=d.delay+1)
- if cash_disc_date >= mx.DateTime.now():
- discount= d
+ discount=""
+ if i.payment_term :
+ disc_list= pool.get('account.payment.term').get_discounts(cr,uid,i.payment_term.id, i.date_invoice)
+
+ for (cash_disc_date,discount) in disc_list:
+ if cash_disc_date >= time.strftime('%Y-%m-%d'):
break
+
lines.append(dta_line_obj.create(cr,uid,{
'name': i.id,
'partner_id': i.partner_id.id,
'due_date': i.date_due,
'invoice_date': i.date_invoice,
- 'cashdisc_date': discount and cash_disc_date.strftime('%Y-%m-%d') or None,
- 'amount_to_pay': discount and i.amount_total*(1-discount.discount) or i.amount_total,
+ 'cashdisc_date': cash_disc_date and cash_disc_date or None,
+ 'amount_to_pay': discount and i.amount_total*(1-discount) or i.amount_total,
'amount_invoice': i.amount_total,
- 'amount_cashdisc': discount and i.amount_total*(1-discount.discount),
+ 'amount_cashdisc': discount and i.amount_total*(1-discount),
'dta_id': id_dta,
}))
@@ -311,14 +304,13 @@ def _create_dta(self,cr,uid,data,context):
date_value = dtal.cashdisc_date or dtal.due_date or ""
date_value = date_value and mx.DateTime.strptime( date_value,'%Y-%m-%d') or mx.DateTime.now()
- #date_value = date_value.strftime("%y%m%d")
try:
#header
hdr= header('000000','',creation_date,company_iban,'idfi',seq,'836','0') # TODO id_file
- # segment 01:
- dta_line = ''.join([segment_01(hdr,company_dta,
+
+ dta_line = ''.join([segment_01(hdr,company_dta,# segment 01:
number,company_iban,date_value.strftime("%y%m%d")
,currency,str(dtal.amount_to_pay)), # adresse donneur d'ordre
segment_02(company.name,co_addr.street,co_addr.zip,co_addr.city,country,cours=''),# donnees de la banque
@@ -346,6 +338,7 @@ def _create_dta(self,cr,uid,data,context):
'partner_id':i.partner_id.id,
'account_id':i.account_id.id,
'statement_id': bk_st_id,
+ 'invoice_id': i.id,
})
dta = dta + dta_line