Join the social network of Tech Nerds, increase skill rank, get work, manage projects...
 
  • How to get right debit / credit in accounting module?

    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 461
    Comment on it

    If you want to get right debit / credit in accounting module follow the following code .

     target_currency = target_currency or company_currency
                line_currency = line.currency_id or company_currency
                amount_currency_str = ""
                total_amount_currency_str = ""
                if line_currency != company_currency:
                    total_amount = line.amount_currency
                    actual_debit = debit > 0 and amount_currency or 0.0
                    actual_credit = credit > 0 and -amount_currency or 0.0
                else:
                    total_amount = abs(debit - credit)
                    actual_debit = debit > 0 and amount or 0.0
                    actual_credit = credit > 0 and -amount or 0.0
                if line_currency != target_currency:
                    amount_currency_str = formatLang(self.env, abs(actual_debit or actual_credit), currency_obj=line_currency)
                    total_amount_currency_str = formatLang(self.env, total_amount, currency_obj=line_currency)
                    ctx = context.copy()
                    ctx.update({'date': line.date})
                    total_amount = line_currency.with_context(ctx).compute(total_amount, target_currency)
                    actual_debit = line_currency.with_context(ctx).compute(actual_debit, target_currency)
                    actual_credit = line_currency.with_context(ctx).compute(actual_credit, target_currency)
                amount_str = formatLang(self.env, abs(actual_debit or actual_credit), currency_obj=target_currency)
                total_amount_str = formatLang(self.env, total_amount, currency_obj=target_currency)
    
                ret_line['debit'] = abs(actual_debit)
                ret_line['credit'] = abs(actual_credit)
                ret_line['amount_str'] = amount_str
                ret_line['total_amount_str'] = total_amount_str
                ret_line['amount_currency_str'] = amount_currency_str
                ret_line['total_amount_currency_str'] = total_amount_currency_str
                ret.append(ret_line)
            return ret
    
        @api.v7
        def process_reconciliations(self, cr, uid, data, context=None):
            """ Used to validate a batch of reconciliations in a single call
                :param data: list of dicts containing:
                    - 'type': either 'partner' or 'account'
                    - 'id': id of the affected res.partner or account.account
                    - 'mv_line_ids': ids of exisiting account.move.line to reconcile
                    - 'new_mv_line_dicts': list of dicts containing values suitable for account_move_line.create()
            """
            for datum in data:
                if len(datum['mv_line_ids']) >= 1 or len(datum['mv_line_ids']) + len(datum['new_mv_line_dicts']) >= 2:
                    self.process_reconciliation(cr, uid, datum['mv_line_ids'], datum['new_mv_line_dicts'], context=context)
    
                if datum['type'] == 'partner':
                    partners = self.pool['res.partner'].browse(cr, uid, datum['id'], context=context)
                    self.pool['res.partner'].mark_as_reconciled(cr, uid, partners.ids, context=context)
                if datum['type'] == 'account':
                    accounts = self.pool['account.account'].browse(cr, uid, datum['id'], context=context)
                    self.pool['account.account'].mark_as_reconciled(cr, uid, accounts.ids, context=context)
    
        @api.v7
        def process_reconciliation(self, cr, uid, mv_line_ids, new_mv_line_dicts, context=None):
            return self.browse(cr, uid, mv_line_ids, context).process_reconciliation(new_mv_line_dicts)
    
        @api.v8
        def process_reconciliation(self, new_mv_line_dicts):
            """ Create new move lines from new_mv_line_dicts (if not empty) then call reconcile_partial on self and new move lines
    
                :param new_mv_line_dicts: list of dicts containing values suitable fot account_move_line.create()
            """
            if len(self) < 1 or len(self) + len(new_mv_line_dicts) < 2:
                raise UserError(_('Error!'), _('A reconciliation must involve at least 2 move lines.'))
    
            # Create writeoff move lines
            if len(new_mv_line_dicts) > 0:
                writeoff_lines = self.env['account.move.line']
                company_currency = self[0].account_id.company_id.currency_id
                account_currency = self[0].account_id.currency_id or company_currency
                for mv_line_dict in new_mv_line_dicts:
                    if account_currency != company_currency:
                        mv_line_dict['debit'] = account_currency.compute(mv_line_dict['debit'], company_currency)
                        mv_line_dict['credit'] = account_currency.compute(mv_line_dict['credit'], company_currency)
                    writeoff_lines += self._create_writeoff(mv_line_dict)
    
                (self + writeoff_lines).reconcile()
            else:
                self.reconcile()
    
        ####################################################
        # Reconciliation methods
        ####################################################
    
        def _get_pair_to_reconcile(self):
            #field is either 'amount_residual' or 'amount_residual_currency' (if the reconciled account has a secondary currency set)
            field = self[0].account_id.currency_id and 'amount_residual_currency' or 'amount_residual'
            #target the pair of move in self that are the oldest
            sorted_moves = sorted(self, key=lambda a: a.date)
            debit = credit = False
            for aml in sorted_moves:
                if credit != False and debit != False:
                    break
                if aml[field] > 0 and debit == False:
                    debit = aml
                elif aml[field] < 0 and credit == False:
                    credit = aml
            return debit, credit
    
        def auto_reconcile_lines(self):
            """ This function iterates recursively on the recordset given as parameter as long as it
                can find a debit and a credit to reconcile together. It returns the recordset of the
                account move lines that were not reconciled during the process.
            """
            if not self.ids:
                return self
            field = self[0].account_id.currency_id and 'amount_residual_currency' or 'amount_residual'
            sm_debit_move, sm_credit_move = self._get_pair_to_reconcile()
            #there is no more pair to reconcile so return what move_line are left
            if not sm_credit_move or not sm_debit_move:
                return self
    
            #Reconcile the pair together
            amount_reconcile = min(sm_debit_move[field], -sm_credit_move[field])
            #Remove from recordset the one(s) that will be totally reconciled
            if amount_reconcile == sm_debit_move[field]:
                self -= sm_debit_move
            if amount_reconcile == -sm_credit_move[field]:
                self -= sm_credit_move
    
            #Check for the currency and amount_currency we can set
            currency = False
            amount_reconcile_currency = 0
            if sm_debit_move.currency_id == sm_credit_move.currency_id and sm_debit_move.currency_id.id:
                currency = sm_credit_move.currency_id.id
                amount_reconcile_currency = min(sm_debit_move.amount_residual_currency, -sm_credit_move.amount_residual_currency)
    
            amount_reconcile = min(sm_debit_move.amount_residual, -sm_credit_move.amount_residual)
    
            self.env['account.partial.reconcile'].create({
                'debit_move_id': sm_debit_move.id,
                'credit_move_id': sm_credit_move.id,
                'amount': amount_reconcile,
                'amount_currency': amount_reconcile_currency,
                'currency_id': currency,
            })
    
            #Iterate process again on self
            return self.auto_reconcile_lines()
    
        @api.multi
        def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False):
            #Perform all checks on lines
            company_ids = set()
            all_accounts = []
            partners = set()
            for line in self:
                company_ids.add(line.company_id.id)
                all_accounts.append(line.account_id)
                if (line.account_id.internal_type in ('receivable', 'payable')):
                    partners.add(line.partner_id.id)
                if line.reconciled:
                    raise UserError(_('You are trying to reconcile some entries that are already reconciled!'))
            if len(company_ids) > 1:
                raise UserError(_('To reconcile the entries company should be the same for all entries!'))
            if len(set(all_accounts)) > 1:
                raise UserError(_('Entries are not of the same account!'))
            if not all_accounts[0].reconcile:
                raise UserError(_('The account %s (%s) is not marked as reconciliable !') % (all_accounts[0].name, all_accounts[0].code))
            if len(partners) > 1:
                raise UserError(_('The partner has to be the same on all lines for receivable and payable accounts!'))
    
            #reconcile everything that can be
            remaining_moves = self.auto_reconcile_lines()
    
            #if writeoff_acc_id specified, then create write-off move with value the remaining amount from move in self
            if writeoff_acc_id and writeoff_journal_id and remaining_moves:
                writeoff_to_reconcile = remaining_moves._create_writeoff({'account_id': writeoff_acc_id.id, 'journal_id': writeoff_journal_id.id})
                #add writeoff line to reconcile algo and finish the reconciliation
                remaining_moves = (remaining_moves + writeoff_to_reconcile).auto_reconcile_lines()
    
        def _create_writeoff(self, vals):
            """ Create a writeoff move for the account.move.lines in self. If debit/credit is not specified in vals,
                the writeoff amount will be computed as the sum of amount_residual of the given recordset.
    
                :param vals: dict containing values suitable fot account_move_line.create(). The data in vals will
                    be processed to create bot writeoff acount.move.line and their enclosing account.move.
            """
            # Check and complete vals
            if 'account_id' not in vals or 'journal_id' not in vals:
                raise UserError(_("It is mandatory to specify an account and a journal to create a write-off."))
            if ('debit' in vals) ^ ('credit' in vals):
                raise UserError(_("Either pass both debit and credit or none."))
            if 'date' not in vals:
                vals['date'] = self._context.get('date_p') or time.strftime('%Y-%m-%d')
            if 'name' not in vals:
                vals['name'] = self._context.get('comment') or _('Write-Off')
            #compute the writeoff amount if not given
            if 'credit' not in vals and 'debit' not in vals:
                amount = sum([r.amount_residual for r in self])
                vals['credit'] = amount > 0 and amount or 0.0
                vals['debit'] = amount < 0 and abs(amount) or 0.0
            vals['partner_id'] = self.env['res.partner']._find_accounting_partner(self[0].partner_id).id
            company_currency = self[0].account_id.company_id.currency_id
            account_currency = self[0].account_id.currency_id or company_currency
            if 'amount_currency' not in vals and account_currency != company_currency:
                vals['currency_id'] = account_currency
                vals['amount_currency'] = sum([r.amount_residual_currency for r in self])
    
            # Writeoff line in the account of self
            first_line_dict = vals.copy()
            first_line_dict['account_id'] = self[0].account_id.id
            if 'analytic_account_id' in vals:
                del vals['analytic_account_id']
    
            # Writeoff line in specified writeoff account
            second_line_dict = vals.copy()
            second_line_dict['debit'], second_line_dict['credit'] = second_line_dict['credit'], second_line_dict['debit']
            if 'amount_currency' in vals:
                second_line_dict['amount_currency'] = -second_line_dict['amount_currency']
    
            # Create the move
            writeoff_move = self.env['account.move'].create({
                'journal_id': vals['journal_id'],
                'date': vals['date'],
                'state': 'draft',
                'line_ids': [(0, 0, first_line_dict), (0, 0, second_line_dict)],
            })
            writeoff_move.post()
    
            # Return the writeoff move.line which is to be reconciled
            return writeoff_move.line_ids.filtered(lambda r: r.account_id == self[0].account_id)

     

 0 Comment(s)

Sign In
                           OR                           
                           OR                           
Register

Sign up using

                           OR                           
Forgot Password
Fill out the form below and instructions to reset your password will be emailed to you:
Reset Password
Fill out the form below and reset your password: