public async Task <IActionResult> Create([FromBody] InterpreterDetailsModel interpreter)
        {
            if (interpreter == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing));
            }

            try
            {
                var brokerId = User.TryGetBrokerId().Value;
                if (EnumHelper.GetEnumByCustomName <InterpreterInformationType>(interpreter.InterpreterInformationType) != InterpreterInformationType.NewInterpreter)
                {
                    ReturnError(ErrorCodes.InterpreterFaultyIntention);
                }
                var createdInterpreter = _apiUserService.GetInterpreter(interpreter, brokerId);
                await _dbContext.SaveChangesAsync();

                var createdInterpreterResponse = ApiUserService.GetModelFromEntity(createdInterpreter);
                return(Ok(new CreateInterpreterResponse {
                    Interpreter = createdInterpreterResponse
                }));
            }
            catch (InvalidApiCallException ex)
            {
                return(ReturnError(ex.ErrorCode));
            }
            catch (Exception e)
            {
                _logger.LogError(e, $"Unexpected error occured when client called Request/{nameof(View)}");
                return(ReturnError(ErrorCodes.UnspecifiedProblem));
            }
        }
        public async Task <ActionResult> Edit(CustomerModel model)
        {
            var customer = _dbContext.CustomerOrganisations.Single(c => c.CustomerOrganisationId == model.CustomerId);

            customer.CustomerSettings = await _dbContext.CustomerSettings.GetCustomerSettingsForCustomer(customer.CustomerOrganisationId).ToListAsync();

            if ((await _authorizationService.AuthorizeAsync(User, customer, Policies.Edit)).Succeeded)
            {
                if (ModelState.IsValid)
                {
                    var customerSettings = model.CustomerSettings.Select(cs => new CustomerSetting {
                        CustomerSettingType = cs.CustomerSettingType, Value = cs.Value
                    });
                    customer.UpdateCustomerSettingsAndHistory(_clock.SwedenNow, User.GetUserId(), customerSettings);

                    model.UpdateCustomer(customer);
                    await _dbContext.SaveChangesAsync();

                    await _cacheService.Flush(CacheKeys.CustomerSettings);

                    await _cacheService.Flush(CacheKeys.OrganisationSettings);

                    return(RedirectToAction(nameof(View), new { Id = model.CustomerId, Message = "Myndighet har uppdaterats" }));
                }
                return(View(model));
            }
            return(Forbid());
        }
        public async Task <ActionResult> Edit(InterpreterModel model)
        {
            if (ModelState.IsValid)
            {
                var interpreter = _dbContext.InterpreterBrokers.SingleOrDefault(u => u.InterpreterBrokerId == model.Id);
                if ((await _authorizationService.AuthorizeAsync(User, interpreter, Policies.Edit)).Succeeded)
                {
                    if (!_interpreterService.IsUniqueOfficialInterpreterId(model.OfficialInterpreterId, User.GetBrokerId(), model.Id))
                    {
                        ModelState.AddModelError(nameof(model.OfficialInterpreterId), $"Er förmedling har redan registrerat en tolk med detta tolknummer (Kammarkollegiets) i tjänsten.");
                    }
                    else
                    {
                        if (interpreter.IsActive != model.IsActive)
                        {
                            model.UpdateAndChangeStatusInterpreter(interpreter, interpreter.IsActive ? (int?)User.GetUserId() : null, interpreter.IsActive ? User.TryGetImpersonatorId() : null, interpreter.IsActive ? (DateTimeOffset?)_clock.SwedenNow : null);
                        }
                        else
                        {
                            model.UpdateInterpreter(interpreter);
                        }
                        await _dbContext.SaveChangesAsync();

                        return(RedirectToAction(nameof(List), new InterpreterListModel {
                            Message = "Tolkinformation har sparats"
                        }));
                    }
                }
            }
            return(View(model));
        }
Example #4
0
        public async Task <ActionResult> Create(CustomerUnitModel model)
        {
            if (ModelState.IsValid)
            {
                if (!IsUniqueName(model.Name))
                {
                    ModelState.AddModelError(nameof(model.Name), $"Namnet används redan för en annan enhet för denna myndighet");
                }
                else if (!_userService.IsUniqueEmail(model.Email))
                {
                    ModelState.AddModelError(nameof(model.Email), $"E-postadressen används redan i tjänsten");
                }
                else
                {
                    int?customerId = User.TryGetCustomerOrganisationId();
                    var unit       = new CustomerUnit();
                    unit.Create(_clock.SwedenNow, User.GetUserId(), User.TryGetImpersonatorId(), User.GetCustomerOrganisationId(), model.Name, model.Email, model.LocalAdministrator);
                    await _userService.LogCustomerUnitUserUpdateAsync(model.LocalAdministrator, User.GetUserId(), User.TryGetImpersonatorId());

                    await _dbContext.AddAsync(unit);

                    await _dbContext.SaveChangesAsync();

                    return(RedirectToAction(nameof(View), new { id = unit.CustomerUnitId }));
                }
            }
            return(View(model));
        }
Example #5
0
        public async Task <IActionResult> Accept([FromBody] ComplaintAcceptModel model)
        {
            if (model == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing, nameof(Accept)));
            }
            try
            {
                var brokerId  = User.TryGetBrokerId().Value;
                var apiUserId = User.UserId();
                _ = await _apiOrderService.GetOrderAsync(model.OrderNumber, brokerId);

                var user = await _apiUserService.GetBrokerUser(model.CallingUser, brokerId);

                var complaint = await GetCreatedComplaint(model.OrderNumber, brokerId);

                _complaintService.Accept(complaint, user?.Id ?? apiUserId, user != null ? (int?)apiUserId : null);

                await _dbContext.SaveChangesAsync();

                //End of service
                return(Ok(new ResponseBase()));
            }
            catch (InvalidApiCallException ex)
            {
                return(ReturnError(ex.ErrorCode, nameof(Accept)));
            }
        }
        public async Task <IActionResult> Create(ComplaintModel model)
        {
            if (ModelState.IsValid)
            {
                var request = await _dbContext.Requests.GetSimpleRequestById(model.RequestId);

                if ((await _authorizationService.AuthorizeAsync(User, request, Policies.CreateComplaint)).Succeeded)
                {
                    try
                    {
                        await _complaintService.Create(request, User.GetUserId(), User.TryGetImpersonatorId(), model.Message, model.ComplaintType.Value);

                        await _dbContext.SaveChangesAsync();
                    }
                    catch (InvalidOperationException ex)
                    {
                        _logger.LogError("Wrong status or complaint exists when trying to Create complaint. Status: {request.Status}, RequestId {request.RequestId}", request.Status, request.RequestId);
                        return(RedirectToAction("Index", "Home", new { errormessage = ex.Message }));
                    }
                    return(RedirectToAction("View", "Order", new { id = request.OrderId, tab = "complaint" }));
                }
                return(Forbid());
            }
            return(View(nameof(Create), model));
        }
        private async Task <IActionResult> CreateUpdateSystemMessage(SystemMessageModel model, bool update)
        {
            if (model.DisplayDate.Start > model.DisplayDate.End)
            {
                model.SystemMessageTypeValue = EnumHelper.Parse <SystemMessageType>(model.SystemMessageType.SelectedItem.Value);
                ModelState.AddModelError($"{nameof(model.DisplayDate)}.{nameof(model.DisplayDate.Start)}", "Visningsdatum för nyheten är fel. Från och med datum kan inte vara större än till och med datum.");
            }
            else
            {
                if (update)
                {
                    var sysMessage = await _dbContext.SystemMessages.GetSystemMessageById(model.SystemMessageId);

                    sysMessage.Update(_clock.SwedenNow, User.GetUserId(), User.TryGetImpersonatorId(), model.DisplayDate.Start.ToDateTimeOffsetSweden(), model.DisplayDate.End.ToDateTimeOffsetSweden(), model.SystemMessageHeader, model.SystemMessageText, EnumHelper.Parse <SystemMessageType>(model.SystemMessageType.SelectedItem.Value), model.DisplayedForUserTypeGroup);
                }
                else
                {
                    var sysMessage = new SystemMessage();
                    sysMessage.Create(_clock.SwedenNow, User.GetUserId(), User.TryGetImpersonatorId(), model.DisplayDate.Start.ToDateTimeOffsetSweden(), model.DisplayDate.End.ToDateTimeOffsetSweden(), model.SystemMessageHeader, model.SystemMessageText, EnumHelper.Parse <SystemMessageType>(model.SystemMessageType.SelectedItem.Value), model.DisplayedForUserTypeGroup);
                    await _dbContext.AddAsync(sysMessage);
                }
                await _dbContext.SaveChangesAsync();

                return(RedirectToAction("List"));
            }
            return(View(model));
        }
