mirror of
https://github.com/bringout/oca-project.git
synced 2026-04-19 19:22:02 +02:00
Move 124 sale modules to oca-sale, create oca-project with 56 project modules from oca-workflow-process
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
9eb7ae5807
commit
6094c218b2
2332 changed files with 125826 additions and 0 deletions
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright 2022 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import test_project_stock
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright 2022 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo.tests import Form, common
|
||||
from odoo.tests.common import new_test_user
|
||||
|
||||
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
|
||||
|
||||
|
||||
class TestProjectStockBase(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
|
||||
cls.product_a = cls.env["product.product"].create(
|
||||
{"name": "Test product A", "detailed_type": "product", "standard_price": 10}
|
||||
)
|
||||
cls.product_b = cls.env["product.product"].create(
|
||||
{"name": "Test product B", "detailed_type": "product", "standard_price": 20}
|
||||
)
|
||||
cls.product_c = cls.env["product.product"].create(
|
||||
{"name": "Test product C", "detailed_type": "product", "standard_price": 0}
|
||||
)
|
||||
cls.picking_type = cls.env.ref("project_stock.stock_picking_type_tm_test")
|
||||
cls.location = cls.picking_type.default_location_src_id
|
||||
cls.location_dest = cls.picking_type.default_location_dest_id
|
||||
cls.plan = cls.env["account.analytic.plan"].create(
|
||||
{
|
||||
"name": "Projects Plan",
|
||||
"company_id": False,
|
||||
}
|
||||
)
|
||||
cls.analytic_account = cls.env["account.analytic.account"].create(
|
||||
{
|
||||
"name": "Test account",
|
||||
"plan_id": cls.plan.id,
|
||||
},
|
||||
)
|
||||
cls.analytic_account_2 = cls.analytic_account.copy(
|
||||
{
|
||||
"name": "Test account 2",
|
||||
"plan_id": cls.plan.id,
|
||||
}
|
||||
)
|
||||
cls.project = cls.env.ref("project_stock.project_project_tm_test")
|
||||
cls.project.analytic_account_id = cls.analytic_account
|
||||
cls.stage_in_progress = cls.env.ref("project.project_stage_1")
|
||||
cls.stage_done = cls.env.ref("project.project_stage_2")
|
||||
group_stock_user = "stock.group_stock_user"
|
||||
cls.basic_user = new_test_user(
|
||||
cls.env,
|
||||
login="basic-user",
|
||||
groups="project.group_project_user,%s" % group_stock_user,
|
||||
)
|
||||
new_test_user(
|
||||
cls.env,
|
||||
login="manager-user",
|
||||
groups="project.group_project_manager,%s,analytic.group_analytic_accounting"
|
||||
% group_stock_user,
|
||||
)
|
||||
new_test_user(
|
||||
cls.env,
|
||||
login="project-task-user",
|
||||
groups="project.group_project_user,stock.group_stock_user",
|
||||
)
|
||||
|
||||
def _prepare_context_task(self):
|
||||
return {
|
||||
"default_project_id": self.project.id,
|
||||
"default_stage_id": self.stage_in_progress.id,
|
||||
# We need to set default values according to compute store fields
|
||||
"default_location_id": self.project.location_id.id,
|
||||
"default_location_dest_id": self.project.location_dest_id.id,
|
||||
"default_picking_type_id": self.project.picking_type_id.id,
|
||||
}
|
||||
|
||||
def _create_task(self, products):
|
||||
task_form = Form(
|
||||
self.env["project.task"].with_context(**self._prepare_context_task(self))
|
||||
)
|
||||
task_form.name = "Test task"
|
||||
# Save task to use default_get() correctlly in stock.moves
|
||||
task_form.save()
|
||||
for product in products:
|
||||
with task_form.move_ids.new() as move_form:
|
||||
move_form.product_id = product[0]
|
||||
move_form.product_uom_qty = product[1]
|
||||
return task_form.save()
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
# Copyright 2022-2025 Tecnativa - Víctor Martínez
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import fields
|
||||
from odoo.tests import Form
|
||||
from odoo.tests.common import users
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
from .common import TestProjectStockBase
|
||||
|
||||
|
||||
class TestProjectStock(TestProjectStockBase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls._create_stock_quant(cls, cls.product_a, cls.location, 2)
|
||||
cls._create_stock_quant(cls, cls.product_b, cls.location, 1)
|
||||
cls._create_stock_quant(cls, cls.product_c, cls.location, 1)
|
||||
cls.task = cls._create_task(cls, [(cls.product_a, 2), (cls.product_b, 1)])
|
||||
cls.move_product_a = cls.task.move_ids.filtered(
|
||||
lambda x: x.product_id == cls.product_a
|
||||
)
|
||||
cls.move_product_b = cls.task.move_ids.filtered(
|
||||
lambda x: x.product_id == cls.product_b
|
||||
)
|
||||
cls.env.ref("base.user_admin").write(
|
||||
{
|
||||
"groups_id": [
|
||||
(4, cls.env.ref("analytic.group_analytic_accounting").id),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
def _create_stock_quant(self, product, location, qty):
|
||||
self.env["stock.quant"].create(
|
||||
{"product_id": product.id, "location_id": location.id, "quantity": qty}
|
||||
)
|
||||
|
||||
def test_project_task_misc(self):
|
||||
self.assertTrue(self.task.group_id)
|
||||
self.assertEqual(self.task.picking_type_id, self.picking_type)
|
||||
self.assertEqual(self.task.location_id, self.location)
|
||||
self.assertEqual(self.task.location_dest_id, self.location_dest)
|
||||
self.assertEqual(self.move_product_a.name, self.task.name)
|
||||
self.assertEqual(self.move_product_a.group_id, self.task.group_id)
|
||||
self.assertEqual(self.move_product_a.reference, self.task.name)
|
||||
self.assertEqual(self.move_product_a.location_id, self.location)
|
||||
self.assertEqual(self.move_product_a.location_dest_id, self.location_dest)
|
||||
self.assertEqual(self.move_product_a.picking_type_id, self.picking_type)
|
||||
self.assertEqual(self.move_product_a.raw_material_task_id, self.task)
|
||||
self.assertEqual(self.move_product_b.group_id, self.task.group_id)
|
||||
self.assertEqual(self.move_product_b.location_id, self.location)
|
||||
self.assertEqual(self.move_product_b.location_dest_id, self.location_dest)
|
||||
self.assertEqual(self.move_product_b.picking_type_id, self.picking_type)
|
||||
self.assertEqual(self.move_product_b.raw_material_task_id, self.task)
|
||||
|
||||
def _test_task_analytic_lines_from_task(self, amount):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
# Prevent error when hr_timesheet addon is installed.
|
||||
stock_analytic_lines = self.task.sudo().stock_analytic_line_ids
|
||||
self.assertEqual(len(stock_analytic_lines), 2)
|
||||
self.assertEqual(sum(stock_analytic_lines.mapped("unit_amount")), 3)
|
||||
self.assertEqual(sum(stock_analytic_lines.mapped("amount")), amount)
|
||||
self.assertIn(
|
||||
self.analytic_account,
|
||||
stock_analytic_lines.mapped("account_id"),
|
||||
)
|
||||
# Prevent incoherence when hr_timesheet addon is installed.
|
||||
if "project_id" in self.task.stock_analytic_line_ids._fields:
|
||||
self.assertFalse(self.task.stock_analytic_line_ids.project_id)
|
||||
|
||||
def test_project_task_without_analytic_account(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
# Prevent error when hr_timesheet addon is installed.
|
||||
if "allow_timesheets" in self.task.project_id._fields:
|
||||
self.task.project_id.allow_timesheets = False
|
||||
self.task.project_id.analytic_account_id = False
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.task.action_done()
|
||||
self.assertFalse(self.task.stock_analytic_line_ids)
|
||||
|
||||
def test_project_task_picking_done_analytic_items(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.task.action_assign()
|
||||
picking = self.task.move_ids.picking_id
|
||||
for move in picking.move_ids:
|
||||
move.quantity_done = move.product_uom_qty
|
||||
picking.button_validate()
|
||||
self.assertEqual(picking.state, "done")
|
||||
self._test_task_analytic_lines_from_task(-40)
|
||||
self.assertEqual(
|
||||
fields.first(self.task.stock_analytic_line_ids).date,
|
||||
fields.Date.from_string("1990-01-01"),
|
||||
)
|
||||
|
||||
@users("manager-user")
|
||||
def test_project_task_without_analytic_account_manager_user(self):
|
||||
self.test_project_task_without_analytic_account()
|
||||
|
||||
def test_project_task_user_access_without_stock_group(self):
|
||||
self.basic_user.write(
|
||||
{
|
||||
"groups_id": [(6, 0, [self.env.ref("project.group_project_user").id])],
|
||||
}
|
||||
)
|
||||
task_form = Form(self.task.with_user(self.basic_user))
|
||||
self.assertEqual(task_form.project_id, self.project)
|
||||
|
||||
def test_project_task_analytic_lines_without_tags(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.task.action_done()
|
||||
self._test_task_analytic_lines_from_task(-40)
|
||||
self.assertEqual(
|
||||
fields.first(self.task.stock_analytic_line_ids).date,
|
||||
fields.Date.from_string("1990-01-01"),
|
||||
)
|
||||
|
||||
@users("manager-user")
|
||||
def test_project_task_analytic_lines_without_tags_manager_user(self):
|
||||
self.test_project_task_analytic_lines_without_tags()
|
||||
|
||||
def test_project_task_analytic_lines_with_tag_1(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.task.write(
|
||||
{
|
||||
"stock_analytic_date": "1991-01-01",
|
||||
}
|
||||
)
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.task.action_done()
|
||||
self._test_task_analytic_lines_from_task(-40)
|
||||
self.assertEqual(
|
||||
fields.first(self.task.stock_analytic_line_ids).date,
|
||||
fields.Date.from_string("1991-01-01"),
|
||||
)
|
||||
|
||||
@users("manager-user")
|
||||
def test_project_task_analytic_lines_with_tag_1_manager_user(self):
|
||||
self.task.stock_analytic_distribution = {self.analytic_account.id: 100}
|
||||
self.test_project_task_analytic_lines_with_tag_1()
|
||||
|
||||
def test_project_task_analytic_lines_with_tag_2(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.task.project_id.stock_analytic_date = False
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.task.action_done()
|
||||
self._test_task_analytic_lines_from_task(-40)
|
||||
self.assertEqual(
|
||||
fields.first(self.task.stock_analytic_line_ids).date, fields.date.today()
|
||||
)
|
||||
|
||||
@users("manager-user")
|
||||
def test_project_task_analytic_lines_with_tag_2_manager_user(self):
|
||||
self.task.stock_analytic_distribution = {
|
||||
self.analytic_account.id: 50,
|
||||
self.analytic_account_2.id: 50,
|
||||
}
|
||||
self.test_project_task_analytic_lines_with_tag_2()
|
||||
|
||||
def test_project_task_process_done(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.assertEqual(self.move_product_a.state, "draft")
|
||||
self.assertEqual(self.move_product_b.state, "draft")
|
||||
# Change task stage (auto-confirm + auto-assign)
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.assertEqual(self.move_product_a.state, "assigned")
|
||||
self.assertEqual(self.move_product_b.state, "assigned")
|
||||
self.assertEqual(self.move_product_a.reserved_availability, 2)
|
||||
self.assertEqual(self.move_product_b.reserved_availability, 1)
|
||||
self.assertTrue(self.task.stock_moves_is_locked)
|
||||
self.task.action_toggle_stock_moves_is_locked()
|
||||
self.assertFalse(self.task.stock_moves_is_locked)
|
||||
# Add new stock_move
|
||||
self.task.write({"stage_id": self.stage_in_progress.id})
|
||||
task_form = Form(self.task)
|
||||
with task_form.move_ids.new() as move_form:
|
||||
move_form.product_id = self.product_c
|
||||
move_form.product_uom_qty = 1
|
||||
task_form.save()
|
||||
move_product_c = self.task.move_ids.filtered(
|
||||
lambda x: x.product_id == self.product_c
|
||||
)
|
||||
self.assertEqual(move_product_c.group_id, self.task.group_id)
|
||||
self.assertEqual(move_product_c.state, "draft")
|
||||
self.task.action_assign()
|
||||
self.assertEqual(move_product_c.state, "assigned")
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
# action_done
|
||||
self.task.action_done()
|
||||
self.assertEqual(self.move_product_a.state, "done")
|
||||
self.assertEqual(self.move_product_b.state, "done")
|
||||
self.assertEqual(self.move_product_a.quantity_done, 2)
|
||||
self.assertEqual(self.move_product_b.quantity_done, 1)
|
||||
self.assertEqual(move_product_c.quantity_done, 1)
|
||||
|
||||
@users("basic-user")
|
||||
def test_project_task_process_done_basic_user(self):
|
||||
self.test_project_task_process_done()
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_project_task_process_cancel(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.assertEqual(self.move_product_a.state, "draft")
|
||||
self.assertEqual(self.move_product_b.state, "draft")
|
||||
# Change task stage
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.assertEqual(self.move_product_a.state, "assigned")
|
||||
self.assertEqual(self.move_product_b.state, "assigned")
|
||||
# action_done
|
||||
self.task.action_done()
|
||||
self.assertEqual(self.move_product_a.state, "done")
|
||||
self.assertEqual(self.move_product_b.state, "done")
|
||||
self.assertEqual(self.move_product_a.quantity_done, 2)
|
||||
self.assertEqual(self.move_product_b.quantity_done, 1)
|
||||
self.assertTrue(self.task.sudo().stock_analytic_line_ids)
|
||||
# action_cancel
|
||||
self.task.action_cancel()
|
||||
self.assertEqual(self.move_product_a.state, "done")
|
||||
self.assertEqual(self.move_product_b.state, "done")
|
||||
self.assertEqual(self.move_product_a.quantity_done, 0)
|
||||
self.assertEqual(self.move_product_b.quantity_done, 0)
|
||||
self.assertFalse(self.task.stock_analytic_line_ids)
|
||||
quant_a = self.product_a.stock_quant_ids.filtered(
|
||||
lambda x: x.location_id == self.location
|
||||
)
|
||||
quant_b = self.product_b.stock_quant_ids.filtered(
|
||||
lambda x: x.location_id == self.location
|
||||
)
|
||||
quant_c = self.product_c.stock_quant_ids.filtered(
|
||||
lambda x: x.location_id == self.location
|
||||
)
|
||||
self.assertEqual(quant_a.quantity, 2)
|
||||
self.assertEqual(quant_b.quantity, 1)
|
||||
self.assertEqual(quant_c.quantity, 1)
|
||||
|
||||
@users("manager-user")
|
||||
def test_project_task_process_cancel_manager_user(self):
|
||||
self.test_project_task_process_cancel()
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_project_task_process_unreserve(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.assertEqual(self.move_product_a.state, "draft")
|
||||
self.assertEqual(self.move_product_b.state, "draft")
|
||||
# Change task stage (auto-confirm + auto-assign)
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.assertTrue(self.move_product_a.move_line_ids)
|
||||
self.assertEqual(self.move_product_a.move_line_ids.task_id, self.task)
|
||||
self.assertEqual(self.move_product_a.state, "assigned")
|
||||
self.assertEqual(self.move_product_b.state, "assigned")
|
||||
self.assertEqual(self.move_product_a.reserved_availability, 2)
|
||||
self.assertEqual(self.move_product_b.reserved_availability, 1)
|
||||
self.assertTrue(self.task.unreserve_visible)
|
||||
# button_unreserve
|
||||
self.task.button_unreserve()
|
||||
self.assertEqual(self.move_product_a.state, "confirmed")
|
||||
self.assertEqual(self.move_product_b.state, "confirmed")
|
||||
self.assertEqual(self.move_product_a.reserved_availability, 0)
|
||||
self.assertEqual(self.move_product_b.reserved_availability, 0)
|
||||
self.assertFalse(self.task.unreserve_visible)
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_project_task_process_01(self):
|
||||
"""Product A move cancel + Product B move OK."""
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.move_product_b.unlink()
|
||||
self.assertEqual(self.move_product_a.state, "draft")
|
||||
# Confirm + Edit to qty=0
|
||||
self.task.action_confirm()
|
||||
self.assertEqual(self.move_product_a.state, "assigned")
|
||||
self.move_product_a.product_uom_qty = 0
|
||||
self.task.action_done()
|
||||
self.assertEqual(self.move_product_a.state, "cancel")
|
||||
# Add extra line
|
||||
task_form = Form(self.task)
|
||||
with task_form.move_ids.new() as move_form:
|
||||
move_form.product_id = self.product_b
|
||||
move_form.product_uom_qty = 1
|
||||
task_form.save()
|
||||
self.move_product_b = self.task.move_ids.filtered(
|
||||
lambda x: x.product_id == self.product_b
|
||||
)
|
||||
self.task.action_confirm()
|
||||
self.assertEqual(self.move_product_b.state, "assigned")
|
||||
self.task.action_done()
|
||||
self.assertEqual(self.move_product_b.state, "done")
|
||||
|
||||
def test_project_task_process_02(self):
|
||||
self.task.action_confirm()
|
||||
self.assertEqual(self.move_product_a.state, "assigned")
|
||||
self.assertEqual(self.move_product_b.state, "assigned")
|
||||
self.task.action_done()
|
||||
self.assertEqual(self.move_product_a.state, "done")
|
||||
self.assertEqual(self.move_product_b.state, "done")
|
||||
self.assertEqual(len(self.task.stock_analytic_line_ids), 2)
|
||||
self.task.action_done()
|
||||
self.assertEqual(len(self.task.stock_analytic_line_ids), 2)
|
||||
|
||||
@users("basic-user")
|
||||
def test_project_task_process_unreserve_basic_user(self):
|
||||
self.test_project_task_process_unreserve()
|
||||
|
||||
def test_project_task_action_cancel(self):
|
||||
self.assertTrue(self.env["project.task"].browse(self.task.id).action_cancel())
|
||||
|
||||
@users("basic-user")
|
||||
def test_project_task_action_cancel_basic_user(self):
|
||||
self.test_project_task_action_cancel()
|
||||
|
||||
def test_project_task_action_done(self):
|
||||
self.task = self.env["project.task"].browse(self.task.id)
|
||||
self.task.write({"stage_id": self.stage_done.id})
|
||||
self.task.action_done()
|
||||
self.assertTrue(self.task.sudo().stock_analytic_line_ids)
|
||||
|
||||
@users("basic-user")
|
||||
def test_project_task_action_done_basic_user(self):
|
||||
self.test_project_task_action_done()
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_project_task_unlink(self):
|
||||
self.assertTrue(self.env["project.task"].browse(self.task.id).unlink())
|
||||
|
||||
@users("basic-user")
|
||||
def test_project_task_unlink_basic_user(self):
|
||||
self.test_project_task_unlink()
|
||||
|
||||
@mute_logger("odoo.models.unlink")
|
||||
def test_project_project_onchange(self):
|
||||
new_type = self.env.ref("stock.picking_type_out")
|
||||
self.project.write({"picking_type_id": new_type.id})
|
||||
self.project._onchange_picking_type_id()
|
||||
self.assertEqual(self.project.location_id, new_type.default_location_src_id)
|
||||
self.assertEqual(
|
||||
self.project.location_dest_id, new_type.default_location_dest_id
|
||||
)
|
||||
self.task.do_unreserve()
|
||||
self.task.write({"picking_type_id": new_type.id})
|
||||
self.task._onchange_picking_type_id()
|
||||
self.assertEqual(self.task.location_id, new_type.default_location_src_id)
|
||||
self.assertEqual(self.task.location_dest_id, new_type.default_location_dest_id)
|
||||
move = fields.first(self.task.move_ids)
|
||||
self.assertEqual(move.location_id, new_type.default_location_src_id)
|
||||
|
||||
def test_project_task_scrap(self):
|
||||
move = fields.first(self.task.move_ids)
|
||||
scrap = self.env["stock.scrap"].create(
|
||||
{
|
||||
"product_id": move.product_id.id,
|
||||
"product_uom_id": move.product_id.uom_id.id,
|
||||
"scrap_qty": 1,
|
||||
"task_id": self.task.id,
|
||||
}
|
||||
)
|
||||
scrap.do_scrap()
|
||||
self.assertEqual(scrap.move_id.raw_material_task_id, self.task)
|
||||
Loading…
Add table
Add a link
Reference in a new issue