1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
22 from osv import fields
29 class payment_type(osv.osv):
31 _description= 'Payment type'
33 'name': fields.char('Name', size=64, required=True,help='Payment Type'),
34 'code': fields.char('Code', size=64, required=True,help='Specify the Code for Payment Type'),
35 'suitable_bank_types': fields.many2many('res.partner.bank.type',
36 'bank_type_payment_type_rel',
37 'pay_type_id','bank_type_id',
38 'Suitable bank types')
44 class payment_mode(osv.osv):
46 _description= 'Payment mode'
48 'name': fields.char('Name', size=64, required=True,help='Mode of Payment'),
49 'bank_id': fields.many2one('res.partner.bank', "Bank account",
50 required=True,help='Bank Account for the Payment Mode'),
51 'journal': fields.many2one('account.journal', 'Journal', required=True,
52 domain=[('type', '=', 'cash')],help='Cash Journal for the Payment Mode'),
53 'type': fields.many2one('payment.type','Payment type',required=True,help='Select the Payment Type for the Payment Mode.'),
56 def suitable_bank_types(self,cr,uid,payment_code=None,context={}):
57 """Return the codes of the bank type that are suitable
58 for the given payment type code"""
61 cr.execute(""" select t.code
62 from res_partner_bank_type t
63 join bank_type_payment_type_rel r on (r.bank_type_id = t.id)
64 join payment_type pt on (r.pay_type_id = pt.id)
65 join payment_mode pm on (pm.type = pt.id)
66 where pm.id = %s """, [payment_code])
67 return [x[0] for x in cr.fetchall()]
71 class payment_order(osv.osv):
72 _name = 'payment.order'
73 _description = 'Payment Order'
74 _rec_name = 'reference'
76 def get_wizard(self,type):
77 logger = netsvc.Logger()
78 logger.notifyChannel("warning", netsvc.LOG_WARNING,
79 "No wizard found for the payment type '%s'." % type)
82 def _total(self, cursor, user, ids, name, args, context=None):
86 for order in self.browse(cursor, user, ids, context=context):
88 res[order.id] = reduce(lambda x, y: x + y.amount, order.line_ids, 0.0)
94 'date_planned': fields.date('Scheduled date if fixed', states={'done':[('readonly',True)]}, help='Select a date if you have chosen Preferred Date to be fixed.'),
95 'reference': fields.char('Reference', size=128, required=1, states={'done':[('readonly',True)]}),
96 'mode': fields.many2one('payment.mode','Payment mode', select=True, required=1, states={'done':[('readonly',True)]}, help='Select the Payment Mode to be applied.'),
97 'state': fields.selection([
100 ('cancel','Cancelled'),
101 ('done','Done')], 'State', select=True),
102 'line_ids': fields.one2many('payment.line','order_id','Payment lines',states={'done':[('readonly',True)]}),
103 'total': fields.function(_total, string="Total", method=True,
105 'user_id': fields.many2one('res.users','User', required=True, states={'done':[('readonly',True)]}),
106 'date_prefered': fields.selection([
109 ('fixed', 'Fixed date')
110 ], "Preferred date", change_default=True, required=True, states={'done':[('readonly',True)]}, help="Choose an option for the Payment Order:'Fixed' stands for a date specified by you.'Directly' stands for the direct execution.'Due date' stands for the scheduled date of execution."),
111 'date_created': fields.date('Creation date', readonly=True),
112 'date_done': fields.date('Execution date', readonly=True),
116 'user_id': lambda self,cr,uid,context: uid,
117 'state': lambda *a: 'draft',
118 'date_prefered': lambda *a: 'due',
119 'date_created': lambda *a: time.strftime('%Y-%m-%d'),
120 'reference': lambda self,cr,uid,context: self.pool.get('ir.sequence').get(cr, uid, 'payment.order'),
123 def set_to_draft(self, cr, uid, ids, *args):
124 self.write(cr, uid, ids, {'state':'draft'})
125 wf_service = netsvc.LocalService("workflow")
127 wf_service.trg_create(uid, 'payment.order', id, cr)
130 def action_open(self, cr, uid, ids, *args):
131 for order in self.read(cr,uid,ids,['reference']):
132 if not order['reference']:
133 reference = self.pool.get('ir.sequence').get(cr, uid, 'payment.order')
134 self.write(cr,uid,order['id'],{'reference':reference})
137 def set_done(self, cr, uid, id, *args):
138 self.write(cr,uid,id,{'date_done': time.strftime('%Y-%m-%d'),
140 wf_service = netsvc.LocalService("workflow")
141 wf_service.trg_validate(uid, 'payment.order', id, 'done', cr)
147 class payment_line(osv.osv):
148 _name = 'payment.line'
149 _description = 'Payment Line'
151 def translate(self, orig):
153 "due_date": "date_maturity",
154 "reference": "ref"}.get(orig, orig)
156 def info_owner(self, cr, uid, ids, name=None, args=None, context=None):
157 if not ids: return {}
160 for line in self.browse(cr, uid, ids, context=context):
161 owner=line.order_id.mode.bank_id.partner_id
162 result[line.id]=False
164 for ads in owner.address:
165 if ads.type=='default':
166 st=ads.street and ads.street or ''
167 st1=ads.street2 and ads.street2 or ''
169 zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or ''
171 zip=ads.zip and ads.zip or ''
172 city= ads.city and ads.city or ''
173 zip_city= zip + ' ' + city
174 cntry= ads.country_id and ads.country_id.name or ''
175 info=owner.name + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry
180 def info_partner(self, cr, uid, ids, name=None, args=None, context=None):
181 if not ids: return {}
184 for line in self.browse(cr, uid, ids, context=context):
185 result[line.id]=False
186 if not line.partner_id:
188 partner = line.partner_id.name or ''
189 if line.partner_id.address:
190 for ads in line.partner_id.address:
191 if ads.type=='default':
192 st=ads.street and ads.street or ''
193 st1=ads.street2 and ads.street2 or ''
195 zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or ''
197 zip=ads.zip and ads.zip or ''
198 city= ads.city and ads.city or ''
199 zip_city= zip + ' ' + city
200 cntry= ads.country_id and ads.country_id.name or ''
201 info=partner + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry
206 def select_by_name(self, cr, uid, ids, name, args, context=None):
207 if not ids: return {}
209 partner_obj = self.pool.get('res.partner')
210 cr.execute("""SELECT pl.id, ml.%s
211 from account_move_line ml
212 inner join payment_line pl
213 on (ml.id = pl.move_line_id)
214 where pl.id in %%s"""% self.translate(name),
216 res = dict(cr.fetchall())
218 if name == 'partner_id':
220 for p_id, p_name in partner_obj.name_get(cr,uid,
221 filter(lambda x:x and x != 0,res.values()),context=context):
222 partner_name[p_id] = p_name
225 if id in res and partner_name:
226 res[id] = (res[id],partner_name[res[id]])
228 res[id] = (False,False)
231 res.setdefault(id, (False, ""))
234 def _amount(self, cursor, user, ids, name, args, context=None):
237 currency_obj = self.pool.get('res.currency')
241 for line in self.browse(cursor, user, ids, context=context):
243 ctx['date'] = line.order_id.date_done or time.strftime('%Y-%m-%d')
244 res[line.id] = currency_obj.compute(cursor, user, line.currency.id,
245 line.company_currency.id,
246 line.amount_currency, context=ctx)
249 def _value_date(self, cursor, user, ids, name, args, context=None):
253 for line in self.browse(cursor, user, ids, context=context):
254 if line.order_id.date_prefered == 'fixed':
255 res[line.id] = line.order_id.date_planned
256 elif line.order_id.date_prefered == 'due':
257 res[line.id] = line.due_date or time.strftime('%Y-%m-%d')
259 res[line.id] = time.strftime('%Y-%m-%d')
262 def _get_currency(self, cr, uid, context):
263 user = self.pool.get('res.users').browse(cr, uid, uid)
265 return user.company_id.currency_id.id
267 return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
269 def _get_ml_inv_ref(self, cr, uid, ids, *a):
271 for id in self.browse(cr, uid, ids):
274 if id.move_line_id.invoice:
275 res[id.id] = id.move_line_id.invoice.id
278 def _get_ml_maturity_date(self, cr, uid, ids, *a):
280 for id in self.browse(cr, uid, ids):
282 res[id.id] = id.move_line_id.date_maturity
287 def _get_ml_created_date(self, cr, uid, ids, *a):
289 for id in self.browse(cr, uid, ids):
291 res[id.id] = id.move_line_id.date_created
297 'name': fields.char('Your Reference', size=64, required=True),
298 'communication': fields.char('Communication', size=64, required=True,help="Used as the message between ordering customer and current company. Depicts 'What do you want to say to the recipient about this order ?'"),
299 'communication2': fields.char('Communication 2', size=64,help='The successor message of Communication.'),
300 'move_line_id': fields.many2one('account.move.line','Entry line', domain=[('reconcile_id','=', False), ('account_id.type', '=','payable')],help='This Entry Line will be referred for the information of the ordering customer.'),
301 'amount_currency': fields.float('Amount in Partner Currency', digits=(16,2),
302 required=True, help='Payment amount in the partner currency'),
303 'currency': fields.many2one('res.currency','Partner Currency',required=True),
304 'company_currency': fields.many2one('res.currency','Company Currency',readonly=True),
305 'bank_id': fields.many2one('res.partner.bank', 'Destination Bank account'),
306 'order_id': fields.many2one('payment.order', 'Order', required=True,
307 ondelete='cascade', select=True),
308 'partner_id': fields.many2one('res.partner', string="Partner",required=True,help='The Ordering Customer'),
309 'amount': fields.function(_amount, string='Amount in Company Currency',
310 method=True, type='float',
311 help='Payment amount in the company currency'),
312 'ml_date_created': fields.function(_get_ml_created_date, string="Effective Date",
313 method=True, type='date',help="Invoice Effective Date"),
314 'ml_maturity_date': fields.function(_get_ml_maturity_date, method=True, type='date', string='Maturity Date'),
315 'ml_inv_ref': fields.function(_get_ml_inv_ref, method=True, type='many2one', relation='account.invoice', string='Invoice Ref.'),
316 'info_owner': fields.function(info_owner, string="Owner Account", method=True, type="text",help='Address of the Main Partner'),
317 'info_partner': fields.function(info_partner, string="Destination Account", method=True, type="text",help='Address of the Ordering Customer.'),
318 'date': fields.date('Payment Date',help="If no payment date is specified, the bank will treat this payment line directly"),
319 'create_date': fields.datetime('Created' ,readonly=True),
320 'state': fields.selection([('normal','Free'), ('structured','Structured')], 'Communication Type', required=True)
323 'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence'
324 ).get(cursor, user, 'payment.line'),
325 'state': lambda *args: 'normal',
326 'currency': _get_currency,
327 'company_currency': _get_currency,
330 ('name_uniq', 'UNIQUE(name)', 'The payment line name must be unique!'),
333 def onchange_move_line(self,cr,uid,ids,move_line_id,payment_type,date_prefered,date_planned,currency=False,company_currency=False,context=None):
336 data['amount_currency']=data['communication']=data['partner_id']=data['reference']=data['date_created']=data['bank_id']=data['amount']=False
339 line = self.pool.get('account.move.line').browse(cr,uid,move_line_id)
340 data['amount_currency']=line.amount_to_pay
342 res = self.onchange_amount(cr, uid, ids, data['amount_currency'], currency,
343 company_currency, context)
345 data['amount'] = res['value']['amount']
346 data['partner_id']=line.partner_id.id
347 temp = line.currency_id and line.currency_id.id or False
350 data['currency'] = line.invoice.currency_id.id
352 data['currency'] = temp
354 # calling onchange of partner and updating data dictionary
355 temp_dict=self.onchange_partner(cr,uid,ids,line.partner_id.id,payment_type)
356 data.update(temp_dict['value'])
358 data['reference']=line.ref
359 data['date_created'] = line.date_created
360 data['communication']=line.ref
362 if date_prefered == 'now':
363 #no payment date => immediate payment
365 elif date_prefered == 'due':
366 data['date'] = line.date_maturity
367 elif date_prefered == 'fixed':
368 data['date'] = date_planned
370 return {'value': data}
372 def onchange_amount(self, cr, uid, ids, amount, currency, cmpny_currency, context=None):
373 if (not amount) or (not cmpny_currency):
374 return {'value': {'amount':False}}
376 currency_obj = self.pool.get('res.currency')
377 company_amount = currency_obj.compute(cr, uid, currency, cmpny_currency, amount)
378 res['amount'] = company_amount
379 return {'value': res}
381 def onchange_partner(self,cr,uid,ids,partner_id,payment_type,context=None):
383 data['info_partner']=data['bank_id']=False
386 part_obj=self.pool.get('res.partner').browse(cr,uid,partner_id)
387 partner=part_obj.name or ''
390 for ads in part_obj.address:
391 if ads.type=='default':
392 st=ads.street and ads.street or ''
393 st1=ads.street2 and ads.street2 or ''
396 zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or ''
398 zip=ads.zip and ads.zip or ''
399 city= ads.city and ads.city or ''
400 zip_city= zip + ' ' + city
402 cntry= ads.country_id and ads.country_id.name or ''
403 info=partner + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry
405 data['info_partner']=info
407 if part_obj.bank_ids and payment_type:
408 bank_type = self.pool.get('payment.mode').suitable_bank_types(cr, uid, payment_type, context=context)
409 for bank in part_obj.bank_ids:
410 if bank.state in bank_type:
411 data['bank_id'] = bank.id
414 return {'value': data}
416 def fields_get(self, cr, uid, fields=None, context=None):
417 res = super(payment_line, self).fields_get(cr, uid, fields, context)
418 if 'communication2' in res:
419 res['communication2'].setdefault('states', {})
420 res['communication2']['states']['structured'] = [('readonly', True)]
421 res['communication2']['states']['normal'] = [('readonly', False)]
427 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: