# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from openerp import api, fields, models, _
from openerp.exceptions import UserError


class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    @api.multi
    def _compute_analytic(self, domain=None):
        lines = {}
        if not domain:
            domain = [('so_line', 'in', self.ids), ('amount', '<=', 0.0)]
        data = self.env['account.analytic.line'].read_group(
            domain,
            ['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False
        )
        for d in data:
            if not d['product_uom_id']:
                continue
            line = self.browse(d['so_line'][0])
            lines.setdefault(line, 0.0)
            uom = self.env['product.uom'].browse(d['product_uom_id'][0])
            if line.product_uom.category_id == uom.category_id:
                qty = self.env['product.uom']._compute_qty_obj(uom, d['unit_amount'], line.product_uom)
            else:
                qty = d['unit_amount']
            lines[line] += qty

        for line, qty in lines.items():
            line.qty_delivered = qty
        return True


class AccountAnalyticLine(models.Model):
    _inherit = "account.analytic.line"
    so_line = fields.Many2one('sale.order.line', string='Sale Order Line')

    def _get_invoice_price(self, order):
        if self.unit_amount == 0.0:
            return 0.0
        price_unit = abs(self.amount / self.unit_amount)
        if self.currency_id and self.currency_id != order.currency_id:
            price_unit = self.currency_id.compute(price_unit, order.currency_id)
        return price_unit

    def _get_sale_order_line_vals(self):
        order = self.env['sale.order'].search([('project_id', '=', self.account_id.id)], limit=1)
        if not order:
            return False
        if order.state != 'sale':
            raise UserError(_('The Sale Order %s linked to the Analytic Account must be validated before registering expenses.' % order.name))

        last_so_line = self.env['sale.order.line'].search([('order_id', '=', order.id)], order='sequence desc', limit=1)
        last_sequence = last_so_line.sequence + 1 if last_so_line else 100

        fpos = order.fiscal_position_id or order.partner_id.property_account_position_id
        taxes = fpos.map_tax(self.product_id.taxes_id)
        price = self._get_invoice_price(order)

        return {
            'order_id': order.id,
            'name': self.name,
            'sequence': last_sequence,
            'price_unit': price,
            'tax_id': [x.id for x in taxes],
            'discount': 0.0,
            'product_id': self.product_id.id,
            'product_uom': self.product_uom_id.id,
            'product_uom_qty': 0.0,
            'qty_delivered': self.unit_amount,
        }

    def _get_sale_order_line(self, vals=None):
        result = dict(vals or {})
        sol = result.get('so_line', False) or self.so_line
        if not sol and self.account_id and self.product_id and self.product_id.invoice_policy in ('cost', 'order'):
            sol = self.env['sale.order.line'].search([
                ('order_id.project_id', '=', self.account_id.id),
                ('state', '=', 'sale'),
                ('product_id', '=', self.product_id.id)],
                limit=1)
            # Use the existing SO line only if the unit prices are the same
            if sol and sol.price_unit == self._get_invoice_price(sol.order_id):
                result.update({'so_line': sol.id})
            else:
                # This will trigger the creation of a new SO line
                sol = False

        if not sol and self.account_id and self.product_id and self.product_id.invoice_policy == 'cost':
            order_line_vals = self._get_sale_order_line_vals()
            if order_line_vals:
                sol = self.env['sale.order.line'].create(order_line_vals)
                sol._compute_tax_id()
                result.update({'so_line': sol.id})

        return result

    @api.multi
    def write(self, values):
        if self._context.get('create', False):
            return super(AccountAnalyticLine, self).write(values)

        lines = super(AccountAnalyticLine, self).write(values)
        for line in self:
            res = line._get_sale_order_line(vals=values)
            super(AccountAnalyticLine, line).write(res)

        self.mapped('so_line')._compute_analytic()
        return lines

    @api.model
    def create(self, values):
        line = super(AccountAnalyticLine, self).create(values)
        res = line._get_sale_order_line(vals=values)
        line.with_context(create=True).write(res)
        line.mapped('so_line')._compute_analytic()
        return line

@@ -2976,17 +2976,21 @@
       so
-l
+_line
  = resul
@@ -3038,33 +3038,37 @@
        if not so
-l
+_line
  and self.accoun
@@ -3155,33 +3155,38 @@
 :%0A            so
-l
+_lines
  = self.env%5B'sal
@@ -3375,33 +3375,8 @@
 id)%5D
-,%0A                limit=1
 )%0A  
@@ -3452,35 +3452,112 @@
 same
-%0A            if sol and sol
+, otherwise we create%0A            # a new line%0A            for line in so_lines:%0A                if line
 .pri
@@ -3591,19 +3591,20 @@
 e_price(
-sol
+line
 .order_i
@@ -3607,16 +3607,20 @@
 er_id):%0A
+    
         
@@ -3653,25 +3653,87 @@
 _line': 
-sol
+line
 .id%7D)%0A
+                    so_line = line%0A                    break%0A
         
@@ -3826,17 +3826,21 @@
       so
-l
+_line
  = False
@@ -3858,17 +3858,21 @@
 f not so
-l
+_line
  and sel
@@ -4063,17 +4063,21 @@
       so
-l
+_line
  = self.
@@ -4141,17 +4141,21 @@
       so
-l
+_line
 ._comput
@@ -4209,17 +4209,21 @@
 ine': so
-l
+_line
 .id%7D)%0A%0A 

_get_sale_order_line