Example #8
0
        public async Task CallWebHooks()
        {
            List <int> callIds = null;

            using (TolkDbContext context = _options.GetContext())
            {
                callIds = await context.OutboundWebHookCalls
                          .Where(e => e.DeliveredAt == null && e.FailedTries < NumberOfTries && !e.IsHandling)
                          .Select(e => e.OutboundWebHookCallId)
                          .ToListAsync();

                if (callIds.Any())
                {
                    var calls = context.OutboundWebHookCalls
                                .Where(e => callIds.Contains(e.OutboundWebHookCallId) && e.IsHandling == false)
                                .Select(c => c);
                    await calls.ForEachAsync(c => c.IsHandling = true);

                    await context.SaveChangesAsync();
                }
            }

            _logger.LogInformation("Found {count} outbound web hook calls to send: {callIds}",
                                   callIds.Count, string.Join(", ", callIds));

            if (callIds.Any())
            {
                var tasks = new List <Task>();
                foreach (var callId in callIds)
                {
                    tasks.Add(Task.Factory.StartNew(() => CallWebhook(callId), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current));
                }
                await Task.Factory.ContinueWhenAny(tasks.ToArray(), r => { });
            }
        }
Example #9
0
        public async Task <IActionResult> Process(int id)
        {
            var requestGroup = await _dbContext.RequestGroups.GetRequestGroupToView(id);

            if ((await _authorizationService.AuthorizeAsync(User, requestGroup, Policies.Accept)).Succeeded)
            {
                if (!requestGroup.IsToBeProcessedByBroker)
                {
                    _logger.LogWarning("Wrong status when trying to process request group. Status: {request.Status}, RequestGroupId: {request.RequestGroupId}", requestGroup.Status, requestGroup.RequestGroupId);
                    return(RedirectToAction(nameof(View), new { id }));
                }
                if (requestGroup.Status == RequestStatus.Created)
                {
                    await _requestService.AcknowledgeGroup(requestGroup, _clock.SwedenNow, User.GetUserId(), User.TryGetImpersonatorId());

                    await _dbContext.SaveChangesAsync();
                }

                OrderGroup orderGroup = await _dbContext.OrderGroups.GetFullOrderGroupById(requestGroup.OrderGroupId);

                await _orderService.AddOrdersWithListsForGroup(orderGroup);

                await _requestService.AddListsForRequestGroup(requestGroup);

                requestGroup.Requests.ForEach(r => r.Order = orderGroup.Orders.Where(o => o.OrderId == r.OrderId).SingleOrDefault());

                var model = RequestGroupProcessModel.GetModelFromRequestGroup(requestGroup, Guid.NewGuid(), _options.CombinedMaxSizeAttachments, _options.AllowDeclineExtraInterpreterOnRequestGroups);
                await _listToModelService.AddInformationFromListsToModel(model, User.GetUserId());

                model.CustomerInformationModel.IsCustomer = false;
                model.CustomerInformationModel.UseSelfInvoicingInterpreter = _cacheService.CustomerSettings.Any(c => c.CustomerOrganisationId == requestGroup.OrderGroup.CustomerOrganisationId && c.UsedCustomerSettingTypes.Any(cs => cs == CustomerSettingType.UseSelfInvoicingInterpreter));
                //if not first broker in rank (requests are not answered and have no pricerows) we need to get a calculated price with correct broker fee
                if (requestGroup.Ranking.Rank != 1)
                {
                    List <OrderOccasionDisplayModel> tempOccasionList = new List <OrderOccasionDisplayModel>();
                    foreach (OrderOccasionDisplayModel occasion in model.OccasionList.Occasions)
                    {
                        var request = requestGroup.Requests.Single(r => r.RequestId == occasion.RouteId);
                        tempOccasionList.Add(OrderOccasionDisplayModel.GetModelFromOrder(request.Order, GetPriceinformationOrderToDisplay(request, model.RequestedCompetenceLevels.ToList()), request));
                    }
                    model.OccasionList.Occasions = tempOccasionList;
                }
                return(View(model));
            }
            return(Forbid());
        }
Example #10
0
        public async Task <IActionResult> Approve(ProcessRequestGroupModel model)
        {
            var requestGroup = await _dbContext.RequestGroups.GetRequestGroupById(model.RequestGroupId);

            if ((await _authorizationService.AuthorizeAsync(User, requestGroup.OrderGroup, Policies.Accept)).Succeeded)
            {
                if (!requestGroup.CanApprove)
                {
                    _logger.LogError("Wrong status when trying to Approve request group. Status: {requestGroup.Status}, RequestGroupId: {requestGroup.RequestGroupId}", requestGroup.Status, requestGroup.RequestGroupId);
                    return(RedirectToAction(nameof(View), new { id = requestGroup.OrderGroupId }));
                }
                await _orderService.ApproveRequestGroupAnswer(requestGroup, User.GetUserId(), User.TryGetImpersonatorId());

                await _dbContext.SaveChangesAsync();

                return(RedirectToAction(nameof(View), new { id = requestGroup.OrderGroupId }));
            }
            return(Forbid());
        }
Example #11
0
        private async Task <IActionResult> PasswordLogin(LoginViewModel model, Uri returnUrl)
        {
            var user = await _userManager.FindByEmailAsync(model.UserName) ?? await _userManager.FindByNameAsync(model.UserName);

            if (user != null)
            {
                var result = await _signInManager.PasswordSignInAsync(user, model.Password, isPersistent : true, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    if (!user.IsActive)
                    {
                        //I want this to be done in two steps, first validating the user, then if valid user but inactive log out again, with proper message.
                        await _signInManager.SignOutAsync();

                        _logger.LogInformation("Inactivated User {userName} tried to log in.", model.UserName);
                        ModelState.AddModelError(nameof(model.UserName), "Ditt konto är tillfälligt inaktiverat, vänligen kontakta [email protected] för mer information.");
                        return(View(model));
                    }
                    user.LastLoginAt = _clock.SwedenNow;
                    await _userManager.UpdateAsync(user);

                    await _dbContext.SaveChangesAsync();

                    await _userService.LogLoginAsync(user.Id);

                    _logger.LogInformation("User {userName} logged in.", model.UserName);
                    return(RedirectToLocal(returnUrl));
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account {userName} locked out.", model.UserName);
                    return(RedirectToAction(nameof(Lockout)));
                }
            }
            //No user found, or wrong password is handled the same
            ModelState.AddModelError(nameof(model.UserName), "Felaktigt användarnamn eller lösenord.");
            return(View(model));
        }
Example #12
0
        public async Task <JsonResult> Delete(int id, Guid groupKey)
        {
            //this delete is just for deleting attachments added in UI before connected to orders, requests and requisitions
            var attachment = await _dbContext.Attachments.GetNonConnectedAttachmentById(id);

            if (attachment != null && attachment.TemporaryAttachmentGroup.TemporaryAttachmentGroupKey == groupKey && (await _authorizationService.AuthorizeAsync(User, attachment, Policies.Delete)).Succeeded)
            {
                _dbContext.TemporaryAttachmentGroups.Remove(attachment.TemporaryAttachmentGroup);
                _dbContext.Attachments.Remove(attachment);
                await _dbContext.SaveChangesAsync();
            }
            return(Json(new { success = true }));
        }
