diff --git a/documentation/changelog.rst b/documentation/changelog.rst index b51fcfe824..9198b2e121 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -18,8 +18,8 @@ Infrastructure / Support Bugfixes ----------- +* Show the child asset creation button to consultants working on a client organisation's assets [see `PR #2851 `_] * Apply storage losses to the starting stock of a state of charge shared by several devices, so its scheduled state of charge no longer drifts above the one the scheduler planned with [see `PR #2838 `_] - * Hovering anywhere over a session in the Charge Points chart shows its tooltip again, listing all of the session's timestamps, as it did before the move to ECharts, without highlighting another charger's session; also, a chart's tooltip no longer shows a point from a neighbouring subplot [see `PR #2829 `_] diff --git a/flexmeasures/ui/tests/test_asset_crud.py b/flexmeasures/ui/tests/test_asset_crud.py index 14d7915908..769f944826 100644 --- a/flexmeasures/ui/tests/test_asset_crud.py +++ b/flexmeasures/ui/tests/test_asset_crud.py @@ -675,9 +675,9 @@ def test_breadcrumb_cross_account_parent( # - GenericAsset.create-children (child assets/sensors) → any organisation member # - Account.create-children (top-level assets) → organisation-admin or consultant # -# "user_can_create_assets" (Account.create-children) gates: -# • The "Create asset" child-asset button on the properties page -# • The "Copy this asset" / "Copy to " copy buttons +# "user_can_create_assets" (Account.edit-assets) gates the +# "Create asset" child-asset button on the properties page. +# The copy buttons have separate permission checks for their target locations. # "user_can_update_asset" (GenericAsset.update) gates the "Edit asset" sidepanel. # "user_can_delete_asset" (GenericAsset.edit-assets, plus delete-data if the asset holds data) gates the "Delete this asset" button. # --------------------------------------------------------------------------- @@ -759,6 +759,7 @@ def test_copy_to_own_account_button_for_cross_account_admin( assert page.status_code == 200 assert b"Copy to Test Dummy Account" in page.data assert b"Copy this asset" not in page.data + assert b"Create asset" not in page.data @pytest.mark.parametrize( @@ -806,11 +807,11 @@ def test_edit_panel_visibility_on_properties_page( ("as_admin", True, True), # Account-admin of same account: same rights. ("as_prosumer_account_admin", True, True), - # Plain account member: cannot delete an asset holding data or create top-level assets. + # Plain account member: cannot delete an asset holding data or use the UI to add children. ("as_prosumer_user1", False, False), ], ) -def test_admin_only_buttons_on_properties_page( +def test_delete_and_create_buttons_on_properties_page( db, client, setup_assets, @@ -820,8 +821,8 @@ def test_admin_only_buttons_on_properties_page( expect_create_asset_btn, ): """ - 'Delete this asset' and 'Create asset' (child asset via account) are - gated on account-admin permissions and must not appear for plain users. + Deleting an asset holding data and creating a child asset through the UI + both require elevated rights. """ from flexmeasures.data.services.users import find_user_by_email @@ -848,6 +849,17 @@ def test_admin_only_buttons_on_properties_page( assert b"Create asset" not in page.data +def test_consultant_can_create_child_asset_from_properties_page( + client, setup_generic_assets, as_consultant +): + parent = setup_generic_assets["test_consultancy_client_asset"] + + page = client.get(url_for("AssetCrudUI:properties", id=parent.id)) + + assert page.status_code == 200 + assert f"/assets/new?parent_asset_id={parent.id}".encode() in page.data + + @pytest.mark.parametrize( "login_fixture, expect_data_query", [ diff --git a/flexmeasures/ui/views/assets/views.py b/flexmeasures/ui/views/assets/views.py index ec61452bf4..db509b3206 100644 --- a/flexmeasures/ui/views/assets/views.py +++ b/flexmeasures/ui/views/assets/views.py @@ -513,7 +513,11 @@ def properties(self, id: str): _own_account.id if _can_copy_to_own_account else None ), own_organisation_name=_own_account.name, - user_can_create_assets=user_can_create_assets(), + user_can_create_assets=( + user_can_create_assets(account=asset.owner) + if asset.owner is not None + else current_user.has_role("admin") + ), user_can_create_children=user_can_create_children(asset), user_can_delete_asset=user_can_delete(asset), user_can_update_asset=user_can_update(asset),