From 63ec226582c81a733e7503757281d422cf3cb867 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 11 Sep 2026 10:04:17 -0400 Subject: [PATCH] feat(management): IsMesReportable on alarm commands, IsMesReportableOverride on SetInstanceAlarmOverride Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB --- .../Messages/Management/InstanceCommands.cs | 14 ++- .../Messages/Management/TemplateCommands.cs | 7 +- .../ManagementActor.cs | 8 +- .../ManagementActorTests.cs | 106 ++++++++++++++++++ 4 files changed, 128 insertions(+), 7 deletions(-) diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/InstanceCommands.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/InstanceCommands.cs index 36e50faa..92eb4370 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/InstanceCommands.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/InstanceCommands.cs @@ -34,13 +34,23 @@ public record SetInstanceAreaCommand(int InstanceId, int? AreaId); /// Sets (or upserts) a per-instance alarm override. For HiLo trigger types the /// TriggerConfigurationOverride JSON is merged setpoint-by-setpoint with /// the inherited config; for binary trigger types it replaces the whole config. -/// Either field is optional — pass null to leave it unchanged. +/// Each override field is optional — null means the instance inherits the template value +/// for that field (the row is replaced whole on every call, not merged). /// +/// ID of the instance the override applies to. +/// Canonical (path-qualified for composed members) alarm name. +/// Trigger configuration JSON override, or null. +/// Priority level override, or null. +/// +/// Per-instance override of the template alarm's MES-reportable flag. Additive trailing +/// optional; null (the default) inherits the template value, true/false forces it. +/// public record SetInstanceAlarmOverrideCommand( int InstanceId, string AlarmCanonicalName, string? TriggerConfigurationOverride, - int? PriorityLevelOverride); + int? PriorityLevelOverride, + bool? IsMesReportableOverride = null); public record DeleteInstanceAlarmOverrideCommand( int InstanceId, diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateCommands.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateCommands.cs index 35178d9b..ba6f1774 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateCommands.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateCommands.cs @@ -42,8 +42,11 @@ public record ResyncInheritedMembersCommand(int TemplateId); public record AddTemplateAttributeCommand(int TemplateId, string Name, string DataType, string? Value, string? Description, string? DataSourceReference, bool IsLocked, string? ElementDataType = null); public record UpdateTemplateAttributeCommand(int AttributeId, string Name, string DataType, string? Value, string? Description, string? DataSourceReference, bool IsLocked, string? ElementDataType = null); public record DeleteTemplateAttributeCommand(int AttributeId); -public record AddTemplateAlarmCommand(int TemplateId, string Name, string TriggerType, int PriorityLevel, string? Description, string? TriggerConfiguration, bool IsLocked); -public record UpdateTemplateAlarmCommand(int AlarmId, string Name, string TriggerType, int PriorityLevel, string? Description, string? TriggerConfiguration, bool IsLocked); +// IsMesReportable is an additive trailing optional (default false = "not reported to MES"): +// it mirrors TemplateAlarm.IsMesReportable and marks the alarm for inclusion in the MES +// alarm-status feed. Additive-only: never reorder the existing parameters. +public record AddTemplateAlarmCommand(int TemplateId, string Name, string TriggerType, int PriorityLevel, string? Description, string? TriggerConfiguration, bool IsLocked, bool IsMesReportable = false); +public record UpdateTemplateAlarmCommand(int AlarmId, string Name, string TriggerType, int PriorityLevel, string? Description, string? TriggerConfiguration, bool IsLocked, bool IsMesReportable = false); public record DeleteTemplateAlarmCommand(int AlarmId); // Native alarm source bindings (read-only mirror of an OPC UA A&C / MxGateway source's alarms) public record AddTemplateNativeAlarmSourceCommand(int TemplateId, string Name, string ConnectionName, string SourceReference, string? ConditionFilter, string? Description, bool IsLocked); diff --git a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs index 0752be61..cbb28e01 100644 --- a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs +++ b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs @@ -1175,7 +1175,7 @@ public class ManagementActor : ReceiveActor var result = await svc.SetAlarmOverrideAsync( cmd.InstanceId, cmd.AlarmCanonicalName, cmd.TriggerConfigurationOverride, cmd.PriorityLevelOverride, - user.Username); + user.Username, cmd.IsMesReportableOverride); return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error); @@ -3179,7 +3179,8 @@ public class ManagementActor : ReceiveActor PriorityLevel = cmd.PriorityLevel, Description = cmd.Description, TriggerConfiguration = cmd.TriggerConfiguration, - IsLocked = cmd.IsLocked + IsLocked = cmd.IsLocked, + IsMesReportable = cmd.IsMesReportable }; var result = await svc.AddAlarmAsync(cmd.TemplateId, alarm, user); return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error); @@ -3194,7 +3195,8 @@ public class ManagementActor : ReceiveActor PriorityLevel = cmd.PriorityLevel, Description = cmd.Description, TriggerConfiguration = cmd.TriggerConfiguration, - IsLocked = cmd.IsLocked + IsLocked = cmd.IsLocked, + IsMesReportable = cmd.IsMesReportable }; var result = await svc.UpdateAlarmAsync(cmd.AlarmId, alarm, user); return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error); diff --git a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/ManagementActorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/ManagementActorTests.cs index 232132b9..779a5cce 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/ManagementActorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/ManagementActorTests.cs @@ -1014,6 +1014,112 @@ public class ManagementActorTests : TestKit, IDisposable Assert.Contains("Valid values:", response.Error); } + [Fact] + public void AddTemplateAlarm_CarriesIsMesReportable() + { + // The MES-reportable flag rides AddTemplateAlarmCommand as a trailing + // optional (additive-only wire contract) and must reach the TemplateAlarm + // the handler hands to TemplateService — verified at the repository + // boundary, which is where the entity is persisted. + var template = new Template("T1") { Id = 1 }; + _templateRepo.GetTemplateByIdAsync(1, Arg.Any()).Returns(template); + _templateRepo.GetAllTemplatesForAnalysisAsync(Arg.Any()) + .Returns(new List