public InjectionTestCase(bool isEpaoSource, bool isEpaoApproved,
                                     string organisationName, bool isOrganisationNameTaken, string tradingName, string organisationType,
                                     int?ukprn, bool isUkprnTaken, string companyNumber, bool isCompanyNumberTaken, string charityNumber,
                                     bool isCharityNumberTaken, string organisationId, string email, string contactGivenNames, string contactFamilyName,
                                     bool isEmailTaken, string warningMessage1)
            {
                var warningMessages = new List <string>();

                if (!string.IsNullOrEmpty(warningMessage1))
                {
                    warningMessages.Add(warningMessage1);
                }

                IsOrganisationNameTaken = isOrganisationNameTaken;
                IsUkprnTaken            = isUkprnTaken;
                IsCompanyNumberTaken    = isCompanyNumberTaken;
                IsCharityNumberTaken    = isCharityNumberTaken;
                IsEmailTaken            = isEmailTaken;

                var response = new CreateOrganisationAndContactFromApplyResponse
                {
                    IsEpaoApproved  = isEpaoApproved,
                    WarningMessages = warningMessages,
                    OrganisationId  = organisationId,
                    ContactId       = Guid.Empty
                };

                Command = new CreateOrganisationContactCommand
                {
                    EndPointAssessorOrganisationId = organisationId,
                    IsRoEpaoApproved          = isEpaoApproved,
                    OrganisationName          = organisationName,
                    TradingName               = tradingName,
                    UseTradingName            = true,
                    OrganisationUkprn         = ukprn,
                    CompanyUkprn              = "87654321",
                    CompanyNumber             = companyNumber,
                    CharityNumber             = charityNumber,
                    OrganisationType          = organisationType,
                    ContactEmail              = email,
                    ContactGivenNames         = contactGivenNames,
                    ContactFamilyName         = contactFamilyName,
                    ApplyingContactFamilyName = "",
                    ApplyingContactGivenNames = "",
                    ContactPhoneNumber        = "11111111",
                    FinancialDueDate          = DateTime.MaxValue,
                    IsFinancialExempt         = false
                };
                ExpectedResponse = response;
            }
        private UpdateEpaOrganisationRequest MapCommandToOrganisationRequest(CreateOrganisationContactCommand command, string organisationName, long?ukprn, int?organisationTypeId)
        {
            organisationName = _cleanser.CleanseStringForSpecialCharacters(organisationName);
            var organisationId = _cleanser.CleanseStringForSpecialCharacters(command.EndPointAssessorOrganisationId);
            var legalName      = _cleanser.CleanseStringForSpecialCharacters(command.OrganisationName);
            var tradingName    = _cleanser.CleanseStringForSpecialCharacters(command.TradingName);
            var email          = _cleanser.CleanseStringForSpecialCharacters(command.ContactEmail);
            var phonenumber    = _cleanser.CleanseStringForSpecialCharacters(command.ContactPhoneNumber);
            var website        = _cleanser.CleanseStringForSpecialCharacters(command.StandardWebsite);
            var address1       = _cleanser.CleanseStringForSpecialCharacters(command.ContactAddress1);
            var address2       = _cleanser.CleanseStringForSpecialCharacters(command.ContactAddress2);
            var address3       = _cleanser.CleanseStringForSpecialCharacters(command.ContactAddress3);
            var address4       = _cleanser.CleanseStringForSpecialCharacters(command.ContactAddress4);
            var postcode       = _cleanser.CleanseStringForSpecialCharacters(command.ContactPostcode);
            var companyNumber  = _cleanser.CleanseStringForSpecialCharacters(command.CompanyNumber);
            var charityNumber  = _cleanser.CleanseStringForSpecialCharacters(command.CharityNumber);

            if (!string.IsNullOrWhiteSpace(companyNumber))
            {
                companyNumber = companyNumber.ToUpper();
            }

            return(new UpdateEpaOrganisationRequest
            {
                Name = organisationName,
                OrganisationId = organisationId,
                OrganisationTypeId = organisationTypeId,
                Ukprn = ukprn,
                Status = null,
                LegalName = legalName,
                TradingName = tradingName,
                Email = email,
                PhoneNumber = phonenumber,
                WebsiteLink = website,
                Address1 = address1,
                Address2 = address2,
                Address3 = address3,
                Address4 = address4,
                Postcode = postcode,
                CompanyNumber = companyNumber,
                CharityNumber = charityNumber,
                FinancialDueDate = command.FinancialDueDate,
                FinancialExempt = command.IsFinancialExempt,
                ActionChoice = "ApproveApplication" // This will set: RoEPAOApproved = true
            });
        }
        private async Task UpdateFinancialDetails(CreateOrganisationContactCommand command)
        {
            var epaOrgs = await _apiClient.SearchOrganisations(command.OrganisationName);

            var result = epaOrgs.FirstOrDefault();

            if (result != null)
            {
                _logger.LogInformation($"Updating FHADetails for {result.Id}");

                var req = new UpdateFinancialsRequest
                {
                    EpaOrgId         = result.Id,
                    FinancialDueDate = command.FinancialDueDate,
                    FinancialExempt  = command.IsFinancialExempt
                };

                await _applyApiClient.UpdateFinancials(req);
            }
        }
        InjectApplyOrganisationAndContactDetailsIntoRegister(CreateOrganisationContactCommand command)
        {
            var response = new CreateOrganisationAndContactFromApplyResponse {
                IsEpaoApproved = false, WarningMessages = new List <string>()
            };

            if (command.IsRoEpaoApproved is true)
            {
                await UpdateFinancialDetails(command);

                _logger.LogInformation("Source is RoEPAO approved. No need to inject organisation details into register");
                response.IsEpaoApproved = true;
                return(response);
            }

            var warningMessages    = new List <string>();
            var organisationName   = DecideOrganisationName(command.UseTradingName, command.TradingName, command.OrganisationName);
            var ukprn              = GetUkprnFromRequestDetails(command.OrganisationUkprn, command.CompanyUkprn);
            var organisationTypeId = await GetOrganisationTypeIdFromDescriptor(command.OrganisationType);

            // Organisation checks
            RaiseWarningIfNoEpaoId(command.EndPointAssessorOrganisationId, warningMessages);
            RaiseWarningIfEpaoIdIsInvalid(command.EndPointAssessorOrganisationId, warningMessages);
            RaiseWarningIfNoOrganisationName(organisationName, warningMessages);
            RaiseWarningIfOrganisationNameTooShort(organisationName, warningMessages);
            RaiseWarningOrganisationTypeNotIdentified(organisationTypeId, warningMessages);
            RaiseWarningIfUkprnIsInvalid(ukprn, warningMessages);
            RaiseWarningIfCompanyNumberIsInvalid(command.CompanyNumber, warningMessages);
            RaiseWarningIfCharityNumberIsInvalid(command.CharityNumber, warningMessages);

            // Contact checks
            RaiseWarningIfEmailIsMissingOrInvalid(command.ContactEmail, warningMessages);
            RaiseWarningIfContactGivenNameIsMissingOrTooShort(command.ContactGivenNames, warningMessages);
            RaiseWarningIfContactFamilyNameIsMissingOrTooShort(command.ContactFamilyName, warningMessages);

            var request = MapCommandToOrganisationRequest(command, organisationName, ukprn, organisationTypeId);

            // If we passed basic pre-checks; then validate fully
            if (warningMessages.Count == 0)
            {
                var validationResponse = await _assessorValidationService.ValidateUpdateOrganisationRequest(request);

                if (!validationResponse.IsValid)
                {
                    var validationResponseErrors = validationResponse.Errors.Select(err => err.ErrorMessage);
                    warningMessages.AddRange(validationResponseErrors);
                    _logger.LogInformation($"Inject organisation failed on Validation Service. OrganisationId: {command.OrganisationId} - Warnings:  {string.Join(",", validationResponseErrors)}");
                }
            }
            else
            {
                _logger.LogInformation($"Inject organisation failed at pre-check. OrganisationId: {command.OrganisationId} - Warnings:  {string.Join(",", warningMessages)}");
            }

            // If everything has checked out; approve the application
            if (warningMessages.Count == 0)
            {
                _logger.LogInformation($"Approving organisation {request?.Name} onto the register");
                request.Status = OrganisationStatus.New;

                var organisationId = await _apiClient.UpdateEpaOrganisation(request);

                response.OrganisationId = organisationId;

                _logger.LogInformation($"Assigning the primary contact");
                var primaryContact = MapCommandToContactRequest(command.ContactEmail, organisationId, command.ContactPhoneNumber, command.ContactGivenNames, command.ContactFamilyName);
                await AssignPrimaryContactToOrganisation(primaryContact, organisationId);

                _logger.LogInformation($"Assign the applying user default permissions");
                await AssignApplyingContactToOrganisation(command.ApplyingContactEmail, organisationId);

                _logger.LogInformation($"Inviting other applying users");
                await InviteOtherApplyingUsersToOrganisation(command.OtherApplyingUserEmails, organisationId);
            }
            else
            {
                _logger.LogWarning($"Cannot inject organisation details into register at this time. OrganisationId: {command.OrganisationId} - Warnings:  {string.Join(",", warningMessages)}");
            }

            response.WarningMessages = warningMessages;

            return(response);
        }
        public void WhenGatheringAnswersForAnApplication(CommandTest commandTestSetup)
        {
            var signinId  = Guid.NewGuid();
            var contactId = Guid.NewGuid();

            var expectedCommand = new CreateOrganisationContactCommand
            {
                UseTradingName    = commandTestSetup.UseTradingName,
                TradingName       = commandTestSetup.TradingName,
                OrganisationName  = commandTestSetup.OrganisationName,
                IsRoEpaoApproved  = commandTestSetup.IsEpaoApproved,
                OrganisationId    = commandTestSetup.OrganisationId,
                OrganisationType  = commandTestSetup.OrganisationType,
                OrganisationUkprn = commandTestSetup.OrganisationUkprn,
                EndPointAssessorOrganisationId = commandTestSetup.OrganisationReferenceType,

                ContactFamilyName = commandTestSetup.ContactFamilyName,
                ContactGivenNames = commandTestSetup.ContactGivenNames,

                ContactAddress1 = commandTestSetup.ContactAddress != null
                    ? commandTestSetup.GetJsonValue(commandTestSetup.ContactAddress, "AddressLine1")
                    : commandTestSetup.ContactAddress1,

                ContactAddress2 = commandTestSetup.ContactAddress != null
                    ? commandTestSetup.GetJsonValue(commandTestSetup.ContactAddress, "AddressLine2")
                    : commandTestSetup.ContactAddress2,

                ContactAddress3 = commandTestSetup.ContactAddress != null
                    ? commandTestSetup.GetJsonValue(commandTestSetup.ContactAddress, "AddressLine3")
                    : commandTestSetup.ContactAddress3,

                ContactAddress4 = commandTestSetup.ContactAddress != null
                    ? commandTestSetup.GetJsonValue(commandTestSetup.ContactAddress, "AddressLine4")
                    : commandTestSetup.ContactAddress4,

                ContactPostcode = commandTestSetup.ContactAddress != null
                    ? commandTestSetup.GetJsonValue(commandTestSetup.ContactAddress, "Postcode")
                    : commandTestSetup.ContactPostcode,

                ContactEmail              = commandTestSetup.ContactEmail,
                ContactPhoneNumber        = commandTestSetup.ContactPhoneNumber,
                CompanyUkprn              = commandTestSetup.CompanyUkprn,
                CompanyNumber             = commandTestSetup.CompanyNumber,
                CharityNumber             = commandTestSetup.CharityNumber,
                StandardWebsite           = commandTestSetup.StandardWebsite,
                ApplyingContactEmail      = "",
                ApplyingContactGivenNames = "",
                ApplyingContactFamilyName = "",
                ApplyingContactId         = contactId,
                FinancialDueDate          = commandTestSetup.FinancialDueDate,
                IsFinancialExempt         = commandTestSetup.IsFinancialExempt,
                OtherApplyingUserEmails   = new List <string>()
            };

            var applicationData = new Dictionary <string, object>
            {
                ["trading_name"]         = commandTestSetup.TradingName,
                ["use_trading_name"]     = commandTestSetup.UseTradingName,
                ["contact_given_name"]   = commandTestSetup.ContactGivenNames,
                ["contact_family_name"]  = commandTestSetup.ContactFamilyName,
                ["contact_address"]      = commandTestSetup.ContactAddress,
                ["contact_address1"]     = commandTestSetup.ContactAddress1,
                ["contact_address2"]     = commandTestSetup.ContactAddress2,
                ["contact_address3"]     = commandTestSetup.ContactAddress3,
                ["contact_address4"]     = commandTestSetup.ContactAddress4,
                ["contact_postcode"]     = commandTestSetup.ContactPostcode,
                ["contact_email"]        = commandTestSetup.ContactEmail,
                ["contact_phone_number"] = commandTestSetup.ContactPhoneNumber,
                ["company_ukprn"]        = commandTestSetup.CompanyUkprn,
                ["company_number"]       = commandTestSetup.CompanyNumber,
                ["charity_number"]       = commandTestSetup.CharityNumber,
                ["standard_website"]     = commandTestSetup.StandardWebsite
            };

            var applicationOrganisation = new Organisation
            {
                Id = commandTestSetup.OrganisationId,
                EndPointAssessorName = commandTestSetup.OrganisationName,
                OrganisationType     = new AssessorService.Domain.Entities.OrganisationType {
                    Type = commandTestSetup.OrganisationType
                },
                EndPointAssessorUkprn          = commandTestSetup.OrganisationUkprn,
                EndPointAssessorOrganisationId = commandTestSetup.OrganisationReferenceType,
                OrganisationData = new AssessorService.Domain.Entities.OrganisationData
                {
                    RoEPAOApproved = commandTestSetup.IsEpaoApproved != null && commandTestSetup.IsEpaoApproved.Value,
                    FHADetails     = new FHADetails
                    {
                        FinancialDueDate = commandTestSetup.FinancialDueDate,
                        FinancialExempt  = commandTestSetup.IsFinancialExempt
                    }
                }
            };

            var applicationContact = new Contact {
                Id = contactId, SignInId = signinId, FamilyName = "", GivenNames = "", Email = ""
            };

            var application = new ApplicationResponse
            {
                Id             = _applicationId,
                ApplicationId  = _applicationId,
                OrganisationId = applicationOrganisation.Id,
                CreatedBy      = applicationContact.Id.ToString()
            };

            _mockApplicationApiClient.Setup(x => x.GetApplication(application.Id)).ReturnsAsync(application);
            _mockQnaApiClient.Setup(x => x.GetApplicationDataDictionary(application.ApplicationId)).ReturnsAsync(applicationData);
            _mockApiClient.Setup(x => x.GetOrganisation(application.OrganisationId)).ReturnsAsync(applicationOrganisation);
            _mockApiClient.Setup(x => x.GetOrganisationContacts(applicationOrganisation.Id)).ReturnsAsync(new List <Contact> {
                applicationContact
            });

            var actualCommand = _answerService.GatherAnswersForOrganisationAndContactForApplication(_applicationId).Result;

            Assert.AreEqual(JsonConvert.SerializeObject(expectedCommand), JsonConvert.SerializeObject(actualCommand));
        }
        public async Task <CreateOrganisationContactCommand> GatherAnswersForOrganisationAndContactForApplication(Guid applicationId)
        {
            var application = await _applyApiClient.GetApplication(applicationId);

            var applicationData = await _qnaApiClient.GetApplicationDataDictionary(application?.ApplicationId ?? Guid.Empty);

            var organisation = await _apiApiClient.GetOrganisation(application?.OrganisationId ?? Guid.Empty);

            var organisationContacts = await _apiApiClient.GetOrganisationContacts(organisation?.Id ?? Guid.Empty);

            var applyingContact = organisationContacts?.FirstOrDefault(c => c.Id.ToString().Equals(application?.CreatedBy, StringComparison.InvariantCultureIgnoreCase));

            if (application is null || applicationData is null || organisation is null || applyingContact is null)
            {
                return(new CreateOrganisationContactCommand());
            }

            var tradingName          = GetAnswer(applicationData, "trading_name");
            var useTradingNameString = GetAnswer(applicationData, "use_trading_name");
            var useTradingName       = "yes".Equals(useTradingNameString, StringComparison.InvariantCultureIgnoreCase) || "true".Equals(useTradingNameString, StringComparison.InvariantCultureIgnoreCase) || "1".Equals(useTradingNameString, StringComparison.InvariantCultureIgnoreCase);

            // get a contact by their contact name parts (application started May 2019 to date)
            var contactGivenNames = GetAnswer(applicationData, "contact_given_name");
            var contactFamilyName = GetAnswer(applicationData, "contact_family_name");

            if (string.IsNullOrEmpty(contactGivenNames) && string.IsNullOrEmpty(contactFamilyName))
            {
                // get a contact by their contact name (application started before May 2019)
                var contactName = GetAnswer(applicationData, "contact_name");
                if (!string.IsNullOrEmpty(contactName))
                {
                    var matches = Regex.Matches(contactName, "^*([,'.-a-zA-z]{1,})");
                    if (matches.Count() > 0)
                    {
                        var contactNameParts = matches.Cast <Group>()
                                               .Where(o => o.Value != string.Empty)
                                               .Select(o => o.Value);

                        contactGivenNames = contactNameParts.Count() == 1
                            ? contactNameParts.First()
                            : string.Join(" ", contactNameParts.Take(contactNameParts.Count() - 1));

                        // using the (Unknown) placeholder for the family name in cases where only a single word was entered
                        contactFamilyName = contactNameParts.Count() == 1
                            ? "(Unknown)"
                            : contactNameParts.Last();
                    }
                }
            }

            // get a contact address which is a single question with multiple answers
            var contactAddress = GetJsonAnswer(applicationData, "contact_address");

            // handle both a contact address which is a single question with multiple answers or multiple questions with a single answer
            var contactAddress1 = contactAddress?["AddressLine1"].ToString() ?? GetAnswer(applicationData, "contact_address1");
            var contactAddress2 = contactAddress?["AddressLine2"].ToString() ?? GetAnswer(applicationData, "contact_address2");
            var contactAddress3 = contactAddress?["AddressLine3"].ToString() ?? GetAnswer(applicationData, "contact_address3");
            var contactAddress4 = contactAddress?["AddressLine4"].ToString() ?? GetAnswer(applicationData, "contact_address4");
            var contactPostcode = contactAddress?["Postcode"].ToString() ?? GetAnswer(applicationData, "contact_postcode");

            var contactEmail       = GetAnswer(applicationData, "contact_email");
            var contactPhoneNumber = GetAnswer(applicationData, "contact_phone_number");
            var companyUkprn       = GetAnswer(applicationData, "company_ukprn");

            var companyNumber = GetAnswer(applicationData, "company_number");

            if ("no".Equals(companyNumber, StringComparison.InvariantCultureIgnoreCase))
            {
                companyNumber = null;
            }

            var charityNumber = GetAnswer(applicationData, "charity_number");

            if ("no".Equals(charityNumber, StringComparison.InvariantCultureIgnoreCase))
            {
                charityNumber = null;
            }

            var standardWebsite = GetAnswer(applicationData, "standard_website");

            var command = new CreateOrganisationContactCommand
                              (organisation.Id,
                              organisation.EndPointAssessorName,
                              organisation.OrganisationType.Type,
                              organisation.EndPointAssessorUkprn,
                              organisation.EndPointAssessorOrganisationId,
                              organisation.OrganisationData.RoEPAOApproved,
                              tradingName,
                              useTradingName,
                              contactGivenNames,
                              contactFamilyName,
                              contactAddress1,
                              contactAddress2,
                              contactAddress3,
                              contactAddress4,
                              contactPostcode,
                              contactEmail,
                              contactPhoneNumber,
                              companyUkprn,
                              companyNumber,
                              charityNumber,
                              standardWebsite,
                              applyingContact.Id,
                              applyingContact.GivenNames,
                              applyingContact.FamilyName,
                              applyingContact.Email,
                              organisationContacts.Where(c => c.Email != applyingContact.Email).Select(c => c.Email).ToList(),
                              organisation.OrganisationData?.FHADetails?.FinancialDueDate,
                              organisation.OrganisationData?.FHADetails?.FinancialExempt);

            return(command);
        }