# -*- coding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2010 Tiny SPRL (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # ############################################################################## import logging import time from openerp.osv import fields, osv _logger = logging.getLogger(__name__) class payment_mode(osv.osv): _name= 'payment.mode' _description= 'Payment Mode' _columns = { 'name': fields.char('Name', 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', 'in', ('bank','cash'))], help='Bank or Cash Journal for the Payment Mode'), 'company_id': fields.many2one('res.company', 'Company',required=True), 'partner_id':fields.related('company_id','partner_id',type='many2one',relation='res.partner',string='Partner',store=True,), } _defaults = { 'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id } def suitable_bank_types(self, cr, uid, payment_code=None, context=None): """Return the codes of the bank type that are suitable for the given payment type code""" if not payment_code: return [] cr.execute(""" SELECT pb.state FROM res_partner_bank pb JOIN payment_mode pm ON (pm.bank_id = pb.id) WHERE pm.id = %s """, [payment_code]) return [x[0] for x in cr.fetchall()] def onchange_company_id (self, cr, uid, ids, company_id=False, context=None): result = {} if company_id: partner_id = self.pool.get('res.company').browse(cr, uid, company_id, context=context).partner_id.id result['partner_id'] = partner_id return {'value': result} class payment_order(osv.osv): _name = 'payment.order' _description = 'Payment Order' _rec_name = 'reference' _order = 'id desc' #dead code def get_wizard(self, type): _logger.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_scheduled': fields.date('Scheduled Date', states={'done':[('readonly', True)]}, help='Select a date if you have chosen Preferred Date to be fixed.'), 'reference': fields.char('Reference', required=1, states={'done': [('readonly', True)]}, copy=False), 'mode': fields.many2one('payment.mode', 'Payment Mode', select=True, required=1, states={'done': [('readonly', True)]}, help='Select the Payment Mode to be applied.'), 'state': fields.selection([ ('draft', 'Draft'), ('cancel', 'Cancelled'), ('open', 'Confirmed'), ('done', 'Done')], 'Status', select=True, copy=False, help='When an order is placed the status is \'Draft\'.\n Once the bank is confirmed the status is set to \'Confirmed\'.\n Then the order is paid the status is \'Done\'.'), 'line_ids': fields.one2many('payment.line', 'order_id', 'Payment lines', states={'done': [('readonly', True)]}), 'total': fields.function(_total, string="Total", type='float'), 'user_id': fields.many2one('res.users', 'Responsible', required=True, states={'done': [('readonly', True)]}), 'date_prefered': fields.selection([ ('now', 'Directly'), ('due', 'Due date'), ('fixed', 'Fixed date') ], "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."), 'date_created': fields.date('Creation Date', readonly=True), 'date_done': fields.date('Execution Date', readonly=True), 'company_id': fields.related('mode', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), } _defaults = { 'user_id': lambda self,cr,uid,context: uid, 'state': 'draft', 'date_prefered': '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'}) self.create_workflow(cr, uid, ids) return True def action_open(self, cr, uid, ids, *args): ir_seq_obj = self.pool.get('ir.sequence') for order in self.read(cr, uid, ids, ['reference']): if not order['reference']: reference = ir_seq_obj.get(cr, uid, 'payment.order') self.write(cr, uid, order['id'], {'reference':reference}) return True def set_done(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'date_done': time.strftime('%Y-%m-%d')}) self.signal_workflow(cr, uid, ids, 'done') return True def write(self, cr, uid, ids, vals, context=None): if context is None: context = {} payment_line_obj = self.pool.get('payment.line') payment_line_ids = [] if (vals.get('date_prefered', False) == 'fixed' and not vals.get('date_scheduled', False)) or vals.get('date_scheduled', False): for order in self.browse(cr, uid, ids, context=context): for line in order.line_ids: payment_line_ids.append(line.id) payment_line_obj.write(cr, uid, payment_line_ids, {'date': vals.get('date_scheduled', False)}, context=context) elif vals.get('date_prefered', False) == 'due': vals.update({'date_scheduled': False}) for order in self.browse(cr, uid, ids, context=context): for line in order.line_ids: payment_line_obj.write(cr, uid, [line.id], {'date': line.ml_maturity_date}, context=context) elif vals.get('date_prefered', False) == 'now': vals.update({'date_scheduled': False}) for order in self.browse(cr, uid, ids, context=context): for line in order.line_ids: payment_line_ids.append(line.id) payment_line_obj.write(cr, uid, payment_line_ids, {'date': False}, context=context) return super(payment_order, self).write(cr, uid, ids, vals, context=context) class payment_line(osv.osv): _name = 'payment.line' _description = 'Payment Line' def translate(self, orig): return { "due_date": "date_maturity", "reference": "ref"}.get(orig, orig) def _info_owner(self, cr, uid, ids, name=None, args=None, context=None): result = {} for line in self.browse(cr, uid, ids, context=context): owner = line.order_id.mode.bank_id.partner_id result[line.id] = self._get_info_partner(cr, uid, owner, context=context) return result def _get_info_partner(self,cr, uid, partner_record, context=None): if not partner_record: return False st = partner_record.street or '' st1 = partner_record.street2 or '' zip = partner_record.zip or '' city = partner_record.city or '' zip_city = zip + ' ' + city cntry = partner_record.country_id and partner_record.country_id.name or '' return partner_record.name + "\n" + st + " " + st1 + "\n" + zip_city + "\n" +cntry def _info_partner(self, cr, uid, ids, name=None, args=None, context=None): result = {} for line in self.browse(cr, uid, ids, context=context): result[line.id] = False if not line.partner_id: break result[line.id] = self._get_info_partner(cr, uid, line.partner_id, context=context) return result #dead code 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), (tuple(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 _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 _get_currency(self, cr, uid, context=None): user_obj = self.pool.get('res.users') currency_obj = self.pool.get('res.currency') user = user_obj.browse(cr, uid, uid, context=context) if user.company_id: return user.company_id.currency_id.id else: return currency_obj.search(cr, uid, [('rate', '=', 1.0)])[0] def _get_date(self, cr, uid, context=None): if context is None: context = {} payment_order_obj = self.pool.get('payment.order') date = False if context.get('order_id') and context['order_id']: order = payment_order_obj.browse(cr, uid, context['order_id'], context=context) if order.date_prefered == 'fixed': date = order.date_scheduled else: date = time.strftime('%Y-%m-%d') return date 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] = False 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] = False return res _columns = { 'name': fields.char('Your Reference', required=True), 'communication': fields.char('Communication', 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 ?'"), 'communication2': fields.char('Communication 2', 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'), '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', type='float', help='Payment amount in the company currency'), 'ml_date_created': fields.function(_get_ml_created_date, string="Effective Date", type='date', help="Invoice Effective Date"), 'ml_maturity_date': fields.function(_get_ml_maturity_date, type='date', string='Due Date'), 'ml_inv_ref': fields.function(_get_ml_inv_ref, type='many2one', relation='account.invoice', string='Invoice Ref.'), 'info_owner': fields.function(_info_owner, string="Owner Account", type="text", help='Address of the Main Partner'), 'info_partner': fields.function(_info_partner, string="Destination Account", type="text", help='Address of the Ordering Customer.'), 'date': fields.date('Payment Date', help="If no payment date is specified, the bank will treat this payment line directly"), 'create_date': fields.datetime('Created', readonly=True), 'state': fields.selection([('normal','Free'), ('structured','Structured')], 'Communication Type', required=True), 'bank_statement_line_id': fields.many2one('account.bank.statement.line', 'Bank statement line'), 'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), } _defaults = { 'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence' ).get(cursor, user, 'payment.line'), 'state': 'normal', 'currency': _get_currency, 'company_currency': _get_currency, 'date': _get_date, } _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_scheduled, currency=False, company_currency=False, context=None): data = {} move_line_obj = self.pool.get('account.move.line') data['amount_currency'] = data['communication'] = data['partner_id'] = data['bank_id'] = data['amount'] = False if move_line_id: line = move_line_obj.browse(cr, uid, move_line_id, context=context) data['amount_currency'] = line.amount_residual_currency 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['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_scheduled return {'value': data} def onchange_amount(self, cr, uid, ids, amount, currency, cmpny_currency, context=None): if (not amount) or (not cmpny_currency): return {'value': {'amount': False}} 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 = {} partner_obj = self.pool.get('res.partner') payment_mode_obj = self.pool.get('payment.mode') data['info_partner'] = data['bank_id'] = False if partner_id: part_obj = partner_obj.browse(cr, uid, partner_id, context=context) partner = part_obj.name or '' data['info_partner'] = self._get_info_partner(cr, uid, part_obj, context=context) if part_obj.bank_ids and payment_type: bank_type = payment_mode_obj.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, write_access=True, attributes=None): res = super(payment_line, self).fields_get(cr, uid, fields, context, write_access, attributes) if 'communication2' in res: res['communication2'].setdefault('states', {}) res['communication2']['states']['structured'] = [('readonly', True)] res['communication2']['states']['normal'] = [('readonly', False)] return res # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: