Skip to content

Commit

Permalink
Merge pull request OCA#18 from guewen/13.0-shopfloor-test-as-user
Browse files Browse the repository at this point in the history
backend: run tests as a stock user
  • Loading branch information
simahawk authored May 27, 2020
2 parents 5a80041 + 11730a7 commit a3baaf2
Show file tree
Hide file tree
Showing 32 changed files with 411 additions and 235 deletions.
12 changes: 9 additions & 3 deletions shopfloor/actions/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class InventoryAction(Component):
_inherit = "shopfloor.process.action"
_usage = "inventory"

@property
def inventory_model(self):
# the _sf_inventory key bypass groups checks,
# see comment in models/stock_inventory.py
return self.env["stock.inventory"].with_context(_sf_inventory=True)

def create_draft_check_empty(self, location, product, ref=None):
"""Create a draft inventory for a product with a zero quantity"""
if ref:
Expand All @@ -35,10 +41,10 @@ def _inventory_exists(
domain.append(("package_id", "=", package.id))
if lot is not None:
domain.append(("lot_id", "=", lot.id))
return self.env["stock.inventory"].search_count(domain)
return self.inventory_model.search_count(domain)

def _create_draft_inventory(self, location, product, name):
return self.env["stock.inventory"].create(
return self.inventory_model.sudo().create(
{
"name": name,
"location_ids": [(6, 0, location.ids)],
Expand Down Expand Up @@ -106,7 +112,7 @@ def create_stock_issue(self, move, location, package, lot):
values = self._stock_issue_inventory_values(
move, location, package, lot, qty_to_keep
)
inventory = self.env["stock.inventory"].create(values)
inventory = self.inventory_model.sudo().create(values)
inventory.action_start()
inventory.action_validate()
move._action_assign()
Expand Down
2 changes: 2 additions & 0 deletions shopfloor/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from . import shopfloor_menu
from . import stock_picking_type
from . import shopfloor_profile
from . import stock_inventory
from . import stock_location
from . import stock_move_line
from . import stock_package_level
from . import stock_picking
from . import stock_picking_batch
from . import stock_quant
from . import stock_quant_package
17 changes: 17 additions & 0 deletions shopfloor/models/stock_inventory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from odoo import models


class StockInventory(models.Model):
_inherit = "stock.inventory"

def user_has_groups(self, groups):
if self.env.context.get("_sf_inventory"):
allow_groups = groups.split(",")
# action_validate checks if the user is a manager, but
# in shopfloor, we want to programmatically create and
# validate inventories under the hood. sudo sets the su
# flag but not the group: allow to bypass the check when
# sudo is used.
if "stock.group_stock_manager" in allow_groups and self.env.su:
return True
return super().user_has_groups(groups)
17 changes: 17 additions & 0 deletions shopfloor/models/stock_quant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from odoo import models


class StockQuant(models.Model):
_inherit = "stock.quant"

def _is_inventory_mode(self):
""" Used to control whether a quant was written on or created during an
"inventory session", meaning a mode where we need to create the stock.move
record necessary to be consistent with the `inventory_quantity` field.
"""
# The default method check if we have the stock.group_stock_manager
# group, however, we want to force using this mode from shopfloor
# (cluster picking) when sudo is used and the user is a stock user.
if self.env.context.get("inventory_mode") is True and self.env.su:
return True
return super()._is_inventory_mode()
6 changes: 5 additions & 1 deletion shopfloor/services/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ def _response(

def _get_openapi_default_parameters(self):
defaults = super()._get_openapi_default_parameters()
demo_api_key = self.env.ref("shopfloor.api_key_demo", raise_if_not_found=False)
# Normal users can't read an API key, ignore it using sudo() only
# because it's a demo key.
demo_api_key = self.env.ref(
"shopfloor.api_key_demo", raise_if_not_found=False
).sudo()
service_params = [
{
"name": "API-KEY",
Expand Down
163 changes: 116 additions & 47 deletions shopfloor/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ def setUpClass(cls):
cls.env = cls.env(
context=dict(cls.env.context, tracking_disable=cls.tracking_disable)
)

cls.setUpComponent()
cls.setUpClassUsers()
cls.setUpClassVars()
cls.setUpClassBaseData()

with cls.work_on_actions(cls) as work:
cls.data = work.component(usage="data")
with cls.work_on_actions(cls) as work:
Expand All @@ -76,73 +79,139 @@ def setUpClass(cls):
with cls.work_on_services(cls) as work:
cls.schema_detail = work.component(usage="schema_detail")

@classmethod
def setUpClassUsers(cls):
Users = cls.env["res.users"].with_context(
{"no_reset_password": True, "mail_create_nosubscribe": True}
)
cls.stock_user = Users.create(
{
"name": "Pauline Poivraisselle",
"login": "pauline2",
"email": "p.p@example.com",
"notification_type": "inbox",
"groups_id": [(6, 0, [cls.env.ref("stock.group_stock_user").id])],
}
)
cls.env = cls.env(user=cls.stock_user)

@classmethod
def setUpClassVars(cls):
stock_location = cls.env.ref("stock.stock_location_stock")
cls.stock_location = stock_location
cls.customer_location = cls.env.ref("stock.stock_location_customers")
cls.customer_location.barcode = "CUSTOMERS"
cls.dispatch_location = cls.env.ref("stock.location_dispatch_zone")
cls.dispatch_location.barcode = "DISPATCH"
cls.packing_location = cls.env.ref("stock.location_pack_zone")
cls.packing_location.barcode = "PACKING"
cls.input_location = cls.env.ref("stock.stock_location_company")
cls.input_location.barcode = "INPUT"
cls.shelf1 = cls.env.ref("stock.stock_location_components")
cls.shelf1.barcode = "SHELF1"
cls.shelf2 = cls.env.ref("stock.stock_location_14")
cls.shelf2.barcode = "SHELF2"
cls.customer = cls.env["res.partner"].create({"name": "Customer"})

@classmethod
def setUpClassBaseData(cls):
cls.product_a = cls.env["product.product"].create(
{
"name": "Product A",
"type": "product",
"default_code": "A",
"barcode": "A",
"weight": 2,
}
cls.customer = cls.env["res.partner"].sudo().create({"name": "Customer"})

cls.customer_location.sudo().barcode = "CUSTOMERS"
cls.dispatch_location.sudo().barcode = "DISPATCH"
cls.packing_location.sudo().barcode = "PACKING"
cls.input_location.sudo().barcode = "INPUT"
cls.shelf1.sudo().barcode = "SHELF1"
cls.shelf2.sudo().barcode = "SHELF2"

cls.product_a = (
cls.env["product.product"]
.sudo()
.create(
{
"name": "Product A",
"type": "product",
"default_code": "A",
"barcode": "A",
"weight": 2,
}
)
)
cls.product_a_packaging = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_a.id, "barcode": "ProductABox"}
cls.product_a_packaging = (
cls.env["product.packaging"]
.sudo()
.create(
{
"name": "Box",
"product_id": cls.product_a.id,
"barcode": "ProductABox",
}
)
)
cls.product_b = cls.env["product.product"].create(
{
"name": "Product B",
"type": "product",
"default_code": "B",
"barcode": "B",
"weight": 3,
}
cls.product_b = (
cls.env["product.product"]
.sudo()
.create(
{
"name": "Product B",
"type": "product",
"default_code": "B",
"barcode": "B",
"weight": 3,
}
)
)
cls.product_b_packaging = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_b.id, "barcode": "ProductBBox"}
cls.product_b_packaging = (
cls.env["product.packaging"]
.sudo()
.create(
{
"name": "Box",
"product_id": cls.product_b.id,
"barcode": "ProductBBox",
}
)
)
cls.product_c = cls.env["product.product"].create(
{
"name": "Product C",
"type": "product",
"default_code": "C",
"barcode": "C",
"weight": 3,
}
cls.product_c = (
cls.env["product.product"]
.sudo()
.create(
{
"name": "Product C",
"type": "product",
"default_code": "C",
"barcode": "C",
"weight": 3,
}
)
)
cls.product_c_packaging = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_b.id, "barcode": "ProductCBox"}
cls.product_c_packaging = (
cls.env["product.packaging"]
.sudo()
.create(
{
"name": "Box",
"product_id": cls.product_b.id,
"barcode": "ProductCBox",
}
)
)
cls.product_d = cls.env["product.product"].create(
{
"name": "Product D",
"type": "product",
"default_code": "D",
"barcode": "D",
"weight": 3,
}
cls.product_d = (
cls.env["product.product"]
.sudo()
.create(
{
"name": "Product D",
"type": "product",
"default_code": "D",
"barcode": "D",
"weight": 3,
}
)
)
cls.product_d_packaging = cls.env["product.packaging"].create(
{"name": "Box", "product_id": cls.product_d.id, "barcode": "ProductDBox"}
cls.product_d_packaging = (
cls.env["product.packaging"]
.sudo()
.create(
{
"name": "Box",
"product_id": cls.product_d.id,
"barcode": "ProductDBox",
}
)
)

def assert_response(
Expand Down
14 changes: 9 additions & 5 deletions shopfloor/tests/test_actions_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@

class ActionsDataCaseBase(CommonCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
def setUpClassVars(cls):
super().setUpClassVars()
cls.wh = cls.env.ref("stock.warehouse0")
cls.picking_type = cls.wh.out_type_id
cls.packaging = cls.env["product.packaging"].create({"name": "Pallet"})

@classmethod
def setUpClassBaseData(cls):
super().setUpClassBaseData()
cls.packaging = cls.env["product.packaging"].sudo().create({"name": "Pallet"})
cls.product_b.tracking = "lot"
cls.product_c.tracking = "lot"
cls.picking = cls._create_picking(
Expand Down Expand Up @@ -230,8 +234,8 @@ def test_data_move_line_raw(self):

class ActionsDataCaseBatchPicking(ActionsDataCaseBase, PickingBatchMixin):
@classmethod
def setUpClass(cls):
super().setUpClass()
def setUpClassBaseData(cls):
super().setUpClassBaseData()
cls.batch = cls._create_picking_batch(
[
[
Expand Down
24 changes: 15 additions & 9 deletions shopfloor/tests/test_actions_data_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ def fake_colored_image(color="#4169E1", size=(800, 500)):

class ActionsDataDetailCaseBase(ActionsDataCaseBase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.package = cls.move_a.move_line_ids.package_id
def setUpClassBaseData(cls):
super().setUpClassBaseData()
cls.lot = cls.env["stock.production.lot"].create(
{"product_id": cls.product_b.id, "company_id": cls.env.company.id}
)
cls.package = cls.move_a.move_line_ids.package_id

@classmethod
def setUpClassVars(cls):
super().setUpClassVars()
cls.storage_type_pallet = cls.env.ref(
"stock_storage_type.package_storage_type_pallets"
)
Expand Down Expand Up @@ -289,24 +293,26 @@ def test_data_move_line_raw(self):
def test_product(self):
move_line = self.move_b.move_line_ids
product = move_line.product_id.with_context(location=move_line.location_id.id)
manuf = self.env["res.partner"].create({"name": "Manuf 1"})
product.write(
Partner = self.env["res.partner"].sudo()
manuf = Partner.create({"name": "Manuf 1"})
product.sudo().write(
{
"image_128": fake_colored_image(size=(128, 128)),
"manufacturer": manuf.id,
}
)
vendor_a = self.env["res.partner"].create({"name": "Supplier A"})
vendor_b = self.env["res.partner"].create({"name": "Supplier B"})
self.env["product.supplierinfo"].create(
vendor_a = Partner.create({"name": "Supplier A"})
vendor_b = Partner.create({"name": "Supplier B"})
SupplierInfo = self.env["product.supplierinfo"].sudo()
SupplierInfo.create(
{
"name": vendor_a.id,
"product_tmpl_id": product.product_tmpl_id.id,
"product_id": product.id,
"product_code": "SUPP1",
}
)
self.env["product.supplierinfo"].create(
SupplierInfo.create(
{
"name": vendor_b.id,
"product_tmpl_id": product.product_tmpl_id.id,
Expand Down
6 changes: 3 additions & 3 deletions shopfloor/tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

class AppCase(CommonCase):
@classmethod
def setUpClass(cls, *args, **kwargs):
super().setUpClass(*args, **kwargs)
def setUpClassVars(cls, *args, **kwargs):
super().setUpClassVars(*args, **kwargs)
cls.profile = cls.env.ref("shopfloor.shopfloor_profile_hb_truck_demo")
cls.profile2 = cls.env.ref("shopfloor.shopfloor_profile_shelf_1_demo")

Expand Down Expand Up @@ -61,7 +61,7 @@ def test_menu_no_profile(self):
def test_menu_by_profile(self):
"""Request /app/menu w/ a specific profile"""
# Simulate the client asking the menu
menus = self.env["shopfloor.menu"].search([])
menus = self.env["shopfloor.menu"].sudo().search([])
menu = menus[0]
menu.profile_ids = self.profile
(menus - menu).profile_ids = self.profile2
Expand Down
Loading

0 comments on commit a3baaf2

Please sign in to comment.