diff --git a/src/Altinn.Notifications.Persistence/Migration/v0.27/01-alter-procedure.sql b/src/Altinn.Notifications.Persistence/Migration/v0.27/01-alter-procedure.sql new file mode 100644 index 00000000..ad835331 --- /dev/null +++ b/src/Altinn.Notifications.Persistence/Migration/v0.27/01-alter-procedure.sql @@ -0,0 +1,41 @@ + +CREATE OR REPLACE PROCEDURE notifications.insertsmsnotification( +_orderid uuid, +_alternateid uuid, +_recipientorgno TEXT, +_recipientnin TEXT, +_mobilenumber TEXT, +_result text, +_smscount integer, +_resulttime timestamptz, +_expirytime timestamptz +) +LANGUAGE 'plpgsql' +AS $BODY$ +DECLARE +__orderid BIGINT := (SELECT _id from notifications.orders + where alternateid = _orderid); +BEGIN + +INSERT INTO notifications.smsnotifications( +_orderid, +alternateid, +recipientorgno, +recipientnin, +mobilenumber, +result, +smscount, +resulttime, +expirytime) +VALUES ( +__orderid, +_alternateid, +_recipientorgno, +_recipientnin, +_mobilenumber, +_result::smsnotificationresulttype, +_smscount, +_resulttime, +_expirytime); +END; +$BODY$; \ No newline at end of file diff --git a/src/Altinn.Notifications.Persistence/Migration/v0.27/02-alter-functions.sql b/src/Altinn.Notifications.Persistence/Migration/v0.27/02-alter-functions.sql new file mode 100644 index 00000000..1b7f948a --- /dev/null +++ b/src/Altinn.Notifications.Persistence/Migration/v0.27/02-alter-functions.sql @@ -0,0 +1,30 @@ +CREATE OR REPLACE FUNCTION notifications.getmetrics( + month_input int, + year_input int +) +RETURNS TABLE ( + org text, + placed_orders bigint, + sent_emails bigint, + succeeded_emails bigint, + sent_sms bigint, + succeeded_sms bigint +) +AS $$ +BEGIN + RETURN QUERY + SELECT + o.creatorname, + COUNT(DISTINCT o._id) AS placed_orders, + SUM(CASE WHEN e._id IS NOT NULL THEN 1 ELSE 0 END) AS sent_emails, + SUM(CASE WHEN e.result = 'Succeeded' THEN 1 ELSE 0 END) AS succeeded_emails, + SUM(CASE WHEN s._id IS NOT NULL THEN s.smscount ELSE 0 END) AS sent_sms, + SUM(CASE WHEN s.result = 'Accepted' THEN 1 ELSE 0 END) AS succeeded_sms + FROM notifications.orders o + LEFT JOIN notifications.emailnotifications e ON o._id = e._orderid + LEFT JOIN notifications.smsnotifications s ON o._id = s._orderid + WHERE EXTRACT(MONTH FROM o.requestedsendtime) = month_input + AND EXTRACT(YEAR FROM o.requestedsendtime) = year_input + GROUP BY o.creatorname; +END; +$$ LANGUAGE plpgsql; diff --git a/src/Altinn.Notifications.Persistence/Repository/SmsNotificationRepository.cs b/src/Altinn.Notifications.Persistence/Repository/SmsNotificationRepository.cs index 6167a82b..15ee22a8 100644 --- a/src/Altinn.Notifications.Persistence/Repository/SmsNotificationRepository.cs +++ b/src/Altinn.Notifications.Persistence/Repository/SmsNotificationRepository.cs @@ -21,7 +21,7 @@ public class SmsNotificationRepository : ISmsNotificationRepository private readonly NpgsqlDataSource _dataSource; private readonly TelemetryClient? _telemetryClient; - private const string _insertSmsNotificationSql = "call notifications.insertsmsnotification($1, $2, $3, $4, $5, $6, $7, $8)"; // (__orderid, _alternateid, _recipientorgno, _recipientnin, _mobilenumber, _result, _resulttime, _expirytime) + private const string _insertSmsNotificationSql = "call notifications.insertsmsnotification($1, $2, $3, $4, $5, $6, $7, $8, $9)"; // (__orderid, _alternateid, _recipientorgno, _recipientnin, _mobilenumber, _result, _smscount, _resulttime, _expirytime) private const string _getSmsNotificationsSql = "select * from notifications.getsms_statusnew_updatestatus()"; private const string _getSmsRecipients = "select * from notifications.getsmsrecipients_v2($1)"; // (_orderid) @@ -55,6 +55,7 @@ public async Task AddNotification(SmsNotification notification, DateTime expiry, pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, (object)DBNull.Value); // recipientnin pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, notification.Recipient.MobileNumber); pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, notification.SendResult.Result.ToString()); + pgcom.Parameters.AddWithValue(NpgsqlDbType.Integer, smsCount); pgcom.Parameters.AddWithValue(NpgsqlDbType.TimestampTz, notification.SendResult.ResultTime); pgcom.Parameters.AddWithValue(NpgsqlDbType.TimestampTz, expiry); diff --git a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/SmsNotificationRepositoryTests.cs b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/SmsNotificationRepositoryTests.cs index 7ffe0400..b17bafea 100644 --- a/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/SmsNotificationRepositoryTests.cs +++ b/test/Altinn.Notifications.IntegrationTests/Notifications.Persistence/SmsNotificationRepositoryTests.cs @@ -56,7 +56,7 @@ public async Task AddNotification() } }; - await repo.AddNotification(smsNotification, DateTime.UtcNow); + await repo.AddNotification(smsNotification, DateTime.UtcNow, 1); // Assert string sql = $@"SELECT count(1) diff --git a/test/Altinn.Notifications.IntegrationTests/Utils/PostgreUtil.cs b/test/Altinn.Notifications.IntegrationTests/Utils/PostgreUtil.cs index bb3faada..906de589 100644 --- a/test/Altinn.Notifications.IntegrationTests/Utils/PostgreUtil.cs +++ b/test/Altinn.Notifications.IntegrationTests/Utils/PostgreUtil.cs @@ -101,7 +101,7 @@ public static async Task PopulateDBWithOrderAndEmailNotificat } await orderRepo.Create(order); - await notificationRepo.AddNotification(smsNotification, DateTime.UtcNow.AddDays(1)); + await notificationRepo.AddNotification(smsNotification, DateTime.UtcNow.AddDays(1), 1); return (order, smsNotification); } diff --git a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsNotificationServiceTests.cs b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsNotificationServiceTests.cs index 9f493e9e..ab063d34 100644 --- a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsNotificationServiceTests.cs +++ b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsNotificationServiceTests.cs @@ -43,10 +43,10 @@ public async Task CreateNotifications_NewSmsNotification_RepositoryCalledOnce() var service = GetTestService(repo: repoMock.Object); // Act - await service.CreateNotification(Guid.NewGuid(), DateTime.UtcNow, new Recipient(new List() { new SmsAddressPoint("999999999") }, nationalIdentityNumber: "enduser-nin")); + await service.CreateNotification(Guid.NewGuid(), DateTime.UtcNow, new Recipient(new List() { new SmsAddressPoint("999999999") }, nationalIdentityNumber: "enduser-nin"), It.IsAny()); // Assert - repoMock.Verify(r => r.AddNotification(It.IsAny(), It.IsAny()), Times.Once); + repoMock.Verify(r => r.AddNotification(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } [Fact] @@ -72,15 +72,15 @@ public async Task CreateNotification_RecipientNumberIsDefined_ResultNew() }; var repoMock = new Mock(); - repoMock.Setup(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry))); + repoMock.Setup(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry), It.IsAny())); var service = GetTestService(repo: repoMock.Object, guidOutput: id, dateTimeOutput: dateTimeOutput); // Act - await service.CreateNotification(orderId, requestedSendTime, new Recipient(new List() { new SmsAddressPoint("+4799999999") })); + await service.CreateNotification(orderId, requestedSendTime, new Recipient(new List() { new SmsAddressPoint("+4799999999") }), 1); // Assert - repoMock.Verify(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry)), Times.Once); + repoMock.Verify(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry), It.IsAny()), Times.Once); } [Fact] @@ -102,12 +102,12 @@ public async Task CreateNotification_RecipientNumberMissing_ResultFailedRecipien }; var repoMock = new Mock(); - repoMock.Setup(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry))); + repoMock.Setup(r => r.AddNotification(It.Is(e => AssertUtils.AreEquivalent(expected, e)), It.Is(d => d == expectedExpiry), It.IsAny())); var service = GetTestService(repo: repoMock.Object, guidOutput: id, dateTimeOutput: dateTimeOutput); // Act - await service.CreateNotification(orderId, requestedSendTime, new Recipient(new List())); + await service.CreateNotification(orderId, requestedSendTime, new Recipient(new List()), It.IsAny()); // Assert repoMock.Verify(); diff --git a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsOrderProcessingServiceTests.cs b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsOrderProcessingServiceTests.cs index 00873f8d..de106e29 100644 --- a/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsOrderProcessingServiceTests.cs +++ b/test/Altinn.Notifications.Tests/Notifications.Core/TestingServices/SmsOrderProcessingServiceTests.cs @@ -5,6 +5,7 @@ using Altinn.Notifications.Core.Enums; using Altinn.Notifications.Core.Models; using Altinn.Notifications.Core.Models.Address; +using Altinn.Notifications.Core.Models.NotificationTemplate; using Altinn.Notifications.Core.Models.Orders; using Altinn.Notifications.Core.Models.Recipients; using Altinn.Notifications.Core.Persistence; @@ -34,13 +35,14 @@ public async Task ProcessOrder_ExpectedInputToService() Recipients = new List() { new Recipient(new List() { new SmsAddressPoint("+4799999999") }, nationalIdentityNumber: "enduser-nin") - } + }, + Templates = [new SmsTemplate("Altinn", "this is the body")] }; Recipient expectedRecipient = new(new List() { new SmsAddressPoint("+4799999999") }, nationalIdentityNumber: "enduser-nin"); var serviceMock = new Mock(); - serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.Is(d => d.Equals(requested)), It.Is(r => AssertUtils.AreEquivalent(expectedRecipient, r)))); + serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.Is(d => d.Equals(requested)), It.Is(r => AssertUtils.AreEquivalent(expectedRecipient, r)), It.IsAny())); var service = GetTestService(smsService: serviceMock.Object); @@ -63,11 +65,12 @@ public async Task ProcessOrder_ServiceCalledOnceForEachRecipient() { new(), new() - } + }, + Templates = [new SmsTemplate("Altinn", "this is the body")] }; var serviceMock = new Mock(); - serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny())); + serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); var service = GetTestService(smsService: serviceMock.Object); @@ -75,7 +78,7 @@ public async Task ProcessOrder_ServiceCalledOnceForEachRecipient() await service.ProcessOrder(order); // Assert - serviceMock.Verify(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(2)); + serviceMock.Verify(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(2)); } [Fact] @@ -92,11 +95,12 @@ public async Task ProcessOrderRetry_ServiceCalledIfRecipientNotInDatabase() new Recipient(new List() { new SmsAddressPoint("+4799999999") }, nationalIdentityNumber: "enduser-nin"), new Recipient(new List() { new SmsAddressPoint("+4799999999") }, organisationNumber: "skd-orgNo"), new Recipient(new List() { new SmsAddressPoint("+4749999999") }) - } + }, + Templates = [new SmsTemplate("Altinn", "this is the body")] }; var serviceMock = new Mock(); - serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny())); + serviceMock.Setup(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); var smsRepoMock = new Mock(); smsRepoMock.Setup(e => e.GetRecipients(It.IsAny())).ReturnsAsync( @@ -113,7 +117,7 @@ public async Task ProcessOrderRetry_ServiceCalledIfRecipientNotInDatabase() // Assert smsRepoMock.Verify(e => e.GetRecipients(It.IsAny()), Times.Once); - serviceMock.Verify(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(2)); + serviceMock.Verify(s => s.CreateNotification(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(2)); } private static SmsOrderProcessingService GetTestService(