Example #13
0
        public async Task <IActionResult> Process(int id)
        {
            var request = await _dbContext.Requests.GetRequestById(id);

            if ((await _authorizationService.AuthorizeAsync(User, request, Policies.Accept)).Succeeded)
            {
                if (!request.IsToBeProcessedByBroker)
                {
                    _logger.LogWarning("Wrong status when trying to process request. Status: {request.Status}, RequestId: {request.RequestId}", request.Status, request.RequestId);
                    return(RedirectToAction(nameof(View), new { id }));
                }
                if (request.Status == RequestStatus.Created)
                {
                    _requestService.Acknowledge(request, _clock.SwedenNow, User.GetUserId(), User.TryGetImpersonatorId());
                    await _dbContext.SaveChangesAsync();
                }

                RequestModel model = await GetModel(request);

                model.FileGroupKey = new Guid();
                model.CombinedMaxSizeAttachments = _options.CombinedMaxSizeAttachments;
                model.ExpectedTravelCosts        = null;
                model.AllowProcessing            = !request.RequestGroupId.HasValue;
                if (model.OrderViewModel.ReplacingOrderId.HasValue)
                {
                    model.ProcessReplacementRequestViewModel = RequestViewModel.GetModelFromRequest(request, request.Order.AllowExceedingTravelCost);
                    model.ProcessReplacementRequestViewModel.LanguageAndDialect       = model.OrderViewModel.LanguageAndDialect;
                    model.ProcessReplacementRequestViewModel.RegionName               = model.OrderViewModel.RegionName;
                    model.ProcessReplacementRequestViewModel.TimeRange                = model.OrderViewModel.TimeRange;
                    model.ProcessReplacementRequestViewModel.DisplayMealBreakIncluded = model.OrderViewModel.DisplayMealBreakIncludedText;
                    model.ProcessReplacementRequestViewModel.IsReplacingOrderRequest  = true;
                    model.ProcessReplacementRequestViewModel.RequirementAnswers       = await RequestRequirementAnswerModel.GetFromList(_dbContext.OrderRequirementRequestAnswer.GetRequirementAnswersForRequest(request.RequestId));
                }
                model.OrderViewModel.UseAttachments = true;
                return(View(model));
            }
            return(Forbid());
        }
        public async Task <IActionResult> Create([FromBody] RequisitionModel model)
        {
            if (model == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing));
            }
            try
            {
                var brokerId  = User.TryGetBrokerId().Value;
                var apiUserId = User.UserId();
                var order     = await _apiOrderService.GetOrderAsync(model.OrderNumber, brokerId);

                var user = await _apiUserService.GetBrokerUser(model.CallingUser, brokerId);

                var request = await _dbContext.Requests.GetActiveRequestForApiWithBrokerAndOrderNumber(model.OrderNumber, brokerId);

                if (request == null)
                {
                    return(ReturnError(ErrorCodes.RequestNotFound));
                }
                if (!request.IsApprovedOrDelivered)
                {
                    return(ReturnError(ErrorCodes.RequestNotInCorrectState));
                }
                try
                {
                    await _requisitionService.Create(request, user?.Id ?? apiUserId, (user != null ? (int?)apiUserId : null), model.Message,
                                                     model.Outlay, model.AcctualStartedAt, model.AcctualEndedAt, model.WasteTime, model.WasteTimeInconvenientHour, EnumHelper.GetEnumByCustomName <TaxCardType>(model.TaxCard).Value,
                                                     new List <RequisitionAttachment>(), Guid.NewGuid(), model.MealBreaks.Select(m => new MealBreak
                    {
                        StartAt = m.StartedAt,
                        EndAt = m.EndedAt,
                    }).ToList(),
                                                     model.CarCompensation,
                                                     model.PerDiem);

                    await _dbContext.SaveChangesAsync();
                }
                catch (InvalidOperationException)
                {
                    //TODO: Should log the acctual exception here!!
                    return(ReturnError(ErrorCodes.RequisitionNotInCorrectState));
                }
                return(Ok(new ResponseBase()));
            }
            catch (InvalidApiCallException ex)
            {
                return(ReturnError(ex.ErrorCode));
            }
        }
        [OpenApiIgnore]//Not applicable for broker api, hence hiding it from swagger
        public async Task <IActionResult> Create([FromBody] CreateOrderModel model)
        {
            var method = $"{nameof(OrderController)}.{nameof(Create)}";

            _logger.LogDebug($"{method} was called");
            if (model == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing, method));
            }
            if (!_tolkBaseOptions.EnableCustomerApi)
            {
                _logger.LogWarning($"{model.CallingUser} called {method}, but CustomerApi is not enabled!");
                return(BadRequest(new ValidationProblemDetails {
                    Title = "CustomerApi is not enabled!"
                }));
            }
            if (string.IsNullOrEmpty(model.CallingUser))
            {
                return(ReturnError(ErrorCodes.CallingUserMissing, method));
            }
            _logger.LogInformation($"{model.CallingUser} is creating a new order");
            if (ModelState.IsValid)
            {
                try
                {
                    var order = await _apiOrderService.GetOrderFromModel(model, User.UserId(), User.TryGetCustomerId().Value);

                    await _orderService.Create(order, model.LatestAnswerBy);

                    await _dbContext.SaveChangesAsync();

                    _logger.LogInformation($"{order.OrderNumber} was created");
                    return(Ok(new CreateOrderResponse
                    {
                        OrderNumber = order.OrderNumber,
                        PriceInformation = order.PriceRows.GetPriceInformationModel(
                            order.PriceCalculatedFromCompetenceLevel.GetCustomName(),
                            (await _dbContext.Requests.GetActiveRequestByOrderId(order.OrderId)).Ranking.BrokerFee),
                    }));
                }
                catch (InvalidOperationException ex)
                {
                    return(ReturnError(ErrorCodes.OrderNotValid, method, ex.Message));
                }
                catch (ArgumentNullException ex)
                {
                    return(ReturnError(ErrorCodes.OrderNotValid, method, ex.Message));
                }
            }
            return(ReturnError(ErrorCodes.OrderNotValid, method));
        }
Example #16
0
        private async Task <IActionResult> CreateUpdateFaq(FaqModel model, bool update)
        {
            Faq faq             = new Faq();
            var displayForRoles = model.DisplayForRoles.SelectedItems.Select(r => EnumHelper.Parse <DisplayUserRole>(r.Value));

            if (update)
            {
                var faqDisplayUserRolesWithFaq = await _dbContext.FaqDisplayUserRole.GetFaqWithFaqDisplayUserRolesByFaqId(model.FaqId).ToListAsync();

                faq = faqDisplayUserRolesWithFaq.Select(f => f.Faq).First();
                faq.Update(_clock.SwedenNow, User.GetUserId(), model.IsDisplayed, model.Question, model.Answer, displayForRoles);
            }
            else
            {
                faq.Create(_clock.SwedenNow, User.GetUserId(), model.IsDisplayed, model.Question, model.Answer, displayForRoles);
                await _dbContext.AddAsync(faq);
            }
            await _dbContext.SaveChangesAsync();

            return(RedirectToAction("List"));
        }
