public async Task <OneOf <NotFound, ModelWithErrors <Command> > > Handle(Query request, CancellationToken cancellationToken) { var(row, otherRows) = await GetRow(request.RowNumber); var command = new Command() { RowNumber = request.RowNumber, ProviderVenueRef = row.ProviderVenueRef, Name = row.VenueName, AddressLine1 = row.AddressLine1, AddressLine2 = row.AddressLine2, Town = row.Town, County = row.County, Postcode = row.Postcode, Email = row.Email, Telephone = row.Telephone, Website = row.Website }; var postcodeInfo = Postcode.TryParse(command.Postcode, out var postcode) ? await _sqlQueryDispatcher.ExecuteQuery(new GetPostcodeInfo() { Postcode = postcode }) : null; var validator = new CommandValidator(otherRows, postcodeInfo); var validationResult = await validator.ValidateAsync(command); return(new ModelWithErrors <Command>(command, validationResult)); }
public void ShouldCreatePostcode(string input, string outwardCode, string inwardCode) { var result = Postcode.TryParse(input, out var postcode); result.ShouldBeTrue(); postcode.Value.ShouldBe(input); postcode.OutwardCode.ShouldBe(outwardCode); }
public void TryParse_ValidOverseasTerritoryPostcode_ParsesSuccessfully(string input) { // Arrange Postcode output; // Act bool result = Postcode.TryParse(input, out output, PostcodeParseOptions.MatchOverseasTerritories); // Assert Assert.That(result, Is.True, string.Format("Unable to parse {0} as valid postcode", input)); }
public void TryParse_InvalidPostcode_ReturnsFalse(string input) { // Arrange Postcode postcode; // Act var result = Postcode.TryParse(input, out postcode); // Assert result.Should().BeFalse(); }
public void TryParse_IncodeInvalidSecondCharacter_Unsuccessful(string input) { // Arrange Postcode output; // Act bool result = Postcode.TryParse(input, out output); // Assert Assert.That(result, Is.False, string.Format("Incorrectly parsed {0} as valid postcode", input)); }
public void Parse_AA9_9AA_ParsesSuccessfully(string input) { // Arrange Postcode output; // Act bool result = Postcode.TryParse(input, out output); // Assert Assert.That(result, Is.True, string.Format("Unable to parse {0} as valid postcode", input)); }
public async Task <OneOf <ModelWithErrors <Command>, Success> > Handle(Command request, CancellationToken cancellationToken) { var journeyInstance = _journeyInstanceProvider.GetInstance <AddVenueJourneyModel>(); journeyInstance.ThrowIfCompleted(); // Normalize the postcode; validation accepts postcodes with no spaces but ONSPD lookup requires spaces. // Also ensures we have postcodes consistently capitalized. if (Postcode.TryParse(request.Postcode, out var postcode)) { request.Postcode = postcode; } var validator = new CommandValidator(); var validationResult = await validator.ValidateAsync(request); if (!validationResult.IsValid) { return(new ModelWithErrors <Command>(request, validationResult)); } var onspdSearchResult = await _onspdSearchClient.Search(new OnspdSearchQuery() { Postcode = request.Postcode }); var onspdPostcodeRecord = onspdSearchResult.Items.SingleOrDefault(); if (onspdPostcodeRecord == null) { validationResult = new ValidationResult(new[] { new ValidationFailure(nameof(request.Postcode), "Enter a valid postcode") }); return(new ModelWithErrors <Command>(request, validationResult)); } journeyInstance.UpdateState(state => { state.AddressLine1 = request.AddressLine1; state.AddressLine2 = request.AddressLine2; state.Town = request.Town; state.County = request.County; state.Postcode = request.Postcode; state.Latitude = onspdPostcodeRecord.Record.lat; state.Longitude = onspdPostcodeRecord.Record.@long; state.AddressIsOutsideOfEngland = !onspdPostcodeRecord.Record.IsInEngland; state.ValidStages |= AddVenueCompletedStages.Address; }); return(new Success()); }
public void TryParse_ValidPostcode_ReturnsTrueAndOutputsNonNullNormalizedPostcode( string input, string expectedNormalizedPostcode) { // Arrange Postcode postcode; // Act var result = Postcode.TryParse(input, out postcode); // Assert result.Should().BeTrue(); postcode.ToString().Should().Equals(expectedNormalizedPostcode); }
private async Task <IDictionary <Postcode, PostcodeInfo> > GetPostcodeInfoForRows( ISqlQueryDispatcher sqlQueryDispatcher, VenueDataUploadRowInfoCollection rows) { var validPostcodes = rows .Select(r => Postcode.TryParse(r.Data.Postcode, out var postcode) ? postcode.ToString() : null) .Where(pc => pc != null) .Distinct(); var postcodeInfo = await sqlQueryDispatcher.ExecuteQuery( new GetPostcodeInfos() { Postcodes = validPostcodes }); return(postcodeInfo.ToDictionary(kvp => new Postcode(kvp.Key), kvp => kvp.Value)); }
public async Task <OneOf <ModelWithErrors <Command>, Success> > Handle(Command request, CancellationToken cancellationToken) { var journeyInstance = _journeyInstanceProvider.GetInstance <AddVenueJourneyModel>(); journeyInstance.ThrowIfCompleted(); // Normalize the postcode; validation accepts postcodes with no spaces but ONSPD lookup requires spaces. // Also ensures we have postcodes consistently capitalized. if (Postcode.TryParse(request.Postcode, out var postcode)) { request.Postcode = postcode; } var postcodeInfo = await _sqlQueryDispatcher.ExecuteQuery(new GetPostcodeInfo() { Postcode = request.Postcode }); var validator = new CommandValidator(postcodeInfo); var validationResult = await validator.ValidateAsync(request); if (!validationResult.IsValid) { return(new ModelWithErrors <Command>(request, validationResult)); } journeyInstance.UpdateState(state => { state.AddressLine1 = request.AddressLine1; state.AddressLine2 = request.AddressLine2; state.Town = request.Town; state.County = request.County; state.Postcode = request.Postcode; state.Latitude = postcodeInfo.Latitude; state.Longitude = postcodeInfo.Longitude; state.AddressIsOutsideOfEngland = !postcodeInfo.InEngland; state.ValidStages |= AddVenueCompletedStages.Address; }); return(new Success()); }
public async Task <OneOf <ModelWithErrors <Command>, UploadStatus> > Handle(Command request, CancellationToken cancellationToken) { var(_, otherRows) = await GetRow(request.RowNumber); var postcodeInfo = Postcode.TryParse(request.Postcode, out var postcode) ? await _sqlQueryDispatcher.ExecuteQuery(new GetPostcodeInfo() { Postcode = postcode }) : null; var validator = new CommandValidator(otherRows, postcodeInfo); var validationResult = await validator.ValidateAsync(request); if (!validationResult.IsValid) { return(new ModelWithErrors <Command>(request, validationResult)); } return(await _fileUploadProcessor.UpdateVenueUploadRowForProvider( _providerContextProvider.GetProviderId(), request.RowNumber, new Core.DataManagement.Schemas.CsvVenueRow() { ProviderVenueRef = request.ProviderVenueRef, VenueName = request.Name, AddressLine1 = request.AddressLine1, AddressLine2 = request.AddressLine2, Town = request.Town, County = request.County, Postcode = request.Postcode, Email = request.Email, Telephone = request.Telephone, Website = request.Website })); }
public void TestInvalid(string s) { Assert.False(Postcode.TryParse(s, out var postcode)); Assert.Equal(default(Postcode), postcode); }
public async Task <OneOf <ProblemDetails, SearchViewModel> > Handle(Query request, CancellationToken cancellationToken) { var filters = new List <string>(); // If either lat or lng is specified then both must be specified if (request.Latitude.HasValue != request.Longitude.HasValue) { return(new ProblemDetails() { Detail = "Latitude & longitude must both be specified.", Status = 400, Title = "InvalidLatLng" }); } if (request.SortBy == SearchSortBy.Distance && (string.IsNullOrWhiteSpace(request.Postcode) && (!request.Latitude.HasValue || !request.Longitude.HasValue))) { return(new ProblemDetails() { Detail = "Postcode is required to sort by Distance.", Status = 400, Title = "PostcodeRequired" }); } Postcode postcode = null; if (!string.IsNullOrWhiteSpace(request.Postcode)) { if (!Postcode.TryParse(request.Postcode, out postcode)) { return(new ProblemDetails() { Detail = "Postcode is not valid.", Status = 400, Title = "InvalidPostcode" }); } } var geoFilterRequired = request.Distance.GetValueOrDefault(0) > 0 && (postcode != null || (request.Latitude.HasValue && request.Longitude.HasValue)); // lat/lng required if Distance filter is specified *or* sorting by Distance var getPostcodeCoords = (geoFilterRequired || request.SortBy == SearchSortBy.Distance) && !request.Latitude.HasValue; double?latitude = request.Latitude; double?longitude = request.Longitude; if (getPostcodeCoords) { var coords = await TryGetCoordinatesForPostcode(postcode); if (!coords.HasValue) { return(new ProblemDetails() { Detail = "Specified postcode cannot be found.", Status = 400, Title = "PostcodeNotFound" }); } latitude = coords.Value.lat; longitude = coords.Value.lng; } if (request.StartDateFrom.HasValue || request.StartDateTo.HasValue || request.HideOutOfDateCourses.HasValue || request.HideFlexiCourses.HasValue) { var dateFilter = TryGetDateFilters( request.StartDateFrom, request.StartDateTo, request.HideOutOfDateCourses, request.HideFlexiCourses); if (!string.IsNullOrEmpty(dateFilter)) { filters.Add(dateFilter); } } if (request.AttendancePatterns?.Any() ?? false) { // TODO Validate AttendancePatterns? Consider using enum instead of int filters.Add($"({string.Join(" or ", request.AttendancePatterns.Select(ap => $"{nameof(FindACourseOffering.AttendancePattern)} eq {ap}"))} or {nameof(FindACourseOffering.DeliveryMode)} ne {(int)CourseDeliveryMode.ClassroomBased})"); } if (request.QualificationLevels?.Any() ?? false) { // TODO Validate QualificationLevels? filters.Add($"search.in({nameof(FindACourseOffering.NotionalNVQLevelv2)}, '{string.Join("|", request.QualificationLevels.Select(EscapeFilterValue))}', '|')"); } if (geoFilterRequired) { var distanceInKm = Convert.ToDecimal(GeoHelper.MilesToKilometers(request.Distance.Value)); filters.Add( $"(geo.distance({nameof(FindACourseOffering.Position)}, geography'POINT({longitude.Value} {latitude.Value})') le {distanceInKm}" + $" or {nameof(FindACourseOffering.National)} eq true" + $" or {nameof(FindACourseOffering.DeliveryMode)} eq 2)"); } if (!string.IsNullOrWhiteSpace(request.Town)) { filters.Add($"search.ismatch('{EscapeFilterValue(request.Town)}', '{nameof(FindACourseOffering.VenueTown)}')"); } if (request.StudyModes?.Any() ?? false) { filters.Add($"({string.Join(" or ", request.StudyModes.Select(sm => $"{nameof(FindACourseOffering.StudyMode)} eq {sm}"))} or {nameof(FindACourseOffering.DeliveryMode)} ne {(int)CourseDeliveryMode.ClassroomBased})"); } if (request.DeliveryModes?.Any() ?? false) { filters.Add($"({string.Join(" or ", request.DeliveryModes.Select(dm => $"{nameof(FindACourseOffering.DeliveryMode)} eq {dm}"))})"); } if (!string.IsNullOrWhiteSpace(request.ProviderName)) { filters.Add($"search.ismatchscoring('{EscapeFilterValue(request.ProviderName)}', '{nameof(FindACourseOffering.ProviderDisplayName)}', 'simple', 'any')"); } if (!string.IsNullOrWhiteSpace(request.CampaignCode)) { filters.Add($"{nameof(FindACourseOffering.CampaignCodes)}/any(c: c eq '{EscapeFilterValue(request.CampaignCode)}')"); } var orderBy = request.SortBy == SearchSortBy.StartDateDescending ? "StartDate desc" : request.SortBy == SearchSortBy.StartDateAscending ? "StartDate asc" : request.SortBy == SearchSortBy.Distance ? $"geo.distance({nameof(FindACourseOffering.Position)}, geography'POINT({longitude.Value} {latitude.Value})')" : "search.score() desc"; if (!TryResolvePagingParams(request.Limit, request.Start, out var size, out var skip, out var problem)) { return(problem); } var searchText = TranslateCourseSearchSubjectText(request.SubjectKeyword); var query = new FindACourseOfferingSearchQuery() { Facets = new[] { "NotionalNVQLevelv2,count:100", "StudyMode", "AttendancePattern", "DeliveryMode", "ProviderDisplayName,count:100", "RegionName,count:100" }, Filters = filters, CourseName = searchText, Size = size, Skip = skip, OrderBy = orderBy }; var result = await _courseSearchClient.Search(query); return(new SearchViewModel() { Limit = size, Start = skip, Total = Convert.ToInt32(result.TotalCount.Value), Facets = result.Facets.ToDictionary( f => _courseSearchFacetMapping.GetValueOrDefault(f.Key, f.Key), f => f.Value.Select(v => new FacetCountResultViewModel() { Value = v.Key.ToString(), Count = v.Value.Value })), Results = result.Items.Select(i => { return new SearchResultViewModel() { Cost = !string.IsNullOrEmpty(i.Record.Cost) ? Convert.ToInt32(decimal.Parse(i.Record.Cost)) : (int?)null, CostDescription = HtmlEncode(i.Record.CostDescription), CourseDescription = HtmlEncode(NormalizeCourseDataEncodedString(i.Record.CourseDescription)), CourseName = NormalizeCourseRunDataEncodedString(i.Record.CourseName), CourseId = i.Record.CourseId, CourseRunId = i.Record.CourseRunId, CourseText = HtmlEncode(NormalizeCourseDataEncodedString(i.Record.CourseDescription)), DeliveryMode = ((int)i.Record.DeliveryMode).ToString(), DeliveryModeDescription = (i.Record.DeliveryMode.GetValueOrDefault(0)).ToDescription(), Distance = GetDistanceFromLatLngForResult(i), DurationUnit = i.Record.DurationUnit ?? 0, DurationValue = i.Record.DurationValue, FlexibleStartDate = i.Record.FlexibleStartDate, LearnAimRef = i.Record.LearnAimRef, National = i.Record.National, QualificationLevel = i.Record.NotionalNVQLevelv2, OfferingType = i.Record.OfferingType, ProviderName = i.Record.ProviderDisplayName, QualificationCourseTitle = HtmlEncode(i.Record.QualificationCourseTitle), Region = i.Record.RegionName, SearchScore = i.Score.Value, StartDate = !i.Record.FlexibleStartDate.GetValueOrDefault() ? i.Record.StartDate : null, TLevelId = i.Record.TLevelId, TLevelLocationId = i.Record.TLevelLocationId, Ukprn = i.Record.ProviderUkprn.ToString(), UpdatedOn = i.Record.UpdatedOn, VenueAddress = HtmlEncode(i.Record.VenueAddress), VenueAttendancePattern = ((int?)i.Record.AttendancePattern)?.ToString(), VenueAttendancePatternDescription = i.Record.DeliveryMode == CourseDeliveryMode.ClassroomBased ? i.Record.AttendancePattern?.ToDescription() : null, VenueLocation = i.Record.Position != null ? new CoordinatesViewModel() { Latitude = i.Record.Position.Latitude, Longitude = i.Record.Position.Longitude } : null, VenueName = HtmlEncode(i.Record.VenueName), VenueStudyMode = ((int?)i.Record.StudyMode)?.ToString(), VenueStudyModeDescription = i.Record.DeliveryMode == CourseDeliveryMode.ClassroomBased ? i.Record.StudyMode?.ToDescription() : null, VenueTown = HtmlEncode(i.Record.VenueTown) };
private void buttonOK_Click(object sender, EventArgs e) { string errorString = "You must fill in this field"; errorProvider.Clear(); //create the patient _patient = new Patient(); //validate and add fields if (comboBoxTitle.SelectedIndex != -1) { _patient.Title = (Patient.TitleType)comboBoxTitle.SelectedIndex; } else { errorProvider.SetError(comboBoxTitle, errorString); return; } if (textBoxLastName.Text.Trim() == "") { errorProvider.SetError(textBoxLastName, errorString); return; } else { _patient.LastName = textBoxLastName.Text; } if (textBoxFirstName.Text.Trim() == "") { errorProvider.SetError(textBoxFirstName, errorString); return; } else { _patient.FirstName = textBoxFirstName.Text; } if (textBoxID.Text.Trim() == "") { errorProvider.SetError(textBoxID, errorString); return; } else { _patient.PatientID = textBoxID.Text; } if (comboBoxGender.SelectedIndex != -1) { _patient.Gender = (Patient.GenderType)comboBoxGender.SelectedIndex; } else { errorProvider.SetError(comboBoxGender, errorString); return; } if (dateTimePicker.Value.Date == DateTime.Today) { errorProvider.SetError(dateTimePicker, errorString); return; } _patient.DOB = dateTimePicker.Value; Postcode validatedPostcode; bool postcodeResult = Postcode.TryParse(textBoxPostcode.Text, out validatedPostcode, true); if (postcodeResult == false) { errorProvider.SetError(textBoxPostcode, "Invalid Post Code"); return; } else { _patient.Address.Postcode = validatedPostcode; } if (!_patient.ContactNumber.TryParse(textBoxContactNumber.Text)) { errorProvider.SetError(textBoxContactNumber, "Invalid Number"); return; } this.DialogResult = DialogResult.OK; this.Close(); }
// internal for testing internal async Task <(UploadStatus uploadStatus, IReadOnlyCollection <VenueUploadRow> Rows)> ValidateVenueUploadFile( ISqlQueryDispatcher sqlQueryDispatcher, Guid venueUploadId, Guid providerId, VenueDataUploadRowInfoCollection rows) { // We need to ensure that any venues that have live offerings attached are not removed when publishing this // upload. We do that by adding an additional row to this upload for any venues that are not included in // this file that have live offerings attached. This must be done *before* validation so that duplicate // checks consider these additional added rows. var originalRowCount = rows.Count; var existingVenues = await sqlQueryDispatcher.ExecuteQuery(new GetVenueMatchInfoForProvider() { ProviderId = providerId }); // For each row in the file try to match it to an existing venue var rowVenueIdMapping = MatchRowsToExistingVenues(rows, existingVenues); // Add a row for any existing venues that are linked to live offerings and haven't been matched var matchedVenueIds = rowVenueIdMapping.Where(m => m.HasValue).Select(m => m.Value).ToArray(); var venuesWithLiveOfferingsNotInFile = existingVenues .Where(v => v.HasLiveOfferings && !matchedVenueIds.Contains(v.VenueId)) .ToArray(); rows = new VenueDataUploadRowInfoCollection( lastRowNumber: rows.LastRowNumber + venuesWithLiveOfferingsNotInFile.Length, rows: rows.Concat( venuesWithLiveOfferingsNotInFile.Select((v, i) => new VenueDataUploadRowInfo(CsvVenueRow.FromModel(v), rowNumber: rows.LastRowNumber + i + 1, isSupplementary: true)))); rowVenueIdMapping = rowVenueIdMapping.Concat(venuesWithLiveOfferingsNotInFile.Select(v => (Guid?)v.VenueId)).ToArray(); // Grab PostcodeInfo for all of the valid postcodes in the file. // We need this for both the validator and to track whether the venue is outside of England var allPostcodeInfo = await GetPostcodeInfoForRows(sqlQueryDispatcher, rows); var uploadIsValid = true; var validator = new VenueUploadRowValidator(rows, allPostcodeInfo); var upsertRecords = new List <SetVenueUploadRowsRecord>(); for (int i = 0; i < rows.Count; i++) { var row = rows[i].Data; var rowNumber = rows[i].RowNumber; var venueId = rowVenueIdMapping[i] ?? Guid.NewGuid(); var isSupplementaryRow = i >= originalRowCount; // A row is deletable if it is *not* matched to an existing venue that has attached offerings var isDeletable = rowVenueIdMapping[i] is null || !existingVenues.Single(v => v.VenueId == rowVenueIdMapping[i]).HasLiveOfferings; row.ProviderVenueRef = row.ProviderVenueRef?.Trim(); row.Postcode = Postcode.TryParse(row.Postcode, out var postcode) ? postcode : row.Postcode; PostcodeInfo postcodeInfo = null; if (postcode != null) { allPostcodeInfo.TryGetValue(postcode, out postcodeInfo); } var rowValidationResult = validator.Validate(row); var errors = rowValidationResult.Errors.Select(e => e.ErrorCode).ToArray(); var rowIsValid = rowValidationResult.IsValid; uploadIsValid &= rowIsValid; upsertRecords.Add(new SetVenueUploadRowsRecord() { RowNumber = rowNumber, IsValid = rowIsValid, Errors = errors, IsSupplementary = isSupplementaryRow, OutsideOfEngland = postcodeInfo != null ? !postcodeInfo.InEngland : (bool?)null, VenueId = venueId, IsDeletable = isDeletable, ProviderVenueRef = row.ProviderVenueRef, VenueName = row.VenueName, AddressLine1 = row.AddressLine1, AddressLine2 = row.AddressLine2, Town = row.Town, County = row.County, Postcode = row.Postcode, Email = row.Email, Telephone = row.Telephone, Website = row.Website }); } var updatedRows = await sqlQueryDispatcher.ExecuteQuery(new SetVenueUploadRows() { VenueUploadId = venueUploadId, ValidatedOn = _clock.UtcNow, Records = upsertRecords }); await sqlQueryDispatcher.ExecuteQuery(new SetVenueUploadProcessed() { VenueUploadId = venueUploadId, ProcessingCompletedOn = _clock.UtcNow, IsValid = uploadIsValid }); var uploadStatus = uploadIsValid ? UploadStatus.ProcessedSuccessfully : UploadStatus.ProcessedWithErrors; return(uploadStatus, updatedRows); }
void backgroundWorkerSearcher_DoWork(object sender, DoWorkEventArgs e) { OnSetStatusLabelValue("Searching..."); this.listViewPatients.ListViewItemSorter = null; AddFoundPatientCallback d = new AddFoundPatientCallback(AddFoundPatient); List <ListViewItem> _temp = new List <ListViewItem>(); //build up the search terms string split = " "; string[] initialSsearchTerms = textBoxSearch.Text.Split(split.ToCharArray()); List <string> tempSearchTerms = new List <string>(); string tempSearchTerm = ""; Postcode postcode = new Postcode(); //check all but the last for a post code for (int i = 0; i < initialSsearchTerms.Length - 1; i++) { //If its a valid if (Postcode.TryParse(initialSsearchTerms[i] + initialSsearchTerms[i + 1], out postcode, true)) { tempSearchTerm = initialSsearchTerms[i] + " " + initialSsearchTerms[i + 1]; i++; } else { tempSearchTerm = initialSsearchTerms[i]; } tempSearchTerms.Add(tempSearchTerm); } //if a post code has not been found the add the last term if (postcode.InCode == null) { tempSearchTerm = initialSsearchTerms[initialSsearchTerms.Length - 1]; tempSearchTerms.Add(tempSearchTerm); } else if (!postcode.InCode.StartsWith(initialSsearchTerms[initialSsearchTerms.Length - 1])) // if one has been found but doesn't match then add last term { tempSearchTerm = initialSsearchTerms[initialSsearchTerms.Length - 1]; tempSearchTerms.Add(tempSearchTerm); } string[] searchTerms = tempSearchTerms.ToArray(); //search for the terms, each term has to be found in an item bool matchedTerm = false; for (int i = 0; i < _listViewItems.Count; i++) { foreach (string term in searchTerms) { matchedTerm = false; for (int j = 0; j < _listViewItems[i].SubItems.Count; j++) { if (_listViewItems[i].SubItems[j].Text.StartsWith(term)) { matchedTerm = true; } } if (!matchedTerm) { break; } } if (matchedTerm) { this.Invoke(d, new object[] { _listViewItems[i] }); OnSetProgressBarValue(i * 100 / _listViewItems.Count); } } }