diff --git a/client/packages/common/src/intl/locales/en/common.json b/client/packages/common/src/intl/locales/en/common.json index 5e9356b397..787885758d 100644 --- a/client/packages/common/src/intl/locales/en/common.json +++ b/client/packages/common/src/intl/locales/en/common.json @@ -284,6 +284,7 @@ "error.no-asset-view-permission": "You do not have permission to view assets.", "error.no-customer-return-items": "No items have been added to this return.", "error.no-customer-returns": "There are no Customer Returns to display.", + "error.no-create-outbound-shipment-permission": "You do not have permission to create an Outbound Shipment from a Requisition", "error.no-data": "No data available", "error.no-immunisation-programs": "No Immunization programs found", "error.no-inbound-items": "No items have been added to this shipment.", diff --git a/client/packages/common/src/types/schema.ts b/client/packages/common/src/types/schema.ts index 93c8cb7ae2..b65bf2a90b 100644 --- a/client/packages/common/src/types/schema.ts +++ b/client/packages/common/src/types/schema.ts @@ -8907,6 +8907,7 @@ export enum UserPermission { PrescriptionMutate = 'PRESCRIPTION_MUTATE', PrescriptionQuery = 'PRESCRIPTION_QUERY', Report = 'REPORT', + RequisitionCreateOutboundShipment = 'REQUISITION_CREATE_OUTBOUND_SHIPMENT', RequisitionMutate = 'REQUISITION_MUTATE', RequisitionQuery = 'REQUISITION_QUERY', RequisitionSend = 'REQUISITION_SEND', diff --git a/client/packages/requisitions/src/ResponseRequisition/DetailView/Footer/CreateShipmentButton.tsx b/client/packages/requisitions/src/ResponseRequisition/DetailView/Footer/CreateShipmentButton.tsx index 605241d3e3..295bbffcd6 100644 --- a/client/packages/requisitions/src/ResponseRequisition/DetailView/Footer/CreateShipmentButton.tsx +++ b/client/packages/requisitions/src/ResponseRequisition/DetailView/Footer/CreateShipmentButton.tsx @@ -7,6 +7,8 @@ import { useAlertModal, RouteBuilder, useNavigate, + useCallbackWithPermission, + UserPermission, } from '@openmsupply-client/common'; import { useResponse } from '../../api'; import { AppRoute } from '@openmsupply-client/config/src'; @@ -55,11 +57,17 @@ export const CreateShipmentButtonComponent = () => { } }; + const handleClick = useCallbackWithPermission( + UserPermission.RequisitionCreateOutboundShipment, + onCreateShipment, + t('error.no-create-outbound-shipment-permission') + ); + return ( } label={t('button.create-shipment')} - onClick={onCreateShipment} + onClick={handleClick} disabled={isDisabled} color="secondary" /> diff --git a/server/graphql/requisition/src/mutations/response_requisition/create_requisition_shipment.rs b/server/graphql/requisition/src/mutations/response_requisition/create_requisition_shipment.rs index 6eb92e0e4d..6591ca927b 100644 --- a/server/graphql/requisition/src/mutations/response_requisition/create_requisition_shipment.rs +++ b/server/graphql/requisition/src/mutations/response_requisition/create_requisition_shipment.rs @@ -48,7 +48,7 @@ pub fn create_requisition_shipment( let user = validate_auth( ctx, &ResourceAccessRequest { - resource: Resource::MutateRequisition, + resource: Resource::CreateOutboundShipmentFromRequisition, store_id: Some(store_id.to_string()), }, )?; diff --git a/server/graphql/tests/permissions.rs b/server/graphql/tests/permissions.rs index 43a82595b9..b01833c4b5 100644 --- a/server/graphql/tests/permissions.rs +++ b/server/graphql/tests/permissions.rs @@ -526,7 +526,7 @@ mod permission_tests { } }"#, expected: ResourceAccessRequest { - resource: Resource::MutateRequisition, + resource: Resource::CreateOutboundShipmentFromRequisition, store_id: Some("some".to_string()), }, }, diff --git a/server/graphql/types/src/types/permissions.rs b/server/graphql/types/src/types/permissions.rs index a1caeefbee..7588da97dc 100644 --- a/server/graphql/types/src/types/permissions.rs +++ b/server/graphql/types/src/types/permissions.rs @@ -30,6 +30,7 @@ pub enum UserPermission { RequisitionQuery, RequisitionMutate, RequisitionSend, + RequisitionCreateOutboundShipment, RnRFormQuery, RnRFormMutate, OutboundShipmentQuery, @@ -113,6 +114,9 @@ impl UserPermission { PermissionType::InventoryAdjustmentMutate => UserPermission::InventoryAdjustmentMutate, PermissionType::RequisitionQuery => UserPermission::RequisitionQuery, PermissionType::RequisitionMutate => UserPermission::RequisitionMutate, + PermissionType::RequisitionCreateOutboundShipment => { + UserPermission::RequisitionCreateOutboundShipment + } PermissionType::RnrFormQuery => UserPermission::RnRFormQuery, PermissionType::RnrFormMutate => UserPermission::RnRFormMutate, PermissionType::RequisitionSend => UserPermission::RequisitionSend, @@ -164,6 +168,9 @@ impl UserPermission { UserPermission::RequisitionQuery => PermissionType::RequisitionQuery, UserPermission::RequisitionMutate => PermissionType::RequisitionMutate, UserPermission::RequisitionSend => PermissionType::RequisitionSend, + UserPermission::RequisitionCreateOutboundShipment => { + PermissionType::RequisitionCreateOutboundShipment + } UserPermission::RnRFormQuery => PermissionType::RnrFormQuery, UserPermission::RnRFormMutate => PermissionType::RnrFormMutate, UserPermission::OutboundShipmentQuery => PermissionType::OutboundShipmentQuery, diff --git a/server/repository/src/db_diesel/user_permission_row.rs b/server/repository/src/db_diesel/user_permission_row.rs index 62623b470b..ddc5f9e292 100644 --- a/server/repository/src/db_diesel/user_permission_row.rs +++ b/server/repository/src/db_diesel/user_permission_row.rs @@ -44,6 +44,7 @@ pub enum PermissionType { RequisitionQuery, RequisitionMutate, RequisitionSend, + RequisitionCreateOutboundShipment, // r&r form, RnrFormQuery, RnrFormMutate, diff --git a/server/repository/src/migrations/v2_06_00/add_create_invoice_from_requisition_permission.rs b/server/repository/src/migrations/v2_06_00/add_create_invoice_from_requisition_permission.rs new file mode 100644 index 0000000000..dce105474d --- /dev/null +++ b/server/repository/src/migrations/v2_06_00/add_create_invoice_from_requisition_permission.rs @@ -0,0 +1,22 @@ +use crate::migrations::*; + +pub(crate) struct Migrate; + +impl MigrationFragment for Migrate { + fn identifier(&self) -> &'static str { + "add_create_invoice_from_requisition_permission" + } + + fn migrate(&self, connection: &StorageConnection) -> anyhow::Result<()> { + if cfg!(feature = "postgres") { + sql!( + connection, + r#" + ALTER TYPE permission_type ADD VALUE IF NOT EXISTS 'REQUISITION_CREATE_OUTBOUND_SHIPMENT'; + "# + )?; + } + + Ok(()) + } +} diff --git a/server/repository/src/migrations/v2_06_00/mod.rs b/server/repository/src/migrations/v2_06_00/mod.rs index 387112686b..076af22bd5 100644 --- a/server/repository/src/migrations/v2_06_00/mod.rs +++ b/server/repository/src/migrations/v2_06_00/mod.rs @@ -1,5 +1,6 @@ use super::{version::Version, Migration, MigrationFragment}; +mod add_create_invoice_from_requisition_permission; mod add_index_to_sync_buffer; mod add_program_deleted_datetime; use crate::StorageConnection; @@ -19,6 +20,7 @@ impl Migration for V2_06_00 { vec![ Box::new(add_index_to_sync_buffer::Migrate), Box::new(add_program_deleted_datetime::Migrate), + Box::new(add_create_invoice_from_requisition_permission::Migrate), ] } } diff --git a/server/service/src/auth.rs b/server/service/src/auth.rs index 425dfcb376..5aa22721af 100644 --- a/server/service/src/auth.rs +++ b/server/service/src/auth.rs @@ -67,6 +67,7 @@ pub enum Resource { RequisitionChart, RequisitionStats, RequisitionSend, + CreateOutboundShipmentFromRequisition, // stock take line InsertStocktakeLine, UpdateStocktakeLine, @@ -335,6 +336,14 @@ fn all_permissions() -> HashMap { PermissionDSL::HasPermission(PermissionType::RequisitionSend), ]), ); + + map.insert( + Resource::CreateOutboundShipmentFromRequisition, + PermissionDSL::And(vec![ + PermissionDSL::HasStoreAccess, + PermissionDSL::HasPermission(PermissionType::RequisitionCreateOutboundShipment), + ]), + ); // r&r form map.insert( Resource::QueryRnRForms, diff --git a/server/service/src/login.rs b/server/service/src/login.rs index f2fafd3180..eed7122370 100644 --- a/server/service/src/login.rs +++ b/server/service/src/login.rs @@ -448,6 +448,9 @@ fn permissions_to_domain(permissions: Vec) -> HashSet { output.insert(PermissionType::RequisitionSend); } + Permissions::CreateCustomerInvoicesFromRequisitions => { + output.insert(PermissionType::RequisitionCreateOutboundShipment); + } // reports Permissions::ViewReports => { output.insert(PermissionType::Report);