Example #17
0
        public async Task CheckForFailuresToReport()
        {
            var callIds = await _tolkDbContext.OutboundWebHookCalls
                          .Where(e => e.DeliveredAt == null && e.HasNotifiedFailure == false)
                          .Select(e => e.OutboundWebHookCallId)
                          .ToListAsync();

            _logger.LogInformation("Found {count} emails to send: {emailIds}",
                                   callIds.Count, string.Join(", ", callIds));

            if (callIds.Any())
            {
                foreach (var callId in callIds)
                {
                    try
                    {
                        var call = await _tolkDbContext.OutboundWebHookCalls
                                   .SingleOrDefaultAsync(e => e.OutboundWebHookCallId == callId && e.DeliveredAt == null && e.HasNotifiedFailure == false);

                        if (call == null)
                        {
                            _logger.LogInformation("Call {callId} was in list to be notifed as a failure, but now appears to have been handled.", callId);
                        }
                        else
                        {
                            _logger.LogInformation("Notifying failure on {callId} of type {notificationType}", callId, call.NotificationType);
                            await _notificationService.NotifyOnFailure(callId);

                            call.HasNotifiedFailure = true;
                            await _tolkDbContext.SaveChangesAsync();
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Failure Notifying failure on {callId}", callId);
                    }
                }
            }
        }
        public async Task <UpdateLanguagesCompetenceResult> UpdateTellusLanguagesCompetenceInfo(bool notify = false)
        {
            _logger.LogInformation($"Starting {nameof(UpdateTellusLanguagesCompetenceInfo)}");
            if (!_tolkBaseOptions.Tellus.IsLanguagesCompetenceActivated)
            {
                return new UpdateLanguagesCompetenceResult
                       {
                           UpdatedLanguages = Enumerable.Empty <Language>(),
                           Message          = "Hämtningen av språkkompetenser från Tellus är inte aktiverad, ändra konfigurering för att aktivera."
                       }
            }
            ;
            try
            {
                var response = await client.GetAsync(_tolkBaseOptions.Tellus.LanguagesCompetenceInfoUri);

                string content = await response.Content.ReadAsStringAsync();

                var result = JsonConvert.DeserializeObject <TellusLanguagesCompetenceInfoResponse>(content);

                if (result.Status != 200)
                {
                    if (notify)
                    {
                        _notificationService.CreateEmail(_tolkBaseOptions.Support.SecondLineEmail,
                                                         $"Hämtningen av språkkompetenser från Tellus misslyckades!",
                                                         $"Här kan du testa att köra en hämtning direkt ifrån tjänsten:\n\n{_tolkBaseOptions.TolkWebBaseUrl}Language/UpdateCompetences",
                                                         null,
                                                         NotificationType.GetCompetencesFromTellusFailed
                                                         );
                    }
                    _logger.LogWarning($"Hämtningen av språkkompetenser från Tellus misslyckades, med status {result.Status}");
                    return(new UpdateLanguagesCompetenceResult
                    {
                        UpdatedLanguages = Enumerable.Empty <Language>(),
                        Message = $"Hämtningen av språkkompetenser från Tellus misslyckades, med status {result.Status}"
                    });
                }
                var currentTellusLanguages = await _dbContext.Languages.Where(l => !string.IsNullOrWhiteSpace(l.TellusName)).ToListAsync();

                var tellusLanguagesWithCompetences = result.Result.Where(t => currentTellusLanguages.Any(l => l.TellusName == t.Id && l.Active));
                if (!result.Result.Any() || !tellusLanguagesWithCompetences.Any())
                {
                    _logger.LogWarning($"Result of {nameof(UpdateTellusLanguagesCompetenceInfo)} had no active languages");
                    if (notify)
                    {
                        await _emailService.SendApplicationManagementEmail(result.Result.Any()? "Hämtningen av språkkompetenser från Tellus innehöll endast ej aktiva språk eller Tellusnamn som inte förekommer i tjänsten" : "Hämtningen av språkkompetenser från Tellus innehöll inga språk",
                                                                           $"Här kan du testa att köra en hämtning direkt ifrån tjänsten:\n\n{_tolkBaseOptions.TolkWebBaseUrl}Language/UpdateCompetences");
                    }
                    return(new UpdateLanguagesCompetenceResult
                    {
                        UpdatedLanguages = Enumerable.Empty <Language>(),
                        Message = result.Result.Any() ? "Hämtningen innehöll endast ej aktiva språk eller Tellusnamn som inte förekommer i tjänsten" : "Hämtningen innehöll inga språk"
                    });
                }
                List <Language> updatedLanguages = new List <Language>();

                foreach (TellusLanguagesInfoModel l in tellusLanguagesWithCompetences)
                {
                    var updates = currentTellusLanguages.Where(ls => ls.TellusName == l.Id &&
                                                               (l.HasLegal != ls.HasLegal ||
                                                                l.HasHealthcare != ls.HasHealthcare ||
                                                                l.HasAuthorized != ls.HasAuthorized ||
                                                                l.HasEducated != ls.HasEducated)).ToList();
                    updates.ForEach(c => { c.HasLegal = l.HasLegal; c.HasHealthcare = l.HasHealthcare; c.HasAuthorized = l.HasAuthorized; c.HasEducated = l.HasEducated; });
                    updatedLanguages.AddRange(updates);
                }
                await _dbContext.SaveChangesAsync();

                _logger.LogInformation($"Update of {nameof(UpdateTellusLanguagesCompetenceInfo)} completed");
                return(new UpdateLanguagesCompetenceResult {
                    UpdatedLanguages = updatedLanguages, Message = updatedLanguages.Any() ? string.Empty : "Inga skillnader i kompetenser fanns mellan tjänsten och Tellus"
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Running {nameof(UpdateTellusLanguagesCompetenceInfo)} failed");
                await SendErrorMail(nameof(UpdateTellusLanguagesCompetenceInfo), ex);

                return(new UpdateLanguagesCompetenceResult
                {
                    UpdatedLanguages = Enumerable.Empty <Language>(),
                    Message = "Hämtningen av språkkompetenser misslyckades."
                });
            }
        }
Example #19
0
        public async Task <IActionResult> Create(int orderId)
        {
            var request = await _dbContext.Requests.GetRequestForOrderAgreementCreation(orderId);

            if (!_cacheService.CustomerSettings.Any(c => c.CustomerOrganisationId == request.Order.CustomerOrganisationId && c.UsedCustomerSettingTypes.Any(cs => cs == CustomerSettingType.UseOrderAgreements)))
            {
                return(Forbid());
            }
            request.Requisitions = await _dbContext.Requisitions.GetRequisitionsForRequest(request.RequestId).ToListAsync();

            request.OrderAgreementPayloads = await _dbContext.OrderAgreementPayloads.GetOrderAgreementPayloadsForRequest(request.RequestId).ToListAsync();

            if (request != null && (await _authorizationService.AuthorizeAsync(User, request, Policies.CreateOrderAgreement)).Succeeded)
            {
                if (request.AllowOrderAgreementCreation())
                {
                    var requisitionId = (await _dbContext.Requisitions.GetRequisitionsForOrder(orderId).Where(r => r.Status == RequisitionStatus.Approved ||
                                                                                                              r.Status == RequisitionStatus.AutomaticGeneratedFromCancelledOrder ||
                                                                                                              r.Status == RequisitionStatus.Created ||
                                                                                                              r.Status == RequisitionStatus.Reviewed).SingleOrDefaultAsync())?.RequisitionId;
                    var    previousIndex     = request.OrderAgreementPayloads.Max(p => p.Index as int?);
                    int    index             = 1;
                    string payloadIdentifier = "";
                    using var memoryStream = new MemoryStream();
                    using var writer       = new StreamWriter(memoryStream, Encoding.UTF8);
                    if (requisitionId.HasValue)
                    {
                        payloadIdentifier = await _orderAgreementService.CreateOrderAgreementFromRequisition(requisitionId.Value, writer, previousIndex);

                        index = previousIndex.HasValue ? previousIndex.Value + 1 : 1;
                    }
                    else
                    {
                        payloadIdentifier = await _orderAgreementService.CreateOrderAgreementFromRequest(request.RequestId, writer);
                    }
                    memoryStream.Position = 0;
                    byte[] byteArray = new byte[memoryStream.Length];
                    memoryStream.Read(byteArray, 0, (int)memoryStream.Length);
                    memoryStream.Close();
                    //Save it to db
                    var payload = new OrderAgreementPayload
                    {
                        CreatedBy = User.GetUserId(),
                        ImpersonatingCreatedBy = User.TryGetImpersonatorId(),
                        Payload              = byteArray,
                        RequisitionId        = requisitionId,
                        CreatedAt            = _clock.SwedenNow,
                        Index                = index,
                        IdentificationNumber = payloadIdentifier
                    };
                    request.OrderAgreementPayloads.Add(payload);
                    if (previousIndex.HasValue)
                    {
                        var previous = request.OrderAgreementPayloads.Single(p => p.Index == previousIndex);
                        previous.ReplacedByPayload = payload;
                    }
                    await _dbContext.SaveChangesAsync();

                    //return a identifier for the saved agreement, to be able to retrieve it.
                    return(RedirectToAction(nameof(View), new { id = payload.OrderAgreementPayloadId }));
                }
            }
            else
            {
                //Handle non-allow
            }
            return(Forbid());
        }
Example #20
0
        public async Task SendInviteAsync(AspNetUser user)
        {
            string subject   = null;
            string body      = null;
            string plainBody = null;
            string htmlBody  = null;

            NullCheckHelper.ArgumentCheckNull(user, nameof(SendInviteAsync), nameof(UserService));
            if (user.InterpreterId.HasValue)
            {
                (subject, body) = CreateInterpreterInvite();
                if (subject == null || body == null)
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                // Not interpreter => must belong to organization.
                (subject, htmlBody)  = CreateOrganizationUserActivation(true);
                (subject, plainBody) = CreateOrganizationUserActivation(false);
                if (subject == null || htmlBody == null || plainBody == null)
                {
                    throw new NotImplementedException();
                }
            }

            var link = await GenerateActivationLinkAsync(user);

            plainBody = plainBody.FormatSwedish(link);
            htmlBody  = HtmlHelper.ToHtmlBreak(htmlBody).FormatSwedish(HtmlHelper.GetButtonDefaultLargeTag(link.AsUri(), "Registrera användarkonto"), link);
            _notificationService.CreateEmail(user.Email, subject, plainBody, htmlBody, NotificationType.UserInvitation);
            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("Sent account confirmation link to {userId} ({email})", user.Id, user.Email);
        }
        private async void Run(bool isInit = false)
        {
            _logger.LogTrace("EntityScheduler waking up.");

            if ((nextDailyRunTime - _clock.SwedenNow).TotalHours > 25 || nextDailyRunTime.Hour != timeToRun)
            {
                _logger.LogWarning("nextDailyRunTime set to invalid time, was {0}", nextDailyRunTime);
                DateTimeOffset now = _clock.SwedenNow;
                now -= now.TimeOfDay;
                nextDailyRunTime = now - now.TimeOfDay;
                nextDailyRunTime = nextDailyRunTime.AddHours(timeToRun);

                if (_clock.SwedenNow.Hour > timeToRun)
                {
                    // Next remind is tomorrow
                    nextDailyRunTime = nextDailyRunTime.AddDays(1);
                }
            }

            if (isInit)
            {
                using TolkDbContext context = _options.GetContext();
                await context.OutboundEmails.Where(e => e.IsHandling == true)
                .Select(c => c).ForEachAsync(c => c.IsHandling = false);

                await context.OutboundWebHookCalls.Where(e => e.IsHandling == true)
                .Select(c => c).ForEachAsync(c => c.IsHandling = false);

                await context.SaveChangesAsync();
            }

            try
            {
                if (nextRunIsNotifications)
                {
                    //Separate these, to get a better parallellism for the notifications
                    // They fail to run together with the other Continous jobs , due to recurring deadlocks around the email table...
                    List <Task> tasksToRunNotifications = new List <Task>
                    {
                        Task.Factory.StartNew(() => _services.GetRequiredService <EmailService>().SendEmails(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current),
                        Task.Factory.StartNew(() => _services.GetRequiredService <WebHookService>().CallWebHooks(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current)
                    };
                    await Task.Factory.ContinueWhenAny(tasksToRunNotifications.ToArray(), r => { });
                }
                else
                {
                    //would like to have a timer here, to make it possible to get tighter runs if the last run ran for longer than 10 seconds or somethng...
                    using var serviceScope = _services.CreateScope();
                    Task[] tasksToRun;

                    if (_clock.SwedenNow > nextDailyRunTime)
                    {
                        nextDailyRunTime  = nextDailyRunTime.AddDays(1);
                        nextDailyRunTime -= nextDailyRunTime.TimeOfDay;
                        nextDailyRunTime  = nextDailyRunTime.AddHours(timeToRun);
                        _logger.LogTrace("Running DailyRunTime, next run on {0}", nextDailyRunTime);

                        tasksToRun = new Task[]
                        {
                            RunDailyJobs(serviceScope.ServiceProvider),
                        };
                    }
                    else
                    {
                        tasksToRun = new Task[]
                        {
                            RunContinousJobs(serviceScope.ServiceProvider),
                        };
                    }
                    if (!Task.WaitAll(tasksToRun, allotedTimeAllTasks))
                    {
                        throw new InvalidOperationException($"All tasks instances didn't complete execution within the allotted time: {allotedTimeAllTasks / 1000} seconds");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogCritical(ex, "Entity Scheduler failed ({message}).", ex.Message);
                _ = _services.GetRequiredService <EmailService>().SendErrorEmail(nameof(EntityScheduler), nameof(Run), ex);
            }
            finally
            {
                nextRunIsNotifications = !nextRunIsNotifications;
                if (_services.GetRequiredService <ITolkBaseOptions>().RunEntityScheduler)
                {
                    await Task.Delay(timeDelayContinousJobs).ContinueWith(t => Run(), TaskScheduler.Default);
                }
            }

            _logger.LogTrace($"EntityScheduler done, scheduled to wake up in {timeDelayContinousJobs / 1000} seconds again");
        }
        public async Task <Requisition> Create(Request request, int userId, int?impersonatorId, string message, decimal?outlay,
                                               DateTimeOffset sessionStartedAt, DateTimeOffset sessionEndedAt, int?timeWasteNormalTime, int?timeWasteIWHTime, TaxCardType interpreterTaxCard,
                                               List <RequisitionAttachment> attachments, Guid fileGroupKey, List <MealBreak> mealbreaks, int?carCompensation, string perDiem)
        {
            NullCheckHelper.ArgumentCheckNull(request, nameof(Create), nameof(RequisitionService));
            request.Requisitions = await _dbContext.Requisitions.GetRequisitionsForRequest(request.RequestId).ToListAsync();

            if (!request.CanCreateRequisition)
            {
                throw new InvalidOperationException($"Cannot create requisition on order {request.OrderId}");
            }
            request.PriceRows = await _dbContext.RequestPriceRows.GetPriceRowsForRequest(request.RequestId).ToListAsync();

            var priceInformation = _priceCalculationService.GetPricesRequisition(
                sessionStartedAt,
                sessionEndedAt,
                request.Order.StartAt,
                request.Order.EndAt,
                EnumHelper.Parent <CompetenceAndSpecialistLevel, CompetenceLevel>((CompetenceAndSpecialistLevel)request.CompetenceLevel),
                request.Order.CustomerOrganisation.PriceListType,
                request.Ranking.RankingId,
                out bool useRequestRows,
                timeWasteNormalTime,
                timeWasteIWHTime,
                request.PriceRows.OfType <PriceRowBase>(),
                outlay,
                request.Order.ReplacingOrderId.HasValue ? request.Order.ReplacingOrder : null,
                request.Order.CreatedAt,
                mealbreaks
                );

            using var transaction = _dbContext.Database.BeginTransaction();
            var requisition = new Requisition
            {
                Status    = RequisitionStatus.Created,
                CreatedBy = userId,
                CreatedAt = _clock.SwedenNow,
                ImpersonatingCreatedBy = impersonatorId,
                Message             = message,
                SessionStartedAt    = sessionStartedAt,
                SessionEndedAt      = sessionEndedAt,
                TimeWasteNormalTime = timeWasteNormalTime,
                TimeWasteIWHTime    = timeWasteIWHTime,
                InterpretersTaxCard = interpreterTaxCard,
                PriceRows           = priceInformation.PriceRows.Select(row => DerivedClassConstructor.Construct <PriceRowBase, RequisitionPriceRow>(row)).ToList(),
                Attachments         = attachments,
                MealBreaks          = mealbreaks,
                CarCompensation     = carCompensation,
                PerDiem             = perDiem,
                RequestOrReplacingOrderPeriodUsed = useRequestRows,
            };

            foreach (var tag in _dbContext.TemporaryAttachmentGroups.Where(t => t.TemporaryAttachmentGroupKey == fileGroupKey))
            {
                _dbContext.TemporaryAttachmentGroups.Remove(tag);
            }
            request.CreateRequisition(requisition);
            await _dbContext.SaveChangesAsync();

            var replacingRequisition = request.Requisitions.SingleOrDefault(r => r.Status == RequisitionStatus.Commented &&
                                                                            !r.ReplacedByRequisitionId.HasValue);

            if (replacingRequisition != null)
            {
                replacingRequisition.ReplacedByRequisitionId = requisition.RequisitionId;
                await _dbContext.SaveChangesAsync();
            }
            transaction.Commit();
            _logger.LogDebug($"Created requisition {requisition.RequisitionId} for request {request.RequestId}");
            _notificationService.RequisitionCreated(requisition);
            return(requisition);
        }
        public async Task <IActionResult> Answer([FromBody] RequestGroupAnswerModel model)
        {
            if (model == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing));
            }
            try
            {
                var brokerId  = User.TryGetBrokerId().Value;
                var apiUserId = User.UserId();
                var user      = await _apiUserService.GetBrokerUser(model.CallingUser, brokerId);

                var requestGroup = await _dbContext.RequestGroups.GetFullRequestGroupForApiWithBrokerAndOrderNumber(model.OrderGroupNumber, brokerId);

                if (requestGroup == null)
                {
                    return(ReturnError(ErrorCodes.RequestGroupNotFound));
                }
                if (!(requestGroup.Status == RequestStatus.Created || requestGroup.Status == RequestStatus.Received))
                {
                    return(ReturnError(ErrorCodes.RequestGroupNotInCorrectState));
                }
                var mainInterpreterAnswer = _apiUserService.GetInterpreterModel(model.InterpreterAnswer, brokerId);

                InterpreterAnswerDto extraInterpreterAnswer = null;
                requestGroup.OrderGroup.Orders = await _dbContext.Orders.GetOrdersForOrderGroup(requestGroup.OrderGroup.OrderGroupId).ToListAsync();

                if (requestGroup.HasExtraInterpreter)
                {
                    extraInterpreterAnswer = _apiUserService.GetInterpreterModel(model.ExtraInterpreterAnswer, brokerId, false);
                }
                var now = _timeService.SwedenNow;
                if (requestGroup.Status == RequestStatus.Created)
                {
                    await _requestService.AcknowledgeGroup(requestGroup, now, user?.Id ?? apiUserId, (user != null ? (int?)apiUserId : null));
                }
                try
                {
                    await _requestService.AcceptGroup(
                        requestGroup,
                        now,
                        user?.Id ?? apiUserId,
                        user != null?(int?)apiUserId : null,
                        EnumHelper.GetEnumByCustomName <InterpreterLocation>(model.InterpreterLocation).Value,
                        mainInterpreterAnswer,
                        extraInterpreterAnswer,
                        //Does not handle attachments yet.
                        new List <RequestGroupAttachment>(),
                        model.LatestAnswerTimeForCustomer,
                        model.BrokerReferenceNumber
                        );

                    await _dbContext.SaveChangesAsync();

                    //End of service
                    return(Ok(new GroupAnswerResponse
                    {
                        InterpreterId = mainInterpreterAnswer.Interpreter.InterpreterBrokerId,
                        ExtraInterpreterId = extraInterpreterAnswer?.Interpreter?.InterpreterBrokerId
                    }));
                }
                catch (InvalidOperationException ex)
                {
                    return(ReturnError(ErrorCodes.RequestNotCorrectlyAnswered, ex.Message));
                }
            }
            catch (InvalidApiCallException ex)
            {
                return(ReturnError(ex.ErrorCode));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to handle request group answer");
                return(ReturnError(ErrorCodes.UnspecifiedProblem));
            }
        }
Example #24
0
        private async Task CallWebhook(int callId)
        {
            using TolkDbContext context = _options.GetContext();
            var call = await context.OutboundWebHookCalls
                       .Include(c => c.RecipientUser)
                       .SingleOrDefaultAsync(e => e.OutboundWebHookCallId == callId && e.DeliveredAt == null && e.FailedTries < NumberOfTries);

            bool   success      = false;
            string errorMessage = string.Empty;

            try
            {
                if (call == null)
                {
                    _logger.LogInformation("Call {callId} was in list to be handled, but seems to have been handled already.", call.OutboundWebHookCallId);
                }
                else
                {
                    //Use short cache, so that each call to the same api user does not have to retrieve claims
                    IEnumerable <IdentityUserClaim <int> > claims = (call.RecipientUser != null) ? await context.UserClaims.GetClaimsForUser(call.RecipientUser.Id) : null;

                    using var requestMessage = new HttpRequestMessage(HttpMethod.Post, call.RecipientUrl);
                    requestMessage.Headers.Add("X-Kammarkollegiet-InterpreterService-Event", call.NotificationType.GetCustomName());
                    requestMessage.Headers.Add("X-Kammarkollegiet-InterpreterService-Delivery", call.OutboundWebHookCallId.ToSwedishString());
                    string encryptedCallbackKey = claims?.SingleOrDefault(c => c.ClaimType == "CallbackApiKey")?.ClaimValue;
                    if (!string.IsNullOrWhiteSpace(encryptedCallbackKey))
                    {
                        requestMessage.Headers.Add("X-Kammarkollegiet-InterpreterService-ApiKey", EncryptHelper.Decrypt(encryptedCallbackKey, _options.PublicOrigin, call.RecipientUser.UserName));
                    }
                    //Also add cert to call
                    _logger.LogInformation("Calling web hook {recipientUrl} with message {callId}", call.RecipientUrl, call.OutboundWebHookCallId);

                    using var content      = new StringContent(call.Payload, Encoding.UTF8, "application/json");
                    requestMessage.Content = content;
                    var response = await client.SendAsync(requestMessage);

                    success = response.IsSuccessStatusCode;
                    if (!success)
                    {
                        _logger.LogWarning("Call {callId} failed with the following status code: {statusCode}, try number {tries}", call.OutboundWebHookCallId, response.StatusCode, call.FailedTries + 1);
                        errorMessage = $"Call {call.OutboundWebHookCallId} failed with the following status code: {response.StatusCode}, try number {call.FailedTries + 1}";
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error on this side when calling web hook {callId}, try number {tries}", call.OutboundWebHookCallId, call.FailedTries + 1);
                errorMessage = $"Error on the \"{Constants.SystemName}\" server side for call {call.OutboundWebHookCallId}. Contact {_options.Support.FirstLineEmail} for more information.";
            }
            finally
            {
                if (success)
                {
                    call.DeliveredAt = _clock.SwedenNow;
                }
                else
                {
                    call.FailedTries++;
                    FailedWebHookCall failedCall = new FailedWebHookCall {
                        OutboundWebHookCallId = call.OutboundWebHookCallId, ErrorMessage = errorMessage, FailedAt = _clock.SwedenNow
                    };
                    context.FailedWebHookCalls.Add(failedCall);
                    if (call.FailedTries == NumberOfTries && call.NotificationType != Enums.NotificationType.ErrorNotification)
                    {
                        call.HasNotifiedFailure = false;
                    }
                }
                call.IsHandling = false;
                await context.SaveChangesAsync();
            }
        }
Example #25
0
        public async Task <bool> HandleOrderAgreementCreation()
        {
            if (!_dateCalculationService.IsWorkingDay(_clock.SwedenNow.UtcDateTime))
            {
                return(false);
            }
            var startAtSettings = _cacheService.OrganisationNotificationSettings
                                  .Where(n => n.NotificationType == NotificationType.OrderAgreementCreated)
                                  .Select(n => new { n.ReceivingOrganisationId, n.StartUsingNotificationAt }).ToList();
            var orderAgreementCustomerIds = _cacheService.CustomerSettings
                                            .Where(c => c.UsedCustomerSettingTypes.Contains(CustomerSettingType.UseOrderAgreements))
                                            .Select(c => c.CustomerOrganisationId).ToList();

            var occasionsEndedAtOrBefore = _dateCalculationService.GetDateForANumberOfWorkdaysAgo(_clock.SwedenNow.UtcDateTime, _options.WorkDaysGracePeriodBeforeOrderAgreementCreation);

            //1. find all nonhandled requests and requisitions for customers that is set as using order agreements
            // a. When requisition is Approved or Reviewed date is irrelevant
            foreach (int customerOrganisationId in orderAgreementCustomerIds)
            {
                var validUseFrom = startAtSettings.SingleOrDefault(s => s.ReceivingOrganisationId == customerOrganisationId)?.StartUsingNotificationAt ??
                                   new DateTime(1900, 1, 1);
                //MOVE GETTER TO EXTENSIONS
                var baseInformationForOrderAgreementsToCreate = await _tolkDbContext.Requisitions.Where(r =>
                                                                                                        (r.Status == RequisitionStatus.Approved ||
                                                                                                         r.Status == RequisitionStatus.Reviewed) &&
                                                                                                        r.OrderAgreementPayload == null &&
                                                                                                        r.Request.Order.CustomerOrganisationId == customerOrganisationId &&
                                                                                                        r.ProcessedAt > validUseFrom)
                                                                .Select(r => new OrderAgreementIdentifierModel {
                    RequisitionId = r.RequisitionId, RequestId = r.RequestId
                })
                                                                .ToListAsync();

                //b.When requisition is AutomaticGeneratedFromCancelledOrder
                baseInformationForOrderAgreementsToCreate.AddRange(await _tolkDbContext.Requisitions.Where(r =>
                                                                                                           r.Status == RequisitionStatus.AutomaticGeneratedFromCancelledOrder &&
                                                                                                           r.OrderAgreementPayload == null &&
                                                                                                           r.Request.Order.CustomerOrganisationId == customerOrganisationId &&
                                                                                                           r.CreatedAt > validUseFrom)
                                                                   .Select(r => new OrderAgreementIdentifierModel {
                    RequisitionId = r.RequisitionId, RequestId = r.RequestId
                })
                                                                   .ToListAsync());

                // c. x workdays after the occasion was ended
                //   - If there is a requisition created, use that, but only if there is no order agreement created on the request before.
                baseInformationForOrderAgreementsToCreate.AddRange(await _tolkDbContext.Requisitions.Where(r =>
                                                                                                           (r.Status == RequisitionStatus.Created) &&
                                                                                                           r.Request.Order.CustomerOrganisationId == customerOrganisationId &&
                                                                                                           r.OrderAgreementPayload == null &&
                                                                                                           !r.Request.OrderAgreementPayloads.Any() &&
                                                                                                           r.Request.Order.EndAt <occasionsEndedAtOrBefore &&
                                                                                                                                  r.Request.Order.EndAt> validUseFrom
                                                                                                           )
                                                                   .Select(r => new OrderAgreementIdentifierModel {
                    RequisitionId = r.RequisitionId, RequestId = r.RequestId
                })
                                                                   .ToListAsync());

                //d. x workdays after the occasion was ended
                //   - If there is a no requisition created, use request.
                baseInformationForOrderAgreementsToCreate.AddRange(await _tolkDbContext.Requests.Where(r =>
                                                                                                       (r.Status == RequestStatus.Delivered || r.Status == RequestStatus.Approved) &&
                                                                                                       r.Order.CustomerOrganisationId == customerOrganisationId &&
                                                                                                       !r.OrderAgreementPayloads.Any() &&
                                                                                                       !r.Requisitions.Any() &&
                                                                                                       r.Order.EndAt <occasionsEndedAtOrBefore &&
                                                                                                                      r.Order.EndAt> validUseFrom
                                                                                                       )
                                                                   .Select(r => new OrderAgreementIdentifierModel {
                    RequestId = r.RequestId
                })
                                                                   .ToListAsync());

                _logger.LogInformation("For customer {customerOrganisationId}:  Found {count} requests to create order agreements for: {requestIds}",
                                       customerOrganisationId, baseInformationForOrderAgreementsToCreate.Count, string.Join(", ", baseInformationForOrderAgreementsToCreate.Select(r => r.RequestId)));

                foreach (var entity in baseInformationForOrderAgreementsToCreate)
                {
                    try
                    {
                        if (entity.RequisitionId.HasValue)
                        {
                            await CreateAndStoreOrderAgreementPayload(entity, CreateOrderAgreementFromRequisition);
                        }
                        else
                        {
                            await CreateAndStoreOrderAgreementPayload(entity, CreateOrderAgreementFromRequest);
                        }
                        await _tolkDbContext.SaveChangesAsync();

                        _logger.LogInformation("Processing completed order agreement for {requestId}.", entity.RequestId);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Failure processing order agreement creation for {requestId}", entity.RequestId);
                        await SendErrorMail(nameof(HandleOrderAgreementCreation), ex);
                    }
                }
            }
            return(true);
        }
Example #26
0
        public async Task SendEmails()
        {
            using TolkDbContext context = _options.GetContext();
            var emailIds = await context.OutboundEmails
                           .Where(e => e.DeliveredAt == null && !e.IsHandling)
                           .Select(e => e.OutboundEmailId)
                           .ToListAsync();

            _logger.LogInformation("Found {count} emails to send: {emailIds}",
                                   emailIds.Count, string.Join(", ", emailIds));

            if (emailIds.Any())
            {
                try
                {
                    var emails = context.OutboundEmails
                                 .Where(e => emailIds.Contains(e.OutboundEmailId) && e.IsHandling == false)
                                 .Select(c => c);
                    await emails.ForEachAsync(c => c.IsHandling = true);

                    await context.SaveChangesAsync();

                    using var client = new SmtpClient();
                    await client.ConnectAsync(_options.Smtp.Host, _options.Smtp.Port, _options.Smtp.UseAuthentication?SecureSocketOptions.StartTls : SecureSocketOptions.Auto);

                    if (_options.Smtp.UseAuthentication)
                    {
                        await client.AuthenticateAsync(_options.Smtp.UserName, _options.Smtp.Password);
                    }
                    var from = new MailboxAddress(_senderPrepend + Constants.SystemName, _options.Smtp.FromAddress);

                    foreach (var emailId in emailIds)
                    {
                        var email = await context.OutboundEmails
                                    .SingleOrDefaultAsync(e => e.OutboundEmailId == emailId && e.DeliveredAt == null);

                        try
                        {
                            if (email == null)
                            {
                                _logger.LogInformation("Email {emailId} was in list to be sent, but now appears to have been sent.", emailId);
                            }
                            else
                            {
                                email.IsHandling = true;
                                await context.SaveChangesAsync();

                                _logger.LogInformation("Sending email {emailId} to {recipient}", emailId, email.Recipient);

                                await client.SendAsync(email.ToMimeKitMessage(from));

                                email.DeliveredAt = _clock.SwedenNow;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Failure sending e-mail {emailId}");
                        }
                        finally
                        {
                            email.IsHandling = false;
                            await context.SaveChangesAsync();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Something went wrong when sending emails");
                }
                finally
                {
                    //Making sure no emails are left hanging
                    var emails = context.OutboundEmails
                                 .Where(e => emailIds.Contains(e.OutboundEmailId) && e.IsHandling == true)
                                 .Select(c => c);
                    await emails.ForEachAsync(c => c.IsHandling = false);

                    await context.SaveChangesAsync();
                }
            }
        }
Example #27
0
        public async Task <IActionResult> Answer([FromBody] RequestAnswerModel model)
        {
            if (model == null)
            {
                return(ReturnError(ErrorCodes.IncomingPayloadIsMissing));
            }
            try
            {
                var brokerId  = User.TryGetBrokerId();
                var apiUserId = User.UserId();

                var order = await _apiOrderService.GetOrderAsync(model.OrderNumber, brokerId.Value);

                if (order.OrderGroupId != null)
                {
                    return(ReturnError(ErrorCodes.RequestIsPartOfAGroup));
                }

                var user = await _apiUserService.GetBrokerUser(model.CallingUser, brokerId.Value);

                var request = await _dbContext.Requests.GetActiveRequestForApiWithBrokerAndOrderNumber(model.OrderNumber, User.TryGetBrokerId().Value);

                if (request == null)
                {
                    return(ReturnError(ErrorCodes.RequestNotFound));
                }
                if (!request.IsToBeProcessedByBroker)
                {
                    return(ReturnError(ErrorCodes.RequestNotInCorrectState));
                }
                InterpreterBroker interpreter;
                try
                {
                    interpreter = _apiUserService.GetInterpreter(new InterpreterDetailsModel(model.Interpreter), brokerId.Value);
                }
                catch (InvalidOperationException)
                {
                    return(ReturnError(ErrorCodes.InterpreterOfficialIdAlreadySaved));
                }

                //Does not handle Kammarkollegiets tolknummer
                if (interpreter == null)
                {
                    //Possibly the interpreter should be added, if not found??
                    return(ReturnError(ErrorCodes.InterpreterNotFound));
                }
                if (model.Location == null)
                {
                    return(ReturnError(ErrorCodes.RequestNotCorrectlyAnswered, "Location was missing"));
                }
                if (model.CompetenceLevel == null)
                {
                    return(ReturnError(ErrorCodes.RequestNotCorrectlyAnswered, "CompetenceLevel was missing"));
                }
                var now = _timeService.SwedenNow;
                if (request.Status == RequestStatus.Created)
                {
                    _requestService.Acknowledge(request, now, user?.Id ?? apiUserId, user != null ? (int?)apiUserId : null);
                }
                try
                {
                    await _requestService.Accept(
                        request,
                        now,
                        user?.Id ?? apiUserId,
                        user != null?(int?)apiUserId : null,
                        interpreter,
                        EnumHelper.GetEnumByCustomName <InterpreterLocation>(model.Location).Value,
                        EnumHelper.GetEnumByCustomName <CompetenceAndSpecialistLevel>(model.CompetenceLevel).Value,
                        model.RequirementAnswers == null?new List <OrderRequirementRequestAnswer>() :
                        model.RequirementAnswers.Select(ra => new OrderRequirementRequestAnswer
                    {
                        Answer = ra.Answer,
                        CanSatisfyRequirement = ra.CanMeetRequirement,
                        OrderRequirementId = ra.RequirementId,
                    }).ToList(),
                        //Does not handle attachments yet.
                        new List <RequestAttachment>(),
                        model.ExpectedTravelCosts,
                        model.ExpectedTravelCostInfo,
                        model.LatestAnswerTimeForCustomer,
                        model.BrokerReferenceNumber
                        );

                    await _dbContext.SaveChangesAsync();

                    return(Ok(new AnswerResponse {
                        InterpreterId = interpreter.InterpreterBrokerId
                    }));
                }
                catch (InvalidOperationException ex)
                {
                    return(ReturnError(ErrorCodes.RequestNotCorrectlyAnswered, ex.Message));
                }
                catch (ArgumentNullException ex)
                {
                    return(ReturnError(ErrorCodes.RequestNotCorrectlyAnswered, ex.Message));
                }
            }
            catch (InvalidApiCallException ex)
            {
                return(ReturnError(ex.ErrorCode));
            }
        }
Example #28
0
        public async Task ChangeInterpreter(
            Request request,
            DateTimeOffset changedAt,
            int userId,
            int?impersonatorId,
            InterpreterBroker interpreter,
            InterpreterLocation interpreterLocation,
            CompetenceAndSpecialistLevel competenceLevel,
            List <OrderRequirementRequestAnswer> requirementAnswers,
            IEnumerable <RequestAttachment> attachedFiles,
            decimal?expectedTravelCosts,
            string expectedTravelCostInfo,
            DateTimeOffset?latestAnswerTimeForCustomer,
            string brokerReferenceNumber
            )
        {
            NullCheckHelper.ArgumentCheckNull(request, nameof(ChangeInterpreter), nameof(RequestService));
            NullCheckHelper.ArgumentCheckNull(interpreter, nameof(ChangeInterpreter), nameof(RequestService));
            CheckSetLatestAnswerTimeForCustomerValid(latestAnswerTimeForCustomer, nameof(ChangeInterpreter));
            request.Order.Requirements = await _tolkDbContext.OrderRequirements.GetRequirementsForOrder(request.Order.OrderId).ToListAsync();

            request.Order.InterpreterLocations = await _tolkDbContext.OrderInterpreterLocation.GetOrderedInterpreterLocationsForOrder(request.Order.OrderId).ToListAsync();

            request.Order.CompetenceRequirements = await _tolkDbContext.OrderCompetenceRequirements.GetOrderedCompetenceRequirementsForOrder(request.Order.OrderId).ToListAsync();

            if (interpreter.InterpreterBrokerId == await GetOtherInterpreterIdForSameOccasion(request) && !(interpreter.Interpreter?.IsProtected ?? false))
            {
                throw new InvalidOperationException("Det går inte att tillsätta samma tolk som redan är tillsatt som extra tolk för samma tillfälle.");
            }

            Request newRequest = new Request(request.Ranking, request.ExpiresAt, changedAt, isChangeInterpreter: true, requestGroup: request.RequestGroup)
            {
                Order  = request.Order,
                Status = RequestStatus.AcceptedNewInterpreterAppointed
            };
            bool noNeedForUserAccept = await NoNeedForUserAccept(request, expectedTravelCosts);

            request.Order.Requests.Add(newRequest);
            VerificationResult?verificationResult = null;

            if (competenceLevel != CompetenceAndSpecialistLevel.OtherInterpreter && _tolkBaseOptions.Tellus.IsActivated)
            {
                //Only check if the selected level is other than other.
                verificationResult = await _verificationService.VerifyInterpreter(interpreter.OfficialInterpreterId, request.OrderId, competenceLevel);
            }

            newRequest.ReplaceInterpreter(changedAt,
                                          userId,
                                          impersonatorId,
                                          interpreter,
                                          interpreterLocation,
                                          competenceLevel,
                                          requirementAnswers,
                                          attachedFiles,
                                          _priceCalculationService.GetPrices(request, competenceLevel, expectedTravelCosts),
                                          noNeedForUserAccept,
                                          request,
                                          expectedTravelCostInfo,
                                          brokerReferenceNumber,
                                          verificationResult,
                                          latestAnswerTimeForCustomer
                                          );
            // need requestid for the link
            await _tolkDbContext.SaveChangesAsync();

            if (noNeedForUserAccept)
            {
                _notificationService.RequestChangedInterpreterAccepted(newRequest, InterpereterChangeAcceptOrigin.NoNeedForUserAccept);
            }
            else
            {
                _notificationService.RequestChangedInterpreter(newRequest);
            }
            request.Status = RequestStatus.InterpreterReplaced;
        }