diff --git a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/InstanceService.cs b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/InstanceService.cs
index 0e7ed342..0d4a497e 100644
--- a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/InstanceService.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/InstanceService.cs
@@ -213,6 +213,7 @@ public class InstanceService
/// Override JSON for the trigger configuration.
/// Override priority level, or null to use template value.
/// Username of the user setting the override.
+ /// Override for the alarm's MES-reportable flag, or null to use the template value.
/// Cancellation token.
/// Result containing the alarm override or failure message.
public async Task> SetAlarmOverrideAsync(
@@ -221,6 +222,7 @@ public class InstanceService
string? triggerConfigurationOverride,
int? priorityLevelOverride,
string user,
+ bool? isMesReportableOverride = null,
CancellationToken cancellationToken = default)
{
var instance = await _repository.GetInstanceByIdAsync(instanceId, cancellationToken);
@@ -254,6 +256,7 @@ public class InstanceService
{
existingOverride.TriggerConfigurationOverride = triggerConfigurationOverride;
existingOverride.PriorityLevelOverride = priorityLevelOverride;
+ existingOverride.IsMesReportableOverride = isMesReportableOverride;
await _repository.UpdateInstanceAlarmOverrideAsync(existingOverride, cancellationToken);
await _repository.SaveChangesAsync(cancellationToken);
@@ -268,7 +271,8 @@ public class InstanceService
{
InstanceId = instanceId,
TriggerConfigurationOverride = triggerConfigurationOverride,
- PriorityLevelOverride = priorityLevelOverride
+ PriorityLevelOverride = priorityLevelOverride,
+ IsMesReportableOverride = isMesReportableOverride
};
await _repository.AddInstanceAlarmOverrideAsync(newOverride, cancellationToken);
diff --git a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs
index c524a344..e559ab45 100644
--- a/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs
+++ b/src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs
@@ -621,6 +621,7 @@ public class TemplateService
existing.Description = proposed.Description;
existing.OnTriggerScriptId = proposed.OnTriggerScriptId;
existing.IsLocked = proposed.IsLocked;
+ existing.IsMesReportable = proposed.IsMesReportable;
if (template?.IsDerived == true)
existing.IsInherited = proposed.IsInherited;
else
diff --git a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/InstanceServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/InstanceServiceTests.cs
index b7e0a7fc..ae38bade 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/InstanceServiceTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/InstanceServiceTests.cs
@@ -220,6 +220,101 @@ public class InstanceServiceTests
Assert.Contains("locked", result.Error, StringComparison.OrdinalIgnoreCase);
}
+ [Fact]
+ public async Task SetAlarmOverrideAsync_StoresIsMesReportableOverride()
+ {
+ var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
+ _repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny()))
+ .ReturnsAsync(instance);
+ _repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny()))
+ .ReturnsAsync(new List
+ {
+ TemplateWithAlarms(1, new TemplateAlarm("HighTemp") { Id = 10, IsLocked = false })
+ });
+ _repoMock.Setup(r => r.GetAlarmOverrideAsync(1, "HighTemp", It.IsAny()))
+ .ReturnsAsync((InstanceAlarmOverride?)null);
+ _repoMock.Setup(r => r.SaveChangesAsync(It.IsAny()))
+ .ReturnsAsync(1);
+
+ InstanceAlarmOverride? added = null;
+ _repoMock.Setup(r => r.AddInstanceAlarmOverrideAsync(
+ It.IsAny(), It.IsAny()))
+ .Callback((o, _) => added = o);
+
+ var result = await _sut.SetAlarmOverrideAsync(
+ 1, "HighTemp", "{}", null, "admin", isMesReportableOverride: true);
+
+ Assert.True(result.IsSuccess);
+ Assert.NotNull(added);
+ Assert.True(added!.IsMesReportableOverride);
+ Assert.True(result.Value.IsMesReportableOverride);
+ }
+
+ [Fact]
+ public async Task SetAlarmOverrideAsync_NullIsMesReportableOverride_ClearsExistingOverride()
+ {
+ var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
+ _repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny()))
+ .ReturnsAsync(instance);
+ _repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny()))
+ .ReturnsAsync(new List
+ {
+ TemplateWithAlarms(1, new TemplateAlarm("HighTemp") { Id = 10, IsLocked = false })
+ });
+
+ var existingOverride = new InstanceAlarmOverride("HighTemp")
+ {
+ Id = 5,
+ InstanceId = 1,
+ IsMesReportableOverride = true
+ };
+ _repoMock.Setup(r => r.GetAlarmOverrideAsync(1, "HighTemp", It.IsAny()))
+ .ReturnsAsync(existingOverride);
+ _repoMock.Setup(r => r.SaveChangesAsync(It.IsAny()))
+ .ReturnsAsync(1);
+
+ var result = await _sut.SetAlarmOverrideAsync(
+ 1, "HighTemp", "{}", null, "admin", isMesReportableOverride: null);
+
+ Assert.True(result.IsSuccess);
+ Assert.Null(existingOverride.IsMesReportableOverride);
+ Assert.Null(result.Value.IsMesReportableOverride);
+ _repoMock.Verify(r => r.UpdateInstanceAlarmOverrideAsync(
+ It.Is(o => o.IsMesReportableOverride == null),
+ It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ public async Task SetAlarmOverrideAsync_UpdatesIsMesReportableOverrideOnExisting()
+ {
+ var instance = new Instance("Inst1") { Id = 1, TemplateId = 1 };
+ _repoMock.Setup(r => r.GetInstanceByIdAsync(1, It.IsAny()))
+ .ReturnsAsync(instance);
+ _repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny()))
+ .ReturnsAsync(new List
+ {
+ TemplateWithAlarms(1, new TemplateAlarm("HighTemp") { Id = 10, IsLocked = false })
+ });
+
+ var existingOverride = new InstanceAlarmOverride("HighTemp")
+ {
+ Id = 5,
+ InstanceId = 1,
+ IsMesReportableOverride = null
+ };
+ _repoMock.Setup(r => r.GetAlarmOverrideAsync(1, "HighTemp", It.IsAny()))
+ .ReturnsAsync(existingOverride);
+ _repoMock.Setup(r => r.SaveChangesAsync(It.IsAny()))
+ .ReturnsAsync(1);
+
+ var result = await _sut.SetAlarmOverrideAsync(
+ 1, "HighTemp", "{}", 3, "admin", isMesReportableOverride: false);
+
+ Assert.True(result.IsSuccess);
+ Assert.False(existingOverride.IsMesReportableOverride);
+ Assert.Equal(3, existingOverride.PriorityLevelOverride);
+ }
+
[Fact]
public async Task Enable_ExistingInstance_SetsEnabled()
{
diff --git a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs
index 7c7adc1f..e00ac6a3 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs
@@ -530,6 +530,65 @@ public class TemplateServiceTests
Assert.Contains("TriggerType", result.Error);
}
+ [Fact]
+ public async Task UpdateAlarmAsync_CopiesIsMesReportable()
+ {
+ var existing = new TemplateAlarm("HighTemp")
+ {
+ Id = 1,
+ TemplateId = 1,
+ TriggerType = AlarmTriggerType.ValueMatch,
+ PriorityLevel = 500,
+ IsMesReportable = false
+ };
+ _repoMock.Setup(r => r.GetTemplateAlarmByIdAsync(1, It.IsAny())).ReturnsAsync(existing);
+
+ var template = new Template("Pump") { Id = 1 };
+ _repoMock.Setup(r => r.GetTemplateByIdAsync(1, It.IsAny())).ReturnsAsync(template);
+
+ var proposed = new TemplateAlarm("HighTemp")
+ {
+ TriggerType = AlarmTriggerType.ValueMatch,
+ PriorityLevel = 500,
+ IsMesReportable = true
+ };
+ var result = await _service.UpdateAlarmAsync(1, proposed, "admin");
+
+ Assert.True(result.IsSuccess);
+ Assert.True(result.Value.IsMesReportable);
+ Assert.True(existing.IsMesReportable);
+ _repoMock.Verify(r => r.UpdateTemplateAlarmAsync(
+ It.Is(a => a.IsMesReportable), It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ public async Task UpdateAlarmAsync_ClearsIsMesReportable()
+ {
+ var existing = new TemplateAlarm("HighTemp")
+ {
+ Id = 1,
+ TemplateId = 1,
+ TriggerType = AlarmTriggerType.ValueMatch,
+ PriorityLevel = 500,
+ IsMesReportable = true
+ };
+ _repoMock.Setup(r => r.GetTemplateAlarmByIdAsync(1, It.IsAny())).ReturnsAsync(existing);
+
+ var template = new Template("Pump") { Id = 1 };
+ _repoMock.Setup(r => r.GetTemplateByIdAsync(1, It.IsAny())).ReturnsAsync(template);
+
+ var proposed = new TemplateAlarm("HighTemp")
+ {
+ TriggerType = AlarmTriggerType.ValueMatch,
+ PriorityLevel = 500,
+ IsMesReportable = false
+ };
+ var result = await _service.UpdateAlarmAsync(1, proposed, "admin");
+
+ Assert.True(result.IsSuccess);
+ Assert.False(result.Value.IsMesReportable);
+ }
+
// ========================================================================
// WP-4: Script Definitions
// ========================================================================