<commit_before># Copyright 2022 Tecnativa - <NAME>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import _, api, fields, models
from odoo.exceptions import UserError


class ProjectTask(models.Model):
    _inherit = "project.task"

    scrap_ids = fields.One2many(
        comodel_name="stock.scrap", inverse_name="task_id", string="Scraps"
    )
    scrap_count = fields.Integer(
        compute="_compute_scrap_move_count", string="Scrap Move"
    )
    move_ids = fields.One2many(
        comodel_name="stock.move",
        inverse_name="raw_material_task_id",
        string="Stock Moves",
        copy=False,
        domain=[("scrapped", "=", False)],
    )
    use_stock_moves = fields.Boolean(related="stage_id.use_stock_moves")
    done_stock_moves = fields.Boolean(related="stage_id.done_stock_moves")
    stock_moves_is_locked = fields.Boolean(default=True)
    allow_moves_action_confirm = fields.Boolean(
        compute="_compute_allow_moves_action_confirm"
    )
    allow_moves_action_assign = fields.Boolean(
        compute="_compute_allow_moves_action_assign"
    )
    stock_state = fields.Selection(
        selection=[
            ("pending", "Pending"),
            ("confirmed", "Confirmed"),
            ("assigned", "Assigned"),
            ("done", "Done"),
            ("cancel", "Cancel"),
        ],
        compute="_compute_stock_state",
    )
    picking_type_id = fields.Many2one(
        comodel_name="stock.picking.type",
        string="Operation Type",
        readonly=False,
        domain="[('company_id', '=', company_id)]",
        index=True,
        check_company=True,
    )
    location_id = fields.Many2one(
        comodel_name="stock.location",
        string="Source Location",
        readonly=False,
        index=True,
        check_company=True,
    )
    location_dest_id = fields.Many2one(
        comodel_name="stock.location",
        string="Destination Location",
        readonly=False,
        index=True,
        check_company=True,
    )
    stock_analytic_date = fields.Date(string="Analytic date")
    unreserve_visible = fields.Boolean(
        string="Allowed to Unreserve Inventory",
        compute="_compute_unreserve_visible",
        help="Technical field to check when we can unreserve",
    )
    stock_analytic_account_id = fields.Many2one(
        comodel_name="account.analytic.account",
        string="Move Analytic Account",
        help="Move created will be assigned to this analytic account",
    )
    stock_analytic_tag_ids = fields.Many2many(
        comodel_name="account.analytic.tag",
        string="Move Analytic Tags",
    )
    stock_analytic_line_ids = fields.One2many(
        comodel_name="account.analytic.line",
        inverse_name="stock_task_id",
        string="Analytic Lines",
    )
    group_id = fields.Many2one(
        comodel_name="procurement.group",
    )

    def _compute_scrap_move_count(self):
        data = self.env["stock.scrap"].read_group(
            [("task_id", "in", self.ids)], ["task_id"], ["task_id"]
        )
        count_data = {item["task_id"][0]: item["task_id_count"] for item in data}
        for item in self:
            item.scrap_count = count_data.get(item.id, 0)

    @api.depends("move_ids", "move_ids.state")
    def _compute_allow_moves_action_confirm(self):
        for item in self:
            item.allow_moves_action_confirm = any(
                move.state == "draft" for move in item.move_ids
            )

    @api.depends("move_ids", "move_ids.state")
    def _compute_allow_moves_action_assign(self):
        for item in self:
            item.allow_moves_action_assign = any(
                move.state in ("confirmed", "partially_available")
                for move in item.move_ids
            )

    @api.depends("move_ids", "move_ids.state")
    def _compute_stock_state(self):
        for task in self:
            task.stock_state = "pending"
            if task.move_ids:
                states = task.mapped("move_ids.state")
                for state in ("confirmed", "assigned", "done", "cancel"):
                    if state in states:
                        task.stock_state = state
                        break

    @api.depends("move_ids", "move_ids.quantity_done")
    def _compute_unreserve_visible(self):
        for item in self:
            already_reserved = item.mapped("move_ids.move_line_ids")
            any_quantity_done = any([m.quantity_done > 0 for m in item.move_ids])
            item.unreserve_visible = not any_quantity_done and already_reserved

    @api.onchange("picking_type_id")
    def _onchange_picking_type_id(self):
        self.location_id = self.picking_type_id.default_location_src_id.id
        self.location_dest_id = self.picking_type_id.default_location_dest_id.id

    def _check_tasks_with_pending_moves(self):
        if self.move_ids and "assigned" in self.mapped("move_ids.state"):
            raise UserError(
                _("It is not possible to change this with reserved movements in tasks.")
            )

    def _update_moves_info(self):
        self._check_tasks_with_pending_moves()
        for item in self:
            picking_type = item.picking_type_id or item.project_id.picking_type_id
            location = item.location_id or item.project_id.location_id
            location_dest = item.location_dest_id or item.project_id.location_dest_id
            moves = item.move_ids.filtered(
                lambda x: x.state not in ("cancel", "done")
                and (x.location_id != location or x.location_dest_id != location_dest)
            )
            moves.update(
                {
                    "warehouse_id": location.get_warehouse().id,
                    "location_id": location.id,
                    "location_dest_id": location_dest.id,
                    "picking_type_id": picking_type.id,<commit_msg>[FIX] project_stock: Apply validation correctly when changing locations in tasks.<commit_after># Copyright 2022 Tecnativa - <NAME>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import _, api, fields, models
from odoo.exceptions import UserError


class ProjectTask(models.Model):
    _inherit = "project.task"

    scrap_ids = fields.One2many(
        comodel_name="stock.scrap", inverse_name="task_id", string="Scraps"
    )
    scrap_count = fields.Integer(
        compute="_compute_scrap_move_count", string="Scrap Move"
    )
    move_ids = fields.One2many(
        comodel_name="stock.move",
        inverse_name="raw_material_task_id",
        string="Stock Moves",
        copy=False,
        domain=[("scrapped", "=", False)],
    )
    use_stock_moves = fields.Boolean(related="stage_id.use_stock_moves")
    done_stock_moves = fields.Boolean(related="stage_id.done_stock_moves")
    stock_moves_is_locked = fields.Boolean(default=True)
    allow_moves_action_confirm = fields.Boolean(
        compute="_compute_allow_moves_action_confirm"
    )
    allow_moves_action_assign = fields.Boolean(
        compute="_compute_allow_moves_action_assign"
    )
    stock_state = fields.Selection(
        selection=[
            ("pending", "Pending"),
            ("confirmed", "Confirmed"),
            ("assigned", "Assigned"),
            ("done", "Done"),
            ("cancel", "Cancel"),
        ],
        compute="_compute_stock_state",
    )
    picking_type_id = fields.Many2one(
        comodel_name="stock.picking.type",
        string="Operation Type",
        readonly=False,
        domain="[('company_id', '=', company_id)]",
        index=True,
        check_company=True,
    )
    location_id = fields.Many2one(
        comodel_name="stock.location",
        string="Source Location",
        readonly=False,
        index=True,
        check_company=True,
    )
    location_dest_id = fields.Many2one(
        comodel_name="stock.location",
        string="Destination Location",
        readonly=False,
        index=True,
        check_company=True,
    )
    stock_analytic_date = fields.Date(string="Analytic date")
    unreserve_visible = fields.Boolean(
        string="Allowed to Unreserve Inventory",
        compute="_compute_unreserve_visible",
        help="Technical field to check when we can unreserve",
    )
    stock_analytic_account_id = fields.Many2one(
        comodel_name="account.analytic.account",
        string="Move Analytic Account",
        help="Move created will be assigned to this analytic account",
    )
    stock_analytic_tag_ids = fields.Many2many(
        comodel_name="account.analytic.tag",
        string="Move Analytic Tags",
    )
    stock_analytic_line_ids = fields.One2many(
        comodel_name="account.analytic.line",
        inverse_name="stock_task_id",
        string="Analytic Lines",
    )
    group_id = fields.Many2one(
        comodel_name="procurement.group",
    )

    def _compute_scrap_move_count(self):
        data = self.env["stock.scrap"].read_group(
            [("task_id", "in", self.ids)], ["task_id"], ["task_id"]
        )
        count_data = {item["task_id"][0]: item["task_id_count"] for item in data}
        for item in self:
            item.scrap_count = count_data.get(item.id, 0)

    @api.depends("move_ids", "move_ids.state")
    def _compute_allow_moves_action_confirm(self):
        for item in self:
            item.allow_moves_action_confirm = any(
                move.state == "draft" for move in item.move_ids
            )

    @api.depends("move_ids", "move_ids.state")
    def _compute_allow_moves_action_assign(self):
        for item in self:
            item.allow_moves_action_assign = any(
                move.state in ("confirmed", "partially_available")
                for move in item.move_ids
            )

    @api.depends("move_ids", "move_ids.state")
    def _compute_stock_state(self):
        for task in self:
            task.stock_state = "pending"
            if task.move_ids:
                states = task.mapped("move_ids.state")
                for state in ("confirmed", "assigned", "done", "cancel"):
                    if state in states:
                        task.stock_state = state
                        break

    @api.depends("move_ids", "move_ids.quantity_done")
    def _compute_unreserve_visible(self):
        for item in self:
            already_reserved = item.mapped("move_ids.move_line_ids")
            any_quantity_done = any([m.quantity_done > 0 for m in item.move_ids])
            item.unreserve_visible = not any_quantity_done and already_reserved

    @api.onchange("picking_type_id")
    def _onchange_picking_type_id(self):
        self.location_id = self.picking_type_id.default_location_src_id.id
        self.location_dest_id = self.picking_type_id.default_location_dest_id.id

    def _check_tasks_with_pending_moves(self):
        if self.move_ids and "assigned" in self.mapped("move_ids.state"):
            raise UserError(
                _("It is not possible to change this with reserved movements in tasks.")
            )

    def _update_moves_info(self):
        for item in self:
            item._check_tasks_with_pending_moves()
            picking_type = item.picking_type_id or item.project_id.picking_type_id
            location = item.location_id or item.project_id.location_id
            location_dest = item.location_dest_id or item.project_id.location_dest_id
            moves = item.move_ids.filtered(
                lambda x: x.state not in ("cancel", "done")
                and (x.location_id != location or x.location_dest_id != location_dest)
            )
            moves.update(
                {
                    "warehouse_id": location.get_warehouse().id,
                    "location_id": location.id,
                    "location_dest_id": location_dest.id,
                    "picking_type_id": picking_type.id,
{'fraction_non_alphanumeric': 0.10496118798515018, 'fraction_numerical': 0.0030374620317246033, 'mean_word_length': 2.4790137951276785, 'pattern_counts': {'":': 8, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '804601', 'n_tokens_mistral': 3671, 'n_tokens_neox': 3541, 'n_words': 652}