# DEEs ## Continuous Flows Below there are the list of DEEs that were created in the context of Continuous Flows Feature ### MedDevAddMaterialRankToResolution Continuous Flows - Resolve Context only for First/Last Material of Lot. Add Material's 'MedDevMaterialRank' to the context resolution values as 'MaterialRank'. - **Action Groups:** `SmartTables.SmartTables.ResolveObjectsToDataSet.Pre` - **Pre Conditions:** Override Native normal (not Line Flows) Checklist and DataCollection resolution Material is present in DEE context - so that its possible to retrieve the 'MedDevMaterialRank' attribute The Table is either 'MedDevMaterialChecklistContext' or 'MedDevMaterialDataCollectionContext' - **Action:** Override Native normal(not Line Flows) Checklist and DataCollection resolution - to pass the additional MaterialRank input key ### MedDevCheckMaterialRankOnTerminate Continuous Flows - Resolve Context only for First/Last Material of Lot. Don't allow Head or Tail materials to be terminated except via merge and Main material cannot be terminated regardless of its current rank or operation. - **Action Groups:** `BusinessObjects.Material.Merge.Pre` `BusinessObjects.Material.Terminate.Post` `BusinessObjects.MaterialCollection.Terminate.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table for the material's context (Flow, LogicalFlowPath, Product, ProductGroup, ProductionOrder). - **Action:** **Except in merge scenarios**, if one of the Materials being terminated has MedDevMaterialRank as "Head" or "Tail", throw an error: - "Head/Tail Material cannot be terminated - Adjust the Head/Trail Material Rank assignments first." (localizable) **In any scenario**, if the `AutoReEvaluationOfMaterialRanksEnabled` setting is enabled (via global config `/MedDev/ContinuousFlows/EnableGlobalAutoReEvaluationOfMaterialRanks` or via `MedDevContinuousFlowFeaturesConfig`) and the material is the main material throw an error: - "Material cannot be terminated - is the original main material of the lot." (localizable) **Rework full-loss exception:** - If termination is triggered by the controlled Continuous Flows rework full-loss path, a non-main material in active rework is allowed to terminate. - This exception only applies to the specific rework full-loss context and does not change the normal terminate validation for other scenarios. ### MedDevSetFutureMergeOnPartialSplit When doing Complex Split and TrackOut (Partial TrackOut) a Future Merge should be created to merge back that splits Material - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Pre` `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Post` `MaterialManagement.MaterialManagementOrchestration.TrackOutMaterials.Post` - **Pre Conditions:** The `MergeFutureActionOnStepEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalMergeFutureActionOnStepFeature` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table. - **Action:** Create Future Action for material being processed. ### MedDevSetMaterialRankOnMerge Continuous Flows - Resolve Context only for First/Last Material of Lot When merging, update ranks in the merged material and in the main material. - **Action Groups:** `BusinessObjects.Material.Merge.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table for the material's context (Flow, LogicalFlowPath, Product, ProductGroup, ProductionOrder). - **Action:** Set up Material attribute 'MedDevMaterialRank' If there is a "Head" + "Tail" material - If there is a "InRework" material, it's not the final merge, set the MedDevMaterialRank to "Head" - Otherwise, remove MedDevMaterialRank and clean the ManufacturerLotNumber in the final target material. (final merge) If there's a "Head" but no "Tail" (lead merge) - set the MedDevMaterialRank to "Head" in the target material. If there's a "Tail" but no "Head" (tail merge) - set the MedDevMaterialRank to "Tail" in the target material. If there's a "Middle" but no "Head" / "Tail" (middle merge) - set the MedDevMaterialRank to "Middle" in the target material. If there's a "InRework" - set the MedDevMaterialRank to the other merged rank If there's no MedDevMaterialRank set in any Material - do nothing (i.e. normal merge behavior). If ranks where changed, update main material attributes with the new CurrentHead and CurrentTail. ### MedDevSetMaterialRankOnPartialSplit Continuous Flows - Resolve Context only for First/Last Material of Lot When splitting, update the Materials attribute 'MedDevMaterialRank'. - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Pre` (> to retrieve Main Material) `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table for the material's context (Flow, LogicalFlowPath, Product, ProductGroup, ProductionOrder). If TrackOut if made with full quantity there are No splits therefore no logic to apply. - **Action:** Set up Material attribute MedDevMaterialRank and ManufacturerLotNumber. If the main material has no MedDevMaterialRank, set(first split) as: - "Tail"(configurable) on the main(that doesn't get tracked out) - "Head"(configurable) on the first split child If the main material has MedDevMaterialRank = "Tail"(subsequent splits) or "Middle" - set it as "Middle"(configurable) for each subsequent split child If the main material has MedDevMaterialRank = "Head"(multi - step partial trackout), set it - as "Middle"(configurable) on the main(that doesn't get tracked out) - as "Head"(configurable) on the new first split child If ranks where changed, update main material attributes with the new CurrentHead and CurrentTail. ### MedDevAutoPartialMerge Continuous Flows - Support Auto Partial Merge - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.MoveMaterialsToNextStep.Post` `BusinessObjects.MaterialCollection.TrackIn.Post` `BusinessObjects.MaterialCollection.TrackOut.Post` - **Pre Conditions:** - The `ContinuousFlowsEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table for the material's context (Flow, LogicalFlowPath, Product, ProductGroup, ProductionOrder). - The attribute `MedDevAllowAutoPartialMerge` of the step needs to be set to true. - The material must be associated with a production order. - **Action:** - If the production order of the material is null, nothing will happen. - If the attribute `MedDevAllowAutoPartialMerge` of a step is `false`, nothing will happen. - If the `MedDevAllowAutoPartialMerge` attribute of a step is set to `true`, and a material associated with a production order moves to the current step, it will automatically find a target material with the same system state(Queued) to merge with and update the material rank accordingly. - If the `MedDevAllowAutoPartialMerge` attribute of a step is set to `true`, and a material associated with a production order tracks in the current step, it will automatically find a target material with the same system state(InProcess) and the same resource to merge with and update the material rank accordingly. - If the `MedDevAllowAutoPartialMerge` attribute of a step is set to `true`, and a material associated with a production order tracks out the current step, it will automatically find a target material with the same system state(Processed) to merge with and update the material rank accordingly. - If no target material with the same system state is found in the current step, nothing will happen. ### MedDevAutoMovementUntilMergeOnRecordLossToZero If a full loss is recorded against a material with associated rank, handle or prepare its termination. - **Action Groups:** `BusinessObjects.Material.RecordLoss.Pre` `BusinessObjects.MaterialCollection.RecordLoss.Pre` `BusinessObjects.MaterialCollection.RecordLoss.Post` `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Pre` `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutMaterials.Post` `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutAndMoveMaterialsToNextStep.Pre` `MaterialManagement.MaterialManagementOrchestration.ComplexTrackOutAndMoveMaterialsToNextStep.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` and `AutoReEvaluationOfMaterialRanksEnabled` settings shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` and `/MedDev/ContinuousFlows/EnableGlobalAutoReEvaluationOfMaterialRanks` configuration entries or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table. Record Loss updated the material to zero primary quantity. If action trigger is the Complex Track-Out operation, then the Action will only be executed on the Complex Track-Out (Post) orchestration method and not on Record Loss operation, to prevent Track-Out to be executed more than once in the same transaction, which would result in a runtime error. Material is of rank Head, Tail, or a main material. --- Pass Through Handling - When the material is in a step configured with **IsPassThrough = true**, the system will: - **Skip dispatch operations** for that step. - **Automatically move the material to the next step** in the flow. - Continue the auto-movement logic from the next valid step. This ensures compatibility with pass-through steps and prevents invalid dispatch operations during automatic movement. --- - **Action:** Capture full-loss and rework context in `Pre`, then execute the auto-movement logic in the matching `Post`. --- Rework specific handling: - If the material is in active rework and it is not the main material, terminate it without updating the main flow. - If the material is in active rework and it is the main material: - Move it through the remaining rework path. - **Pass-through steps (if any) are automatically skipped without dispatch.** - Return it to the main flow. - Continue with the normal Continuous Flows auto-movement logic. This applies to `Record Loss/Bonus`, `Track-Out`, and `Track-Out and Move Next`. --- For **Head or Middle (main material)**: - Merge within the current step if possible, otherwise, leave material queued ready to be merged in the current or in the next step. 1. If the material is in **"Queued"** or **"Dispatched > UnDispatch"**: - Search for a **Queued** lot material in the current step to merge with. - If found, perform the merge. - If not found, do nothing: - The material is already ready to be merged (another material may come later to merge with it or this material might later be updated to a **Tail**, in which case it will perform the search actively). 2. If the material is in **"In Process" > TrackOut** or **"Processed"**: - Search for a **Processed** lot material in the current step to merge with. - If found, perform the merge. - If not found: - Move the material to the next step. - Leave it in queued state, ready to be merged. --- For **Tail**: - Actively move the material through steps until it finds another material from the same group and merges directly. 1. Search for a material from the same lot within the current step. - If found, perform the merge. - If not found: - Move to the next step and repeat the search. - **If the step is Pass Through, skip dispatch and continue moving automatically.** --- When performing the merge: - Do not terminate the source material if it is the **main material**. - If necessary, **switch** the direction of the merge (choose who merges into whom) to preserve the main material. ### MedDevUpdateMaterialRanksOnMoveNext When material moves to the next step, its rank (and those of related materials) will be recalculated. - **Action Groups:** `BusinessObjects.MaterialCollection.MoveToNextStep.Pre` `BusinessObjects.MaterialCollection.MoveToNextStep.Post` `BusinessObjects.MaterialCollection.ChangeOffFlowInformation.Pre` `BusinessObjects.MaterialCollection.ChangeOffFlowInformation.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` and `AutoReEvaluationOfMaterialRanksEnabled` settings shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` and `/MedDev/ContinuousFlows/EnableGlobalAutoReEvaluationOfMaterialRanks` configuration entries or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table. - **Action:** **Re-evaluate Material Ranks within Lot** Group materials by ManufacturerLotNumber, then sort and re-evaluate: - Prioritize **Middle**, then **Tail** and **ignore Head** materials. - Prevents Tails from merging first when a **Head quantity 0** is found in the same step, leaving out the possibility of Middles being left behind. - If the material returns from a rework flow: - If there is a Tail in the previous, update it to Tail: - If there is a Middle or a Head in the previous of the Tail, update the original Tail to Middle. - If the material was originally tracked in as Tail, store the previous `MedDevMaterialRank` in `MedDevInProcessMaterialRank` when the `KeepInProcessRankOnReworkMaterialReturnEnabled` setting is enabled via the `/MedDev/ContinuousFlows/EnableGlobalKeepInProcessRankOnReworkMaterialReturn` global configuration entry or via the `MedDevContinuousFlowFeaturesConfig` smart table. - `MedDevInProcessMaterialRank` is then used for context resolution and other scenarios that require the material’s rank. - If there is nothing in the previous of the Tail, update the original Tail to Head. - If there is a Middle in the previous: - If there is a Middle or a Tail in the behind, update it to Middle. - If there is nothing in the behind, update it to Tail. - If there is a Head in the previous: - If there is a Middle or a Tail in the behind, update it to Middle. - If there is nothing in the behind, update it to Tail. - If there is nothing in the previous, update it to Head: - If there is a Head in the behind: - If there is a Middle or Tail in the behind of the Head, update the original Head to Middle. - If there is nothing in the behind of the Head, update the original Head to Tail. **Middle** - **Step 1:** Check for a **Head** of the same lot in the **old step**: - Indicates the current Middle is not truly a middle. - **Switch roles**: - Front material becomes **Head**. - Back material becomes **Middle**. - Update the main material head attribute accordingly. - **Step 2:** If no Head in the old step, check for a **Head with quantity 0** in the **current step**: - Indicates the Head intends to terminate. - Check if there is already a Future Merge Action for Head - If exist, skip the Merge and wait for the Future Action to handle it - If not exist, Merge Head into Middle (lead merge). - **Merge logic:** - Do **not terminate** the source if it's the main material. - If necessary, **switch merge target** to preserve main material status. **TAIL** - **Step 1:** Check for any material from the same lot in the **old step**: - Indicates the current Tail is not truly a tail. - **Switch roles**: - Front material becomes **Middle** (or **Head**). - Back material becomes **Tail**. - Update both main material head and tail attributes accordingly. - **Step 2:** If switched material is now a Tail with PrimaryQuantity == 0: - Trigger Tail search for a suitable merge target. - **Step 3:** Check for a **Head with quantity 0** in the **current step**: - Indicates the Head intends to terminate. - Merge Head into Tail(unless switched to Middle already). - **Merge logic:** - Do **not terminate** the source if it's the main material. - If necessary, **switch merge target** to preserve main material status. **HEAD** - **No re-evaluation needed** for Heads. - Re-evaluations already occur during: - Merges (where Head is the final material merged with the old Head). - Splits (where ranks are reassigned post-split). - MoveNext of Middles or Tail (which automatically updates the Head as needed). **MoveNext Action** - `MedDevInProcessMaterialRank` is cleared when the material moves to the next step. ### MedDevUpdateMaterialWhenSentToRework Update material's rank when sent to rework or temporary off-flow. - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.ComplexReworkMaterial.Pre` `MaterialManagement.MaterialManagementOrchestration.ComplexReworkMaterial.Post` `MaterialManagement.MaterialManagementOrchestration.TemporaryOffFlowMaterials.Pre` `MaterialManagement.MaterialManagementOrchestration.TemporaryOffFlowMaterials.Post` - **Pre Conditions:** The `ContinuousFlowsEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalContinuousFlows` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table for the material's context (Flow, LogicalFlowPath, Product, ProductGroup, ProductionOrder). - **Action:** 1. Change the rework or temporary off-flow material's rank to the configured "**In Rework**" rank 2. Assign the new Head/Tail: - If the material is originally a "Head" and was sent to Rework or Temporary Off-Flow while Queued, find a material of the same group/flow path/state and assign it the Head rank. - If the material is originally a "Tail" and was sent to Rework Temporary Off-Flow while Queued: - if the return step is behind, find a middle material of the same group/flow path/state and assign it the Tail rank (the Head will continue to be the Head) - else do nothing ### MedDevResetInProcessMaterialRankOnAbort Reset material's attribute "MedDevInProcessMaterialRank" when abort. - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.AbortMaterialProcess.Post` - **Pre Conditions:** The `KeepInProcessRankOnReworkMaterialReturnEnabled` setting shall be enabled, either globally via the `/MedDev/ContinuousFlows/EnableGlobalKeepInProcessRankOnReworkMaterialReturn` configuration entry or contextually via the `MedDevContinuousFlowFeaturesConfig` smart table. The material must also have a non-empty `MedDevInProcessMaterialRank` attribute. - **Action Flow Overview** This action is triggered during **Abort Material Process (Post)** to clear the in-process rank history attribute when applicable. --- 1. ValidateAction (Condition Check) - Runs on: `MaterialManagement.MaterialManagementOrchestration.AbortMaterialProcess.Post` - Checks if input contains a material collection - Loads attribute: `MedDevInProcessMaterialRank` - Filters materials where this attribute is not empty - If any exist: - Stores them in context parameter `MedDevResetInProcessMaterialRankOnAbort_Materials` - Marks action for execution 2. EvaluateRule (Execution) - Retrieves stored materials from context - Clears attribute `MedDevInProcessMaterialRank` by setting it to empty string --- Result - The in-process rank history is removed for all aborted materials. ## Label Verification and Reconciliation ### MedDevRecordPrintHistory Record History of Printing Printable Documents - **Action Groups:** `BusinessObjects.PrintableDocument.Print.Post` `BusinessObjects.MaterialCollection.PrintMaterialLabel.Post` `PrintManagement.PrintManagementOrchestration.PrintPrintableDocuments.Post` - **Pre Conditions:** N/A - **Action:** Update Material Relation MedDevMaterialPrintableDocument with the requested print counts ### MedDevPreFillDataCollectionInstance Fill out the DataCollection instance based on the relation MedDevMaterialPrintableDocument of the material. - **Action Groups:** `MaterialManagement.MaterialManagementOrchestration.ComplexTrackInMaterials.Post` - **Pre Conditions:**
N/A - **Action:** If the relation MedDevMaterialPrintableDocument of a material has some values and dispatch and track in the material,then open a DataCollection instance through post data or track out wizard,the values are being populated to the DataCollection instance from MedDevMaterialPrintableDocument the relation ### MedDevIgnoreProtocolInstanceCreationOnDCViolation Prevent duplicated Protocol Instance creation when a Data Collection parameter violation targets a Protocol that already has an open instance associated with the Material or with the main Material of its Continuous Flow group. - **Action Groups:** `BusinessObjects.DataCollectionInstance.VerifyParameterViolationInfo.Post` - **Pre Conditions:** - The Data Collection Instance has a Material. - The evaluated parameter has a violation result different from `NoViolation`. - The violation is configured with a warning or error violation Protocol. - The target Protocol has the `MedDevIgnoreInstanceCreationIfAlreadyAssigned` attribute enabled. - **Action:** Check if the violating Material is already associated with an open and active Protocol Instance for the same Protocol. If so, change the `ParameterViolationInfo` result to `NoViolation`, preventing the automatic creation of a new Protocol Instance. If the Material is part of a Continuous Flow group, the action loads the main Material from the violating Material `ManufacturerLotNumber`. When the main Material is already associated with an open and active Protocol Instance for the same Protocol, the violating Material is associated to that existing instance and the `ParameterViolationInfo` result is changed to `NoViolation`. In all other scenarios, the result is not modified and the standard Data Collection violation flow continues. ### MedDevHandleProtocolInstanceCreation Handle the addition of materials when Protocol Instance is opened. - **Action Groups:** `ExceptionManagement.ExceptionManagementOrchestration.OpenProtocolInstance.Post` `BusinessObjects.DataCollectionInstance.Post.Post` - **Pre Conditions:** N/A - **Action:** When Protocol Instance is opened on label verification/reconciliation on continuous flows, associate materials from the same group (with the same Manufacturer Lot Number as the original materials) to the Protocol Instance. ## eDHR Validation and Sign-off ### MedDevMaterialProtocolContextPreValidation Pre-validates configuration to insert or update in the MedDevMaterialProtocolContext Smart Table. - **Action Groups:** N/A - **Pre Conditions:** N/A - **Action:** Checks that if the Step has **MedDevIsMatProtocolStep** attribute enabled, then for each Operation, the required fields are validated as follows: - When Operation is **AssociateMaterial**, one and only one of GroupingProperty or GroupingRule is set. - When Operation is **AttachDocument**, validate the Report column is not empty. If any of these constraints is not met, a localized exception is thrown. ### MedDevHandleProtocolValidation Handle the protocol association to materials and report generation triggering. - **Action Groups:** - `BusinessObjects.MaterialCollection.TrackOut.Post` - `BusinessObjects.MaterialCollection.MoveToNextStep.Post` - **Pre Conditions:** - Step has attribute `MedDevIsMatProtocolStep` enabled. - Protocol operations configured in SmartTable `MedDevMaterialProtocolContext`. - **Action:** Check if the Step has the `MedDevIsMatProtocolStep` attribute enabled. If so, resolve the SmartTable `MedDevMaterialProtocolContext` to get the protocol information for the current material. Depending on the resolved `Operation` value, one of two branches is executed: **Operation: `AssociateMaterial`** Determine the grouping strategy from the resolved row: - **If grouping by property:** - If property = `Name`, associate only the current material to the protocol. - If property = `ManufacturerLotNumber`, get all active materials sharing the same Manufacturer Lot Number. Returns an error if the material has no Manufacturer Lot Number set. - If property = `ProductionOrder`, get all active materials from the same Production Order. Returns an error if the material is not associated with a Production Order. - **If grouping by rule:** - Execute the configured rule, passing the current material as input, and retrieve the list of materials to associate with the Protocol. Check if there is already an open Protocol Instance for the Protocol where any of the grouped materials is assigned: - **If yes:** check which materials from the group are not yet part of the Protocol Instance, and add them to it. - **If no:** create a new Protocol Instance and associate all grouped materials to it. **Operation: `AttachDocument`** Determine the Protocol and Report name from the resolved row. If a `MaterialSelectionRule` is configured, execute it with the current material as `SourceMaterial`. If the rule returns `false`, skip this material entirely — no Integration Entry is created. Check if the current material is associated with an instance of the resolved Protocol: - **If yes:** create an Integration Entry with: - **Message Type:** `GenerateAndAttachReportToProtocol` - **Source System:** `MES` - **Target System:** `MES` - **Payload (JSON):** - `ProtocolInstanceId` — the ID of the associated Protocol Instance - `ServiceHistoryId` — the ID of the Service History that triggered this request - `ReportName` — the name/path of the report to be generated - `ReportParameters` — parameters for report to be generated - `OverrideExisting` — whether to replace an existing attachment with the same report path - `TimeZone` — Time zone of the report to be generated - `Culture` — Language of the report to be generated - **If no:** MES will prompt an error message and blocked the user from proceeding. ### MedDevCheckSourceMaterialIsTailMaterial Continuous Flows — Checks if the source material is a Tail material for Protocol Report Validation. - **Action Groups:** - Custom Rule (invoked explicitly via `MaterialSelectionRule` in `MedDevMaterialProtocolContext`) - **Pre Conditions:** - `SourceMaterial` input key is present and is a valid Material. - Continuous Flows are enabled for the material’s context. - **Action:** Evaluates whether the provided `SourceMaterial` holds the Tail rank within a Continuous Flow material group. 1. Resolves the Continuous Flows settings for the material. If Continuous Flows are not enabled, sets `Input["Result"] = false` and returns. 2. Retrieves the configured Tail rank name from the system settings. 3. Compares the material’s `MedDevMaterialRank` attribute against the Tail rank name. 4. Sets `Input["Result"] = true` if the material is the Tail material; `false` otherwise. Use this rule as the `MaterialSelectionRule` in the `MedDevMaterialProtocolContext` Smart Table to ensure only the Tail material in a Continuous Flow lot triggers report generation during the `AttachDocument` operation. ### MedDevGenerateAndAttachReportToProtocol Generate a Stimulsoft report and attach it as a PDF document to a Protocol Instance. - **Action Groups:** - Integration Handler — triggered by an Integration Entry with message type `GenerateAndAttachReport` - **Pre Conditions:** - An Integration Entry with the `GenerateAndAttachReport` message type exists and is pending processing. - The Protocol Instance referenced in the message exists. - If `OverrideExisting` is `false`, no attachment with the same report path already exists on the Protocol Instance (otherwise the action skips execution). - **Action:** Processes a `GenerateAndAttachReport` Integration Entry created by `MedDevHandleProtocolValidation`. 1. Parses the JSON message body from the Integration Entry, extracting: - `ProtocolInstanceId` — the target Protocol Instance ID. - `ServiceHistoryId` — the Service History ID that originated the request. - `ReportName` — the full path of the Stimulsoft report to generate. - `ReportParameters` — optional key-value parameters passed to the report. - `OverrideExisting` — whether to replace an existing attachment. - `ValidateReplication` - whether to validate the Service History ID has already been replicated to ODS. - `TimeZone` and `Culture` — locale settings for the report. 2. Checks if `ValidateReplication` is `true`, by querying ODS (via OData Services) to confirm that the provided `ServiceHistoryId` has been replicated. - If yes, then proceeds with report generation. - If no, then execution is aborted and the integration entry is marked as failed. 2. Checks if the Protocol Instance already has an attachment for the same report path: - If yes and `OverrideExisting` is `false`, execution is aborted. - If yes and `OverrideExisting` is `true`, the existing attachment is queued for removal. 3. Loads the Stimulsoft report definition from the Analytics Views folder. 4. Updates OData data source connection strings to point to the internal Data Manager service, injecting an access token for authentication. 5. Applies the provided report parameters (timezone, culture, and any custom parameters) to the report variables. 6. Renders the report and exports it to a PDF file. 7. Attaches the generated PDF to the Protocol Instance via `FullUpdateEntityAttachments`, removing the old attachment if applicable. ### MedDevPreventTailMaterialTrackInWhenMaterialIsInRework Prevent Tail material from performing Track-In when there are rework materials returning to the same step. - **Action Groups:** `BusinessObjects.Material.TrackIn.Pre` - **Pre Conditions:** - Material exists in context (MedDevPreventTailMaterialTrackInWhenMaterialIsInRework_Material) - Material has a valid Manufacturer Lot Number - Material is considered a Tail material (handled externally by context/flow logic) - **Action:** Retrieve the current material from context. - Validate that the material is not null. If null, throw exception. Check if the material has a valid Manufacturer Lot Number. If empty or null: Do nothing and allow Track-In to proceed. Retrieve all materials belonging to the same Manufacturer Lot Number. Load OffFlow information for all materials in the same lot. Filter materials that: - Are not the current Tail material - Have OffFlows defined - Have at least one OffFlow where: - ReturnStep is defined - ReturnStep.Id matches the current material Step - ReturnLogicalFlowPath matches the current material logical flowpath Evaluate if there are any materials in rework returning to the same step. If yes: - Block the Track-In operation by throwing localized exception MEDDEV_TAIL_MATERIAL_CANNOT_TRACK_IN Exception parameters: - Material Name - Step Name If no: - Allow Track-In to proceed normally Purpose: - Ensure that a Tail material does not advance in the flow when there are rework materials returning to the same step, preserving the integrity of the Tail position in Continuous Flow scenarios. ### MedDevPreventZeroQuantityHeadMaterialTrackIn Prevent Head materials with zero quantity from performing Track-In. - **Action Groups:** `BusinessObjects.MaterialCollection.TrackIn.Pre` - **Pre Conditions:** - Features `/MedDev/ContinuousFlows/EnableContinuousFlows` and `/MedDev/ContinuousFlows/EnableAutoReEvaluationOfMaterialRanks` are enabled - At least one material in the collection is identified as Head - The Head material has PrimaryQuantity equal to 0 - **Action:** Retrieve the MaterialCollection from input. Validate that: - The action group is `BusinessObjects.MaterialCollection.TrackIn.Pre` - The MaterialCollection is not null or empty - Continuous Flows and Auto Re-evaluation of Material Ranks are enabled Load Continuous Flows context parameters and retrieve the configured Head rank name. Evaluate the materials in the collection and identify whether there is a Head material with zero quantity. - If the material PrimaryQuantity is not loaded, load the material first - If no invalid Head material is found: - Do nothing and allow Track-In to proceed - If a Head material with zero quantity is found: - Store the material in context (`MedDevPreventZeroQuantityHeadMaterialTrackIn_Material`) - Block the Track-In operation by throwing localized exception `MEDDEV_ZERO_QUANTITY_HEAD_MATERIAL_CANNOT_TRACK_IN` Purpose: - Prevent invalid manual Track-In of zero-quantity Head materials that are waiting to be merged in Auto Reevaluate Ranks scenarios, avoiding inconsistent states before `MedDevUpdateMaterialRanksOnMoveNext` executes. ## Integration Handler ### MedDevHandleFailedIntegrationEntries This is an error handling action for Integration Entries. If hooked into a `IntegrationHandlerResolution` smart table row, it will be triggered when an Integration Entry processing fails. The action will check the error message and if it contains certain keywords, it will automatically set the entry to be retried. Currently, this action will set to auto retry entries in the following scenarios: - Report generation failure due to ODS replication latency **Action groups** N/A **Pre-conditions** N/A **Action** - First compare the number of retries from the integration entry to the max number of retries supported by the environment (config entry `/Cmf/System/Configuration/Integration/MaxNumberOfRetries/`). If the entry has already been retried the maximum number of times, the entry is not set as retriable. - For each event we need to reprocess, there will be one or more tokens. If those tokens are present in the entry's error message, then the entry is set to be retried.