#This file is part of Tryton.  The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.model import ModelView, ModelSQL
from trytond.transaction import Transaction
from trytond.pool import Pool


class ShipmentInternal(ModelSQL, ModelView):
    _name = 'stock.shipment.internal'

    def init(self, module_name):
        cursor = Transaction().cursor
        # Migration from 1.2: packing renamed into shipment
        cursor.execute("UPDATE ir_model_data "\
                "SET fs_id = REPLACE(fs_id, 'packing', 'shipment') "\
                "WHERE fs_id like '%%packing%%' AND module = %s",
                (module_name,))
        cursor.execute("UPDATE ir_model "\
                "SET model = REPLACE(model, 'packing', 'shipment') "\
                "WHERE model like '%%packing%%' AND module = %s",
                (module_name,))
        super(ShipmentInternal, self).init(module_name)

    def generate_internal_shipment(self):
        """
        Generate internal shipments to meet order points defined on
        non-warehouse location.
        """
        pool = Pool()
        order_point_obj = pool.get('stock.order_point')
        uom_obj = pool.get('product.uom')
        product_obj = pool.get('product.product')
        date_obj = pool.get('ir.date')
        user_obj = pool.get('res.user')
        user_record = user_obj.browse(Transaction().user)
        today = date_obj.today()
        # fetch quantities on order points
        op_ids = order_point_obj.search([
            ('type', '=', 'internal'),
            ])
        order_points = order_point_obj.browse(op_ids)
        id2product = {}
        location_ids = []
        for op in order_points:
            id2product[op.product.id] = op.product
            location_ids.append(op.storage_location.id)

        with Transaction().set_context(stock_date_end=today):
            pbl = product_obj.products_by_location(location_ids,
                list(id2product.iterkeys()), with_childs=True)

        # Create a list of move to create
        moves = {}
        for op in order_points:
            qty = pbl.get((op.storage_location.id, op.product.id), 0)
            if qty < op.min_quantity:
                key = (op.storage_location.id,
                       op.provisioning_location.id,
                       op.product.id)
                moves[key] = op.max_quantity - qty

        # Compare with existing draft shipments
        shipment_ids = self.search([
                ('state', '=', 'draft'),
                ['OR',
                    ('planned_date', '<=', today),
                    ('planned_date', '=', None),
                    ],
                ])
        for shipment in self.browse(shipment_ids):
            for move in shipment.moves:
                key = (shipment.to_location.id,
                       shipment.from_location.id,
                       move.product.id)
                if key not in moves:
                    continue
                quantity = uom_obj.compute_qty(move.uom, move.quantity,
                    id2product[move.product.id].default_uom)
                moves[key] = max(0, moves[key] - quantity)

        # Group moves by {from,to}_location
        shipments = {}
        for key, qty in moves.iteritems():
            from_location, to_location, product = key
            shipments.setdefault(
                (from_location, to_location), []).append((product, qty))
        # Create shipments and moves
        for shipment, moves in shipments.iteritems():
            from_location, to_location = shipment
            values = {
                'from_location': from_location,
                'to_location': to_location,
                'planned_date': today,
                'moves': [],
                }
            for move in moves:
                product, qty = move
                values['moves'].append(
                    ('create',
                        {
                            'from_location': from_location,
                            'to_location': to_location,
                            'product': product,
                            'quantity': qty,
                            'uom': id2product[product].default_uom.id,
                            'company': user_record.company.id,
                            }
                        ))
            self.create(values)

ShipmentInternal()
