Launchpad automatic translations update.
[odoo/odoo.git] / addons / account / account_move_line.py
old mode 100755 (executable)
new mode 100644 (file)
index 2522e53..bd22bd2
@@ -45,7 +45,11 @@ class account_move_line(osv.osv):
         if context.get('company_id', False):
             company_clause = " AND " +obj+".company_id = %s" % context.get('company_id', False)
         if not context.get('fiscalyear', False):
-            fiscalyear_ids = fiscalyear_obj.search(cr, uid, [('state', '=', 'draft')])
+            if context.get('all_fiscalyear', False):
+                #this option is needed by the aged balance report because otherwise, if we search only the draft ones, an open invoice of a closed fiscalyear won't be displayed
+                fiscalyear_ids = fiscalyear_obj.search(cr, uid, [])
+            else:
+                fiscalyear_ids = fiscalyear_obj.search(cr, uid, [('state', '=', 'draft')])
         else:
             #for initial balance as well as for normal query, we check only the selected FY because the best practice is to generate the FY opening entries
             fiscalyear_ids = [context['fiscalyear']]
@@ -57,7 +61,7 @@ class account_move_line(osv.osv):
 
         if context.get('date_from', False) and context.get('date_to', False):
             if initial_bal:
-                where_move_lines_by_date = " OR " +obj+".move_id IN (SELECT id FROM account_move WHERE date < '" +context['date_from']+"')"
+                where_move_lines_by_date = " AND " +obj+".move_id IN (SELECT id FROM account_move WHERE date < '" +context['date_from']+"')"
             else:
                 where_move_lines_by_date = " AND " +obj+".move_id IN (SELECT id FROM account_move WHERE date >= '" +context['date_from']+"' AND date <= '"+context['date_to']+"')"
 
@@ -74,7 +78,7 @@ class account_move_line(osv.osv):
                 context['periods'] = fiscalperiod_obj.build_ctx_periods(cr, uid, context['period_from'], context['period_to'])
         if context.get('periods', False):
             if initial_bal:
-                query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s) %s %s)" % (fiscalyear_clause, where_move_state, where_move_lines_by_date)
+                query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s)) %s %s" % (fiscalyear_clause, where_move_state, where_move_lines_by_date)
                 period_ids = fiscalperiod_obj.search(cr, uid, [('id', 'in', context['periods'])], order='date_start', limit=1)
                 if period_ids and period_ids[0]:
                     first_period = fiscalperiod_obj.browse(cr, uid, period_ids[0], context=context)
@@ -87,7 +91,7 @@ class account_move_line(osv.osv):
                 ids = ','.join([str(x) for x in context['periods']])
                 query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s) AND id IN (%s)) %s %s" % (fiscalyear_clause, ids, where_move_state, where_move_lines_by_date)
         else:
-            query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s) %s %s)" % (fiscalyear_clause, where_move_state, where_move_lines_by_date)
+            query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s)) %s %s" % (fiscalyear_clause, where_move_state, where_move_lines_by_date)
 
         if context.get('journal_ids', False):
             query += ' AND '+obj+'.journal_id IN (%s)' % ','.join(map(str, context['journal_ids']))
@@ -97,9 +101,59 @@ class account_move_line(osv.osv):
             query += ' AND '+obj+'.account_id IN (%s)' % ','.join(map(str, child_ids))
 
         query += company_clause
-
         return query
 
