diff --git a/src/Portal.Backend.sln b/src/Portal.Backend.sln index 1f7093b921..4772611400 100644 --- a/src/Portal.Backend.sln +++ b/src/Portal.Backend.sln @@ -214,6 +214,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keycloak.Seeding", "keycloa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keycloak.Seeding.Tests", "..\tests\keycloak\Keycloak.Seeding.Tests\Keycloak.Seeding.Tests.csproj", "{A5BEDD89-7280-466E-8D14-EC5E177AAD07}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailing.Service", "mailing\Mailing.Service\Mailing.Service.csproj", "{6113B579-C995-47F8-9AC1-4CC6EFDDD883}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailing.Service.Tests", "..\tests\mailing\Mailing.Service.Tests\Mailing.Service.Tests.csproj", "{1EAF34DA-6D16-4F5E-86F4-344185F53942}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1340,6 +1344,30 @@ Global {A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x64.Build.0 = Release|Any CPU {A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x86.ActiveCfg = Release|Any CPU {A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x86.Build.0 = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x64.ActiveCfg = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x64.Build.0 = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x86.ActiveCfg = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x86.Build.0 = Debug|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|Any CPU.Build.0 = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x64.ActiveCfg = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x64.Build.0 = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x86.ActiveCfg = Release|Any CPU + {6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x86.Build.0 = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x64.ActiveCfg = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x64.Build.0 = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x86.ActiveCfg = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x86.Build.0 = Debug|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|Any CPU.Build.0 = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x64.ActiveCfg = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x64.Build.0 = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x86.ActiveCfg = Release|Any CPU + {1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1348,6 +1376,7 @@ Global SolutionGuid = {2EB6265F-323A-4BF3-969E-003D64A14B64} EndGlobalSection GlobalSection(NestedProjects) = preSolution + {1EAF34DA-6D16-4F5E-86F4-344185F53942} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {A5BEDD89-7280-466E-8D14-EC5E177AAD07} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {EA9BA26E-83F6-47C4-BA3B-880AF1AD6A82} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {4B40193E-2C67-4DC4-8EF4-3286DAA01D8B} = {323C198D-A8C6-4EB0-8B79-72624275E35F} @@ -1441,5 +1470,6 @@ Global {47E089E3-E875-4045-9E58-C1223BE899E9} = {23500169-FC01-4D2B-A997-E7FAE2169FC0} {9D574E57-75A6-4965-AF23-ACE0BB9CD0B3} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {E1D41A07-F468-4D13-8185-35F127230B17} = {46383371-8252-4598-9350-A97692851408} + {6113B579-C995-47F8-9AC1-4CC6EFDDD883} = {68D43DB1-DFC5-4F15-A2B4-6BA18B875F9E} EndGlobalSection EndGlobal diff --git a/src/mailing/Mailing.Service/DependencyInjection/MailingServiceExtensions.cs b/src/mailing/Mailing.Service/DependencyInjection/MailingServiceExtensions.cs new file mode 100644 index 0000000000..4ef3117111 --- /dev/null +++ b/src/mailing/Mailing.Service/DependencyInjection/MailingServiceExtensions.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; + +namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service.DependencyInjection; + +public static class MailingServiceExtensions +{ + public static IServiceCollection AddMailingService(this IServiceCollection services) + { + return services + .AddTransient(); + } +} diff --git a/src/mailing/Mailing.Service/IRoleBaseMailService.cs b/src/mailing/Mailing.Service/IRoleBaseMailService.cs new file mode 100644 index 0000000000..58b71419ab --- /dev/null +++ b/src/mailing/Mailing.Service/IRoleBaseMailService.cs @@ -0,0 +1,28 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 BMW Group AG + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; + +namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; + +public interface IRoleBaseMailService +{ + Task RoleBaseSendMail(IEnumerable receiverRoles, IEnumerable<(string ParameterName, string ParameterValue)> parameters, (string ParameterName, string ParameterValue)? userNameParameter, IEnumerable template, Guid companyId); +} diff --git a/src/mailing/Mailing.Service/Mailing.Service.csproj b/src/mailing/Mailing.Service/Mailing.Service.csproj new file mode 100644 index 0000000000..a1de10af95 --- /dev/null +++ b/src/mailing/Mailing.Service/Mailing.Service.csproj @@ -0,0 +1,33 @@ + + + + + + + + + + Org.Eclipse.TractusX.Portal.Backend.Mailing.Service + net7.0 + enable + enable + + \ No newline at end of file diff --git a/src/mailing/Mailing.Service/RoleBaseMailService.cs b/src/mailing/Mailing.Service/RoleBaseMailService.cs new file mode 100644 index 0000000000..395997c64c --- /dev/null +++ b/src/mailing/Mailing.Service/RoleBaseMailService.cs @@ -0,0 +1,76 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 BMW Group AG + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; +using System.Collections.Immutable; + +namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; + +public class RoleBaseMailService : IRoleBaseMailService +{ + + private readonly IPortalRepositories _portalRepositories; + private readonly IMailingService _mailingService; + + public RoleBaseMailService(IPortalRepositories portalRepositories, IMailingService mailingService) + { + _portalRepositories = portalRepositories; + _mailingService = mailingService; + } + public async Task RoleBaseSendMail(IEnumerable receiverRoles, IEnumerable<(string ParameterName, string ParameterValue)> parameters, (string ParameterName, string ParameterValue)? userNameParameter, IEnumerable template, Guid companyId) + { + var receiverUserRoles = receiverRoles; + var userRolesRepository = _portalRepositories.GetInstance(); + var roleData = await userRolesRepository + .GetUserRoleIdsUntrackedAsync(receiverUserRoles) + .ToListAsync() + .ConfigureAwait(false); + if (roleData.Count < receiverUserRoles.Sum(clientRoles => clientRoles.UserRoleNames.Count())) + { + throw new ConfigurationException( + $"invalid configuration, at least one of the configured roles does not exist in the database: {string.Join(", ", receiverUserRoles.Select(clientRoles => $"client: {clientRoles.ClientId}, roles: [{string.Join(", ", clientRoles.UserRoleNames)}]"))}"); + } + + var companyUserWithRoleIdForCompany = _portalRepositories.GetInstance() + .GetCompanyUserEmailForCompanyAndRoleId(roleData, companyId); + + await foreach (var (receiver, firstName, lastName) in companyUserWithRoleIdForCompany) + { + IEnumerable<(string ParameterName, string ParameterValue)> ParametersWithUserName() + { + if (userNameParameter.HasValue) + { + var userName = string.Join(" ", new[] { firstName, lastName }.Where(item => !string.IsNullOrWhiteSpace(item))); + return parameters.Append( + string.IsNullOrWhiteSpace(userName) + ? userNameParameter.Value + : new(userNameParameter.Value.ParameterName, userName)); + } + return parameters; + } + + await _mailingService.SendMails(receiver, ParametersWithUserName().ToImmutableDictionary(x => x.ParameterName, x => x.ParameterValue), template).ConfigureAwait(false); + } + } +} diff --git a/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs b/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs index 8a3ae9aef0..836f0c2418 100644 --- a/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs +++ b/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs @@ -178,7 +178,7 @@ public async Task AddFavouriteAppForUserAsync(Guid appId, Guid userId) /// public Task AddOwnCompanyAppSubscriptionAsync(Guid appId, IEnumerable offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity) => - _offerSubscriptionService.AddOfferSubscriptionAsync(appId, offerAgreementConsentData, identity, OfferTypeId.APP, _settings.BasePortalAddress); + _offerSubscriptionService.AddOfferSubscriptionAsync(appId, offerAgreementConsentData, identity, OfferTypeId.APP, _settings.BasePortalAddress, _settings.SubscriptionManagerRoles); /// public async Task ActivateOwnCompanyProvidedAppSubscriptionAsync(Guid subscriptionId, (Guid UserId, Guid CompanyId) identity) diff --git a/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs b/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs index 5048a9e0a3..2ecde22d7b 100644 --- a/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs +++ b/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs @@ -176,6 +176,13 @@ public class AppsSettings [Required] [DistinctValues("x => x.ClientId")] public IEnumerable CompanyAdminRoles { get; set; } = null!; + + /// + /// Roles to notify when a new subscription was created + /// + [Required] + [DistinctValues("x => x.ClientId")] + public IEnumerable SubscriptionManagerRoles { get; set; } = null!; } /// diff --git a/src/marketplace/Offers.Library/DependencyInjection/OfferSetupServiceExtensions.cs b/src/marketplace/Offers.Library/DependencyInjection/OfferSetupServiceExtensions.cs index 63ba0b490b..ec176e1c93 100644 --- a/src/marketplace/Offers.Library/DependencyInjection/OfferSetupServiceExtensions.cs +++ b/src/marketplace/Offers.Library/DependencyInjection/OfferSetupServiceExtensions.cs @@ -20,6 +20,7 @@ using Microsoft.Extensions.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Framework.Logging; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Service; using Org.Eclipse.TractusX.Portal.Backend.Processes.OfferSubscription.Library.DependencyInjection; @@ -35,6 +36,7 @@ public static IServiceCollection AddOfferServices(this IServiceCollection servic return services .AddTransient() .AddTransient() + .AddTransient() .AddTransient() .AddOfferSubscriptionProcess(); } diff --git a/src/marketplace/Offers.Library/Offers.Library.csproj b/src/marketplace/Offers.Library/Offers.Library.csproj index 2f349c6205..ee6a01ad8b 100644 --- a/src/marketplace/Offers.Library/Offers.Library.csproj +++ b/src/marketplace/Offers.Library/Offers.Library.csproj @@ -36,6 +36,7 @@ + diff --git a/src/marketplace/Offers.Library/Service/IOfferSubscriptionService.cs b/src/marketplace/Offers.Library/Service/IOfferSubscriptionService.cs index 10035b2bbc..d51f161f2a 100644 --- a/src/marketplace/Offers.Library/Service/IOfferSubscriptionService.cs +++ b/src/marketplace/Offers.Library/Service/IOfferSubscriptionService.cs @@ -18,6 +18,7 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; @@ -27,5 +28,5 @@ public interface IOfferSubscriptionService { Task AddOfferSubscriptionAsync(Guid offerId, IEnumerable offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity, - OfferTypeId offerTypeId, string basePortalAddress); + OfferTypeId offerTypeId, string basePortalAddress, IEnumerable notificationRecipients); } diff --git a/src/marketplace/Offers.Library/Service/OfferService.cs b/src/marketplace/Offers.Library/Service/OfferService.cs index e5c791067b..e5c489643f 100644 --- a/src/marketplace/Offers.Library/Service/OfferService.cs +++ b/src/marketplace/Offers.Library/Service/OfferService.cs @@ -22,7 +22,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; -using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; using Org.Eclipse.TractusX.Portal.Backend.Notifications.Library; using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; @@ -40,7 +40,7 @@ public class OfferService : IOfferService { private readonly IPortalRepositories _portalRepositories; private readonly INotificationService _notificationService; - private readonly IMailingService _mailingService; + private readonly IRoleBaseMailService _roleBaseMailService; private readonly IOfferSetupService _offerSetupService; /// @@ -52,12 +52,12 @@ public class OfferService : IOfferService /// The offer Setup Service public OfferService(IPortalRepositories portalRepositories, INotificationService notificationService, - IMailingService mailingService, + IRoleBaseMailService roleBaseMailService, IOfferSetupService offerSetupService) { _portalRepositories = portalRepositories; _notificationService = notificationService; - _mailingService = mailingService; + _roleBaseMailService = roleBaseMailService; _offerSetupService = offerSetupService; } @@ -559,45 +559,30 @@ public async Task DeclineOfferAsync(Guid offerId, Guid userId, OfferDeclineReque DeclineMessage = data.Message }; - var serializeNotificationContent = JsonSerializer.Serialize(notificationContent); - var content = Enumerable.Repeat(notificationTypeId, 1).Select(typeId => new ValueTuple(serializeNotificationContent, typeId)); + var content = new (string?, NotificationTypeId)[] + { + (JsonSerializer.Serialize(notificationContent), notificationTypeId) + }; + await _notificationService.CreateNotifications(notificationRecipients, userId, content, declineData.CompanyId.Value).AwaitAll().ConfigureAwait(false); await _notificationService.SetNotificationsForOfferToDone(catenaAdminRoles, submitOfferNotificationTypeIds, offerId).ConfigureAwait(false); await _portalRepositories.SaveAsync().ConfigureAwait(false); - await SendMail(notificationRecipients, declineData.OfferName, basePortalAddress, data.Message, declineData.CompanyId.Value); - } - - private async Task SendMail(IEnumerable receiverRoles, string offerName, string basePortalAddress, string message, Guid companyId) - { - var receiverUserRoles = receiverRoles; - var userRolesRepository = _portalRepositories.GetInstance(); - var roleData = await userRolesRepository - .GetUserRoleIdsUntrackedAsync(receiverUserRoles) - .ToListAsync() - .ConfigureAwait(false); - if (roleData.Count < receiverUserRoles.Sum(clientRoles => clientRoles.UserRoleNames.Count())) - { - throw new ConfigurationException( - $"invalid configuration, at least one of the configured roles does not exist in the database: {string.Join(", ", receiverUserRoles.Select(clientRoles => $"client: {clientRoles.ClientId}, roles: [{string.Join(", ", clientRoles.UserRoleNames)}]"))}"); - } - - var companyUserWithRoleIdForCompany = _portalRepositories.GetInstance() - .GetCompanyUserEmailForCompanyAndRoleId(roleData, companyId); - await foreach (var (receiver, firstName, lastName) in companyUserWithRoleIdForCompany) - { - var userName = string.Join(" ", new[] { firstName, lastName }.Where(item => !string.IsNullOrWhiteSpace(item))); - - var mailParams = new Dictionary + await _roleBaseMailService.RoleBaseSendMail( + notificationRecipients, + new[] { - { "offerName", offerName }, - { "url", basePortalAddress }, - { "declineMessage", message }, - { "offerProviderName", !string.IsNullOrWhiteSpace(userName) ? userName : "Service Manager"}, - }; - await _mailingService.SendMails(receiver, mailParams, new List { "offer-request-decline" }).ConfigureAwait(false); - } + ("offerName", declineData.OfferName), + ("url", basePortalAddress), + ("declineMessage", data.Message), + }, + ("offerProviderName", "Service Manager"), + new[] + { + "offer-request-decline" + }, + declineData.CompanyId.Value).ConfigureAwait(false); } private async Task CheckLanguageCodesExist(IEnumerable languageCodes) diff --git a/src/marketplace/Offers.Library/Service/OfferSubscriptionService.cs b/src/marketplace/Offers.Library/Service/OfferSubscriptionService.cs index 02b29a1a1c..c0455dffaf 100644 --- a/src/marketplace/Offers.Library/Service/OfferSubscriptionService.cs +++ b/src/marketplace/Offers.Library/Service/OfferSubscriptionService.cs @@ -19,7 +19,8 @@ ********************************************************************************/ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; @@ -33,7 +34,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Service; public class OfferSubscriptionService : IOfferSubscriptionService { private readonly IPortalRepositories _portalRepositories; - private readonly IMailingService _mailingService; + private readonly IRoleBaseMailService _roleBaseMailService; /// /// Constructor. @@ -42,17 +43,23 @@ public class OfferSubscriptionService : IOfferSubscriptionService /// Mail service. public OfferSubscriptionService( IPortalRepositories portalRepositories, - IMailingService mailingService) + IRoleBaseMailService roleBaseMailService) { _portalRepositories = portalRepositories; - _mailingService = mailingService; + _roleBaseMailService = roleBaseMailService; } /// - public async Task AddOfferSubscriptionAsync(Guid offerId, IEnumerable offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity, OfferTypeId offerTypeId, string basePortalAddress) + public async Task AddOfferSubscriptionAsync(Guid offerId, IEnumerable offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity, OfferTypeId offerTypeId, string basePortalAddress, IEnumerable notificationRecipients) { var companyInformation = await ValidateCompanyInformationAsync(identity.CompanyId).ConfigureAwait(false); var offerProviderDetails = await ValidateOfferProviderDetailDataAsync(offerId, offerTypeId).ConfigureAwait(false); + + if (offerProviderDetails.ProviderCompanyId == null) + { + throw new ConflictException($"{offerTypeId} providing company is not set"); + } + await ValidateConsent(offerAgreementConsentData, offerId).ConfigureAwait(false); var offerSubscriptionsRepository = _portalRepositories.GetInstance(); @@ -64,16 +71,20 @@ public async Task AddOfferSubscriptionAsync(Guid offerId, IEnumerable - { - { "offerProviderName", offerProviderDetails.ProviderName}, - { "offerName", offerProviderDetails.OfferName! }, - { "url", basePortalAddress }, - }; - await _mailingService.SendMails(offerProviderDetails.ProviderContactEmail!, mailParams, new List { "subscription-request" }).ConfigureAwait(false); return offerSubscription.Id; } diff --git a/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs b/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs index b9bc70bf24..58f1655b14 100644 --- a/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs +++ b/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs @@ -74,7 +74,7 @@ public ServiceBusinessLogic( /// public Task AddServiceSubscription(Guid serviceId, IEnumerable offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity) => - _offerSubscriptionService.AddOfferSubscriptionAsync(serviceId, offerAgreementConsentData, identity, OfferTypeId.SERVICE, _settings.BasePortalAddress); + _offerSubscriptionService.AddOfferSubscriptionAsync(serviceId, offerAgreementConsentData, identity, OfferTypeId.SERVICE, _settings.BasePortalAddress, _settings.SubscriptionManagerRoles); /// public async Task GetServiceDetailsAsync(Guid serviceId, string lang, Guid companyId) diff --git a/src/marketplace/Services.Service/ServiceSettings.cs b/src/marketplace/Services.Service/ServiceSettings.cs index fd8fdd273c..c0b8d825c0 100644 --- a/src/marketplace/Services.Service/ServiceSettings.cs +++ b/src/marketplace/Services.Service/ServiceSettings.cs @@ -139,6 +139,14 @@ public class ServiceSettings [Required] [DistinctValues("x => x.ClientId")] public IEnumerable CompanyAdminRoles { get; set; } = null!; + + /// + /// Roles to notify when a new subscription was created + /// + [Required] + [DistinctValues("x => x.ClientId")] + public IEnumerable SubscriptionManagerRoles { get; init; } = null!; + } public static class ServiceSettingsExtension diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/OfferProviderDetailsData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/OfferProviderDetailsData.cs index 2d0ea7ecef..6dc0a9ca62 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/OfferProviderDetailsData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/OfferProviderDetailsData.cs @@ -35,5 +35,6 @@ public record OfferProviderDetailsData( string? ProviderContactEmail, Guid? SalesManagerId, string? AutoSetupUrl, - bool IsSingleInstance + bool IsSingleInstance, + Guid? ProviderCompanyId ); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs index 3dd20719fa..fd451d0852 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs @@ -57,7 +57,8 @@ public Task CheckAppExistsById(Guid appId) => c.ContactEmail, c.SalesManagerId, c.ProviderCompany!.ProviderCompanyDetail!.AutoSetupUrl, - c.AppInstanceSetup != null && c.AppInstanceSetup!.IsSingleInstance + c.AppInstanceSetup != null && c.AppInstanceSetup!.IsSingleInstance, + c.ProviderCompanyId )).SingleOrDefaultAsync(); /// diff --git a/tests/mailing/Mailing.Service.Tests/Mailing.Service.Tests.csproj b/tests/mailing/Mailing.Service.Tests/Mailing.Service.Tests.csproj new file mode 100644 index 0000000000..0532751633 --- /dev/null +++ b/tests/mailing/Mailing.Service.Tests/Mailing.Service.Tests.csproj @@ -0,0 +1,50 @@ + + + + Org.Eclipse.TractusX.Portal.Backend.Mailing.Service.Tests + Org.Eclipse.TractusX.Portal.Backend.Mailing.Service.Tests + net7.0 + enable + enable + false + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/tests/mailing/Mailing.Service.Tests/RoleBaseMailServiceTests.cs b/tests/mailing/Mailing.Service.Tests/RoleBaseMailServiceTests.cs new file mode 100644 index 0000000000..9a53836b82 --- /dev/null +++ b/tests/mailing/Mailing.Service.Tests/RoleBaseMailServiceTests.cs @@ -0,0 +1,150 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 BMW Group AG + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; + +namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service.Tests; + +public class RoleBaseMailServiceTests +{ + private const string BasePortalUrl = "http//base-url.com"; + private readonly IFixture _fixture; + private readonly IPortalRepositories _portalRepositories; + private readonly IMailingService _mailingService; + private readonly IUserRolesRepository _userRolesRepository; + private readonly IUserRepository _userRepository; + private readonly Guid _companyId; + private readonly IEnumerable _userRoleIds; + private readonly RoleBaseMailService _sut; + + public RoleBaseMailServiceTests() + { + _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); + _fixture.Behaviors.OfType().ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _portalRepositories = A.Fake(); + _mailingService = A.Fake(); + _userRolesRepository = A.Fake(); + _userRepository = A.Fake(); + _companyId = _fixture.Create(); + _userRoleIds = _fixture.CreateMany(2); + + SetupRepositories(); + + _sut = new RoleBaseMailService(_portalRepositories, _mailingService); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task RoleBaseSendMail_WithUserNameParameter_ReturnsExpectedCalls(bool hasUserNameParameter) + { + // Arrange + var template = new[] { "test-request" }; + var offerName = _fixture.Create(); + var mailParams = new[] + { + ("offerName", offerName), + ("url", BasePortalUrl) + }; + var userNameParam = hasUserNameParameter + ? ("offerProviderName", "user") + : ((string, string)?)null; + var receiverRoles = new[] + { + new UserRoleConfig("ClientId", new[] { "TestApp Manager", "TestSale Manager" }) + }; + var companyUserData = new (string, string?, string?)[] + { + ("TestApp@bmw", "AppFirst", "AppLast"), + ("TestSale@bmw", "SaleFirst", "SaleLast") + }; + + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>._)) + .Returns(_userRoleIds.ToAsyncEnumerable()); + A.CallTo(() => _userRepository.GetCompanyUserEmailForCompanyAndRoleId(A>._, A._)) + .Returns(companyUserData.ToAsyncEnumerable()); + + // Act + await _sut.RoleBaseSendMail(receiverRoles, mailParams, userNameParam, template, _companyId); + + // Assert + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>.That.Matches(x => x.Any(y => y.ClientId == "ClientId")))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.GetCompanyUserEmailForCompanyAndRoleId(A>.That.IsSameSequenceAs(_userRoleIds), _companyId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _mailingService.SendMails( + "TestApp@bmw", + A>.That.Matches(x => x.Count() == (hasUserNameParameter ? 3 : 2) && x["offerName"] == offerName && x["url"] == BasePortalUrl && (!hasUserNameParameter || x["offerProviderName"] == "AppFirst AppLast")), + A>.That.IsSameSequenceAs(template))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _mailingService.SendMails( + "TestSale@bmw", + A>.That.Matches(x => x.Count() == (hasUserNameParameter ? 3 : 2) && x["offerName"] == offerName && x["url"] == BasePortalUrl && (!hasUserNameParameter || x["offerProviderName"] == "SaleFirst SaleLast")), + A>.That.IsSameSequenceAs(template))).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RoleBaseSendMail_ThrowsConfigurationException() + { + // Arrange + var template = new List { "test-request" }; + var mailParams = new[] + { + ("offerName", _fixture.Create()), + ("url", BasePortalUrl), + }; + var userNameParam = ("offerProviderName", "user"); + + var roleData = _fixture.CreateMany(1); + var receiverRoles = new[]{ + new UserRoleConfig("ClientId", new [] { "App Manager", "Sales Manager" }) + }; + + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>._)) + .Returns(roleData.ToAsyncEnumerable()); + + // Act + async Task Action() => await _sut.RoleBaseSendMail(receiverRoles, mailParams, userNameParam, template, _companyId); + + // Assert + var ex = await Assert.ThrowsAsync(Action); + ex.Message.Should().Be( + $"invalid configuration, at least one of the configured roles does not exist in the database: {string.Join(", ", receiverRoles.Select(clientRoles => $"client: {clientRoles.ClientId}, roles: [{string.Join(", ", clientRoles.UserRoleNames)}]"))}"); + A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>.That.IsSameSequenceAs(receiverRoles))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.GetCompanyUserEmailForCompanyAndRoleId(A>.That.IsSameSequenceAs(roleData), _companyId)).MustNotHaveHappened(); + A.CallTo(() => _mailingService.SendMails(A._, A>._, A>._)).MustNotHaveHappened(); + } + + #region Setup + + private void SetupRepositories() + { + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_mailingService); + _fixture.Inject(_portalRepositories); + } + + #endregion +} diff --git a/tests/mailing/Mailing.Service.Tests/Usings.cs b/tests/mailing/Mailing.Service.Tests/Usings.cs new file mode 100644 index 0000000000..d0c35ff438 --- /dev/null +++ b/tests/mailing/Mailing.Service.Tests/Usings.cs @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 BMW Group AG + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FakeItEasy; +global using FluentAssertions; +global using Xunit; diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs index 7a92f7e7f7..4ab77afa8c 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs @@ -178,10 +178,17 @@ public async Task AddServiceSubscription_ReturnsCorrectId() .With(x => x.UserEntityId, "44638c72-690c-42e8-bd5e-c8ac3047ff82") .Create(); + var appsSettings = new AppsSettings + { + SubscriptionManagerRoles = new[] + { + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" }) + } + }; var offerSubscriptionId = Guid.NewGuid(); var offerSubscriptionService = A.Fake(); var consentData = _fixture.CreateMany(2); - A.CallTo(() => offerSubscriptionService.AddOfferSubscriptionAsync(A._, A>._, A>._, A._, A._)) + A.CallTo(() => offerSubscriptionService.AddOfferSubscriptionAsync(A._, A>._, A>._, A._, A._, A>._)) .Returns(offerSubscriptionId); var sut = new AppsBusinessLogic(null!, offerSubscriptionService, null!, null!, Options.Create(new AppsSettings()), null!); @@ -195,7 +202,8 @@ public async Task AddServiceSubscription_ReturnsCorrectId() A>._, A>._, A.That.Matches(x => x == OfferTypeId.APP), - A._)) + A._, + A>._)) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json index e65e979862..643dcfd6a3 100644 --- a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json @@ -65,6 +65,15 @@ ] } ], + "SubscriptionManagerRoles": [ + { + "ClientId": "Cl2-CX-Portal", + "UserRoleNames": [ + "App Manager", + "Sales Manager" + ] + } + ], "OfferStatusIds": [ "IN_REVIEW", "ACTIVE" diff --git a/tests/marketplace/Offers.Library.Tests/Offers.Library.Tests.csproj b/tests/marketplace/Offers.Library.Tests/Offers.Library.Tests.csproj index 8f3366cee8..d47f6acc5e 100644 --- a/tests/marketplace/Offers.Library.Tests/Offers.Library.Tests.csproj +++ b/tests/marketplace/Offers.Library.Tests/Offers.Library.Tests.csproj @@ -48,5 +48,6 @@ + diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs index 979e6121b2..065c89eead 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs @@ -22,6 +22,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; using Org.Eclipse.TractusX.Portal.Backend.Notifications.Library; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; @@ -62,7 +63,7 @@ public class OfferServiceTests private readonly IUserRepository _userRepository; private readonly IUserRolesRepository _userRolesRepository; private readonly ILanguageRepository _languageRepository; - private readonly IMailingService _mailingService; + private readonly IRoleBaseMailService _roleBaseMailService; private readonly IDocumentRepository _documentRepository; private readonly OfferService _sut; private readonly IOfferSetupService _offerSetupService; @@ -96,12 +97,12 @@ public OfferServiceTests() _languageRepository = A.Fake(); _technicalUserProfileRepository = A.Fake(); _notificationService = A.Fake(); - _mailingService = A.Fake(); + _roleBaseMailService = A.Fake(); _documentRepository = A.Fake(); _offerSetupService = A.Fake(); _connectorsRepository = A.Fake(); - _sut = new OfferService(_portalRepositories, _notificationService, _mailingService, _offerSetupService); + _sut = new OfferService(_portalRepositories, _notificationService, _roleBaseMailService, _offerSetupService); SetupRepositories(); _createNotificationsEnumerator = SetupServices(); @@ -1110,15 +1111,20 @@ public async Task DeclineOfferAsync_WithValidData_CallsExpected(OfferTypeId offe // Arrange var offer = _fixture.Create(); var offerId = _fixture.Create(); - var recipients = new[] { new UserRoleConfig("Test", new[] { "Abc" }) }; + var recipients = new[] + { + new UserRoleConfig("Test", new[] { "Abc" }) + }; var roleIds = _fixture.CreateMany(); var documentStatusDatas = new DocumentStatusData[] { new(Guid.NewGuid(), DocumentStatusId.LOCKED), new(Guid.NewGuid(), DocumentStatusId.PENDING), }; + var companyId = Guid.NewGuid(); + var offerName = _fixture.Create(); A.CallTo(() => _offerRepository.GetOfferDeclineDataAsync(offerId, offerTypeId)) - .Returns(("test", OfferStatusId.IN_REVIEW, Guid.NewGuid(), documentStatusDatas)); + .Returns((offerName, OfferStatusId.IN_REVIEW, companyId, documentStatusDatas)); A.CallTo(() => _offerRepository.AttachAndModifyOffer(offerId, A>._, A?>._)) .Invokes((Guid _, Action setOptionalParameters, Action? initializeParemeters) => { @@ -1128,7 +1134,7 @@ public async Task DeclineOfferAsync_WithValidData_CallsExpected(OfferTypeId offe A.CallTo(() => _userRolesRepository.GetUserRoleIdsUntrackedAsync(A>._)) .Returns(roleIds.ToAsyncEnumerable()); A.CallTo(() => _userRepository.GetCompanyUserEmailForCompanyAndRoleId(A>._, A._)) - .Returns(new (string Email, string? Firstname, string? Lastname)[] { new("test@email.com", "Test User 1", "cx-user-2") }.ToAsyncEnumerable()); + .Returns(new[] { ("test@email.com", (string?)"Test User 1", (string?)"cx-user-2") }.ToAsyncEnumerable()); IEnumerable? initial = null; IEnumerable? modified = null; @@ -1151,15 +1157,35 @@ public async Task DeclineOfferAsync_WithValidData_CallsExpected(OfferTypeId offe ).ToImmutableArray(); }); + var declineMessage = _fixture.Create(); + var basePortalAddress = _fixture.Create(); + + var mailParameters = new[] + { + ("offerName", offerName), + ("url", basePortalAddress), + ("declineMessage", declineMessage) + }; + var userNameParameter = ("offerProviderName", "Service Manager"); + var template = new[] + { + "offer-request-decline" + }; + // Act - await _sut.DeclineOfferAsync(offerId, _identity.UserId, new OfferDeclineRequest("Test"), offerTypeId, NotificationTypeId.SERVICE_RELEASE_REJECTION, recipients, string.Empty, new[] { NotificationTypeId.APP_SUBSCRIPTION_REQUEST }, _fixture.CreateMany()).ConfigureAwait(false); + await _sut.DeclineOfferAsync(offerId, _identity.UserId, new OfferDeclineRequest(declineMessage), offerTypeId, NotificationTypeId.SERVICE_RELEASE_REJECTION, recipients, basePortalAddress, new[] { NotificationTypeId.APP_SUBSCRIPTION_REQUEST }, _fixture.CreateMany()).ConfigureAwait(false); // Assert A.CallTo(() => _offerRepository.AttachAndModifyOffer(offerId, A>._, A?>._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); A.CallTo(() => _notificationService.CreateNotifications(A>._, A._, A>._, A._, A._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _createNotificationsEnumerator.MoveNextAsync()).MustHaveHappened(2, Times.Exactly); - A.CallTo(() => _mailingService.SendMails(A._, A>._, A>._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _roleBaseMailService.RoleBaseSendMail( + A>.That.IsSameSequenceAs(recipients), + A>.That.IsSameSequenceAs(mailParameters), + userNameParameter, + A>.That.IsSameSequenceAs(template), + companyId)).MustHaveHappenedOnceExactly(); offer.OfferStatusId.Should().Be(OfferStatusId.CREATED); A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>._)).MustHaveHappenedOnceExactly(); initial.Should().HaveCount(2).And.Satisfy( diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs index 54cd7ca068..3707da74f2 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs @@ -21,7 +21,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; -using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; +using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; @@ -34,7 +34,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Tests.Service; public class OfferSubscriptionServiceTests { - private const string BasePortalUrl = "http//base-url.com"; + private const string BasePortalUrl = "http://base-url.com"; private const string ClientId = "Client1"; private readonly Guid _salesManagerId = new("ac1cf001-7fbc-1f2f-817f-bce058020001"); @@ -65,7 +65,7 @@ public class OfferSubscriptionServiceTests private readonly IPortalRepositories _portalRepositories; private readonly IUserRepository _userRepository; private readonly IUserRolesRepository _userRolesRepository; - private readonly IMailingService _mailingService; + private readonly IRoleBaseMailService _roleBaseMailService; private readonly IProcessStepRepository _processStepRepository; private readonly OfferSubscriptionService _sut; @@ -104,11 +104,11 @@ public OfferSubscriptionServiceTests() _processStepRepository = A.Fake(); _userRepository = A.Fake(); _userRolesRepository = A.Fake(); - _mailingService = A.Fake(); + _roleBaseMailService = A.Fake(); SetupRepositories(); - _sut = new OfferSubscriptionService(_portalRepositories, _mailingService); + _sut = new OfferSubscriptionService(_portalRepositories, _roleBaseMailService); } #region Add Offer Subscription @@ -119,6 +119,15 @@ public OfferSubscriptionServiceTests() public async Task AddOfferSubscription_WithExistingId_CreatesServiceSubscription(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP + ? new[] + { + new UserRoleConfig(ClientId, new[] { "App Manager", "Sales Manager" }) + } + : new[] + { + new UserRoleConfig(ClientId, new[] { "Service Manager", "Sales Manager" }) + }; A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(A._, A._, A._)) .Returns(false); var companyAssignedApps = new List(); @@ -129,8 +138,19 @@ public async Task AddOfferSubscription_WithExistingId_CreatesServiceSubscription companyAssignedApps.Add(companyAssignedApp); }); + var mailParameters = new[] + { + ("offerName", "Test Offer"), + ("url", BasePortalUrl) + }; + var userParameter = ("offerProviderName", "User"); + var template = new[] + { + "subscription-request" + }; + // Act - await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert companyAssignedApps.Should().HaveCount(1); @@ -139,7 +159,12 @@ public async Task AddOfferSubscription_WithExistingId_CreatesServiceSubscription A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(_existingOfferId, _companyId, offerTypeId)).MustHaveHappenedOnceExactly(); } A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>.That.Matches(x => x.Count() == 1 && x.Single().ProcessStepTypeId == ProcessStepTypeId.TRIGGER_PROVIDER))).MustHaveHappenedOnceExactly(); - A.CallTo(() => _mailingService.SendMails(A._, A>._, A>._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _roleBaseMailService.RoleBaseSendMail( + A>.That.IsSameSequenceAs(subscriptionManagerRoles), + A>.That.IsSameSequenceAs(mailParameters), + userParameter, + A>.That.IsSameSequenceAs(template), + _companyId)).MustHaveHappenedOnceExactly(); } [Theory] @@ -148,6 +173,16 @@ public async Task AddOfferSubscription_WithExistingId_CreatesServiceSubscription public async Task AddOfferSubscription_WithSalesManagerEqualsReceiver_CreatesServiceSubscription(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP + ? new[] + { + new UserRoleConfig("portal", new[] { "App Manager", "Sales Manager" }) + } + : new[] + { + new UserRoleConfig("portal", new[] { "Service Manager", "Sales Manager" }) + }; + var offerProviderDetails = _fixture.Create(); A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(A._, A._, A._)) .Returns(false); var companyAssignedApps = new List(); @@ -157,13 +192,28 @@ public async Task AddOfferSubscription_WithSalesManagerEqualsReceiver_CreatesSer var companyAssignedApp = new OfferSubscription(_newOfferSubscriptionId, offerId, companyId, offerSubscriptionStatusId, requesterId); companyAssignedApps.Add(companyAssignedApp); }); + var mailParameters = new[] + { + ("offerName", "Test Offer"), + ("url", BasePortalUrl) + }; + var userParameter = ("offerProviderName", "User"); + var template = new[] + { + "subscription-request" + }; // Act - await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert companyAssignedApps.Should().HaveCount(1); - A.CallTo(() => _mailingService.SendMails(A._, A>._, A>._)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _roleBaseMailService.RoleBaseSendMail( + A>.That.IsSameSequenceAs(subscriptionManagerRoles), + A>.That.IsSameSequenceAs(mailParameters), + userParameter, + A>.That.IsSameSequenceAs(template), + _companyId)).MustHaveHappenedOnceExactly(); } [Theory] @@ -171,7 +221,10 @@ public async Task AddOfferSubscription_WithSalesManagerEqualsReceiver_CreatesSer [InlineData(OfferTypeId.APP)] public async Task AddOfferSubscription_WithExistingIdWithoutProviderEmail_CreatesServiceSubscription(OfferTypeId offerTypeId) { - // Arrange + // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("Client1", new [] { "Service Manager", "Sales Manager" })}; A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(A._, A._, A._)) .Returns(false); var companyAssignedApps = new List(); @@ -183,24 +236,25 @@ public async Task AddOfferSubscription_WithExistingIdWithoutProviderEmail_Create }); // Act - await _sut.AddOfferSubscriptionAsync(_existingOfferIdWithoutProviderEmail, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + await _sut.AddOfferSubscriptionAsync(_existingOfferIdWithoutProviderEmail, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert companyAssignedApps.Should().HaveCount(1); A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>.That.Matches(x => x.Count() == 1 && x.Single().ProcessStepTypeId == ProcessStepTypeId.TRIGGER_PROVIDER))).MustHaveHappenedOnceExactly(); - A.CallTo(() => _mailingService.SendMails(A._, A>._, A>._)).MustNotHaveHappened(); } [Fact] public async Task AddOfferSubscription_WithExistingAppSubscriptionAndProcessSteps_SkipsProcessStepsCreation() { // Arrange + var subscriptionManagerRoles = new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })}; var subscriptionId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(A._, A._, A._)) .Returns(false); // Act - await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), OfferTypeId.APP, BasePortalUrl).ConfigureAwait(false); + await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), OfferTypeId.APP, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(_existingOfferId, _companyId, OfferTypeId.APP)).MustHaveHappenedOnceExactly(); @@ -214,11 +268,13 @@ public async Task AddOfferSubscription_WithExistingAppSubscriptionAndProcessStep public async Task AddOfferSubscription_WithExistingActiveAppSubscription_Throws() { // Arrange + var subscriptionManagerRoles = new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })}; var subscriptionId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionsRepository.CheckPendingOrActiveSubscriptionExists(A._, A._, A._)) .Returns(true); - var Act = () => _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), OfferTypeId.APP, BasePortalUrl); + var Act = () => _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), OfferTypeId.APP, BasePortalUrl, subscriptionManagerRoles); // Act var result = await Assert.ThrowsAsync(Act).ConfigureAwait(false); @@ -238,12 +294,15 @@ public async Task AddOfferSubscription_WithExistingActiveAppSubscription_Throws( public async Task AddOfferSubscription_NotAssignedCompany_ThrowsException(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var identity = _fixture.Build() .With(x => x.CompanyId, _notAssignedCompanyId) .Create(); // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, new List(), (identity.UserId, identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, new List(), (identity.UserId, identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -257,10 +316,13 @@ public async Task AddOfferSubscription_NotAssignedCompany_ThrowsException(OfferT public async Task AddOfferSubscription_WithNotExistingId_ThrowsException(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var notExistingServiceId = Guid.NewGuid(); // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(notExistingServiceId, new List(), (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(notExistingServiceId, new List(), (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -272,8 +334,13 @@ public async Task AddOfferSubscription_WithNotExistingId_ThrowsException(OfferTy [InlineData(OfferTypeId.APP)] public async Task AddOfferSubscription_WithoutOfferProviderDetails_ThrowsException(OfferTypeId offerTypeId) { + // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; + // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferWithoutDetailsFilled, new List(), (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferWithoutDetailsFilled, new List(), (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -286,10 +353,13 @@ public async Task AddOfferSubscription_WithoutOfferProviderDetails_ThrowsExcepti public async Task AddOfferSubscription_WithMissingConsentData_ThrowsControllerArgumentException(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var consentData = Enumerable.Empty(); // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -304,11 +374,14 @@ public async Task AddOfferSubscription_WithMissingConsentData_ThrowsControllerAr public async Task AddOfferSubscription_WithAdditionalConsentData_ThrowsControllerArgumentException(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var additional = _fixture.CreateMany().ToImmutableArray(); var consentData = _validConsentData.Concat(additional).ToImmutableArray(); // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -323,10 +396,13 @@ public async Task AddOfferSubscription_WithAdditionalConsentData_ThrowsControlle public async Task AddOfferSubscription_WithInactiveConsentData_ThrowsControllerArgumentException(OfferTypeId offerTypeId) { // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var consentData = _offerAgreementIds.Select(id => new OfferAgreementConsentData(id, ConsentStatusId.INACTIVE)).ToImmutableArray(); // Act - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, consentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); @@ -341,16 +417,40 @@ public async Task AddOfferSubscription_WithInactiveConsentData_ThrowsControllerA public async Task AddOfferSubscription_WithoutBuisnessPartnerNumber_ThrowsConflictException(OfferTypeId offerTypeId) { // Act + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" })}; var identity = _fixture.Build() .With(x => x.CompanyId, _noBpnSetCompanyId) .Create(); - async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, new List(), (identity.UserId, identity.CompanyId), offerTypeId, BasePortalUrl).ConfigureAwait(false); + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, new List(), (identity.UserId, identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Action); ex.Message.Should().Contain("has no BusinessPartnerNumber assigned"); } + [Theory] + [InlineData(OfferTypeId.SERVICE)] + [InlineData(OfferTypeId.APP)] + public async Task AddOfferSubscription_EmptyProviderCompanyId_ThrowsConflictException(OfferTypeId offerTypeId) + { + // Arrange + var subscriptionManagerRoles = offerTypeId == OfferTypeId.APP ? new[]{ + new UserRoleConfig(ClientId, new [] { "App Manager", "Sales Manager" })} : new[]{ + new UserRoleConfig(ClientId, new [] { "Service Manager", "Sales Manager" })}; + + A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingOfferId), A._)) + .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", "provider@mail.de", _salesManagerId, "https://www.testurl.com", false, null)); + + // Act + async Task Action() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (_identity.UserId, _identity.CompanyId), offerTypeId, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); + + // Assert + var ex = await Assert.ThrowsAsync(Action); + ex.Message.Should().Be($"{offerTypeId} providing company is not set"); + } + #endregion #region APP - Specialcases @@ -358,7 +458,9 @@ public async Task AddOfferSubscription_WithoutBuisnessPartnerNumber_ThrowsConfli [Fact] public async Task AddOfferSubscription_WithExistingActiveSubscription_ThrowsConflictException() { - // Arrange + // Arrange + var subscriptionManagerRoles = new[]{ + new UserRoleConfig("portal", new [] { "App Manager", "Sales Manager" })}; var identity = _fixture.Build() .With(x => x.CompanyId, _existingActiveSubscriptionCompanyId) .Create(); @@ -366,7 +468,7 @@ public async Task AddOfferSubscription_WithExistingActiveSubscription_ThrowsConf .Returns(true); // Act - async Task Act() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (identity.UserId, identity.CompanyId), OfferTypeId.APP, BasePortalUrl).ConfigureAwait(false); + async Task Act() => await _sut.AddOfferSubscriptionAsync(_existingOfferId, _validConsentData, (identity.UserId, identity.CompanyId), OfferTypeId.APP, BasePortalUrl, subscriptionManagerRoles).ConfigureAwait(false); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -434,13 +536,13 @@ private void SetupRepositories() .Returns((OfferDetailData?)null); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingOfferId), A._)) - .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", "provider@mail.de", _salesManagerId, "https://www.testurl.com", false)); + .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", "provider@mail.de", _salesManagerId, "https://www.testurl.com", false, _companyId)); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingOfferIdWithoutProviderEmail), A._)) - .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", null, _salesManagerId, "https://www.testurl.com", false)); + .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", null, _salesManagerId, "https://www.testurl.com", false, _companyId)); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingOfferWithFailingAutoSetupId), A._)) - .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", "provider@mail.de", _salesManagerId, "https://www.fail.com", false)); + .Returns(new OfferProviderDetailsData("Test Offer", "Test Company", "provider@mail.de", _salesManagerId, "https://www.fail.com", false, _companyId)); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingOfferWithoutDetailsFilled), A._)) - .Returns(new OfferProviderDetailsData(null, "Test Company", null, _salesManagerId, "https://www.fail.com", false)); + .Returns(new OfferProviderDetailsData(null, "Test Company", null, _salesManagerId, "https://www.fail.com", false, _companyId)); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Not.Matches(x => x == _existingOfferId || x == _existingOfferWithFailingAutoSetupId || x == _existingOfferWithoutDetailsFilled || x == _existingOfferIdWithoutProviderEmail), A._)) .Returns((OfferProviderDetailsData?)null); @@ -482,6 +584,7 @@ private void SetupRepositories() A.CallTo(() => _portalRepositories.GetInstance()).Returns(_processStepRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_roleBaseMailService); _fixture.Inject(_portalRepositories); } diff --git a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs index 1e448bb4eb..24cddc1d94 100644 --- a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs +++ b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs @@ -152,13 +152,13 @@ public async Task AddServiceSubscription_ReturnsCorrectId() // Arrange var offerSubscriptionId = Guid.NewGuid(); var consentData = _fixture.CreateMany(2); - A.CallTo(() => _offerSubscriptionService.AddOfferSubscriptionAsync(A._, A>._, A>._, A._, A._)) + A.CallTo(() => _offerSubscriptionService.AddOfferSubscriptionAsync(A._, A>._, A>._, A._, A._, A>._)) .Returns(offerSubscriptionId); var serviceSettings = new ServiceSettings { - ServiceManagerRoles = new[] + SubscriptionManagerRoles = new[] { - new UserRoleConfig("portal", new [] { "ServiceManager" }) + new UserRoleConfig("portal", new [] { "Service Manager", "Sales Manager" }) }, BasePortalAddress = "https://base-portal-address-test.de" }; @@ -174,7 +174,8 @@ public async Task AddServiceSubscription_ReturnsCorrectId() A>._, A>._, A.That.Matches(x => x == OfferTypeId.SERVICE), - A._)) + A._, + A>._)) .MustHaveHappenedOnceExactly(); } @@ -651,9 +652,9 @@ private void SetupRepositories() .Returns((ServiceDetailData?)null); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingServiceId), A._)) - .Returns(new OfferProviderDetailsData("Test Service", "Test Company", "provider@mail.de", new Guid("ac1cf001-7fbc-1f2f-817f-bce058020001"), "https://www.testurl.com", false)); + .Returns(new OfferProviderDetailsData("Test Service", "Test Company", "provider@mail.de", new Guid("ac1cf001-7fbc-1f2f-817f-bce058020001"), "https://www.testurl.com", false, Guid.NewGuid())); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Matches(x => x == _existingServiceWithFailingAutoSetupId), A._)) - .Returns(new OfferProviderDetailsData("Test Service", "Test Company", "provider@mail.de", new Guid("ac1cf001-7fbc-1f2f-817f-bce058020001"), "https://www.fail.com", false)); + .Returns(new OfferProviderDetailsData("Test Service", "Test Company", "provider@mail.de", new Guid("ac1cf001-7fbc-1f2f-817f-bce058020001"), "https://www.fail.com", false, Guid.NewGuid())); A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Not.Matches(x => x == _existingServiceId || x == _existingServiceWithFailingAutoSetupId), A._)) .Returns((OfferProviderDetailsData?)null); diff --git a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json index ccba9abb4a..a81a79ef4a 100644 --- a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json @@ -68,6 +68,15 @@ "Sales Manager" ] }, + "SubscriptionManagerRoles": [ + { + "ClientId": "Cl2-CX-Portal", + "UserRoleNames": [ + "Service Manager", + "Sales Manager" + ] + } + ], "DocumentTypeIds": [ "ADDITIONAL_DETAILS" ], diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs index 923b82da22..10d41d9697 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs @@ -95,6 +95,7 @@ public async Task GetOfferProviderDetailsAsync_ReturnsExpectedResult() // Assert offerDetail.Should().NotBeNull(); offerDetail!.OfferName.Should().Be("Trace-X"); + offerDetail.ProviderCompanyId.Should().Be(new Guid("2dc4249f-b5ca-4d42-bef1-7a7a950a4f87")); } [Fact]