def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, currency_type_from_code=False, currency_type_to_code=False, context=None): if not context: context = {} if not from_currency_id: from_currency_id = to_currency_id if not to_currency_id: to_currency_id = from_currency_id # Added to check context for currency rate types 'ask_rate', 'middle_rate' or 'bid_rate' if not currency_type_from_code: currency_type_from_code = context.get('currency_type_from_code') if not currency_type_to_code: currency_type_to_code = context.get('currency_type_to_code') # Check ends xc = self.browse(cr, uid, [from_currency_id, to_currency_id], context=context) from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1] to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1] force_currency_rate = 0.0 if context.get('force_currency_rate'): if not float_is_zero(context.get('force_currency_rate'), precision_digits=8): # if self.is_zero(self.cr, self.uid, currency, res['credit']) force_currency_rate = 1. / context.get('force_currency_rate') if context.get('force_currency_inv_rate'): force_currency_rate = context.get('force_currency_inv_rate') if not float_is_zero(force_currency_rate, precision_digits=8): if round: return self.round(cr, uid, to_currency, from_amount * force_currency_rate) else: return (from_amount * force_currency_rate) if (to_currency_id == from_currency_id) and (currency_type_from_code == currency_type_to_code): if round: return self.round(cr, uid, to_currency, from_amount) else: return from_amount else: context.update({'currency_type_from_code': currency_type_from_code, 'currency_type_to_code': currency_type_to_code}) rate = self._get_conversion_rate(cr, uid, from_currency, to_currency, context=context) if round: return self.round(cr, uid, to_currency, from_amount * rate) else: return (from_amount * rate)
def is_zero(self, cr, uid, currency, amount): """Returns true if ``amount`` is small enough to be treated as zero according to ``currency``'s rounding rules. Warning: ``is_zero(amount1-amount2)`` is not always equivalent to ``compare_amounts(amount1,amount2) == 0``, as the former will round after computing the difference, while the latter will round before, giving different results for e.g. 0.006 and 0.002 at 2 digits precision. :param browse_record currency: currency for which we are rounding :param float amount: amount to compare with currency's zero """ return float_is_zero(amount, precision_rounding=currency.rounding)
def reconcile_cash_discount(self, cr, uid, ids, move_ids, lines, write_off_ids=None, context=None): if not context: context = {} self._logger.debug( 'reconcile - action_move_line_create voucher ids, context %s,%s' % (ids, context)) move_obj = self.pool.get('account.move') move_line_obj = self.pool.get('account.move.line') voucher_obj = self.pool.get('account.voucher') invoice_obj = self.pool.get('account.invoice') invoice_tax_obj = self.pool.get('account.invoice.tax') move_reconcile_obj = self.pool.get('account.move.reconcile') obj_precision = self.pool.get('decimal.precision') prec = obj_precision.precision_get(cr, uid, 'Account') reconcile_ids = [] reconcile_base_id = '' write_off_debit = 0.0 write_off_credit = 0.0 partner_id = '' # collect necessary data for line in move_line_obj.browse(cr, uid, lines): self._logger.debug( 'reconcile voucher reconcile_id, acc_id, partner_id %s,%s %s %s' % (line.reconcile_id.id, line.account_id.id, line.partner_id.id, line.name)) # search move_ids which are reconciled if line.reconcile_id and line.reconcile_id.id not in reconcile_ids: reconcile_ids.append(line.reconcile_id.id) if not partner_id and line.partner_id: partner_id = line.partner_id.id if not reconcile_base_id: reconcile_base_id = line.reconcile_id.id if line.is_write_off: write_off_debit += line.debit write_off_credit += line.credit write_off_id = line.id if not reconcile_ids: return True self._logger.debug( 'reconcile - partner_id, line_ids, reconcile_ids: %s %s %s' % (partner_id, lines, reconcile_ids)) self._logger.debug('reconcile - writeoff deb/cred: %s/%s ' % (write_off_debit, write_off_credit)) if not isinstance(move_ids, list): move_ids = [move_ids] reconciled_move_line_ids = move_line_obj.search( cr, uid, [('move_id', 'not in', move_ids), ('partner_id', '=', partner_id), ('reconcile_id', 'in', reconcile_ids)]) if not isinstance(reconciled_move_line_ids, list): reconciled_move_line_ids = [reconciled_move_line_ids] self._logger.debug('reconcile - reconcile_move_line_ids: %s' % (reconciled_move_line_ids)) reconciled_move_ids = [] for move in move_line_obj.browse(cr, uid, reconciled_move_line_ids): if move.move_id.id not in reconciled_move_ids: reconciled_move_ids.append(move.move_id.id) if not isinstance(reconciled_move_ids, list): reconciled_move_ids = [reconciled_move_ids] self._logger.debug('reconcile - reconcile_move_ids: %s' % (reconciled_move_ids)) # now we find the invoice(s) invoice_ids = invoice_obj.search( cr, uid, [('move_id', 'in', reconciled_move_ids)]) if not isinstance(invoice_ids, list): invoice_ids = [invoice_ids] invoice_discount_ids = [] invoice_total = 0.0 invoice_discount_total = 0.0 invoice_discount_net = 0.0 tax_base_total = 0.0 tax_total = 0.0 for invoice in invoice_obj.browse(cr, uid, invoice_ids): invoice_total += invoice.amount_total if invoice.payment_term.is_discount: invoice_discount_ids.append(invoice.id) invoice_discount_total += invoice.amount_total invoice_discount_net += invoice.amount_untaxed for tax in invoice.tax_line: tax_base_total += tax.base_amount tax_total += tax.tax_amount # process of invoicees with cash discount if invoice_discount_ids: #tax_base_total = 0.0 #tax_total = 0.0 #invoice_tax_ids = invoice_tax_obj.search(cr, uid, [('invoice_id','in',invoice_discount_ids)]) #for tax in invoice_tax_obj.browse(cr, uid, invoice_tax_ids): # tax_base_total += tax.base_amount # tax_total += tax.tax_amount if write_off_debit > 0: factor = write_off_debit / invoice_total else: factor = write_off_credit / invoice_total self._logger.debug( 'reconcile - compare: %s invoice_discount_net= %s, factor : %s' % (invoice_discount_net, tax_base_total, factor)) #if not float_is_zero(invoice_discount_net - tax_base_total, prec): factor = factor * (tax_base_total / invoice_discount_net) self._logger.debug('reconcile - recalculate factor %s' % factor) self._logger.debug( 'reconcile - invoice_discount_ids: %s invoice_discount_total= %s, factor: %s' % (invoice_discount_ids, invoice_discount_total, factor)) invoice_discount_ids2 = ','.join( [str(id) for id in invoice_discount_ids]) # group cr.execute(""" select tax_code_id, payment_term, split_part(pi.value_reference,',',2)::int as discount_income_account_id, split_part(pe.value_reference,',',2)::int as discount_expense_account_id, t.account_id, t.tax_code_id, t.base_code_id, sum(base_amount) as base_amount, sum(tax_amount) as tax_amount, sum(tax_amount) * %s as tax_discount_amount, sum(base_amount) * %s as base_discount_amount from account_invoice i, account_invoice_tax t, account_payment_term p, account_payment_term_line pl, ir_property pe, ir_property pi where i.id in (%s) and t.invoice_id = i.id and p.id = i.payment_term and pl.payment_id = p.id and pl.discount > 0 and pi.res_id = 'account.payment.term.line,'||pl.id and pi.name ='discount_income_account_id' and pe.res_id = 'account.payment.term.line,'||pl.id and pe.name ='discount_expense_account_id' group by 1,2,3,4,5,6,7""" % (factor, factor, invoice_discount_ids2)) tax_moves = cr.dictfetchall() #if not tax_moves: # self._logger.debug('reconcile - no tax_lines: %s' % res) # return True self._logger.debug('reconcile - tax_moves: %s' % tax_moves) # get interesting data from write off record, which later will be deleted #tax_cum_amount=0.0 for r_line in move_line_obj.browse(cr, uid, [write_off_id]): ml = { 'move_id': r_line.move_id.id, 'journal_id': r_line.journal_id.id, 'period_id': r_line.period_id.id, 'date': r_line.date, 'name': r_line.name, 'debit': 0.0, 'credit': 0.0, 'company_id': r_line.company_id.id, 'name': _('Discount'), } for tax_move in tax_moves: # FIXME code can be simplified / condensed #base mlt = dict(ml) if write_off_debit > 0.0: mlt.update({ 'debit': tax_move['base_discount_amount'], 'credit': 0.0, 'account_id': tax_move['discount_expense_account_id'], 'tax_code_id': tax_move['base_code_id'], 'tax_amount': tax_move['base_discount_amount'], }) write_off_debit -= tax_move['base_discount_amount'] else: mlt.update({ 'debit': 0.0, 'credit': tax_move['base_discount_amount'], 'account_id': tax_move['discount_income_account_id'], 'tax_code_id': tax_move['base_code_id'], 'tax_amount': tax_move['base_discount_amount'], }) write_off_credit -= tax_move['base_discount_amount'] self._logger.debug('reconcile - base credit: %s' % mlt) move_line_obj.create(cr, uid, mlt) # tax mlt = dict(ml) if write_off_debit > 0.0: mlt.update({ 'debit': tax_move['tax_discount_amount'], 'credit': 0.0, 'account_id': tax_move['account_id'], 'analytic_account_id': False, 'tax_code_id': tax_move['tax_code_id'], 'tax_amount': tax_move['tax_discount_amount'], }) write_off_debit -= tax_move['tax_discount_amount'] else: mlt.update({ 'debit': 0.0, 'credit': tax_move['tax_discount_amount'], 'account_id': tax_move['account_id'], 'analytic_account_id': False, 'tax_code_id': tax_move['tax_code_id'], 'tax_amount': tax_move['tax_discount_amount'], }) write_off_credit -= tax_move['tax_discount_amount'] move_line_obj.create(cr, uid, mlt) # create move lines for remaining not discountable amount self._logger.debug( 'reconcile - writeoff deb/cred remaining: %s/%s ' % (write_off_debit, write_off_credit)) if not float_is_zero(write_off_debit, prec): self._logger.debug('reconcile - write_off_debit: %s' % write_off_debit) if not context.get('writeoff_acc_id', False): raise osv.except_osv(_('Error !'), _('No write off account defined.')) mlt = dict(ml) mlt.update({ 'debit': write_off_debit, 'credit': 0.0, 'account_id': context['writeoff_acc_id'], 'tax_code_id': False, 'tax_amount': False, }) move_line_obj.create(cr, uid, mlt) if not float_is_zero(write_off_credit, prec): self._logger.debug('reconcile - write_off_credit: %s' % write_off_credit) if not context.get('writeoff_acc_id', False): raise osv.except_osv(_('Error !'), _('No write off account defined.')) mlt = dict(ml) mlt.update({ 'credit': write_off_credit, 'debit': 0.0, 'account_id': context['writeoff_acc_id'], 'tax_code_id': False, 'tax_amount': False, }) move_line_obj.create(cr, uid, mlt) # delete originial move move_line_obj.unlink(cr, uid, [write_off_id], context) # set only ONE reconcile_id (instead of 2 or more) reconcile_lines_to_update = move_line_obj.search( cr, uid, [('reconcile_id', 'in', reconcile_ids), ('reconcile_id', '!=', reconcile_base_id)]) move_line_obj.write(cr, uid, reconcile_lines_to_update, {'reconcile_id': reconcile_base_id}, context) # delete unused recocile lines reconcile_ids_to_delete = [] for r_id in reconcile_ids: if r_id != reconcile_base_id: reconcile_ids_to_delete.append(r_id) move_reconcile_obj.unlink(cr, uid, reconcile_ids_to_delete) return True
def reconcile_cash_discount(self, cr, uid, ids, move_ids, lines, write_off_ids=None, context=None): if not context: context = {} self._logger.debug('reconcile - action_move_line_create voucher ids, context %s,%s' % (ids, context)) move_obj = self.pool.get('account.move') move_line_obj = self.pool.get('account.move.line') voucher_obj = self.pool.get('account.voucher') invoice_obj = self.pool.get('account.invoice') invoice_tax_obj = self.pool.get('account.invoice.tax') move_reconcile_obj = self.pool.get('account.move.reconcile') obj_precision = self.pool.get('decimal.precision') prec = obj_precision.precision_get(cr, uid, 'Account') reconcile_ids = [] reconcile_base_id = '' write_off_debit = 0.0 write_off_credit = 0.0 partner_id = '' # collect necessary data for line in move_line_obj.browse(cr, uid, lines): self._logger.debug('reconcile voucher reconcile_id, acc_id, partner_id %s,%s %s %s' % (line.reconcile_id.id, line.account_id.id, line.partner_id.id, line.name)) # search move_ids which are reconciled if line.reconcile_id and line.reconcile_id.id not in reconcile_ids: reconcile_ids.append(line.reconcile_id.id) if not partner_id and line.partner_id: partner_id = line.partner_id.id if not reconcile_base_id: reconcile_base_id = line.reconcile_id.id if line.is_write_off: write_off_debit += line.debit write_off_credit += line.credit write_off_id = line.id if not reconcile_ids: return True self._logger.debug('reconcile - partner_id, line_ids, reconcile_ids: %s %s %s' % (partner_id,lines, reconcile_ids)) self._logger.debug('reconcile - writeoff deb/cred: %s/%s ' % (write_off_debit,write_off_credit)) if not isinstance(move_ids,list): move_ids = [move_ids] reconciled_move_line_ids = move_line_obj.search(cr, uid, [('move_id','not in',move_ids),('partner_id','=', partner_id),('reconcile_id','in', reconcile_ids ) ]) if not isinstance(reconciled_move_line_ids, list): reconciled_move_line_ids = [reconciled_move_line_ids] self._logger.debug('reconcile - reconcile_move_line_ids: %s' % (reconciled_move_line_ids)) reconciled_move_ids = [] for move in move_line_obj.browse(cr, uid, reconciled_move_line_ids): if move.move_id.id not in reconciled_move_ids: reconciled_move_ids.append(move.move_id.id) if not isinstance(reconciled_move_ids, list): reconciled_move_ids = [reconciled_move_ids] self._logger.debug('reconcile - reconcile_move_ids: %s' % (reconciled_move_ids)) # now we find the invoice(s) invoice_ids = invoice_obj.search(cr, uid, [('move_id','in', reconciled_move_ids)]) if not isinstance(invoice_ids, list): invoice_ids = [invoice_ids] invoice_discount_ids = [] invoice_total = 0.0 invoice_discount_total = 0.0 invoice_discount_net = 0.0 tax_base_total = 0.0 tax_total = 0.0 for invoice in invoice_obj.browse(cr, uid, invoice_ids): invoice_total += invoice.amount_total if invoice.payment_term.is_discount: invoice_discount_ids.append(invoice.id) invoice_discount_total += invoice.amount_total invoice_discount_net += invoice.amount_untaxed for tax in invoice.tax_line: tax_base_total += tax.base_amount tax_total += tax.tax_amount # process of invoicees with cash discount if invoice_discount_ids: #tax_base_total = 0.0 #tax_total = 0.0 #invoice_tax_ids = invoice_tax_obj.search(cr, uid, [('invoice_id','in',invoice_discount_ids)]) #for tax in invoice_tax_obj.browse(cr, uid, invoice_tax_ids): # tax_base_total += tax.base_amount # tax_total += tax.tax_amount if write_off_debit > 0: factor = write_off_debit / invoice_total else: factor = write_off_credit / invoice_total self._logger.debug('reconcile - compare: %s invoice_discount_net= %s, factor : %s' % (invoice_discount_net, tax_base_total, factor)) #if not float_is_zero(invoice_discount_net - tax_base_total, prec): factor = factor * (tax_base_total / invoice_discount_net) self._logger.debug('reconcile - recalculate factor %s' % factor) self._logger.debug('reconcile - invoice_discount_ids: %s invoice_discount_total= %s, factor: %s' % (invoice_discount_ids, invoice_discount_total, factor)) invoice_discount_ids2 = ','.join([str(id) for id in invoice_discount_ids]) # group cr.execute(""" select tax_code_id, payment_term, split_part(pi.value_reference,',',2)::int as discount_income_account_id, split_part(pe.value_reference,',',2)::int as discount_expense_account_id, t.account_id, t.tax_code_id, t.base_code_id, sum(base_amount) as base_amount, sum(tax_amount) as tax_amount, sum(tax_amount) * %s as tax_discount_amount, sum(base_amount) * %s as base_discount_amount from account_invoice i, account_invoice_tax t, account_payment_term p, account_payment_term_line pl, ir_property pe, ir_property pi where i.id in (%s) and t.invoice_id = i.id and p.id = i.payment_term and pl.payment_id = p.id and pl.discount > 0 and pi.res_id = 'account.payment.term.line,'||pl.id and pi.name ='discount_income_account_id' and pe.res_id = 'account.payment.term.line,'||pl.id and pe.name ='discount_expense_account_id' group by 1,2,3,4,5,6,7""" % (factor, factor, invoice_discount_ids2)) tax_moves = cr.dictfetchall() #if not tax_moves: # self._logger.debug('reconcile - no tax_lines: %s' % res) # return True self._logger.debug('reconcile - tax_moves: %s' % tax_moves) # get interesting data from write off record, which later will be deleted #tax_cum_amount=0.0 for r_line in move_line_obj.browse(cr, uid, [write_off_id]): ml = { 'move_id' : r_line.move_id.id, 'journal_id' : r_line.journal_id.id, 'period_id' : r_line.period_id.id, 'date' : r_line.date , 'name' : r_line.name, 'debit' : 0.0, 'credit' : 0.0, 'company_id' : r_line.company_id.id, 'name' : _('Discount'), } for tax_move in tax_moves: # FIXME code can be simplified / condensed #base mlt = dict(ml) if write_off_debit > 0.0: mlt.update({ 'debit' : tax_move['base_discount_amount'], 'credit':0.0, 'account_id' : tax_move['discount_expense_account_id'], 'tax_code_id' : tax_move['base_code_id'], 'tax_amount' : tax_move['base_discount_amount'], }) write_off_debit -= tax_move['base_discount_amount'] else: mlt.update({ 'debit' : 0.0, 'credit' : tax_move['base_discount_amount'], 'account_id' : tax_move['discount_income_account_id'], 'tax_code_id' : tax_move['base_code_id'], 'tax_amount' : tax_move['base_discount_amount'], }) write_off_credit -= tax_move['base_discount_amount'] self._logger.debug('reconcile - base credit: %s' % mlt) move_line_obj.create(cr, uid, mlt) # tax mlt = dict(ml) if write_off_debit > 0.0: mlt.update({ 'debit' : tax_move['tax_discount_amount'], 'credit':0.0, 'account_id' : tax_move['account_id'], 'analytic_account_id' : False, 'tax_code_id' : tax_move['tax_code_id'], 'tax_amount' : tax_move['tax_discount_amount'], }) write_off_debit -= tax_move['tax_discount_amount'] else: mlt.update({ 'debit' : 0.0, 'credit' : tax_move['tax_discount_amount'], 'account_id' : tax_move['account_id'], 'analytic_account_id' : False, 'tax_code_id' : tax_move['tax_code_id'], 'tax_amount' : tax_move['tax_discount_amount'], }) write_off_credit -= tax_move['tax_discount_amount'] move_line_obj.create(cr, uid, mlt) # create move lines for remaining not discountable amount self._logger.debug('reconcile - writeoff deb/cred remaining: %s/%s ' % (write_off_debit,write_off_credit)) if not float_is_zero(write_off_debit, prec): self._logger.debug('reconcile - write_off_debit: %s' % write_off_debit) if not context.get('writeoff_acc_id',False): raise osv.except_osv (_('Error !'), _('No write off account defined.')) mlt = dict(ml) mlt.update({ 'debit' : write_off_debit, 'credit':0.0, 'account_id' : context['writeoff_acc_id'], 'tax_code_id' : False, 'tax_amount' : False, }) move_line_obj.create(cr, uid, mlt) if not float_is_zero(write_off_credit, prec): self._logger.debug('reconcile - write_off_credit: %s' % write_off_credit) if not context.get('writeoff_acc_id',False): raise osv.except_osv (_('Error !'), _('No write off account defined.')) mlt = dict(ml) mlt.update({ 'credit' : write_off_credit, 'debit' : 0.0, 'account_id' : context['writeoff_acc_id'], 'tax_code_id' : False, 'tax_amount' : False, }) move_line_obj.create(cr, uid, mlt) # delete originial move move_line_obj.unlink(cr, uid, [write_off_id], context) # set only ONE reconcile_id (instead of 2 or more) reconcile_lines_to_update = move_line_obj.search(cr, uid, [('reconcile_id','in',reconcile_ids),('reconcile_id','!=',reconcile_base_id)]) move_line_obj.write(cr, uid, reconcile_lines_to_update,{'reconcile_id':reconcile_base_id}, context) # delete unused recocile lines reconcile_ids_to_delete = [] for r_id in reconcile_ids: if r_id != reconcile_base_id: reconcile_ids_to_delete.append(r_id) move_reconcile_obj.unlink(cr, uid, reconcile_ids_to_delete) return True