+    def _amount_residual(self, cr, uid, ids, field_names, args, context=None):
+        """
+           This function returns the residual amount on a receivable or payable account.move.line.
+           By default, it returns an amount in the currency of this journal entry (maybe different
+           of the company currency), but if you pass 'residual_in_company_currency' = True in the
+           context then the returned amount will be in company currency.
+        """
+        res = {}
+        if context is None:
+            context = {}
+        cur_obj = self.pool.get('res.currency')
+        for move_line in self.browse(cr, uid, ids, context=context):
+            res[move_line.id] = {
+                'amount_residual': 0.0,
+                'amount_residual_currency': 0.0,
+            }
+
+            if move_line.reconcile_id:
+                continue
+            if not move_line.account_id.type in ('payable', 'receivable'):
+                #this function does not suport to be used on move lines not related to payable or receivable accounts
+                continue
+
+            if move_line.currency_id:
+                move_line_total = move_line.amount_currency
+                sign = move_line.amount_currency < 0 and -1 or 1
+            else:
+                move_line_total = move_line.debit - move_line.credit
+                sign = (move_line.debit - move_line.credit) < 0 and -1 or 1
+            line_total_in_company_currency =  move_line.debit - move_line.credit
+            context_unreconciled = context.copy()
+            if move_line.reconcile_partial_id:
+                for payment_line in move_line.reconcile_partial_id.line_partial_ids:
+                    if payment_line.id == move_line.id:
+                        continue
+                    if payment_line.currency_id and move_line.currency_id and payment_line.currency_id.id == move_line.currency_id.id:
+                            move_line_total += payment_line.amount_currency
+                    else:
+                        if move_line.currency_id:
+                            context_unreconciled.update({'date': payment_line.date})
+                            amount_in_foreign_currency = cur_obj.compute(cr, uid, move_line.company_id.currency_id.id, move_line.currency_id.id, (payment_line.debit - payment_line.credit), round=False, context=context_unreconciled)
+                            move_line_total += amount_in_foreign_currency
+                        else:
+                            move_line_total += (payment_line.debit - payment_line.credit)
+                    line_total_in_company_currency += (payment_line.debit - payment_line.credit)
+
+            result = move_line_total
+            res[move_line.id]['amount_residual_currency'] =  sign * (move_line.currency_id and self.pool.get('res.currency').round(cr, uid, move_line.currency_id, result) or result)
+            res[move_line.id]['amount_residual'] = sign * line_total_in_company_currency
+        return res
+
     def default_get(self, cr, uid, fields, context=None):
         data = self._default_get(cr, uid, fields, context=context)
         for f in data.keys():
@@ -172,11 +226,14 @@ class account_move_line(osv.osv):
         # Starts: Manual entry from account.move form
         if context.get('lines',[]):
             total_new = 0.00
-            for i in context['lines']:
-                if i[2]:
-                    total_new += (i[2]['debit'] or 0.00)- (i[2]['credit'] or 0.00)
-                    for item in i[2]:
-                            data[item] = i[2][item]
+            for line_record in context['lines']:
+                if not isinstance(line_record, (tuple, list)):
+                    line_record_detail = self.read(cr, uid, line_record, ['analytic_account_id','debit','credit','name','reconcile_id','tax_code_id','tax_amount','account_id','ref','currency_id','date_maturity','amount_currency','partner_id', 'reconcile_partial_id'])
+                else:
+                    line_record_detail = line_record[2]
+                total_new += (line_record_detail['debit'] or 0.00)- (line_record_detail['credit'] or 0.00)
+                for item in line_record_detail.keys():
+                    data[item] = line_record_detail[item]
             if context['journal']:
                 journal_data = journal_obj.browse(cr, uid, context['journal'], context=context)
                 if journal_data.type == 'purchase':
@@ -433,19 +490,21 @@ class account_move_line(osv.osv):
         'reconcile_id': fields.many2one('account.move.reconcile', 'Reconcile', readonly=True, ondelete='set null', select=2),
         'reconcile_partial_id': fields.many2one('account.move.reconcile', 'Partial Reconcile', readonly=True, ondelete='set null', select=2),
         'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')),
+        'amount_residual_currency': fields.function(_amount_residual, method=True, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in its currency (maybe different of the company currency)."),
+        'amount_residual': fields.function(_amount_residual, method=True, string='Residual Amount', multi="residual", help="The residual amount on a receivable or payable of a journal entry expressed in the company currency."),
         'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."),
         'period_id': fields.many2one('account.period', 'Period', required=True, select=2),
         'journal_id': fields.many2one('account.journal', 'Journal', required=True, select=1),
         'blocked': fields.boolean('Litigation', help="You can check this box to mark this journal item as a litigation with the associated partner"),
         'partner_id': fields.many2one('res.partner', 'Partner', select=1, ondelete='restrict'),
-        'date_maturity': fields.date('Due date', help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
-        'date': fields.related('move_id','date', string='Effective date', type='date', required=True,
+        'date_maturity': fields.date('Due date', select=True ,help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
+        'date': fields.related('move_id','date', string='Effective date', type='date', required=True, select=True,
                                 store = {
                                     'account.move': (_get_move_lines, ['date'], 20)
                                 }),
-        'date_created': fields.date('Creation date'),
+        'date_created': fields.date('Creation date', select=True),
         'analytic_lines': fields.one2many('account.analytic.line', 'move_id', 'Analytic lines'),
-        'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation')], 'Centralisation', size=6),
+        'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation'),('currency','Currency Adjustment')], 'Centralisation', size=8),
         'balance': fields.function(_balance, fnct_search=_balance_search, method=True, string='Balance'),
         'state': fields.selection([('draft','Unbalanced'), ('valid','Valid')], 'State', readonly=True,
                                   help='When new move line is created the state will be \'Draft\'.\n* When all the payments are done it will be in \'Valid\' state.'),
@@ -494,7 +553,7 @@ class account_move_line(osv.osv):
         'date_created': lambda *a: time.strftime('%Y-%m-%d'),
         'state': 'draft',
         'currency_id': _get_currency,
-        'journal_id': lambda self, cr, uid, c: c.get('journal_id', False),
+        'journal_id': lambda self, cr, uid, c: c.get('journal_id', c.get('journal',False)),
         'account_id': lambda self, cr, uid, c: c.get('account_id', False),
         'period_id': lambda self, cr, uid, c: c.get('period_id', False),
         'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.move.line', context=c)
@@ -532,18 +591,10 @@ class account_move_line(osv.osv):
                 return False
         return True
 
-    def _check_partner_id(self, cr, uid, ids, context=None):
-        lines = self.browse(cr, uid, ids, context=context)
-        for l in lines:
-            if l.account_id.type in ('receivable', 'payable') and not l.partner_id:
-                return False
-        return True
-
     _constraints = [
         (_check_no_view, 'You can not create move line on view account.', ['account_id']),
         (_check_no_closed, 'You can not create move line on closed account.', ['account_id']),
         (_check_company_id, 'Company must be same for its related account and period.',['company_id'] ),
-        (_check_partner_id, 'You can not create move line on receivable/payable account without partner', ['account_id'] )
     ]
 
     #TODO: ONCHANGE_ACCOUNT_ID: set account_tax_id
@@ -676,6 +727,7 @@ class account_move_line(osv.osv):
             company_list.append(line.company_id.id)
 
         for line in self.browse(cr, uid, ids, context=context):
+            company_currency_id = line.company_id.currency_id
             if line.reconcile_id:
                 raise osv.except_osv(_('Warning'), _('Already Reconciled!'))
             if line.reconcile_partial_id:
@@ -688,8 +740,7 @@ class account_move_line(osv.osv):
             else:
                 unmerge.append(line.id)
                 total += (line.debit or 0.0) - (line.credit or 0.0)
-
-        if not total:
+        if self.pool.get('res.currency').is_zero(cr, uid, company_currency_id, total):
             res = self.reconcile(cr, uid, merges+unmerge, context=context)
             return res
         r_id = move_rec_obj.create(cr, uid, {
@@ -771,6 +822,19 @@ class account_move_line(osv.osv):
                 libelle = context['comment']
             else:
                 libelle = _('Write-Off')
+
+            cur_obj = self.pool.get('res.currency')
+            cur_id = False
+            amount_currency_writeoff = 0.0
+            if context.get('company_currency_id',False) != context.get('currency_id',False):
+                cur_id = context.get('currency_id',False)
+                for line in unrec_lines:
+                    if line.currency_id and line.currency_id.id == context.get('currency_id',False):
+                        amount_currency_writeoff += line.amount_currency
+                    else:
+                        tmp_amount = cur_obj.compute(cr, uid, line.account_id.company_id.currency_id.id, context.get('currency_id',False), abs(line.debit-line.credit), context={'date': line.date})
+                        amount_currency_writeoff += (line.debit > 0) and tmp_amount or -tmp_amount
+
             writeoff_lines = [
                 (0, 0, {
                     'name': libelle,
@@ -779,8 +843,8 @@ class account_move_line(osv.osv):
                     'account_id': account_id,
                     'date': date,
                     'partner_id': partner_id,
-                    'currency_id': account.currency_id.id or False,
-                    'amount_currency': account.currency_id.id and -currency or 0.0
+                    'currency_id': cur_id or (account.currency_id.id or False),
+                    'amount_currency': amount_currency_writeoff and -1 * amount_currency_writeoff or (account.currency_id.id and -1 * currency or 0.0)
                 }),
                 (0, 0, {
                     'name': libelle,
@@ -789,7 +853,9 @@ class account_move_line(osv.osv):
                     'account_id': writeoff_acc_id,
                     'analytic_account_id': context.get('analytic_id', False),
                     'date': date,
-                    'partner_id': partner_id
+                    'partner_id': partner_id,
+                    'currency_id': cur_id or (account.currency_id.id or False),
+                    'amount_currency': amount_currency_writeoff and amount_currency_writeoff or (account.currency_id.id and currency or 0.0)
                 })
             ]
 
@@ -802,6 +868,8 @@ class account_move_line(osv.osv):
             })
 
             writeoff_line_ids = self.search(cr, uid, [('move_id', '=', writeoff_move_id), ('account_id', '=', account_id)])
+            if account_id == writeoff_acc_id:
+                writeoff_line_ids = [writeoff_line_ids[1]]
             ids += writeoff_line_ids
 
         r_id = move_rec_obj.create(cr, uid, {
@@ -828,7 +896,8 @@ class account_move_line(osv.osv):
         if context.get('account_id', False):
             cr.execute('SELECT code FROM account_account WHERE id = %s', (context['account_id'], ))
             res = cr.fetchone()
-            res = _('Entries: ')+ (res[0] or '')
+            if res:
+                res = _('Entries: ')+ (res[0] or '')
             return res
         if (not context.get('journal_id', False)) or (not context.get('period_id', False)):
             return False
@@ -837,7 +906,7 @@ class account_move_line(osv.osv):
         cr.execute('SELECT code FROM account_period WHERE id = %s', (context['period_id'], ))
         p = cr.fetchone()[0] or ''
         if j or p:
-            return j+(p and (':'+p) or '')
+            return j + (p and (':' + p) or '')
         return False
 
     def onchange_date(self, cr, user, ids, date, context=None):
@@ -871,7 +940,7 @@ class account_move_line(osv.osv):
         journal_pool = self.pool.get('account.journal')
         if context is None:
             context = {}
-        result = super(osv.osv, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
+        result = super(account_move_line, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
         if view_type != 'tree':
             #Remove the toolbar from the form view
             if view_type == 'form':
@@ -880,6 +949,14 @@ class account_move_line(osv.osv):
             #Restrict the list of journal view in search view
             if view_type == 'search' and result['fields'].get('journal_id', False):
                 result['fields']['journal_id']['selection'] = journal_pool.name_search(cr, uid, '', [], context=context)
+                ctx = context.copy()
+                #we add the refunds journal in the selection field of journal
+                if context.get('journal_type', False) == 'sale':
+                    ctx.update({'journal_type': 'sale_refund'})
+                    result['fields']['journal_id']['selection'] += journal_pool.name_search(cr, uid, '', [], context=ctx)
+                elif context.get('journal_type', False) == 'purchase':
+                    ctx.update({'journal_type': 'purchase_refund'})
+                    result['fields']['journal_id']['selection'] += journal_pool.name_search(cr, uid, '', [], context=ctx)
             return result
         if context.get('view_mode', False):
             return result
@@ -962,7 +1039,13 @@ class account_move_line(osv.osv):
 
             if field in widths:
                 attrs.append('width="'+str(widths[field])+'"')
-            attrs.append("invisible=\"context.get('visible_id') not in %s\"" % (fields.get(field)))
+
+            if field in ('journal_id',):
+                attrs.append("invisible=\"context.get('journal_id', False)\"")
+            elif field in ('period_id',):
+                attrs.append("invisible=\"context.get('period_id', False)\"")
+            else:
+                attrs.append("invisible=\"context.get('visible_id') not in %s\"" % (fields.get(field)))
             xml += '''<field name="%s" %s/>\n''' % (field,' '.join(attrs))
 
         xml += '''</tree>'''
@@ -1012,6 +1095,7 @@ class account_move_line(osv.osv):
             context['period_id'] = line.period_id.id
             result = super(account_move_line, self).unlink(cr, uid, [line.id], context=context)
             if check:
+                context.update({'lines_cancel': 'cancel'})
                 move_obj.validate(cr, uid, [line.move_id.id], context=context)
         return result
 
@@ -1283,4 +1367,4 @@ class account_move_line(osv.osv):
 
 account_move_line()
 
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: