# -*- encoding: utf-8 -*- ############################################################################## # # Copyright (c) 2004-2008 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. # ############################################################################## from osv import fields from osv import osv import time import netsvc import pooler class payment_type(osv.osv): _name= 'payment.type' _description= 'Payment type' _columns= { 'name': fields.char('Name', size=64, required=True,help='Payment Type'), 'code': fields.char('Code', size=64, required=True,help='Specify the Code for Payment Type'), 'suitable_bank_types': fields.many2many('res.partner.bank.type', 'bank_type_payment_type_rel', 'pay_type_id','bank_type_id', 'Suitable bank types') } payment_type() class payment_mode(osv.osv): _name= 'payment.mode' _description= 'Payment mode' _columns= { 'name': fields.char('Name', size=64, required=True,help='Mode of Payment'), 'bank_id': fields.many2one('res.partner.bank', "Bank account", required=True,help='Bank Account for the Payment Mode'), 'journal': fields.many2one('account.journal', 'Journal', required=True, domain=[('type', '=', 'cash')],help='Cash Journal for the Payment Mode'), 'type': fields.many2one('payment.type','Payment type',required=True,help='Select the Payment Type for the Payment Mode.'), } def suitable_bank_types(self,cr,uid,payment_code=None,context={}): """Return the codes of the bank type that are suitable for the given payment type code""" if not payment_code: return [] cr.execute(""" select t.code from res_partner_bank_type t 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_mode pm on (pm.type = pt.id) where pm.id = %s """, [payment_code]) return [x[0] for x in cr.fetchall()] payment_mode() class payment_order(osv.osv): _name = 'payment.order' _description = 'Payment Order' _rec_name = 'reference' def get_wizard(self,type): logger = netsvc.Logger() logger.notifyChannel("warning", netsvc.LOG_WARNING, "No wizard found for the payment type '%s'." % type) return None def _total(self, cursor, user, ids, name, args, context=None): if not ids: return {} res = {} for order in self.browse(cursor, user, ids, context=context): if order.line_ids: res[order.id] = reduce(lambda x, y: x + y.amount, order.line_ids, 0.0) else: res[order.id] = 0.0 return res _columns = { 'date_planned': fields.date('Scheduled date if fixed',help='Select a date if you have chosen Preferred Date to be fixed.'), 'reference': fields.char('Reference',size=128,required=1), 'mode': fields.many2one('payment.mode','Payment mode', select=True, required=1,help='Select the Payment Mode to be applied.'), 'state': fields.selection([ ('draft', 'Draft'), ('open','Confirmed'), ('cancel','Cancelled'), ('done','Done')], 'State', select=True), 'line_ids': fields.one2many('payment.line','order_id','Payment lines',states={'done':[('readonly',True)]}), 'total': fields.function(_total, string="Total", method=True, type='float'), 'user_id': fields.many2one('res.users','User',required=True), 'date_prefered': fields.selection([ ('now', 'Directly'), ('due', 'Due date'), ('fixed', 'Fixed date') ], "Prefered date", change_default=True, required=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."), 'date_created': fields.date('Creation date', readonly=True), 'date_done': fields.date('Execution date', readonly=True), } _defaults = { 'user_id': lambda self,cr,uid,context: uid, 'state': lambda *a: 'draft', 'date_prefered': lambda *a: 'due', '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): self.write(cr, uid, ids, {'state':'draft'}) wf_service = netsvc.LocalService("workflow") for id in ids: wf_service.trg_create(uid, 'payment.order', id, cr) return True def action_open(self, cr, uid, ids, *args): for order in self.read(cr,uid,ids,['reference']): if not order['reference']: reference = self.pool.get('ir.sequence').get(cr, uid, 'payment.order') self.write(cr,uid,order['id'],{'reference':reference}) return True def set_done(self, cr, uid, id, *args): self.write(cr,uid,id,{'date_done': time.strftime('%Y-%m-%d'), 'state': 'done',}) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'payment.order', id, 'done', cr) return True payment_order() class payment_line(osv.osv): _name = 'payment.line' _description = 'Payment Line' #~ def partner_payable(self, cr, uid, ids, name, args, context={}): #~ if not ids: return {} #~ partners= self.read(cr, uid, ids, ['partner_id'], context) #~ partners= dict(map(lambda x: (x['id'], x['partner_id'][0]), partners)) #~ debit = self.pool.get('res.partner')._debit_get(cr, uid, #~ partners.values(), name, args, context) #~ for i in partners: #~ partners[i] = debit[partners[i]] #~ return partners def translate(self, orig): return { # "to_pay": "credit", "due_date": "date_maturity", "reference": "ref"}.get(orig, orig) def info_owner(self, cr, uid, ids, name=None, args=None, context=None): if not ids: return {} result = {} info='' for line in self.browse(cr, uid, ids, context=context): owner=line.order_id.mode.bank_id.partner_id result[line.id]=False if owner.address: for ads in owner.address: if ads.type=='default': st=ads.street and ads.street or '' st1=ads.street2 and ads.street2 or '' if 'zip_id' in ads: zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or '' else: zip=ads.zip and ads.zip or '' city= ads.city and ads.city or '' zip_city= zip + ' ' + city cntry= ads.country_id and ads.country_id.name or '' info=owner.name + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry result[line.id]=info break return result def info_partner(self, cr, uid, ids, name=None, args=None, context=None): if not ids: return {} result = {} info='' for line in self.browse(cr, uid, ids, context=context): result[line.id]=False if not line.partner_id: break partner = line.partner_id.name or '' if line.partner_id.address: for ads in line.partner_id.address: if ads.type=='default': st=ads.street and ads.street or '' st1=ads.street2 and ads.street2 or '' if 'zip_id' in ads: zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or '' else: zip=ads.zip and ads.zip or '' city= ads.city and ads.city or '' zip_city= zip + ' ' + city cntry= ads.country_id and ads.country_id.name or '' info=partner + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry result[line.id]=info break return result def select_by_name(self, cr, uid, ids, name, args, context=None): if not ids: return {} 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 and partner_name: 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.company_currency.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 def _get_currency(self, cr, uid, context): user = self.pool.get('res.users').browse(cr, uid, uid) if user.company_id: return user.company_id.currency_id.id else: return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0] # def select_move_lines(*a): # print a # return [] # def create(self, cr, uid, vals, context): # print "created!!!" # vals['company_currency'] = self._get_currency(cr, uid, context) # return super(payment_line, self).create(cr, uid, vals, context) def _get_ml_inv_ref(self, cr, uid, ids, *a): res={} for id in self.browse(cr, uid, ids): res[id.id] = False if id.move_line_id: if id.move_line_id.invoice: res[id.id] = id.move_line_id.invoice.id return res def _get_ml_maturity_date(self, cr, uid, ids, *a): res={} for id in self.browse(cr, uid, ids): if id.move_line_id: res[id.id] = id.move_line_id.date_maturity else: res[id.id] = "" return res def _get_ml_created_date(self, cr, uid, ids, *a): res={} for id in self.browse(cr, uid, ids): if id.move_line_id: res[id.id] = id.move_line_id.date_created else: res[id.id] = "" return res _columns = { 'name': fields.char('Your Reference', size=64, required=True), '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 receipent about this oder?'"), 'communication2': fields.char('Communication 2', size=64,help='The successor message of Communication.'), '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.'), 'amount_currency': fields.float('Amount in Partner Currency', digits=(16,2), required=True, help='Payment amount in the partner currency'), # 'to_pay_currency': fields.function(_to_pay_currency, string='To Pay', # method=True, type='float', # help='Amount to pay in the partner currency'), # 'currency': fields.function(_currency, string='Currency', # method=True, type='many2one', obj='res.currency'), 'currency': fields.many2one('res.currency','Partner Currency',required=True), 'company_currency': fields.many2one('res.currency','Company Currency',readonly=True), 'bank_id': fields.many2one('res.partner.bank', 'Destination Bank account'), 'order_id': fields.many2one('payment.order', 'Order', required=True, ondelete='cascade', select=True), 'partner_id': fields.many2one('res.partner', string="Partner",required=True,help='The Ordering Customer'), 'amount': fields.function(_amount, string='Amount in Company Currency', 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'), 'ml_date_created': fields.function(_get_ml_created_date, string="Effective Date", method=True, type='date',help="Invoice Effective Date"), # 'reference': fields.function(select_by_name, string="Ref", method=True, # type='char'), 'ml_maturity_date': fields.function(_get_ml_maturity_date, method=True, type='char', string='Maturity Date'), 'ml_inv_ref': fields.function(_get_ml_inv_ref, method=True, type='many2one', relation='account.invoice', string='Invoice Ref'), 'info_owner': fields.function(info_owner, string="Owner Account", method=True, type="text",help='Address of the Main Partner'), 'info_partner': fields.function(info_partner, string="Destination Account", method=True, type="text",help='Address of the Ordering Customer.'), # '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'), 'date': fields.date('Payment Date',help="If no payment date is specified, the bank will treat this payment line direclty"), 'create_date': fields.datetime('Created' ,readonly=True), 'state': fields.selection([('normal','Free'), ('structured','Structured')], 'Communication Type', required=True) } _defaults = { 'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence' ).get(cursor, user, 'payment.line'), 'state': lambda *args: 'normal', 'currency': _get_currency, 'company_currency': _get_currency, } _sql_constraints = [ ('name_uniq', 'UNIQUE(name)', 'The payment line name must be unique!'), ] def onchange_move_line(self,cr,uid,ids,move_line_id,payment_type,date_prefered,date_planned,currency=False,company_currency=False,context=None): data={} data['amount_currency']=data['communication']=data['partner_id']=data['reference']=data['date_created']=data['bank_id']=data['amount']=False if move_line_id: line = self.pool.get('account.move.line').browse(cr,uid,move_line_id) data['amount_currency']=line.amount_to_pay res = self.onchange_amount(cr, uid, ids, data['amount_currency'], currency, company_currency, context) if res: data['amount'] = res['value']['amount'] data['partner_id']=line.partner_id.id temp = line.currency_id and line.currency_id.id or False if not temp: if line.invoice: data['currency'] = line.invoice.currency_id.id else: data['currency'] = temp # calling onchange of partner and updating data dictionary temp_dict=self.onchange_partner(cr,uid,ids,line.partner_id.id,payment_type) data.update(temp_dict['value']) data['reference']=line.ref data['date_created'] = line.date_created data['communication']=line.ref if date_prefered == 'now': #no payment date => immediate payment data['date'] = False elif date_prefered == 'due': data['date'] = line.date_maturity elif date_prefered == 'fixed': data['date'] = date_planned return {'value': data} def onchange_amount(self,cr,uid,ids,amount,currency,cmpny_currency,context=None): if not amount: return {} res = {} currency_obj = self.pool.get('res.currency') company_amount = currency_obj.compute(cr, uid, currency, cmpny_currency,amount) res['amount'] = company_amount return {'value': res} def onchange_partner(self,cr,uid,ids,partner_id,payment_type,context=None): data={} data['info_partner']=data['bank_id']=False if partner_id: part_obj=self.pool.get('res.partner').browse(cr,uid,partner_id) partner=part_obj.name or '' if part_obj.address: for ads in part_obj.address: if ads.type=='default': st=ads.street and ads.street or '' st1=ads.street2 and ads.street2 or '' if 'zip_id' in ads: zip_city= ads.zip_id and self.pool.get('res.partner.zip').name_get(cr,uid,[ads.zip_id.id])[0][1] or '' else: zip=ads.zip and ads.zip or '' city= ads.city and ads.city or '' zip_city= zip + ' ' + city cntry= ads.country_id and ads.country_id.name or '' info=partner + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry data['info_partner']=info if part_obj.bank_ids and payment_type: bank_type = self.pool.get('payment.mode').suitable_bank_types(cr, uid, payment_type, context=context) for bank in part_obj.bank_ids: if bank.state in bank_type: data['bank_id'] = bank.id break return {'value': data} def fields_get(self, cr, uid, fields=None, context=None): res = super(payment_line, self).fields_get(cr, uid, fields, context) if 'communication2' in res: res['communication2'].setdefault('states', {}) res['communication2']['states']['structured'] = [('readonly', True)] res['communication2']['states']['normal'] = [('readonly', False)] return res payment_line() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: