[MERGE] lp:929373. Courtesy of Arif
authorQuentin (OpenERP) <qdp-launchpad@openerp.com>
Thu, 16 Feb 2012 16:52:53 +0000 (17:52 +0100)
committerQuentin (OpenERP) <qdp-launchpad@openerp.com>
Thu, 16 Feb 2012 16:52:53 +0000 (17:52 +0100)
bzr revid: qdp-launchpad@openerp.com-20120216165253-01d70hrlf8pmnn7x

1  2 
addons/sale/sale.py

diff --combined addons/sale/sale.py
@@@ -25,7 -25,7 +25,7 @@@ import tim
  import pooler
  from osv import fields, osv
  from tools.translate import _
 -from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
 +from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, float_compare
  import decimal_precision as dp
  import netsvc
  
@@@ -147,11 -147,15 +147,14 @@@ class sale_order(osv.osv)
          res = {}
          for sale in self.browse(cursor, user, ids, context=context):
              res[sale.id] = True
 -            invoices = []
++            invoice_existence = False
              for invoice in sale.invoice_ids:
-                 if invoice.state != 'paid':
-                     res[sale.id] = False
-                     break
-             if not sale.invoice_ids:
+                 if invoice.state!='cancel':
 -                    invoices.append(invoice)
 -            for invoice in invoices: 
 -                if invoice.state != 'paid':
 -                    res[sale.id] = False
 -                    break
 -            if not invoices:
++                    invoice_existence = True
++                    if invoice.state != 'paid':
++                        res[sale.id] = False
++                        break
++            if not invoice_existence:
                  res[sale.id] = False
          return res
  
      def button_dummy(self, cr, uid, ids, context=None):
          return True
  
 -    #FIXME: the method should return the list of invoices created (invoice_ids)
 -    # and not the id of the last invoice created (res). The problem is that we
 -    # cannot change it directly since the method is called by the sales order
 -    # workflow and I suppose it expects a single id...
 +    # FIXME: deprecated method, overriders should be using _prepare_invoice() instead.
 +    #        can be removed after 6.1.
      def _inv_get(self, cr, uid, order, context=None):
          return {}
  
 -    def _make_invoice(self, cr, uid, order, lines, context=None):
 -        journal_obj = self.pool.get('account.journal')
 -        inv_obj = self.pool.get('account.invoice')
 -        obj_invoice_line = self.pool.get('account.invoice.line')
 +    def _prepare_invoice(self, cr, uid, order, lines, context=None):
 +        """Prepare the dict of values to create the new invoice for a
 +           sale order. This method may be overridden to implement custom
 +           invoice generation (making sure to call super() to establish
 +           a clean extension chain).
 +
 +           :param browse_record order: sale.order record to invoice
 +           :param list(int) line: list of invoice line IDs that must be
 +                                  attached to the invoice
 +           :return: dict of value to create() the invoice
 +        """
          if context is None:
              context = {}
 -
 -        journal_ids = journal_obj.search(cr, uid, [('type', '=', 'sale'), ('company_id', '=', order.company_id.id)], limit=1)
 +        journal_ids = self.pool.get('account.journal').search(cr, uid,
 +            [('type', '=', 'sale'), ('company_id', '=', order.company_id.id)],
 +            limit=1)
          if not journal_ids:
              raise osv.except_osv(_('Error !'),
                  _('There is no sales journal defined for this company: "%s" (id:%d)') % (order.company_id.name, order.company_id.id))
 -        a = order.partner_id.property_account_receivable.id
 -        pay_term = order.payment_term and order.payment_term.id or False
 -        invoiced_sale_line_ids = self.pool.get('sale.order.line').search(cr, uid, [('order_id', '=', order.id), ('invoiced', '=', True)], context=context)
 -        from_line_invoice_ids = []
 -        for invoiced_sale_line_id in self.pool.get('sale.order.line').browse(cr, uid, invoiced_sale_line_ids, context=context):
 -            for invoice_line_id in invoiced_sale_line_id.invoice_lines:
 -                if invoice_line_id.invoice_id.id not in from_line_invoice_ids:
 -                    from_line_invoice_ids.append(invoice_line_id.invoice_id.id)
 -        for preinv in order.invoice_ids:
 -            if preinv.state not in ('cancel',) and preinv.id not in from_line_invoice_ids:
 -                for preline in preinv.invoice_line:
 -                    inv_line_id = obj_invoice_line.copy(cr, uid, preline.id, {'invoice_id': False, 'price_unit': -preline.price_unit})
 -                    lines.append(inv_line_id)
 -        inv = {
 +
 +        invoice_vals = {
              'name': order.client_order_ref or '',
              'origin': order.name,
              'type': 'out_invoice',
              'reference': order.client_order_ref or order.name,
 -            'account_id': a,
 +            'account_id': order.partner_id.property_account_receivable.id,
              'partner_id': order.partner_id.id,
              'journal_id': journal_ids[0],
              'address_invoice_id': order.partner_invoice_id.id,
              'invoice_line': [(6, 0, lines)],
              'currency_id': order.pricelist_id.currency_id.id,
              'comment': order.note,
 -            'payment_term': pay_term,
 +            'payment_term': order.payment_term and order.payment_term.id or False,
              'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
 -            'date_invoice': context.get('date_invoice',False),
 +            'date_invoice': context.get('date_invoice', False),
              'company_id': order.company_id.id,
              'user_id': order.user_id and order.user_id.id or False
          }
 -        inv.update(self._inv_get(cr, uid, order))
 +
 +        # Care for deprecated _inv_get() hook - FIXME: to be removed after 6.1
 +        invoice_vals.update(self._inv_get(cr, uid, order, context=context))
 +
 +        return invoice_vals
 +
 +    def _make_invoice(self, cr, uid, order, lines, context=None):
 +        inv_obj = self.pool.get('account.invoice')
 +        obj_invoice_line = self.pool.get('account.invoice.line')
 +        if context is None:
 +            context = {}
 +        invoiced_sale_line_ids = self.pool.get('sale.order.line').search(cr, uid, [('order_id', '=', order.id), ('invoiced', '=', True)], context=context)
 +        from_line_invoice_ids = []
 +        for invoiced_sale_line_id in self.pool.get('sale.order.line').browse(cr, uid, invoiced_sale_line_ids, context=context):
 +            for invoice_line_id in invoiced_sale_line_id.invoice_lines:
 +                if invoice_line_id.invoice_id.id not in from_line_invoice_ids:
 +                    from_line_invoice_ids.append(invoice_line_id.invoice_id.id)
 +        for preinv in order.invoice_ids:
 +            if preinv.state not in ('cancel',) and preinv.id not in from_line_invoice_ids:
 +                for preline in preinv.invoice_line:
 +                    inv_line_id = obj_invoice_line.copy(cr, uid, preline.id, {'invoice_id': False, 'price_unit': -preline.price_unit})
 +                    lines.append(inv_line_id)
 +        inv = self._prepare_invoice(cr, uid, order, lines, context=context)
          inv_id = inv_obj.create(cr, uid, inv, context=context)
 -        data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], pay_term, time.strftime(DEFAULT_SERVER_DATE_FORMAT))
 +        data = inv_obj.onchange_payment_term_date_invoice(cr, uid, [inv_id], inv['payment_term'], time.strftime(DEFAULT_SERVER_DATE_FORMAT))
          if data.get('value', False):
              inv_obj.write(cr, uid, [inv_id], data['value'], context=context)
          inv_obj.button_compute(cr, uid, [inv_id])
@@@ -997,16 -985,11 +1000,16 @@@ class sale_order_line(osv.osv)
          'price_unit': 0.0,
      }
  
 -    def _prepare_order_line_invoice_line(self, cr, uid, ids, line, account_id=False, context=None):
 -        """ Builds the invoice line dict from a sale order line
 -            @param line: sale order line object
 -            @param account_id: the id of the account to force eventually (the method is used for picking return including service)
 -            @return: dict that will be used to create the invoice line
 +    def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None):
 +        """Prepare the dict of values to create the new invoice line for a
 +           sale order line. This method may be overridden to implement custom
 +           invoice generation (making sure to call super() to establish
 +           a clean extension chain).
 +
 +           :param browse_record line: sale.order.line record to invoice
 +           :param int account_id: optional ID of a G/L account to force
 +               (this is used for returning products including service)
 +           :return: dict of values to create() the invoice line
          """
  
          def _get_line_qty(line):
          create_ids = []
          sales = set()
          for line in self.browse(cr, uid, ids, context=context):
 -            vals = self._prepare_order_line_invoice_line(cr, uid, ids, line, False, context)
 +            vals = self._prepare_order_line_invoice_line(cr, uid, line, False, context)
              if vals:
                  inv_id = self.pool.get('account.invoice.line').create(cr, uid, vals, context=context)
                  cr.execute('insert into sale_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id))
  
          if not uom2:
              uom2 = product_obj.uom_id
 -        if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < qty * product_obj.uom_id.factor) \
 +        compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
 +        if (product_obj.type=='product') and int(compare_qty) == -1 \
            and (product_obj.procure_method=='make_to_stock'):
              warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
                      (qty, uom2 and uom2.name or product_obj.uom_id.name,