Improve payment, invoice, statement

- Use the right reference from invoice on account move lines
- Add a reference type on invoice
- Payment are now multi-currency
- Add wizard to populate statement
- Make thread safe payment wizard
- Add mod10r in utils
- Add colors on statement lines

bzr revid: ced-35849fea0ca75fec483ba54836f4954c1b26d2c9
This commit is contained in:
ced 2007-10-04 05:59:39 +00:00
parent ddae539d94
commit 1d480a1df3
13 changed files with 635 additions and 227 deletions

View File

@ -507,6 +507,25 @@ class account_bank_statement_line(osv.osv):
currency_id, balance, context=context) currency_id, balance, context=context)
return {'value': {'amount': balance, 'account_id': account_id}} return {'value': {'amount': balance, 'account_id': account_id}}
def _reconcile_amount(self, cursor, user, ids, name, args, context=None):
if not ids:
return {}
res_currency_obj = self.pool.get('res.currency')
res_users_obj = self.pool.get('res.users')
res = {}
company_currency_id = res_users_obj.browse(cursor, user, user,
context=context).company_id.currency_id.id
for line in self.browse(cursor, user, ids, context=context):
if line.reconcile_id:
res[line.id] = res_currency_obj.compute(cursor, user,
company_currency_id, line.statement_id.currency.id,
line.reconcile_id.total_entry, context=context)
else:
res[line.id] = 0.0
return res
_order = "date,name desc" _order = "date,name desc"
_name = "account.bank.statement.line" _name = "account.bank.statement.line"
_description = "Bank Statement Line" _description = "Bank Statement Line"
@ -514,14 +533,25 @@ class account_bank_statement_line(osv.osv):
'name': fields.char('Name', size=64, required=True), 'name': fields.char('Name', size=64, required=True),
'date': fields.date('Date', required=True), 'date': fields.date('Date', required=True),
'amount': fields.float('Amount'), 'amount': fields.float('Amount'),
'type': fields.selection([('supplier','Supplier'),('customer','Customer'),('general','General')], 'Type', required=True), 'type': fields.selection([
('supplier','Supplier'),
('customer','Customer'),
('general','General')
], 'Type', required=True),
'partner_id': fields.many2one('res.partner', 'Partner'), 'partner_id': fields.many2one('res.partner', 'Partner'),
'account_id': fields.many2one('account.account','Account', required=True), 'account_id': fields.many2one('account.account','Account',
'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True, required=True), required=True),
'reconcile_id': fields.many2one('account.bank.statement.reconcile', 'Reconcile', states={'confirm':[('readonly',True)]}), 'statement_id': fields.many2one('account.bank.statement', 'Statement',
'move_ids': fields.many2many('account.move', 'account_bank_statement_line_move_rel', 'move_id','statement_id', 'Moves'), select=True, required=True),
'reconcile_id': fields.many2one('account.bank.statement.reconcile',
'Reconcile', states={'confirm':[('readonly',True)]}),
'move_ids': fields.many2many('account.move',
'account_bank_statement_line_move_rel', 'move_id','statement_id',
'Moves'),
'ref': fields.char('Ref.', size=32), 'ref': fields.char('Ref.', size=32),
'note': fields.text('Notes') 'note': fields.text('Notes'),
'reconcile_amount': fields.function(_reconcile_amount,
string='Amount reconciled', method=True, type='float'),
} }
_defaults = { _defaults = {
'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'), 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'),

View File

@ -139,8 +139,10 @@
<field name="name" select="2"/> <field name="name" select="2" colspan="4"/>
<newline/>
<field name="reference" select="1"/> <field name="reference" select="1"/>
<field name="reference_type" select="2"/>
<field name="check_total" required="2"/> <field name="check_total" required="2"/>
<field name="currency_id" on_change="onchange_currency_id(currency_id)" select="2"/> <field name="currency_id" on_change="onchange_currency_id(currency_id)" select="2"/>
@ -261,7 +263,9 @@
<newline/> <newline/>
<field name="partner_bank_id" domain="[('partner_id','=',partner_id)]"/> <field name="partner_bank_id" domain="[('partner_id','=',partner_id)]"/>
<field name="date_due" select="1"/> <field name="date_due" select="1"/>
<newline/>
<field name="reference" select="2"/> <field name="reference" select="2"/>
<field name="reference_type" select="2"/>
<field name="origin"/> <field name="origin"/>
<field name="address_contact_id" domain="[('partner_id','=',partner_id)]" colspan="4"/> <field name="address_contact_id" domain="[('partner_id','=',partner_id)]" colspan="4"/>
<field name="move_id"/> <field name="move_id"/>

View File

@ -324,7 +324,8 @@
<notebook colspan="4"> <notebook colspan="4">
<page string="Entry encoding"> <page string="Entry encoding">
<field name="line_ids" colspan="4" nolabel="1"> <field name="line_ids" colspan="4" nolabel="1">
<tree string="Statement lines" editable="bottom"> <tree string="Statement lines" editable="bottom"
colors="red:amount!=reconcile_amount and reconcile_id">
<field name="date"/> <field name="date"/>
<field name="ref"/> <field name="ref"/>
<field name="name"/> <field name="name"/>
@ -335,7 +336,8 @@
domain="[('journal_id','=',parent.journal_id)]"/> domain="[('journal_id','=',parent.journal_id)]"/>
<field name="amount"/> <field name="amount"/>
<field name="reconcile_id" <field name="reconcile_id"
context="{'partner_id': partner_id, 'amount': amount, 'account_id': account_id, 'currency_id': parent.currency}"/> context="{'partner_id': partner_id, 'amount': amount, 'account_id': account_id, 'currency_id': parent.currency}"/>
<field name="reconcile_amount" invisible="1"/>
</tree> </tree>
<form string="Statement lines"> <form string="Statement lines">
<field name="date"/> <field name="date"/>

View File

@ -95,6 +95,9 @@ class account_invoice(osv.osv):
res[id] = self.test_paid(cr, uid, [id]) res[id] = self.test_paid(cr, uid, [id])
return res return res
def _get_reference_type(self, cursor, user, context=None):
return [('none', 'None')]
_name = "account.invoice" _name = "account.invoice"
_description = 'Invoice' _description = 'Invoice'
_order = "number" _order = "number"
@ -110,6 +113,8 @@ class account_invoice(osv.osv):
'number': fields.char('Invoice Number', size=32, readonly=True), 'number': fields.char('Invoice Number', size=32, readonly=True),
'reference': fields.char('Invoice Reference', size=64), 'reference': fields.char('Invoice Reference', size=64),
'reference_type': fields.selection(_get_reference_type, 'Reference Type',
required=True),
'comment': fields.text('Additionnal Information'), 'comment': fields.text('Additionnal Information'),
'state': fields.selection([ 'state': fields.selection([
@ -152,9 +157,12 @@ class account_invoice(osv.osv):
'state': lambda *a: 'draft', 'state': lambda *a: 'draft',
'journal_id': _get_journal, 'journal_id': _get_journal,
'currency_id': _get_currency, 'currency_id': _get_currency,
'company_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id, 'company_id': lambda self, cr, uid, context: \
self.pool.get('res.users').browse(cr, uid, uid,
context=context).company_id.id,
'reference_type': lambda *a: 'none',
} }
def unlink(self, cr, uid, ids): def unlink(self, cr, uid, ids):
invoices = self.read(cr, uid, ids, ['state']) invoices = self.read(cr, uid, ids, ['state'])
unlink_ids = [] unlink_ids = []
@ -317,6 +325,10 @@ class account_invoice(osv.osv):
iml = self.pool.get('account.invoice.line').move_line_get(cr, uid, inv.id) iml = self.pool.get('account.invoice.line').move_line_get(cr, uid, inv.id)
for il in iml: for il in iml:
if il['account_analytic_id']: if il['account_analytic_id']:
if inv.type in ('in_invoice', 'in_refund'):
ref = inv.reference
else:
ref = self._convert_ref(cr, uid, inv.number)
il['analytic_lines'] = [(0,0, { il['analytic_lines'] = [(0,0, {
'name': il['name'], 'name': il['name'],
'date': inv['date_invoice'], 'date': inv['date_invoice'],
@ -327,7 +339,7 @@ class account_invoice(osv.osv):
'product_uom_id': il['uos_id'], 'product_uom_id': il['uos_id'],
'general_account_id': il['account_id'], 'general_account_id': il['account_id'],
'journal_id': self._get_journal_analytic(cr, uid, inv.type), 'journal_id': self._get_journal_analytic(cr, uid, inv.type),
'ref': self._convert_ref(cr, uid, inv['number']), 'ref': ref,
})] })]
return iml return iml
@ -370,7 +382,12 @@ class account_invoice(osv.osv):
# one move line per tax line # one move line per tax line
iml += ait_obj.move_line_get(cr, uid, inv.id) iml += ait_obj.move_line_get(cr, uid, inv.id)
if inv.type in ('in_invoice', 'in_refund'):
ref = inv.reference
else:
ref = self._convert_ref(cr, uid, inv.number)
diff_currency_p = inv.currency_id.id <> company_currency
# create one move line for the total and possibly adjust the other lines amount # create one move line for the total and possibly adjust the other lines amount
total = 0 total = 0
total_currency = 0 total_currency = 0
@ -378,11 +395,13 @@ class account_invoice(osv.osv):
if inv.currency_id.id != company_currency: if inv.currency_id.id != company_currency:
i['currency_id'] = inv.currency_id.id i['currency_id'] = inv.currency_id.id
i['amount_currency'] = i['price'] i['amount_currency'] = i['price']
i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id, company_currency, i['price'], context={'date': inv.date_invoice}) i['price'] = cur_obj.compute(cr, uid, inv.currency_id.id,
company_currency, i['price'],
context={'date': inv.date_invoice})
else: else:
i['amount_currency'] = False i['amount_currency'] = False
i['currency_id'] = False i['currency_id'] = False
i['ref'] = self._convert_ref(cr, uid, inv.number) i['ref'] = ref
if inv.type in ('out_invoice','in_refund'): if inv.type in ('out_invoice','in_refund'):
total += i['price'] total += i['price']
total_currency += i['amount_currency'] or i['price'] total_currency += i['amount_currency'] or i['price']
@ -409,9 +428,31 @@ class account_invoice(osv.osv):
if i == len(totlines): if i == len(totlines):
amount_currency += res_amount_currency amount_currency += res_amount_currency
iml.append({ 'type':'dest', 'name':name, 'price': t[1], 'account_id':acc_id, 'date_maturity': t[0], 'amount_currency': amount_currency, 'currency_id': inv.currency_id.id, 'ref': inv.number}) iml.append({
'type': 'dest',
'name': name,
'price': t[1],
'account_id': acc_id,
'date_maturity': t[0],
'amount_currency': diff_currency_p \
and amount_currency or False,
'currency_id': diff_currency_p \
and inv.currency_id.id or False,
'ref': ref,
})
else: else:
iml.append({ 'type':'dest', 'name':name, 'price': total, 'account_id':acc_id, 'date_maturity' : inv.date_due or False, 'amount_currency': total_currency, 'currency_id': inv.currency_id.id, 'ref': inv.number}) iml.append({
'type': 'dest',
'name': name,
'price': total,
'account_id': acc_id,
'date_maturity' : inv.date_due or False,
'amount_currency': diff_currency_p \
and total_currency or False,
'currency_id': diff_currency_p \
and inv.currency_id.id or False,
'ref': ref
})
date = inv.date_invoice date = inv.date_invoice
part = inv.partner_id.id part = inv.partner_id.id
@ -452,13 +493,17 @@ class account_invoice(osv.osv):
} }
def action_number(self, cr, uid, ids, *args): def action_number(self, cr, uid, ids, *args):
cr.execute('SELECT id, type, number, move_id FROM account_invoice WHERE id IN ('+','.join(map(str,ids))+')') cr.execute('SELECT id, type, number, move_id, reference FROM account_invoice WHERE id IN ('+','.join(map(str,ids))+')')
for (id, invtype, number, move_id) in cr.fetchall(): for (id, invtype, number, move_id, reference) in cr.fetchall():
if not number: if not number:
number = self.pool.get('ir.sequence').get(cr, uid, 'account.invoice.'+invtype) number = self.pool.get('ir.sequence').get(cr, uid, 'account.invoice.'+invtype)
if type in ('in_invoice', 'in_refund'):
ref = reference
else:
ref = self._convert_ref(cr, uid, number)
cr.execute('UPDATE account_invoice SET number=%s WHERE id=%d', (number, id)) cr.execute('UPDATE account_invoice SET number=%s WHERE id=%d', (number, id))
cr.execute('UPDATE account_move_line SET ref=%s WHERE move_id=%d and ref is null', (self._convert_ref(cr, uid, number), move_id)) cr.execute('UPDATE account_move_line SET ref=%s WHERE move_id=%d and ref is null', (ref, move_id))
cr.execute('UPDATE account_analytic_line SET ref=%s FROM account_move_line WHERE account_move_line.move_id=%d AND account_analytic_line.move_id=account_move_line.id', (self._convert_ref(cr, uid, number), move_id)) cr.execute('UPDATE account_analytic_line SET ref=%s FROM account_move_line WHERE account_move_line.move_id=%d AND account_analytic_line.move_id=account_move_line.id', (ref, move_id))
return True return True
def action_cancel(self, cr, uid, ids, *args): def action_cancel(self, cr, uid, ids, *args):

View File

@ -1,16 +1,18 @@
{ {
"name" : "Payment Management", "name": "Payment Management",
"version" : "1.0", "version": "1.0",
"author" : "Tiny", "author": "Tiny",
"category" : "Generic Modules/Payment", "category": "Generic Modules/Payment",
"depends" : ["account"], "depends": ["account"],
"init_xml" : [], "init_xml": [],
"description": """ "description": """
This is the module which Provide an more efficient way to manage invoice payment, This module provide :
Provide a basic mechanism to easily plug various automated payment. * a more efficient way to manage invoice payment.
""", * a basic mechanism to easily plug various automated payment.
"demo_xml" : [], """,
"update_xml" : ["payment_wizard.xml","payment_view.xml","payment_workflow.xml","payment_sequence.xml"], "demo_xml": [],
"update_xml": ["payment_wizard.xml", "payment_view.xml",
"payment_workflow.xml", "payment_sequence.xml"],
"active": False, "active": False,
"installable": True "installable": True
} }

View File

@ -25,8 +25,8 @@
# #
############################################################################## ##############################################################################
from osv import fields from osv import fields, osv
from osv import osv
class account_move_line(osv.osv): class account_move_line(osv.osv):
_inherit = "account.move.line" _inherit = "account.move.line"
@ -37,8 +37,11 @@ class account_move_line(osv.osv):
if not ids: if not ids:
return {} return {}
cr.execute("""SELECT ml.id, cr.execute("""SELECT ml.id,
ml.credit - CASE WHEN ml.amount_currency < 0
(SELECT coalesce(sum(amount),0) THEN - ml.amount_currency
ELSE ml.credit
END -
(SELECT coalesce(sum(amount_currency),0)
FROM payment_line pl FROM payment_line pl
INNER JOIN payment_order po INNER JOIN payment_order po
ON (pl.order_id = po.id) ON (pl.order_id = po.id)
@ -49,36 +52,42 @@ class account_move_line(osv.osv):
r=dict(cr.fetchall()) r=dict(cr.fetchall())
return r return r
def _to_pay_search(self, cr, uid, obj, name, args): def _to_pay_search(self, cr, uid, obj, name, args):
if not len(args): if not len(args):
return [] return []
query = self.pool.get('account.move.line')._query_get(cr, uid, context={}) line_obj = self.pool.get('account.move.line')
where = ' and '.join(map(lambda x: '''(select l.credit - coalesce(sum(amount),0) query = line_obj._query_get(cr, uid, context={})
from payment_line pl where = ' and '.join(map(lambda x: '''(SELECT
inner join payment_order po on (pl.order_id = po.id) CASE WHEN l.amount_currency < 0
where move_line_id = l.id and po.state != 'cancel') '''+x[1]+str(x[2])+' ',args)) THEN - l.amount_currency
ELSE l.credit
END - coalesce(sum(pl.amount_currency), 0)
FROM payment_line pl
INNER JOIN payment_order po ON (pl.order_id = po.id)
WHERE move_line_id = l.id AND po.state != 'cancel')''' \
+ x[1] + str(x[2])+' ',args))
cr.execute(('''select id cr.execute(('''select id
from account_move_line l from account_move_line l
where account_id in (select id from account_account where type=%s and active) where account_id in (select id
and reconcile_id is null from account_account
and credit > 0 where type=%s and active)
and '''+where+' and '+query), ('payable',) ) and reconcile_id is null
and credit > 0
and ''' + where + ' and ' + query), ('payable',) )
res = cr.fetchall() res = cr.fetchall()
if not len(res): if not len(res):
return [('id','=','0')] return [('id','=','0')]
return [('id','in',map(lambda x:x[0], res))] return [('id','in',map(lambda x:x[0], res))]
def line2bank(self,cr,uid,ids,payment_type= 'manual',context=None): def line2bank(self,cr,uid,ids,payment_type= 'manual',context=None):
""" """
Try to return for each account move line a corresponding bank Try to return for each account move line a corresponding bank
account according to the payment type. This work using one of account according to the payment type. This work using one of
the bank of the partner defined on the invoice eventually the bank of the partner defined on the invoice eventually
associated to the line. associated to the line.
Return the first suitable bank for the corresponding partner. Return the first suitable bank for the corresponding partner.
""" """
if not ids: return {} if not ids: return {}
bank_type= self.pool.get('payment.mode').suitable_bank_types(cr,uid,payment_type,context=context) bank_type= self.pool.get('payment.mode').suitable_bank_types(cr,uid,payment_type,context=context)
@ -102,10 +111,11 @@ class account_move_line(osv.osv):
elif (line not in type_ok) and (t in bank_type) : elif (line not in type_ok) and (t in bank_type) :
line2bank[line]= bank line2bank[line]= bank
type_ok.append(line) type_ok.append(line)
return line2bank return line2bank
_columns = { _columns = {
'amount_to_pay' : fields.function(amount_to_pay, method=True, type='float', string='Amount to pay', fnct_search=_to_pay_search), 'amount_to_pay' : fields.function(amount_to_pay, method=True,
} type='float', string='Amount to pay', fnct_search=_to_pay_search),
}
account_move_line() account_move_line()

View File

@ -29,6 +29,8 @@ from osv import fields
from osv import osv from osv import osv
import time import time
import netsvc import netsvc
class payment_type(osv.osv): class payment_type(osv.osv):
_name= 'payment.type' _name= 'payment.type'
_description= 'Payment type' _description= 'Payment type'
@ -36,12 +38,11 @@ class payment_type(osv.osv):
'name': fields.char('Name', size=64, required=True), 'name': fields.char('Name', size=64, required=True),
'code': fields.char('Code', size=64, required=True), 'code': fields.char('Code', size=64, required=True),
'suitable_bank_types': fields.many2many('res.partner.bank.type', 'suitable_bank_types': fields.many2many('res.partner.bank.type',
'bank_type_payment_type_rel', 'bank_type_payment_type_rel',
'pay_type_id','bank_type_id', 'pay_type_id','bank_type_id',
'Suitable bank types') 'Suitable bank types')
} }
payment_type() payment_type()
@ -50,19 +51,23 @@ class payment_mode(osv.osv):
_description= 'Payment mode' _description= 'Payment mode'
_columns= { _columns= {
'name': fields.char('Name', size=64, required=True), 'name': fields.char('Name', size=64, required=True),
'bank_id': fields.many2one('res.partner.bank',"Bank account",required=True), 'bank_id': fields.many2one('res.partner.bank', "Bank account",
'journal': fields.many2one('account.journal','Journal',required=True,domain=[('type','=','cash')]), required=True),
'journal': fields.many2one('account.journal', 'Journal', required=True,
domain=[('type', '=', 'cash')]),
'type': fields.many2one('payment.type','Payment type',required=True), 'type': fields.many2one('payment.type','Payment type',required=True),
'account': fields.many2one('account.account','Default payable account',domain=[('type','=','payable')],required=True), 'account': fields.many2one('account.account', 'Default payable account',
} domain=[('type', '=', 'payable')], required=True),
}
def suitable_bank_types(self,cr,uid,payment_code= 'manual',context={}): def suitable_bank_types(self,cr,uid,payment_code= 'manual',context={}):
""" Return the codes of the bank type that are suitable for the given payment type code""" """Return the codes of the bank type that are suitable
for the given payment type code"""
cr.execute(""" select t.code cr.execute(""" select t.code
from res_partner_bank_type t from res_partner_bank_type t
join bank_type_payment_type_rel r on (r.bank_type_id = t.id) join bank_type_payment_type_rel r on (r.bank_type_id = t.id)
join payment_type pt on (r.pay_type_id = pt.id) join payment_type pt on (r.pay_type_id = pt.id)
where pt.code = %s """, [payment_code]) where pt.code = %s """, [payment_code])
return [x[0] for x in cr.fetchall()] return [x[0] for x in cr.fetchall()]
payment_mode() payment_mode()
@ -75,18 +80,20 @@ class payment_order(osv.osv):
def get_wizard(self,type): def get_wizard(self,type):
logger = netsvc.Logger() logger = netsvc.Logger()
logger.notifyChannel("warning", netsvc.LOG_WARNING, "No wizard found for the payment type '%s'."%type) logger.notifyChannel("warning", netsvc.LOG_WARNING,
"No wizard found for the payment type '%s'." % type)
return None return None
def _total(self, cr, uid, ids, name, args, context={}): def _total(self, cursor, user, ids, name, args, context=None):
if not ids: return {} if not ids:
cr.execute("""SELECT o.id, coalesce(sum(l.amount),0) return {}
FROM payment_order o res = {}
LEFT JOIN payment_line l for order in self.browse(cursor, user, ids, context=context):
ON (o.id = l.order_id) if order.line_ids:
WHERE o.id in (%s) res[order.id] = reduce(lambda x, y: x + y.amount, order.line_ids, 0.0)
GROUP BY o.id""" % ','.join(map(str,ids))) else:
return dict(cr.fetchall()) res[order.id] = 0.0
return res
def nb_line(self, cr, uid, ids, name, args, context={}): def nb_line(self, cr, uid, ids, name, args, context={}):
if not ids: return {} if not ids: return {}
@ -102,15 +109,24 @@ class payment_order(osv.osv):
'date_planned': fields.date('Scheduled date if fixed'), 'date_planned': fields.date('Scheduled date if fixed'),
'reference': fields.char('Reference',size=128), 'reference': fields.char('Reference',size=128),
'mode': fields.many2one('payment.mode','Payment mode', select=True), 'mode': fields.many2one('payment.mode','Payment mode', select=True),
'state': fields.selection([('draft', 'Draft'),('open','Open'), 'state': fields.selection([
('cancel','Cancelled'),('done','Done')], 'State', select=True), ('draft', 'Draft'),
('open','Open'),
('cancel','Cancelled'),
('done','Done')], 'State', select=True),
'line_ids': fields.one2many('payment.line','order_id','Payment lines'), 'line_ids': fields.one2many('payment.line','order_id','Payment lines'),
'total': fields.function(_total, string="Total", method=True, type='float'), 'total': fields.function(_total, string="Total", method=True,
type='float'),
'user_id': fields.many2one('res.users','User',required=True), 'user_id': fields.many2one('res.users','User',required=True),
'nb_line': fields.function(nb_line,string='Number of payment',method=True, type='integer'), 'nb_line': fields.function(nb_line,string='Number of payment',
'date_prefered': fields.selection([('now','Directly'),('due','Due date'),('fixed','Fixed date')],"Prefered date",required=True), method=True, type='integer'),
'date_created': fields.date('Creation date',readonly=True), 'date_prefered': fields.selection([
'date_done': fields.date('Execution date',readonly=True), ('now', 'Directly'),
('due', 'Due date'),
('fixed', 'Fixed date')
], "Prefered date", required=True),
'date_created': fields.date('Creation date', readonly=True),
'date_done': fields.date('Execution date', readonly=True),
} }
_defaults = { _defaults = {
@ -118,7 +134,9 @@ class payment_order(osv.osv):
'state': lambda *a: 'draft', 'state': lambda *a: 'draft',
'date_prefered': lambda *a: 'due', 'date_prefered': lambda *a: 'due',
'date_created': lambda *a: time.strftime('%Y-%m-%d'), 'date_created': lambda *a: time.strftime('%Y-%m-%d'),
} 'reference': lambda self,cr,uid,context: self.pool.get('ir.sequence'
).get(cr, uid, 'payment.order'),
}
def set_to_draft(self, cr, uid, ids, *args): def set_to_draft(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state':'draft'}) self.write(cr, uid, ids, {'state':'draft'})
@ -135,70 +153,198 @@ class payment_order(osv.osv):
return True return True
def set_done(self, cr, uid, id, *args): def set_done(self, cr, uid, id, *args):
self.write(cr,uid,id,{'date_done':time.strftime('%Y-%m-%d'), self.write(cr,uid,id,{'date_done': time.strftime('%Y-%m-%d'),
'state':'done',}) 'state': 'done',})
wf_service = netsvc.LocalService("workflow") wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'payment.order', id, 'done', cr) wf_service.trg_validate(uid, 'payment.order', id, 'done', cr)
return True return True
payment_order() payment_order()
class payment_line(osv.osv): class payment_line(osv.osv):
_name = 'payment.line' _name = 'payment.line'
_description = 'Payment Line' _description = 'Payment Line'
_rec_name = 'move_line_id'
def partner_payable(self, cr, uid, ids, name, args, context={}): def partner_payable(self, cr, uid, ids, name, args, context={}):
if not ids: return {} if not ids: return {}
partners= self.read(cr, uid, ids, ['partner_id'], context) partners= self.read(cr, uid, ids, ['partner_id'], context)
partners= dict(map(lambda x: (x['id'],x['partner_id']),partners)) partners= dict(map(lambda x: (x['id'], x['partner_id'][0]), partners))
debit= self.pool.get('res.partner')._debit_get(cr, uid, debit = self.pool.get('res.partner')._debit_get(cr, uid,
partners.values(), name, partners.values(), name, args, context)
args, context)
for i in partners: for i in partners:
partners[i]= debit[partners[i]] partners[i] = debit[partners[i]]
return partners return partners
def translate(self,orig):
return {"to_pay":"credit",
"due_date":"date_maturity",
"reference":"ref"}.get(orig,orig)
def select_by_name(self, cr, uid, ids, name, args, context={}): def translate(self, orig):
return {"to_pay": "credit",
"due_date": "date_maturity",
"reference": "ref"}.get(orig, orig)
def select_by_name(self, cr, uid, ids, name, args, context=None):
if not ids: return {} if not ids: return {}
cr.execute("""SELECT pl.id, ml.%s
from account_move_line ml
inner join payment_line pl on (ml.id= pl.move_line_id)
where pl.id in (%s)"""% (self.translate(name),','.join(map(str,ids))) )
return dict(cr.fetchall())
partner_obj = self.pool.get('res.partner')
cr.execute("""SELECT pl.id, ml.%s
from account_move_line ml
inner join payment_line pl
on (ml.id = pl.move_line_id)
where pl.id in (%s)"""%
(self.translate(name), ','.join(map(str,ids))) )
res = dict(cr.fetchall())
if name == 'partner_id':
partner_name = {}
for p_id, p_name in partner_obj.name_get(cr,uid,
filter(lambda x:x and x != 0,res.values()),context=context):
partner_name[p_id] = p_name
for id in ids:
if id in res:
res[id] = (res[id],partner_name[res[id]])
else:
res[id] = (False,False)
else:
for id in ids:
res.setdefault(id, (False, ""))
return res
def _currency(self, cursor, user, ids, name, args, context=None):
if not ids:
return {}
res = {}
currency_obj = self.pool.get('res.currency')
account_obj = self.pool.get('account.account')
cursor.execute('''SELECT pl.id, ml.currency_id, ml.account_id
FROM account_move_line ml
INNER JOIN payment_line pl
ON (ml.id = pl.move_line_id)
WHERE pl.id in (''' + ','.join([str(x) for x in ids]) + ')')
res2 = {}
account_ids = []
for payment_line_id, currency_id, account_id in cursor.fetchall():
res2[payment_line_id] = [currency_id, account_id]
account_ids.append(account_id)
account2currency_id = {}
for account in account_obj.browse(cursor, user, account_ids,
context=context):
account2currency_id[account.id] = account.company_currency_id.id
for payment_line_id in ids:
if res2[payment_line_id][0]:
res[payment_line_id] = res2[payment_line_id][0]
else:
res[payment_line_id] = \
account2currency_id[res2[payment_line_id][1]]
currency_names = {}
for currency_id, name in currency_obj.name_get(cursor, user, res.values(),
context=context):
currency_names[currency_id] = name
for payment_line_id in ids:
res[payment_line_id] = (res[payment_line_id],
currency_names[res[payment_line_id]])
return res
def _to_pay_currency(self, cursor, user, ids, name , args, context=None):
if not ids:
return {}
cursor.execute('''SELECT pl.id,
CASE WHEN ml.amount_currency < 0
THEN - ml.amount_currency
ELSE ml.credit
END
FROM account_move_line ml
INNER JOIN payment_line pl
ON (ml.id = pl.move_line_id)
WHERE pl.id in (''' + ','.join([str(x) for x in ids]) + ')')
return dict(cursor.fetchall())
def _amount(self, cursor, user, ids, name, args, context=None):
if not ids:
return {}
currency_obj = self.pool.get('res.currency')
if context is None:
context = {}
res = {}
for line in self.browse(cursor, user, ids, context=context):
ctx = context.copy()
ctx['date'] = line.order_id.date_done or time.strftime('%Y-%m-%d')
res[line.id] = currency_obj.compute(cursor, user, line.currency.id,
line.move_line_id.account_id.company_currency_id.id,
line.amount_currency, context=ctx)
return res
def _value_date(self, cursor, user, ids, name, args, context=None):
if not ids:
return {}
res = {}
for line in self.browse(cursor, user, ids, context=context):
if line.order_id.date_prefered == 'fixed':
res[line.id] = line.order_id.date_planned
elif line.order_id.date_prefered == 'due':
res[line.id] = line.due_date or time.strftime('%Y-%m-%d')
else:
res[line.id] = time.strftime('%Y-%m-%d')
return res
_columns = { _columns = {
'move_line_id': fields.many2one('account.move.line','Entry line',required=True), 'name': fields.char('Name', size=64, required=True, readonly=True),
'amount': fields.float('Payment Amount', digits=(16,2), required=True), 'move_line_id': fields.many2one('account.move.line','Entry line',
'bank_id': fields.many2one('res.partner.bank','Bank account'), required=True),
'order_id': fields.many2one('payment.order','Order', ondelete='cascade', select=True), 'amount_currency': fields.float('Amount', digits=(16,2),
'partner_id': fields.function(select_by_name, string="Partner", method=True, type='many2one', obj='res.partner'), required=True, help='Payment amount in the partner currency'),
'to_pay': fields.function(select_by_name, string="To pay", method=True, type='float'), 'to_pay_currency': fields.function(_to_pay_currency, string='To Pay',
'due_date': fields.function(select_by_name, string="Due date", method=True, type='date'), method=True, type='float',
'date_created': fields.function(select_by_name, string="Creation date", method=True, type='date'), help='Amount to pay in the partner currency'),
'reference': fields.function(select_by_name, string="Ref", method=True, type='char'), 'currency': fields.function(_currency, string='Currency',
'partner_payable': fields.function(partner_payable, string="Partner payable", method=True, type='float'), method=True, type='many2one', obj='res.currency'),
'bank_id': fields.many2one('res.partner.bank', 'Bank account'),
'order_id': fields.many2one('payment.order', 'Order', required=True,
ondelete='cascade', select=True),
'partner_id': fields.function(select_by_name, string="Partner",
method=True, type='many2one', obj='res.partner'),
'amount': fields.function(_amount, string='Amount',
method=True, type='float',
help='Payment amount in the company currency'),
'to_pay': fields.function(select_by_name, string="To Pay", method=True,
type='float', help='Amount to pay in the company currency'),
'due_date': fields.function(select_by_name, string="Due date",
method=True, type='date'),
'date_created': fields.function(select_by_name, string="Creation date",
method=True, type='date'),
'reference': fields.function(select_by_name, string="Ref", method=True,
type='char'),
'partner_payable': fields.function(partner_payable,
string="Partner payable", method=True, type='float'),
'value_date': fields.function(_value_date, string='Value Date',
method=True, type='date'),
} }
def onchange_move_line(self, cr, uid, id, move_line_id, payment_type,context={}): _defaults = {
'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence'
).get(cursor, user, 'payment.line'),
}
_sql_constraints = [
('name_uniq', 'UNIQUE(name)', 'The payment line name must be unique!'),
]
def onchange_move_line(self, cr, uid, id, move_line_id, payment_type,context=None):
if not move_line_id: if not move_line_id:
return {} return {}
line=self.pool.get('account.move.line').browse(cr,uid,move_line_id) line=self.pool.get('account.move.line').browse(cr,uid,move_line_id)
return {'value': {'amount': line.amount_to_pay, return {'value': {
'to_pay': line.amount_to_pay, 'amount_currency': line.amount_to_pay,
'to_pay_currency': line.amount_to_pay,
'partner_id': line.partner_id.id, 'partner_id': line.partner_id.id,
'reference': line.ref, 'reference': line.ref,
'date_created': line.date_created, 'date_created': line.date_created,
'bank_id': self.pool.get('account.move.line').line2bank(cr, uid, 'bank_id': self.pool.get('account.move.line').line2bank(cr, uid,
[move_line_id], [move_line_id],
payment_type or 'manual',context)[move_line_id] payment_type or 'manual', context)[move_line_id]
}} }}
payment_line() payment_line()

View File

@ -1,16 +1,29 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<terp> <terp>
<data noupdate="1"> <data noupdate="1">
<record model="ir.sequence.type" id="seq_type_payment_order"> <record model="ir.sequence.type" id="seq_type_payment_order" forcecreate="1">
<field name="name">Payment order</field> <field name="name">Payment order</field>
<field name="code">payment.order</field> <field name="code">payment.order</field>
</record> </record>
<record model="ir.sequence" id="seq_payment_order"> <record model="ir.sequence" id="seq_payment_order" forcecreate="1">
<field name="name">Payment order</field> <field name="name">Payment order</field>
<field name="code">payment.order</field> <field name="code">payment.order</field>
<field name="padding" eval="3"/> <field name="padding" eval="3"/>
<field name="prefix">%(year)s/</field> <field name="prefix">%(year)s/</field>
</record> </record>
</data>
<record model="ir.sequence.type" id="seq_type_payment_line" forcecreate="1">
<field name="name">Payment Line</field>
<field name="code">payment.line</field>
</record>
<record model="ir.sequence" id="seq_payment_line" forcecreate="1">
<field name="name">Payment Line</field>
<field name="code">payment.line</field>
<field name="prefix"></field>
<field name="padding">3</field>
</record>
</data>
</terp> </terp>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<terp> <terp>
<data> <data>
<menuitem name="Financial Management/Payment Management" id="menu_main" /> <menuitem name="Financial Management/Payment" id="menu_main" />
<menuitem name="Financial Management/Payment Management/Configuration" groups="admin" sequence="1"/> <menuitem name="Financial Management/Configuration" groups="admin" sequence="1"/>
<record model="ir.ui.view" id="view_payment_type_form"> <record model="ir.ui.view" id="view_payment_type_form">
<field name="name">payment.type.form</field> <field name="name">payment.type.form</field>
@ -13,7 +13,7 @@
<field name="name" select="1"/> <field name="name" select="1"/>
<field name="code"/> <field name="code"/>
<newline/> <newline/>
<field name="suitable_bank_types" select="1"/> <field name="suitable_bank_types" select="1" colspan="4"/>
</form> </form>
</field> </field>
</record> </record>
@ -23,7 +23,8 @@
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem name="Financial Management/Payment Management/Configuration/Payment Type" id="menu_action_payment_type_form" action="action_payment_type_form"/> <menuitem name="Financial Management/Configuration/Payment/Payment Type"
id="menu_action_payment_type_form" action="action_payment_type_form"/>
<record model="ir.ui.view" id="view_payment_mode_tree"> <record model="ir.ui.view" id="view_payment_mode_tree">
<field name="name">payment.mode.tree</field> <field name="name">payment.mode.tree</field>
@ -58,10 +59,11 @@
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem <menuitem
name="Financial Management/Payment Management/Configuration/Payment Mode" name="Financial Management/Configuration/Payment/Payment Mode"
id="menu_action_payment_mode_form" action="action_payment_mode_form"/> id="menu_action_payment_mode_form" action="action_payment_mode_form"/>
<record model="ir.ui.view" id="view_payment_order_form">
<record model="ir.ui.view" id="view_payment_order_form">
<field name="name">payment.order.form</field> <field name="name">payment.order.form</field>
<field name="model">payment.order</field> <field name="model">payment.order</field>
<field name="type">form</field> <field name="type">form</field>
@ -88,7 +90,7 @@
<button name="set_to_draft" states="cancel" <button name="set_to_draft" states="cancel"
type="object" string="Set to draft"/> type="object" string="Set to draft"/>
</group> </group>
</form> </form>
</field> </field>
</record> </record>
@ -115,12 +117,12 @@
<field name="name">Payment order</field> <field name="name">Payment order</field>
<field name="res_model">payment.order</field> <field name="res_model">payment.order</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">form,tree</field>
</record> </record>
<menuitem name="Financial Management/Payment Management/Payment Orders" <menuitem name="Financial Management/Payment/Payment Orders"
id="menu_action_payment_order_form" id="menu_action_payment_order_form"
action="action_payment_order_tree" action="action_payment_order_tree"
sequence="3"/> sequence="3"/>
<record model="ir.actions.act_window" id="action_payment_order_draft"> <record model="ir.actions.act_window" id="action_payment_order_draft">
<field name="name">Draft payment order</field> <field name="name">Draft payment order</field>
@ -129,10 +131,10 @@
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="domain">[('state','=','draft')]</field> <field name="domain">[('state','=','draft')]</field>
</record> </record>
<menuitem name="Financial Management/Payment Management/Payment Orders/Draft Payment Orders" <menuitem name="Financial Management/Payment/Payment Orders/Draft Payment Orders"
id="menu_action_payment_order_draft" id="menu_action_payment_order_draft"
action="action_payment_order_draft" action="action_payment_order_draft"
sequence="1"/> sequence="1"/>
<record model="ir.actions.act_window" id="action_payment_order_open"> <record model="ir.actions.act_window" id="action_payment_order_open">
<field name="name">Payment orders to validate</field> <field name="name">Payment orders to validate</field>
@ -141,14 +143,10 @@
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="domain">[('state','=','open')]</field> <field name="domain">[('state','=','open')]</field>
</record> </record>
<menuitem name="Financial Management/Payment Management/Payment Orders/Payment Orders to Validate" <menuitem name="Financial Management/Payment/Payment Orders/Payment Orders to Validate"
id="menu_action_payment_order_open" id="menu_action_payment_order_open"
action="action_payment_order_open" action="action_payment_order_open"
sequence="2"/> sequence="2"/>
<record model="ir.ui.view" id="view_payment_line_form"> <record model="ir.ui.view" id="view_payment_line_form">
<field name="name">Payment Line</field> <field name="name">Payment Line</field>
@ -156,15 +154,21 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Payment Line"> <form string="Payment Line">
<field name="move_line_id" <field name="move_line_id"
select="1" on_change="onchange_move_line(move_line_id,parent.mode.type.code)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_to_pay','>',0)] "/> select="1"
<field name="amount" select="1" /> on_change="onchange_move_line(move_line_id,parent.mode.type.code)"
domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_to_pay','>',0)] "/>
<newline/>
<field name="amount_currency" select="1"/>
<field name="to_pay_currency"/>
<field name="currency"/>
<field name="bank_id" domain="[('partner_id','=',partner_id)]"/> <field name="bank_id" domain="[('partner_id','=',partner_id)]"/>
<field name="to_pay"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="partner_payable"/>
<field name="reference"/> <field name="reference"/>
<field name="due_date"/> <field name="due_date"/>
<field name="amount" select="2" />
<field name="to_pay"/>
<field name="partner_payable"/>
<field name="date_created"/> <field name="date_created"/>
</form> </form>
</field> </field>
@ -175,16 +179,23 @@
<field name="type">tree</field> <field name="type">tree</field>
<field name="priority" eval="4"/> <field name="priority" eval="4"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Payment Line" editable="bottom" colors="red:to_pay&lt;amount" > <tree string="Payment Line" editable="bottom"
<field name="move_line_id" select="1" on_change="onchange_move_line(move_line_id,parent.mode)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_to_pay','>',0)] "/> colors="red:to_pay_currency&lt;amount_currency">
<field name="bank_id" domain="[('partner_id','=',partner_id)]"/> <field name="move_line_id" select="1"
<field name="amount"/> on_change="onchange_move_line(move_line_id,parent.mode)"
<field name="to_pay"/> domain="[('reconcile_id', '=', False), ('credit', '>', 0), ('amount_to_pay', '>', 0)]"/>
<field name="bank_id" domain="[('partner_id', '=', partner_id)]"/>
<field name="amount_currency"/>
<field name="to_pay_currency"/>
<field name="currency"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="partner_payable"/>
<field name="reference"/> <field name="reference"/>
<field name="due_date"/> <field name="due_date"/>
<field name="amount"/>
<field name="to_pay"/>
<field name="partner_payable"/>
<field name="date_created"/> <field name="date_created"/>
<field name="name"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -195,6 +206,18 @@
<field name="view_mode">form,tree</field> <field name="view_mode">form,tree</field>
</record> </record>
<record model="ir.ui.view" id="view_bank_statement_form">
<field name="name">account.bank.statement.form.inherit</field>
<field name="model">account.bank.statement</field>
<field name="type">form</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<field name="period_id" position="after">
<button name="%(wizard_populate_statement)d"
string="Import payment lines" type="action" colspan="2"/>
</field>
</field>
</record>
</data> </data>
</terp> </terp>

View File

@ -2,18 +2,25 @@
<terp> <terp>
<data> <data>
<wizard <wizard
string="Populate payment" string="Populate payment"
model="payment.order" model="payment.order"
name="populate_payment" name="populate_payment"
menu="False" menu="False"
id="wizard_populate_payment"/> id="wizard_populate_payment"/>
<wizard <wizard
string="Pay" string="Pay"
model="payment.order" model="payment.order"
name="pay_payment" name="pay_payment"
menu="False" menu="False"
id="wizard_pay_payment"/> id="wizard_pay_payment"/>
<wizard
string="Populate Statement with Payment lines"
model="account.bank.statement"
name="populate_statement"
menu="False"
id="wizard_populate_statement"/>
</data> </data>
</terp> </terp>

View File

@ -29,3 +29,4 @@
import wizard_payment_order import wizard_payment_order
import wizard_pay import wizard_pay
import wizard_populate_statement

View File

@ -25,88 +25,92 @@
# #
############################################################################## ##############################################################################
import wizard import wizard
from osv import osv
import pooler import pooler
from osv import fields from tools.misc import UpdateableStr
import time
ask_form="""<?xml version="1.0"?> FORM = UpdateableStr()
<form string="Populate Payment : ">
<field name="entries"/> FIELDS = {
</form> 'entries': {'string':'Entries', 'type':'many2many',
""" 'relation': 'account.move.line',},
ask_fields={ }
'entries': {'string':'Entries', 'type':'many2many',
'relation': 'account.move.line',},
}
def search_entries(self, cr, uid, data, context): def search_entries(self, cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
line_obj = pool.get('account.move.line')
pool= pooler.get_pool(cr.dbname)
# Search for move line to pay: # Search for move line to pay:
mline_ids = pool.get('account.move.line').search(cr, uid, line_ids = line_obj.search(cr, uid, [
[('reconcile_id', '=', False), ('reconcile_id', '=', False),
('amount_to_pay', '>', 0)], ('amount_to_pay', '>', 0)], context=context)
context=context)
if not mline_ids: FORM.string = '''<?xml version="1.0"?>
ask_fields['entries']['domain']= [('id', 'in', [])] <form string="Populate Payment:">
return {} <field name="entries" colspan="4" height="300" width="800" nolabel="1"
domain="[('id', 'in', [%s])]"/>
ask_fields['entries']['domain']= [('id', 'in', mline_ids)] </form>''' % (','.join([str(x) for x in line_ids]))
return {'entries': mline_ids} return {'entries': line_ids}
def create_payment(self, cr, uid, data, context): def create_payment(self, cr, uid, data, context):
mline_ids= data['form']['entries'][0][2] line_ids= data['form']['entries'][0][2]
if not mline_ids: return {} if not line_ids: return {}
pool= pooler.get_pool(cr.dbname) pool= pooler.get_pool(cr.dbname)
payment = pool.get('payment.order').browse(cr, uid, data['id'], order_obj = pool.get('payment.order')
line_obj = pool.get('account.move.line')
payment = order_obj.browse(cr, uid, data['id'],
context=context) context=context)
t= payment.mode and payment.mode.type.code or 'manual' t = payment.mode and payment.mode.type.code or 'manual'
line2bank= pool.get('account.move.line').line2bank(cr,uid, line2bank= pool.get('account.move.line').line2bank(cr, uid,
mline_ids,t,context) line_ids, t, context)
## Finally populate the current payment with new lines: ## Finally populate the current payment with new lines:
for line in pool.get('account.move.line').browse(cr, uid, mline_ids, for line in line_obj.browse(cr, uid, line_ids, context=context):
context=context):
pool.get('payment.line').create(cr,uid,{ pool.get('payment.line').create(cr,uid,{
'move_line_id': line.id, 'move_line_id': line.id,
'amount': line.amount_to_pay, 'amount_currency': line.amount_to_pay,
'bank_id': line2bank.get(line.id), 'bank_id': line2bank.get(line.id),
'order_id': payment.id, 'order_id': payment.id,
}) }, context=context)
return {} return {}
class wizard_payment_order(wizard.interface): class wizard_payment_order(wizard.interface):
""" """
Create a payment object with lines corresponding to the account move line Create a payment object with lines corresponding to the account move line
to pay according to the date and the mode provided by the user. to pay according to the date and the mode provided by the user.
Hypothesis: Hypothesis:
- Small number of non-reconcilied move line , payment mode and bank account type, - Small number of non-reconcilied move line , payment mode and bank account type,
- Big number of partner and bank account. - Big number of partner and bank account.
If a type is given, unsuitable account move lines are ignored. If a type is given, unsuitable account move lines are ignored.
""" """
states = {'init' : {'actions':[search_entries], states = {
'result': {'type':'form', 'init': {
'arch':ask_form, 'actions': [search_entries],
'fields':ask_fields, 'result': {
'state':[('end','_Cancel'),('create','_Add to payment order')]} 'type': 'form',
'arch': FORM,
}, 'fields': FIELDS,
'state': [
'create': {'actions': [], ('end','_Cancel'),
'result': {'type':'action', ('create','_Add to payment order', '', True)
'action':create_payment, ]
'state':'end'} },
}, },
'create': {
'actions': [],
'result': {
'type': 'action',
'action': create_payment,
'state': 'end'}
},
} }
wizard_payment_order('populate_payment') wizard_payment_order('populate_payment')

View File

@ -0,0 +1,121 @@
##############################################################################
#
# Copyright (c) 2005-2007 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# 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 wizard
import pooler
from tools.misc import UpdateableStr
FORM = UpdateableStr()
FIELDS = {
'lines': {'string': 'Payment Lines', 'type': 'many2many',
'relation': 'payment.line'},
}
def _search_entries(obj, cursor, user, data, context):
pool = pooler.get_pool(cursor.dbname)
line_obj = pool.get('payment.line')
statement_obj = pool.get('account.bank.statement')
statement = statement_obj.browse(cursor, user, data['id'], context=context)
line_ids = line_obj.search(cursor, user, [
('move_line_id.reconcile_id', '=', False),
('order_id.mode.journal.id', '=', statement.journal_id.id)])
line_ids.extend(line_obj.search(cursor, user, [
('move_line_id.reconcile_id', '=', False),
('order_id.mode', '=', False)]))
FORM.string = '''<?xml version="1.0"?>
<form string="Populate Statement:">
<field name="lines" colspan="4" height="300" width="800" nolabel="1"
domain="[('id', 'in', [%s])]"/>
</form>''' % (','.join([str(x) for x in line_ids]))
return {'lines': line_ids}
def _populate_statement(obj, cursor, user, data, context):
line_ids = data['form']['lines'][0][2]
if not line_ids:
return {}
pool = pooler.get_pool(cursor.dbname)
line_obj = pool.get('payment.line')
statement_obj = pool.get('account.bank.statement')
statement_line_obj = pool.get('account.bank.statement.line')
currency_obj = pool.get('res.currency')
statement_reconcile_obj = pool.get('account.bank.statement.reconcile')
statement = statement_obj.browse(cursor, user, data['id'], context=context)
for line in line_obj.browse(cursor, user, line_ids, context=context):
ctx = context.copy()
ctx['date'] = line.value_date
amount = currency_obj.compute(cursor, user, line.currency.id,
statement.currency.id, line.amount_currency, context=ctx)
reconcile_id = statement_reconcile_obj.create(cursor, user, {
'line_ids': [(6, 0, [line.move_line_id.id])]
}, context=context)
statement_line_obj.create(cursor, user, {
'name': line.order_id.reference or '?',
'amount': - amount,
'type': 'supplier',
'partner_id': line.partner_id.id,
'account_id': line.move_line_id.account_id.id,
'statement_id': statement.id,
'ref': line.reference,
'reconcile_id': reconcile_id,
}, context=context)
return {}
class PopulateStatement(wizard.interface):
"""
Populate the current statement with selected payement lines
"""
states = {
'init': {
'actions': [_search_entries],
'result': {
'type': 'form',
'arch': FORM,
'fields': FIELDS,
'state': [
('end', '_Cancel'),
('add', '_Add', '', True)
]
},
},
'add': {
'actions': [],
'result': {
'type': 'action',
'action': _populate_statement,
'state': 'end'
},
},
}
PopulateStatement('populate_statement')