From 2f7c2882d276720635bd117df4f1abde34ec4024 Mon Sep 17 00:00:00 2001 From: Brandon Moffett Date: Tue, 7 May 2024 11:28:16 -0700 Subject: [PATCH 1/5] Update to .NET 8.0 and enhance FedEx API integration This commit includes a major update to the .NET framework from `net7.0` to `net8.0` across all projects. It also introduces significant enhancements to the FedEx API integration, including new classes and interfaces for authentication and address validation. The `Microsoft.Extensions.Hosting` and `Microsoft.Extensions.Http.Polly` packages have been updated to version `8.0.0` and `8.0.4` respectively. The `FedExAddressValidationProvider` class now uses the FedEx Web Services client for address validation, with a note that this SOAP-based service will be disabled on August 31, 2024, and replaced with FedEx RESTful APIs. The `FedExApiOptions` class now includes a `Url` property for switching between development and production URLs for the FedEx API. The `FedExAuthClient` and `FedExAddressValidationApiClient` classes have been updated to handle token refreshes and API alerts respectively. The `AddressValidationResponse` class now includes a `IsValidAddress` method for validating addresses. --- EasyKeys.Shipping.sln | 4 +- build/dependencies.props | 4 +- .../EasyKeys.Shipping.Abstractions.csproj | 24 ++-- .../Api/Middleware/AuthRequestMiddleware.cs | 50 ++++++++ .../Api/V1/Auth/IFedexAuthClient.cs | 13 ++ .../Api/V1/Auth/Impl/FedExAuthClient.cs | 73 +++++++++++ .../Api/V1/Auth/Models/TokenResponse.cs | 20 +++ .../FedExServiceCollectionExtensions.cs | 25 +++- ...asyKeys.Shipping.FedEx.Abstractions.csproj | 51 ++++---- .../Options/FedExApiOptions.cs | 12 ++ .../V1/IFedExAddressValidationApiClient.cs | 23 ++++ .../Impl/FedExAddressValidationApiClient.cs | 121 ++++++++++++++++++ .../Api/V1/Models/AddressValidationRequest.cs | 34 +++++ .../V1/Models/AddressValidationResponse.cs | 113 ++++++++++++++++ .../AddressValidationServiceExtensions.cs | 27 +++- ...ys.Shipping.FedEx.AddressValidation.csproj | 39 +++--- .../IFedExAddressValidationProvider.cs | 14 -- .../IFedExAddressValidationProvider.cs | 17 +++ .../Impl}/FedExAddressValidationProvider.cs | 22 ++-- .../EasyKeys.Shipping.FedEx.Console.csproj | 15 +-- src/EasyKeys.Shipping.FedEx.Console/Main.cs | 2 +- .../EasyKeys.Shipping.FedEx.Rates.csproj | 41 +++--- .../EasyKeys.Shipping.FedEx.Shipment.csproj | 39 +++--- .../EasyKeys.Shipping.FedEx.Tracking.csproj | 42 +++--- ...yKeys.Shipping.FedEx.UploadDocument.csproj | 30 ++--- .../EasyKeys.Shipping.PostalAddress.csproj | 25 ++-- ...syKeys.Shipping.Stamps.Abstractions.csproj | 73 +++++------ ...s.Shipping.Stamps.AddressValidation.csproj | 29 ++--- .../EasyKeys.Shipping.Stamps.Console.csproj | 64 ++++----- .../EasyKeys.Shipping.Stamps.Rates.csproj | 38 +++--- .../EasyKeys.Shipping.Stamps.Shipment.csproj | 31 ++--- .../EasyKeys.Shipping.Stamps.Tracking.csproj | 25 ++-- ...EasyKeys.Shipping.Usps.Abstractions.csproj | 17 +-- .../EasyKeys.Shipping.Usps.Rates.csproj | 38 +++--- .../EasyKeys.Shipping.Usps.Tracking.csproj | 33 ++--- src/Minimal.Apis/Minimal.Apis.csproj | 61 ++++----- src/Minimal.Apis/Program.cs | 2 +- .../EasyKeys.Shipping.FuncTest.csproj | 11 +- .../FedExAddressValidationProviderTests.cs | 28 +++- .../TestHelpers/ServiceProviderInstance.cs | 7 +- .../EasyKeysShipping.UnitTest.csproj | 76 +++++------ 41 files changed, 906 insertions(+), 507 deletions(-) create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs delete mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs rename src/EasyKeys.Shipping.FedEx.AddressValidation/{ => WebServices/Impl}/FedExAddressValidationProvider.cs (90%) diff --git a/EasyKeys.Shipping.sln b/EasyKeys.Shipping.sln index 251170d..43c2dbe 100644 --- a/EasyKeys.Shipping.sln +++ b/EasyKeys.Shipping.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31825.309 @@ -80,7 +80,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minimal.Apis", "src\Minimal EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyKeys.Shipping.FuncTest", "test\EasyKeys.Shipping.FuncTest\EasyKeys.Shipping.FuncTest.csproj", "{48385BA3-B5AE-47E6-9C41-189EE6334D1E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyKeys.Shipping.FedEx.UploadDocument", "src\EasyKeys.Shipping.FedEx.UploadDocument\EasyKeys.Shipping.FedEx.UploadDocument.csproj", "{CCFE77D6-0A82-4EC9-AB2F-6FCD885FC489}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyKeys.Shipping.FedEx.UploadDocument", "src\EasyKeys.Shipping.FedEx.UploadDocument\EasyKeys.Shipping.FedEx.UploadDocument.csproj", "{CCFE77D6-0A82-4EC9-AB2F-6FCD885FC489}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/build/dependencies.props b/build/dependencies.props index b0aff80..929c168 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -7,8 +7,8 @@ - 7.0.* + Condition="'$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'netstandard2.0'"> + 8.0.* diff --git a/src/EasyKeys.Shipping.Abstractions/EasyKeys.Shipping.Abstractions.csproj b/src/EasyKeys.Shipping.Abstractions/EasyKeys.Shipping.Abstractions.csproj index fe72d34..58c26e0 100644 --- a/src/EasyKeys.Shipping.Abstractions/EasyKeys.Shipping.Abstractions.csproj +++ b/src/EasyKeys.Shipping.Abstractions/EasyKeys.Shipping.Abstractions.csproj @@ -1,16 +1,12 @@ - - - net7.0 - - - - DotNetCore Abstractions of Shipment Library. - DotNetCore, Shipment Abstractions - - - - - - + + net8.0 + + + DotNetCore Abstractions of Shipment Library. + DotNetCore, Shipment Abstractions + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs new file mode 100644 index 0000000..6acde94 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; + +using Microsoft.Extensions.Logging; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; +public class AuthRequestMiddleware : DelegatingHandler +{ + private readonly IFedExAuthClient _authClient; + private ILogger _logger; + + public AuthRequestMiddleware( + IFedExAuthClient authClient, + ILogger logger) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _authClient = authClient ?? throw new ArgumentNullException(nameof(authClient)); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var response = new HttpResponseMessage(); + try + { + // Perform any custom logic here before the request is sent + _logger.LogDebug($"Intercepted request to {request.RequestUri}"); + + var token = await _authClient.GetTokenAsync(); + + request.Headers.Add("Authorization", token); + + // Call the base SendAsync method to continue processing the request + response = await base.SendAsync(request, cancellationToken); + + response.EnsureSuccessStatusCode(); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + } + + return response; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs new file mode 100644 index 0000000..5b8710b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; + +public interface IFedExAuthClient +{ + Task GetTokenAsync(); +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs new file mode 100644 index 0000000..dd1d761 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs @@ -0,0 +1,73 @@ +using System.Collections.Concurrent; +using System.Net.Http.Json; + +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Impl; + +public class FedExAuthClient : IFedExAuthClient +{ + private readonly HttpClient _httpClient; + private readonly FedExApiOptions _options; + private readonly ILogger _logger; + private readonly ConcurrentDictionary _token = new(); + private readonly ConcurrentDictionary _expirationClock = new(); + + public FedExAuthClient( + IHttpClientFactory clientFactory, + IOptionsMonitor optionsMonitor, + ILogger logger) + { + _options = optionsMonitor.CurrentValue; + _httpClient = clientFactory.CreateClient(nameof(IFedExAuthClient)); + _logger = logger; + } + + public async Task GetTokenAsync() + { + try + { + if (DateTimeOffset.Now < _expirationClock.GetValueOrDefault(nameof(_expirationClock))) + { + _logger.LogDebug("Token is returned"); + _token.TryGetValue(nameof(TokenResponse), out var existingToken); + ArgumentNullException.ThrowIfNull(existingToken, nameof(TokenResponse)); + return existingToken; + } + + _logger.LogDebug("Token being requested."); + + // Send a POST request to FedEx's token endpoint + var response = await _httpClient.PostAsync($"{_options.Url}oauth/token", new FormUrlEncodedContent(new Dictionary + { + { "client_id", _options.ClientId }, + { "client_secret", _options.ClientSecret }, + { "grant_type", "client_credentials" } + })); + + response.EnsureSuccessStatusCode(); + + var tokenObj = await response.Content.ReadFromJsonAsync(); + + ArgumentNullException.ThrowIfNull(tokenObj, nameof(TokenResponse)); + + _logger.LogInformation("Token being updated"); + + _token.AddOrUpdate(nameof(TokenResponse), tokenObj.Token, (x, y) => tokenObj.Token); + + _expirationClock.AddOrUpdate(nameof(_expirationClock), (x) => DateTimeOffset.Now.AddSeconds(tokenObj.ExpiresIn - 5), (x, y) => y.AddSeconds(tokenObj.ExpiresIn - 5)); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + } + + _token.TryGetValue(nameof(TokenResponse), out var token); + return token; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs new file mode 100644 index 0000000..c8c8582 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Models; + +public record TokenResponse +{ + [JsonPropertyName("token_type")] + public string TokenType { get; init; } = string.Empty; + + [JsonPropertyName("scope")] + public string Scope { get; init; } = string.Empty; + + [JsonPropertyName("access_token")] + public string AccessToken { get; init; } = string.Empty; + + [JsonPropertyName("expires_in")] + public long ExpiresIn { get; init; } + + public string Token => $"{TokenType} {AccessToken}"; +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs index 2f69b2d..4f38eb7 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs @@ -1,4 +1,7 @@ -using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Impl; +using EasyKeys.Shipping.FedEx.Abstractions.Options; using EasyKeys.Shipping.FedEx.Abstractions.Services; using EasyKeys.Shipping.FedEx.Abstractions.Services.Impl; @@ -26,4 +29,24 @@ public static class FedExServiceCollectionExtensions return services; } + + /// + /// Adds FedEx Api Client Service with configuration options . + /// + /// The DI services. + /// The section name for the options. + /// The configuration of options. + /// + public static IServiceCollection AddFedExAuthApiClient( + this IServiceCollection services, + string sectionName = nameof(FedExApiOptions), + Action? configure = null) + { + services.AddChangeTokenOptions(sectionName, null, (options, config) => configure?.Invoke(options, config)); + services.AddHttpClient(name: nameof(IFedExAuthClient)); + services.AddTransient(); + services.AddSingleton(); + + return services; + } } diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj b/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj index 9069e80..143ed2d 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj @@ -1,31 +1,24 @@  - - - net7.0 - $(NoWarn);CS0108 - - - - DotNetCore Implementation of FedEx Web Services 2020 of WCF. - DotNetCore, FedEx 2020 WCF - - - - - - - - - - - - - - - - - - - + + net8.0 + $(NoWarn);CS0108 + + + DotNetCore Implementation of FedEx Web Services 2020 of WCF. + DotNetCore, FedEx 2020 WCF + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs new file mode 100644 index 0000000..16d0909 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs @@ -0,0 +1,12 @@ +namespace EasyKeys.Shipping.FedEx.Abstractions.Options; + +public class FedExApiOptions +{ + public string Url => IsDevelopment ? "https://apis-sandbox.fedex.com/" : "https://apis-sandbox.fedex.com/"; + + public string ClientId { get; set; } = string.Empty; + + public string ClientSecret { get; set; } = string.Empty; + + public bool IsDevelopment { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs new file mode 100644 index 0000000..7b145ad --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using EasyKeys.Shipping.Abstractions.Models; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; + +/// +/// This validates recipient address information and identifies it as either business or residential.Uses Fedex REST Api Address Validation Client V1. +/// +public interface IFedExAddressValidationApiClient +{ + /// + /// Validates USA based address and other countries, please refer to the manual. + /// + /// + /// + /// + Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken = default); +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs new file mode 100644 index 0000000..36e16f6 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs @@ -0,0 +1,121 @@ +using System.Diagnostics; +using System.Net.Http.Json; + +using EasyKeys.Shipping.Abstractions; +using EasyKeys.Shipping.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; +using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Impl; +public class FedExAddressValidationApiClient : IFedExAddressValidationApiClient, IAddressValidationProvider +{ + private readonly HttpClient _client; + private readonly FedExApiOptions _options; + private readonly ILogger _logger; + + public FedExAddressValidationApiClient( + HttpClient client, + IOptionsMonitor optionsMonitor, + ILogger logger) + { + _options = optionsMonitor.CurrentValue; + _client = client; + _logger = logger; + } + + public string Name => nameof(FedExAddressValidationApiClient); + + public async Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken) + { + var watch = ValueStopwatch.StartNew(); + + try + { + var apiRequest = new AddressValidationRequest + { + InEffectAsOfTimestamp = "2019-09-06", + ValidateAddressControlParameters = new ValidateAddressControlParameters + { + IncludeResolutionTokens = true + }, + AddressesToValidate = new List + { + new AddressToValidate + { + Address = new Models.Address + { + StreetLines = request.OriginalAddress.GetStreetLines(), + City = request.OriginalAddress.City, + StateOrProvinceCode = request.OriginalAddress.StateOrProvince, + PostalCode = request.OriginalAddress.PostalCode, + CountryCode = request.OriginalAddress.CountryCode + }, + ClientReferenceId = request.Id + } + } + }; + var result = await _client.PostAsJsonAsync($"{_options.Url}address/v1/addresses/resolve", apiRequest, cancellationToken); + + result.EnsureSuccessStatusCode(); + + var content = await result.Content.ReadAsStringAsync(cancellationToken); + + var response = await result.Content.ReadFromJsonAsync(cancellationToken); + + ArgumentNullException.ThrowIfNull(response); + + var lines = response.Output.ResolvedAddresses.FirstOrDefault()?.StreetLinesToken ?? [string.Empty]; + var address1 = lines.FirstOrDefault() ?? string.Empty; + var address2 = lines.Length > 1 ? lines[1] : string.Empty; + + request.ProposedAddress = new Shipping.Abstractions.Models.Address( + address1, + address2, + response.Output.ResolvedAddresses.FirstOrDefault()?.CityToken?.FirstOrDefault()?.Value ?? string.Empty, + response.Output.ResolvedAddresses.FirstOrDefault()?.StateOrProvinceCode ?? string.Empty, + response.Output.ResolvedAddresses.FirstOrDefault()?.PostalCodeToken.Value ?? string.Empty, + response.Output.ResolvedAddresses.FirstOrDefault()?.CountryCode ?? string.Empty, + response.Output.ResolvedAddresses.FirstOrDefault()?.Classification == "RESIDENTIAL"); + + if (lines.Length == 2) + { + request.ProposedAddress.StreetLine2 = lines[1]; + } + + foreach (var a in response.Output.ResolvedAddresses[0].Attributes) + { + if (!request.ValidationBag.ContainsKey(a.Key)) + { + request.ValidationBag.Add(a.Key, a.Value?.ToString() ?? string.Empty); + } + } + + if (response.Output.Alerts != null) + { + foreach (var notification in response.Output.Alerts) + { + request.Errors.Add(new Error + { + Source = notification.AlertType, + Number = notification.Code, + Description = notification.Message + }); + } + + _logger.LogWarning("{providerName} alerts: {errors} ", nameof(FedExAddressValidationApiClient), request.Errors.Select(x => x.Description).Flatten(",")); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "{providerName} failed", nameof(FedExAddressValidationApiClient)); + request.InternalErrors.Add(ex?.Message ?? $"{nameof(FedExAddressValidationApiClient)} failed"); + } + + _logger.LogDebug("[FedEx][ValidateAddressAsync] completed: {mil}", watch.GetElapsedTime().TotalMilliseconds); + return request; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs new file mode 100644 index 0000000..d8f17d7 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs @@ -0,0 +1,34 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; +internal class AddressValidationRequest +{ + public string InEffectAsOfTimestamp { get; set; } = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); + + public ValidateAddressControlParameters ValidateAddressControlParameters { get; set; } = new(); + + public List AddressesToValidate { get; set; } = new(); +} + +internal class ValidateAddressControlParameters +{ + public bool IncludeResolutionTokens { get; set; } = true; +} + +internal class AddressToValidate +{ + public Address Address { get; set; } = new(); + + public string ClientReferenceId { get; set; } = Guid.NewGuid().ToString(); +} + +internal class Address +{ + public string[] StreetLines { get; set; } = Array.Empty(); + + public string City { get; set; } = string.Empty; + + public string StateOrProvinceCode { get; set; } = string.Empty; + + public string PostalCode { get; set; } = string.Empty; + + public string CountryCode { get; set; } = string.Empty; +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs new file mode 100644 index 0000000..59fc714 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs @@ -0,0 +1,113 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; + +internal class AddressValidationResponse +{ + public string TransactionId { get; set; } + + public string CustomerTransactionId { get; set; } + + public Output Output { get; set; } + + public bool IsValidAddress() + { + if (Output == null || Output.ResolvedAddresses == null) + return false; + + foreach (var address in Output.ResolvedAddresses) + { + // Checking primary validation criteria + var isStandardized = address.Attributes.TryGetValue("AddressType", out var addressType) && addressType.ToString() == "STANDARDIZED"; + var isDPVTrue = address.Attributes.TryGetValue("DPV", out var dpv) && dpv.ToString() == "true"; + var isInterpolated = address.Attributes.TryGetValue("InterpolatedStreetAddress", out var interpolated) && interpolated.ToString() == "true"; + + // Check for specific customer message indicating invalidity + var hasInvalidCustomerMessage = address.CustomerMessage?.Any(cm => cm.Value == "INTERPOLATED.STREET.ADDRESS") ?? false; + + // Check if additional validation attributes meet the required conditions + var buildingValidated = address.Attributes.TryGetValue("BuildingValidated", out var buildingValid) && buildingValid.ToString() == "true"; + var postalValidated = address.Attributes.TryGetValue("PostalValidated", out var postalValid) && postalValid.ToString() == "true"; + + // Final validation logic + if (isStandardized && isDPVTrue && !isInterpolated && !hasInvalidCustomerMessage) + { + return true; + } + } + + return false; + } +} + +internal class Output +{ + public List ResolvedAddresses { get; set; } + + public List Alerts { get; set; } +} + +internal class ResolvedAddress +{ + public string[] StreetLinesToken { get; set; } + + public string City { get; set; } + + public string StateOrProvinceCode { get; set; } + + public string CountryCode { get; set; } + + public List? CustomerMessage { get; set; } + + public List CityToken { get; set; } + + public ResolutionToken PostalCodeToken { get; set; } + + public ParsedPostalCode ParsedPostalCode { get; set; } + + public string Classification { get; set; } + + public bool PostOfficeBox { get; set; } + + public bool NormalizedStatusNameDPV { get; set; } + + public string StandardizedStatusNameMatchSource { get; set; } + + public string ResolutionMethodName { get; set; } + + public bool RuralRouteHighwayContract { get; set; } + + public bool GeneralDelivery { get; set; } + + public Dictionary Attributes { get; set; } +} + +internal class CustomerMessage +{ + public bool Changed { get; set; } + + public string Value { get; set; } +} + +internal class ResolutionToken +{ + public bool Changed { get; set; } + + public string Value { get; set; } +} + +internal class ParsedPostalCode +{ + public string Base { get; set; } + + public string AddOn { get; set; } + + public string DeliveryPoint { get; set; } +} + +internal class Alert +{ + public string Code { get; set; } + + public string Message { get; set; } + + public string AlertType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs index 4616000..5456b7e 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs @@ -1,6 +1,10 @@ using EasyKeys.Shipping.Abstractions; +using EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; using EasyKeys.Shipping.FedEx.Abstractions.Options; -using EasyKeys.Shipping.FedEx.AddressValidation; +using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; +using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Impl; +using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; +using EasyKeys.Shipping.FedEx.AddressValidation.WebServices.Impl; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -35,4 +39,25 @@ public static class AddressValidationServiceExtensions return services; } + + public static IServiceCollection AddFedExAddressValidationApiV1( + this IServiceCollection services, + string sectionName = nameof(FedExApiOptions), + Action? configOptions = null) + { + services.AddChangeTokenOptions( + sectionName: sectionName, + configureAction: (options, sp) => configOptions?.Invoke(options, sp)); + + services.AddLogging(); + + services.AddFedExAuthApiClient(); + + services.AddHttpClient() + .AddHttpMessageHandler(); + + services.AddTransient(); + + return services; + } } diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj b/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj index a84e899..f9d68f4 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj @@ -1,25 +1,18 @@  - - - net7.0 - - - - DotNetCore Implementation of FedEx Web Services 2020 for AddressValidation + + net8.0 + + + DotNetCore Implementation of FedEx Web Services 2020 for AddressValidation Endpoint. - DotNetCore, Address Validation, FedEx 2020 WCF - - - - - - - - - - - - - \ No newline at end of file + DotNetCore, Address Validation, FedEx 2020 WCF + + + + + + + + + + diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs deleted file mode 100644 index 247299f..0000000 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using EasyKeys.Shipping.Abstractions.Models; - -namespace EasyKeys.Shipping.FedEx.AddressValidation; - -public interface IFedExAddressValidationProvider -{ - /// - /// Validates USA based address and other countries, please refer to the manual. - /// - /// - /// - /// - Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken = default); -} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs new file mode 100644 index 0000000..606adf0 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs @@ -0,0 +1,17 @@ +using EasyKeys.Shipping.Abstractions.Models; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.WebServices; + +/// +/// Caution: FedEx Web Services Tracking, Address Validation, and Validate Postal Codes WSDLS will be disabled on August 31, 2024. The SOAP based FedEx Web Services is in development containment and has been replaced with FedEx RESTful APIs. To learn more and upgrade your integration from Web Services to FedEx APIs, please visit the FedEx Developer Portal. +/// +public interface IFedExAddressValidationProvider +{ + /// + /// Validates USA based address and other countries, please refer to the manual. Uses Web Services Client. + /// + /// + /// + /// + Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken = default); +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/FedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs similarity index 90% rename from src/EasyKeys.Shipping.FedEx.AddressValidation/FedExAddressValidationProvider.cs rename to src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs index 1c42332..ac1d2fb 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/FedExAddressValidationProvider.cs +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs @@ -12,7 +12,7 @@ using v4 = AddressValidationClient.v4; -namespace EasyKeys.Shipping.FedEx.AddressValidation; +namespace EasyKeys.Shipping.FedEx.AddressValidation.WebServices.Impl; public class FedExAddressValidationProvider : IFedExAddressValidationProvider, IAddressValidationProvider { @@ -45,7 +45,7 @@ public async Task ValidateAddressAsync(ValidateAddress request, var client = _addressValidationClient; var wrap = CreateRequest(request); - var serviceRequest = new v4.addressValidationRequest1(wrap); + var serviceRequest = new addressValidationRequest1(wrap); var reply = await client.addressValidationAsync(serviceRequest); @@ -129,11 +129,11 @@ public async Task ValidateAddressAsync(ValidateAddress request, return request; } - private v4.AddressValidationRequest CreateRequest(ValidateAddress request) + private AddressValidationRequest CreateRequest(ValidateAddress request) { var address = request.OriginalAddress; - var addressToValidate = new v4.AddressToValidate + var addressToValidate = new AddressToValidate { ClientReferenceId = request.Id, Address = new v4.Address @@ -146,30 +146,30 @@ private v4.AddressValidationRequest CreateRequest(ValidateAddress request) } }; - return new v4.AddressValidationRequest + return new AddressValidationRequest { - WebAuthenticationDetail = new v4.WebAuthenticationDetail + WebAuthenticationDetail = new WebAuthenticationDetail { - UserCredential = new v4.WebAuthenticationCredential + UserCredential = new WebAuthenticationCredential { Key = _options.FedExKey, Password = _options.FedExPassword } }, - ClientDetail = new v4.ClientDetail + ClientDetail = new ClientDetail { AccountNumber = _options.FedExAccountNumber, MeterNumber = _options.FedExMeterNumber }, - TransactionDetail = new v4.TransactionDetail + TransactionDetail = new TransactionDetail { CustomerTransactionId = nameof(FedExAddressValidationProvider) }, - Version = new v4.VersionId(), - AddressesToValidate = new v4.AddressToValidate[1] + Version = new VersionId(), + AddressesToValidate = new AddressToValidate[1] { addressToValidate }, diff --git a/src/EasyKeys.Shipping.FedEx.Console/EasyKeys.Shipping.FedEx.Console.csproj b/src/EasyKeys.Shipping.FedEx.Console/EasyKeys.Shipping.FedEx.Console.csproj index 157fade..bfb8c8a 100644 --- a/src/EasyKeys.Shipping.FedEx.Console/EasyKeys.Shipping.FedEx.Console.csproj +++ b/src/EasyKeys.Shipping.FedEx.Console/EasyKeys.Shipping.FedEx.Console.csproj @@ -1,31 +1,23 @@  - - net7.0 + net8.0 dotnet-easykeys.shipping.fedex.console-a96b3bea-52eb-4aea-aefc-913b782d749a Linux false - - - - - - - + - @@ -34,5 +26,4 @@ - - + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.FedEx.Console/Main.cs b/src/EasyKeys.Shipping.FedEx.Console/Main.cs index 490f769..2a3680f 100644 --- a/src/EasyKeys.Shipping.FedEx.Console/Main.cs +++ b/src/EasyKeys.Shipping.FedEx.Console/Main.cs @@ -4,7 +4,7 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation; +using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; using EasyKeys.Shipping.FedEx.Rates; using EasyKeys.Shipping.FedEx.Shipment; using EasyKeys.Shipping.FedEx.Shipment.Models; diff --git a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj index 908d4f0..b38b2ab 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj +++ b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj @@ -1,26 +1,19 @@  - - net7.0 - $(NoWarn);CS0108 - - - - DotNetCore Implementation of FedEx Web Services 2020 for Rates Available + + net8.0 + $(NoWarn);CS0108 + + + DotNetCore Implementation of FedEx Web Services 2020 for Rates Available Endpoint. - DotNetCore, FedEx Shipment Rates, FedEx 2020 WCF - - - - - - - - - - - - - - \ No newline at end of file + DotNetCore, FedEx Shipment Rates, FedEx 2020 WCF + + + + + + + + + + diff --git a/src/EasyKeys.Shipping.FedEx.Shipment/EasyKeys.Shipping.FedEx.Shipment.csproj b/src/EasyKeys.Shipping.FedEx.Shipment/EasyKeys.Shipping.FedEx.Shipment.csproj index da1e33c..be4160c 100644 --- a/src/EasyKeys.Shipping.FedEx.Shipment/EasyKeys.Shipping.FedEx.Shipment.csproj +++ b/src/EasyKeys.Shipping.FedEx.Shipment/EasyKeys.Shipping.FedEx.Shipment.csproj @@ -1,24 +1,17 @@  - - - net7.0 - - - - DotNetCore Implementation of FedEx Web Services 2020 for Shipment Endpoint. - DotNetCore, FedEx Shipment Label Generation, FedEx 2020 WCF - - - - - - - - - - - - - \ No newline at end of file + + net8.0 + + + DotNetCore Implementation of FedEx Web Services 2020 for Shipment Endpoint. + DotNetCore, FedEx Shipment Label Generation, FedEx 2020 WCF + + + + + + + + + + diff --git a/src/EasyKeys.Shipping.FedEx.Tracking/EasyKeys.Shipping.FedEx.Tracking.csproj b/src/EasyKeys.Shipping.FedEx.Tracking/EasyKeys.Shipping.FedEx.Tracking.csproj index 1b20922..9a68a8d 100644 --- a/src/EasyKeys.Shipping.FedEx.Tracking/EasyKeys.Shipping.FedEx.Tracking.csproj +++ b/src/EasyKeys.Shipping.FedEx.Tracking/EasyKeys.Shipping.FedEx.Tracking.csproj @@ -1,26 +1,18 @@ - - - net7.0 - - - - DotNetCore Implementation of FedEx Web Services 2020 for Tracking Endpoint. - DotNetCore, FedEx Package Tracking, FedEx 2020 WCF - - - - - - - - - - - - - - \ No newline at end of file + + net8.0 + + + DotNetCore Implementation of FedEx Web Services 2020 for Tracking Endpoint. + DotNetCore, FedEx Package Tracking, FedEx 2020 WCF + + + + + + + + + + + diff --git a/src/EasyKeys.Shipping.FedEx.UploadDocument/EasyKeys.Shipping.FedEx.UploadDocument.csproj b/src/EasyKeys.Shipping.FedEx.UploadDocument/EasyKeys.Shipping.FedEx.UploadDocument.csproj index 05c5298..9aecb37 100644 --- a/src/EasyKeys.Shipping.FedEx.UploadDocument/EasyKeys.Shipping.FedEx.UploadDocument.csproj +++ b/src/EasyKeys.Shipping.FedEx.UploadDocument/EasyKeys.Shipping.FedEx.UploadDocument.csproj @@ -1,26 +1,20 @@  - - net7.0 - $(NoWarn);CS0108 - - - - + net8.0 + $(NoWarn);CS0108 + + + DotNetCore Implementation of FedEx Web Services 2021 for ETD Available Endpoint. - DotNetCore, FedEx Upload Document Services, FedEx ETD, FedEx 2021 WCF - - - - - - - - - + DotNetCore, FedEx Upload Document Services, FedEx ETD, FedEx 2021 WCF + + + + + + - diff --git a/src/EasyKeys.Shipping.PostalAddress/EasyKeys.Shipping.PostalAddress.csproj b/src/EasyKeys.Shipping.PostalAddress/EasyKeys.Shipping.PostalAddress.csproj index 30a868e..06430e9 100644 --- a/src/EasyKeys.Shipping.PostalAddress/EasyKeys.Shipping.PostalAddress.csproj +++ b/src/EasyKeys.Shipping.PostalAddress/EasyKeys.Shipping.PostalAddress.csproj @@ -1,17 +1,12 @@ - - - net7.0 - - - - - DotNetCore Postal Address Parsing. - DotNetCore, Shipment Address Parsing - - - - - - + + net8.0 + + + DotNetCore Postal Address Parsing. + DotNetCore, Shipment Address Parsing + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Stamps.Abstractions/EasyKeys.Shipping.Stamps.Abstractions.csproj b/src/EasyKeys.Shipping.Stamps.Abstractions/EasyKeys.Shipping.Stamps.Abstractions.csproj index 1383322..e12c2c4 100644 --- a/src/EasyKeys.Shipping.Stamps.Abstractions/EasyKeys.Shipping.Stamps.Abstractions.csproj +++ b/src/EasyKeys.Shipping.Stamps.Abstractions/EasyKeys.Shipping.Stamps.Abstractions.csproj @@ -1,43 +1,34 @@  - - - net7.0 - $(NoWarn);CS0108 - - - - DotNetCore Implementation of Stamps.com SWS/IM API. - DotNetCore, Stamps.com WCF, Stamps.com SWS/IM API - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + net8.0 + $(NoWarn);CS0108 + + + DotNetCore Implementation of Stamps.com SWS/IM API. + DotNetCore, Stamps.com WCF, Stamps.com SWS/IM API + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Stamps.AddressValidation/EasyKeys.Shipping.Stamps.AddressValidation.csproj b/src/EasyKeys.Shipping.Stamps.AddressValidation/EasyKeys.Shipping.Stamps.AddressValidation.csproj index 4faf9f7..3a2fabf 100644 --- a/src/EasyKeys.Shipping.Stamps.AddressValidation/EasyKeys.Shipping.Stamps.AddressValidation.csproj +++ b/src/EasyKeys.Shipping.Stamps.AddressValidation/EasyKeys.Shipping.Stamps.AddressValidation.csproj @@ -1,21 +1,14 @@  - - - net7.0 - - - - DotNetCore Implementation of Stamps.com SWS/IM API. - DotNetCore,Address Validatio, Address Cleansing, Stamps.com WCF, Stamps.com + + net8.0 + + + DotNetCore Implementation of Stamps.com SWS/IM API. + DotNetCore,Address Validatio, Address Cleansing, Stamps.com WCF, Stamps.com SWS/IM API - - - - - - - - + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Stamps.Console/EasyKeys.Shipping.Stamps.Console.csproj b/src/EasyKeys.Shipping.Stamps.Console/EasyKeys.Shipping.Stamps.Console.csproj index 39f548a..8ad2e52 100644 --- a/src/EasyKeys.Shipping.Stamps.Console/EasyKeys.Shipping.Stamps.Console.csproj +++ b/src/EasyKeys.Shipping.Stamps.Console/EasyKeys.Shipping.Stamps.Console.csproj @@ -1,37 +1,29 @@  - - - net7.0 - dotnet-easykeys.shipping.stamps.console-7A678870-7B37-4774-8229-462ECD6DF7EA - Linux - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + net8.0 + dotnet-easykeys.shipping.stamps.console-7A678870-7B37-4774-8229-462ECD6DF7EA + Linux + false + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Stamps.Rates/EasyKeys.Shipping.Stamps.Rates.csproj b/src/EasyKeys.Shipping.Stamps.Rates/EasyKeys.Shipping.Stamps.Rates.csproj index 11df31d..df56a1f 100644 --- a/src/EasyKeys.Shipping.Stamps.Rates/EasyKeys.Shipping.Stamps.Rates.csproj +++ b/src/EasyKeys.Shipping.Stamps.Rates/EasyKeys.Shipping.Stamps.Rates.csproj @@ -1,24 +1,16 @@  - - - net7.0 - - - - DotNetCore Implementation of Stamps.com SWS/IM API. - DotNetCore, Stamps.com Rate service, Stamps.com WCF, Stamps.com SWS/IM API - - - - - - - - - - - - - \ No newline at end of file + + net8.0 + + + DotNetCore Implementation of Stamps.com SWS/IM API. + DotNetCore, Stamps.com Rate service, Stamps.com WCF, Stamps.com SWS/IM API + + + + + + + + + diff --git a/src/EasyKeys.Shipping.Stamps.Shipment/EasyKeys.Shipping.Stamps.Shipment.csproj b/src/EasyKeys.Shipping.Stamps.Shipment/EasyKeys.Shipping.Stamps.Shipment.csproj index de7e20b..a4aa370 100644 --- a/src/EasyKeys.Shipping.Stamps.Shipment/EasyKeys.Shipping.Stamps.Shipment.csproj +++ b/src/EasyKeys.Shipping.Stamps.Shipment/EasyKeys.Shipping.Stamps.Shipment.csproj @@ -1,21 +1,14 @@  - - - net7.0 - - - - DotNetCore Implementation of Stamps.com SWS/IM API. - DotNetCore, Stamps.com Shipment service, Stamps.com WCF, Stamps.com SWS/IM API - - - - - - - - + + net8.0 + + + DotNetCore Implementation of Stamps.com SWS/IM API. + DotNetCore, Stamps.com Shipment service, Stamps.com WCF, Stamps.com SWS/IM API + + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Stamps.Tracking/EasyKeys.Shipping.Stamps.Tracking.csproj b/src/EasyKeys.Shipping.Stamps.Tracking/EasyKeys.Shipping.Stamps.Tracking.csproj index 49f05de..0a67348 100644 --- a/src/EasyKeys.Shipping.Stamps.Tracking/EasyKeys.Shipping.Stamps.Tracking.csproj +++ b/src/EasyKeys.Shipping.Stamps.Tracking/EasyKeys.Shipping.Stamps.Tracking.csproj @@ -1,17 +1,12 @@ - - - net7.0 - - - - DotNetCore Implementation of Stamps.com SWS/IM API. - DotNetCore, Stamps.com tracking service, Stamps.com WCF, Stamps.com SWS/IM API - - - - - - + + net8.0 + + + DotNetCore Implementation of Stamps.com SWS/IM API. + DotNetCore, Stamps.com tracking service, Stamps.com WCF, Stamps.com SWS/IM API + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Usps.Abstractions/EasyKeys.Shipping.Usps.Abstractions.csproj b/src/EasyKeys.Shipping.Usps.Abstractions/EasyKeys.Shipping.Usps.Abstractions.csproj index ebc83cb..7898428 100644 --- a/src/EasyKeys.Shipping.Usps.Abstractions/EasyKeys.Shipping.Usps.Abstractions.csproj +++ b/src/EasyKeys.Shipping.Usps.Abstractions/EasyKeys.Shipping.Usps.Abstractions.csproj @@ -1,12 +1,9 @@ - - - net7.0 - - - - DotNetCore Implementation of USPS WCF API. - DotNetCore, USPS WCF - - + + net8.0 + + + DotNetCore Implementation of USPS WCF API. + DotNetCore, USPS WCF + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Usps.Rates/EasyKeys.Shipping.Usps.Rates.csproj b/src/EasyKeys.Shipping.Usps.Rates/EasyKeys.Shipping.Usps.Rates.csproj index 140a0eb..5e47c71 100644 --- a/src/EasyKeys.Shipping.Usps.Rates/EasyKeys.Shipping.Usps.Rates.csproj +++ b/src/EasyKeys.Shipping.Usps.Rates/EasyKeys.Shipping.Usps.Rates.csproj @@ -1,25 +1,17 @@  - - - net7.0 - - - - DotNetCore Implementation of USPS WCF API. - DotNetCore, USPS Rate service, USPS WCF - - - - - - - - - - - - - + + net8.0 + + + DotNetCore Implementation of USPS WCF API. + DotNetCore, USPS Rate service, USPS WCF + + + + + + + + + \ No newline at end of file diff --git a/src/EasyKeys.Shipping.Usps.Tracking/EasyKeys.Shipping.Usps.Tracking.csproj b/src/EasyKeys.Shipping.Usps.Tracking/EasyKeys.Shipping.Usps.Tracking.csproj index 0a2d05d..a0a707f 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/EasyKeys.Shipping.Usps.Tracking.csproj +++ b/src/EasyKeys.Shipping.Usps.Tracking/EasyKeys.Shipping.Usps.Tracking.csproj @@ -1,21 +1,16 @@  - - net7.0 - - - - DotNetCore Implementation of USPS WCF API. - DotNetCore, USPS Tracking Service, USPS WCF - - - - - - - - - - - + + net8.0 + + + DotNetCore Implementation of USPS WCF API. + DotNetCore, USPS Tracking Service, USPS WCF + + + + + + + + \ No newline at end of file diff --git a/src/Minimal.Apis/Minimal.Apis.csproj b/src/Minimal.Apis/Minimal.Apis.csproj index c850256..d767430 100644 --- a/src/Minimal.Apis/Minimal.Apis.csproj +++ b/src/Minimal.Apis/Minimal.Apis.csproj @@ -1,34 +1,29 @@  - - - net7.0 - b24b4bb8-6f6a-4769-8ab5-bee702b3ea47 - Linux - false - - - - - - - - - - - - - - - - - - - - - - - - - - - + + net8.0 + b24b4bb8-6f6a-4769-8ab5-bee702b3ea47 + Linux + false + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Minimal.Apis/Program.cs b/src/Minimal.Apis/Program.cs index f391448..67b0467 100644 --- a/src/Minimal.Apis/Program.cs +++ b/src/Minimal.Apis/Program.cs @@ -2,7 +2,7 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation; +using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; using EasyKeys.Shipping.FedEx.Rates; using EasyKeys.Shipping.FedEx.Shipment; using EasyKeys.Shipping.Stamps.Abstractions.Models; diff --git a/test/EasyKeys.Shipping.FuncTest/EasyKeys.Shipping.FuncTest.csproj b/test/EasyKeys.Shipping.FuncTest/EasyKeys.Shipping.FuncTest.csproj index 3dd90fb..668f91e 100644 --- a/test/EasyKeys.Shipping.FuncTest/EasyKeys.Shipping.FuncTest.csproj +++ b/test/EasyKeys.Shipping.FuncTest/EasyKeys.Shipping.FuncTest.csproj @@ -1,16 +1,13 @@ - - net7.0 + net8.0 false true - - Always @@ -19,7 +16,6 @@ Always - @@ -30,12 +26,10 @@ - - @@ -50,5 +44,4 @@ - - + \ No newline at end of file diff --git a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs index 775a9c4..89eb688 100644 --- a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs @@ -1,7 +1,8 @@ using Bet.Extensions.Testing.Logging; using EasyKeys.Shipping.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation; +using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; +using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; using EasyKeysShipping.FuncTest.TestHelpers; @@ -14,12 +15,15 @@ public class FedExAddressValidationProviderTests { private readonly ITestOutputHelper _output; private readonly IFedExAddressValidationProvider _validator; + private readonly IFedExAddressValidationApiClient _apiClient; public FedExAddressValidationProviderTests(ITestOutputHelper output) { _output = output; _validator = ServiceProviderInstance.GetFedExServices(output) .GetRequiredService(); + _apiClient = ServiceProviderInstance.GetFedExServices(output) + .GetRequiredService(); } [Fact] @@ -37,9 +41,12 @@ public async Task NORMALIZED_Unknown_Address_Successfully() false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); + var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); Assert.Equal(string.Empty, proposed?.StreetLine); Assert.Equal(string.Empty, proposed?.StreetLine2); Assert.Equal("52722", proposed?.PostalCode); @@ -71,9 +78,12 @@ public async Task Valid_Standardized_Business_Address_Remove_StreetLine1_Success false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); + var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); Assert.Equal("11435 W BUCKEYE RD", proposed?.StreetLine); Assert.Equal("STE 104-118", proposed?.StreetLine2); Assert.Equal("85323-6812", proposed?.PostalCode); @@ -105,9 +115,12 @@ public async Task Valid_Standardized_Resedintial_Address_Remove_StreetLine1_Succ false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); + var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); Assert.Equal("5 HOOD RD", proposed?.StreetLine); Assert.Equal(string.Empty, proposed?.StreetLine2); Assert.Equal("03038-2012", proposed?.PostalCode); @@ -139,9 +152,12 @@ public async Task Valid_Standardized_Resedintial_Address_Remove_Dup_StreetLine1_ false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); + var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); Assert.Equal("39W210 E BURNHAM LN", proposed?.StreetLine); Assert.Equal(string.Empty, proposed?.StreetLine2); Assert.Equal("60134-4915", proposed?.PostalCode); @@ -173,9 +189,12 @@ public async Task Valid_Standardized_Resedintial_Address_Successfully2() false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); + var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); Assert.Equal("W2155 COUNTY ROAD HH", proposed?.StreetLine); Assert.Equal(string.Empty, proposed?.StreetLine2); @@ -206,9 +225,12 @@ public async Task Valid_Standardized_Resedintial_Address_Successfully() false)); var result = await _validator.ValidateAddressAsync(request); + var apiResult = await _apiClient.ValidateAddressAsync(request); var proposed = result.ProposedAddress; Assert.NotNull(proposed); + Assert.Equal(proposed, apiResult.ProposedAddress); + Assert.Equal("2139 45TH RD", proposed?.StreetLine); Assert.Equal("FL 1", proposed?.StreetLine2); @@ -224,7 +246,7 @@ public async Task Valid_Standardized_Resedintial_Address_Successfully() Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); } - private IFedExAddressValidationProvider GetAddressValidator() + private EasyKeys.Shipping.FedEx.AddressValidation.WebServices.IFedExAddressValidationProvider GetAddressValidator() { var services = new ServiceCollection(); @@ -242,6 +264,6 @@ private IFedExAddressValidationProvider GetAddressValidator() services.AddFedExAddressValidation(); var sp = services.BuildServiceProvider(); - return sp.GetRequiredService(); + return sp.GetRequiredService(); } } diff --git a/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs b/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs index aab86a3..2a0c634 100644 --- a/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs +++ b/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs @@ -15,8 +15,10 @@ public static IServiceProvider GetFedExServices(ITestOutputHelper output) var services = new ServiceCollection(); var dic = new Dictionary { - { "AzureVault:BaseUrl", "https://easykeys.vault.azure.net/" }, + { "AzureVault:BaseUrl", "https://easykeysshipping.vault.azure.net/" }, { "FedExOptions:IsDevelopment", "true" }, + { "FedExApiOptions:IsDevelopment", "true" }, + }; var configBuilder = new ConfigurationBuilder().AddInMemoryCollection(dic); @@ -32,6 +34,9 @@ public static IServiceProvider GetFedExServices(ITestOutputHelper output) services.AddFedExShipmenProvider(); services.AddFedExTrackingProvider(); + // adress validation apis + services.AddFedExAddressValidationApiV1(); + return services.BuildServiceProvider(); } diff --git a/test/EasyKeys.Shipping.UnitTest/EasyKeysShipping.UnitTest.csproj b/test/EasyKeys.Shipping.UnitTest/EasyKeysShipping.UnitTest.csproj index 9495d6b..d93dab2 100644 --- a/test/EasyKeys.Shipping.UnitTest/EasyKeysShipping.UnitTest.csproj +++ b/test/EasyKeys.Shipping.UnitTest/EasyKeysShipping.UnitTest.csproj @@ -1,42 +1,36 @@  - - - net7.0 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + net8.0 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From fad6a364a1dadf5693d159f48bc60dda4c56f64f Mon Sep 17 00:00:00 2001 From: Brandon Moffett Date: Wed, 8 May 2024 14:59:20 -0700 Subject: [PATCH 2/5] Updated codebase with major refactoring and enhancements This commit includes a significant overhaul of the codebase, with numerous updates, additions, and deletions. Key changes include: - Updated `.editorconfig` and `settings.props` files with new rules and warning suppressions. - Enhanced several files with `cancellationToken` parameter and improved documentation. - Added `ApiError.cs` for API error representation and updated `FedExApiOptions.cs` and `README.md`. - Removed and replaced several files related to address validation with a new implementation. - Refactored namespaces and updated methods for better organization and clarity. - Added new interfaces, classes, and methods for FedEx Rates and Transit Times client. - Added numerous classes for handling FedEx shipping rates requests and responses. - Updated several classes for better null safety and improved retry policy. - Removed unused `using` directives and updated project references. - Refactored test classes to accommodate the new changes and improve test coverage. These changes aim to improve the overall code quality, enhance the functionality of the library, and provide a more robust implementation for address validation and FedEx Rates and Transit Times client. --- .editorconfig | 65 +++++ build/settings.props | 2 +- .../IAddressValidationProvider.cs | 2 +- .../Api/V1/Auth/IFedexAuthClient.cs | 13 - .../Client/V1/Auth/IFedexAuthClient.cs | 15 ++ .../V1/Auth/Impl/FedExAuthClient.cs | 18 +- .../V1/Auth/Models/TokenResponse.cs | 0 .../FedExServiceCollectionExtensions.cs | 6 +- .../Middleware/AuthRequestMiddleware.cs | 29 ++- .../Models/ApiError.cs | 11 + .../Options/FedExApiOptions.cs | 13 +- .../README.md | 2 +- .../V1/IFedExAddressValidationApiClient.cs | 23 -- .../Impl/FedExAddressValidationApiClient.cs | 121 --------- .../Api/V1/Models/AddressValidationRequest.cs | 34 --- .../V1/Models/AddressValidationResponse.cs | 113 --------- .../V1/IFedexAddressValidationClient.cs | 19 ++ .../V1/Impl/FedExAddressValidationClient.cs | 47 ++++ .../Client/V1/Models/Request/Address.cs | 21 ++ .../V1/Models/Request/AddressToValidate.cs | 12 + .../Client/V1/Models/Request/RequestRoot.cs | 14 ++ .../ValidateAddressControlParameters.cs | 9 + .../Client/V1/Models/Response/Alert.cs | 10 + .../V1/Models/Response/CustomerMessage.cs | 8 + .../Client/V1/Models/Response/Output.cs | 8 + .../V1/Models/Response/ParsedPostalCode.cs | 10 + .../V1/Models/Response/ResolutionToken.cs | 8 + .../V1/Models/Response/ResolvedAddress.cs | 36 +++ .../Client/V1/Models/Response/ResponseRoot.cs | 51 ++++ .../AddressValidationServiceExtensions.cs | 37 ++- .../IFedExAddressValidationProvider.cs | 5 +- .../Impl/FedExAddressValidationProvider.cs | 132 ++++++++++ .../Impl/FedExAddressValidationProvider.cs | 3 + .../ConsoleServiceCollectionExtensions.cs | 4 +- src/EasyKeys.Shipping.FedEx.Console/Main.cs | 2 +- .../V1/IFedexRatesAndTransitTimesApiClient.cs | 13 + .../FedexRatesAndTransitTimesApiClient.cs | 46 ++++ .../Client/V1/Models/Request/AccountNumber.cs | 9 + .../Request/AddTransportationChargesDetail.cs | 18 ++ .../Client/V1/Models/Request/Address.cs | 24 ++ .../Client/V1/Models/Request/AlcoholDetail.cs | 12 + .../Client/V1/Models/Request/BatteryDetail.cs | 15 ++ .../Client/V1/Models/Request/Broker.cs | 27 ++ .../Client/V1/Models/Request/Broker2.cs | 15 ++ .../Client/V1/Models/Request/BrokerAddress.cs | 36 +++ .../V1/Models/Request/CodCollectionAmount.cs | 12 + .../Client/V1/Models/Request/CodRecipient.cs | 9 + .../V1/Models/Request/CommercialInvoice.cs | 9 + .../Client/V1/Models/Request/Commodity.cs | 39 +++ .../Client/V1/Models/Request/Contact.cs | 24 ++ .../Client/V1/Models/Request/Container.cs | 30 +++ .../Client/V1/Models/Request/ContentRecord.cs | 18 ++ .../Models/Request/CustomsClearanceDetail.cs | 21 ++ .../Client/V1/Models/Request/CustomsValue.cs | 12 + .../V1/Models/Request/DangerousGoodsDetail.cs | 27 ++ .../Client/V1/Models/Request/DeclaredValue.cs | 12 + .../DeliveryOnInvoiceAcceptanceDetail.cs | 9 + .../Client/V1/Models/Request/Description.cs | 45 ++++ .../Client/V1/Models/Request/Dimensions.cs | 18 ++ .../V1/Models/Request/DocumentReference.cs | 18 ++ .../Client/V1/Models/Request/DryIceWeight.cs | 12 + .../Client/V1/Models/Request/DutiesPayment.cs | 12 + .../V1/Models/Request/EmailLabelDetail.cs | 12 + .../Models/Request/EmailNotificationDetail.cs | 15 ++ .../Models/Request/EmergencyContactNumber.cs | 21 ++ .../V1/Models/Request/ExpressFreightDetail.cs | 12 + .../FinancialInstitutionContactAndAddress.cs | 12 + .../Client/V1/Models/Request/FixedValue.cs | 12 + .../V1/Models/Request/HazardousCommodity.cs | 18 ++ .../V1/Models/Request/HoldAtLocationDetail.cs | 15 ++ .../Request/HomeDeliveryPremiumDetail.cs | 15 ++ .../V1/Models/Request/InnerReceptacle.cs | 9 + .../InternationalControlledExportDetail.cs | 9 + ...rnationalTrafficInArmsRegulationsDetail.cs | 9 + .../Client/V1/Models/Request/Locale.cs | 12 + .../Request/LocationContactAndAddress.cs | 12 + .../Client/V1/Models/Request/Options.cs | 12 + .../V1/Models/Request/OptionsRequested.cs | 9 + .../V1/Models/Request/PackageCODDetail.cs | 12 + .../Models/Request/PackageSpecialServices.cs | 30 +++ .../Client/V1/Models/Request/Packaging.cs | 12 + .../V1/Models/Request/PackingDetails.cs | 12 + .../Client/V1/Models/Request/Payor.cs | 9 + .../Models/Request/PendingShipmentDetail.cs | 27 ++ .../Client/V1/Models/Request/PhoneNumber.cs | 21 ++ .../V1/Models/Request/PrintedReference.cs | 12 + .../V1/Models/Request/ProcessingOptions.cs | 9 + .../Client/V1/Models/Request/Quantity.cs | 15 ++ .../Request/RateRequestControlParameters.cs | 18 ++ .../Client/V1/Models/Request/Recipient.cs | 15 ++ .../Client/V1/Models/Request/Recipient2.cs | 33 +++ .../RecommendedDocumentSpecification.cs | 9 + .../Client/V1/Models/Request/RequestRoot.cs | 21 ++ .../Request/RequestedPackageLineItem.cs | 30 +++ .../V1/Models/Request/RequestedShipment.cs | 69 +++++ .../V1/Models/Request/ResponsibleParty.cs | 15 ++ .../V1/Models/Request/ReturnShipmentDetail.cs | 9 + .../V1/Models/Request/ServiceTypeDetail.cs | 18 ++ .../V1/Models/Request/ShipmentCODDetail.cs | 24 ++ .../V1/Models/Request/ShipmentDryIceDetail.cs | 12 + .../Models/Request/ShipmentSpecialServices.cs | 36 +++ .../Client/V1/Models/Request/Shipper.cs | 9 + .../V1/Models/Request/SmartPostInfoDetail.cs | 18 ++ .../Client/V1/Models/Request/SmsDetail.cs | 12 + .../Client/V1/Models/Request/TotalWeight.cs | 12 + .../Client/V1/Models/Request/UnitPrice.cs | 12 + .../Request/VariableHandlingChargeDetail.cs | 21 ++ .../Client/V1/Models/Request/Weight.cs | 12 + .../Client/V1/Models/Response/Alert.cs | 15 ++ .../V1/Models/Response/BillingWeight.cs | 12 + .../Client/V1/Models/Response/Commit.cs | 9 + .../Models/Response/CurrencyExchangeRate.cs | 15 ++ .../V1/Models/Response/CustomerMessage.cs | 12 + .../Client/V1/Models/Response/DateDetail.cs | 12 + .../Client/V1/Models/Response/Name.cs | 15 ++ .../V1/Models/Response/OperationalDetail.cs | 93 +++++++ .../Client/V1/Models/Response/Output.cs | 18 ++ .../V1/Models/Response/PackageRateDetail.cs | 45 ++++ .../V1/Models/Response/RateReplyDetail.cs | 36 +++ .../Client/V1/Models/Response/RatedPackage.cs | 58 +++++ .../V1/Models/Response/RatedShipmentDetail.cs | 64 +++++ .../Client/V1/Models/Response/ResponseRoot.cs | 20 ++ .../V1/Models/Response/ServiceDescription.cs | 30 +++ .../V1/Models/Response/ShipmentRateDetail.cs | 36 +++ .../Client/V1/Models/Response/SurCharge.cs | 18 ++ .../V1/Models/Response/TotalBillingWeight.cs | 12 + .../FedExRatesServiceCollectionExtensions.cs | 38 ++- .../EasyKeys.Shipping.FedEx.Rates.csproj | 2 +- .../FedExRateConfigurator.cs | 2 +- .../RestApi/Impl/FedexRateProvider.cs | 145 +++++++++++ .../Extensions/PackageExtensions.cs | 2 +- .../Extensions/RateAddressExtensions.cs | 2 +- .../RateRequestedShipmentExtensions.cs | 2 +- .../Impl}/FedExRateProvider.cs | 4 +- ...loadDocumentServiceCollectionExtensions.cs | 2 +- .../FedExDocumentProvider.cs | 4 +- .../Services/Impl/StampsClientService.cs | 1 - .../IStampsShipmentProvider.cs | 2 - .../UspsRateProvider.cs | 16 +- ...UspsTrackingServiceCollectionExtensions.cs | 4 +- .../Models/TrackFieldRequest.cs | 3 +- .../Models/TrackInfo.cs | 3 +- .../Models/TrackRequest.cs | 3 +- .../Models/TrackResponse.cs | 3 +- .../UspsTrackingClient.cs | 4 +- src/Minimal.Apis/Program.cs | 10 +- .../FedExAddressValidationProviderTests.cs | 237 +++++++++--------- .../FedEx/FedExRateProviderTests.cs | 217 +++++++++------- .../FedEx/FedExShipmentProviderTests.cs | 5 +- .../FedEx/FedExUploadDocumentProviderTests.cs | 12 +- .../Stamps/StampsShipmentProviderTests.cs | 2 +- .../TestHelpers/ServiceProviderInstance.cs | 11 +- .../Usps/UspsRateProviderTests.cs | 5 +- 153 files changed, 2847 insertions(+), 627 deletions(-) delete mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/IFedexAuthClient.cs rename src/EasyKeys.Shipping.FedEx.Abstractions/{Api => Client}/V1/Auth/Impl/FedExAuthClient.cs (83%) rename src/EasyKeys.Shipping.FedEx.Abstractions/{Api => Client}/V1/Auth/Models/TokenResponse.cs (100%) rename src/EasyKeys.Shipping.FedEx.Abstractions/{Api => }/Middleware/AuthRequestMiddleware.cs (53%) create mode 100644 src/EasyKeys.Shipping.FedEx.Abstractions/Models/ApiError.cs delete mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs delete mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs delete mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs delete mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/IFedexAddressValidationClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Impl/FedExAddressValidationClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/Address.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/AddressToValidate.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/RequestRoot.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/ValidateAddressControlParameters.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Alert.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/CustomerMessage.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Output.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ParsedPostalCode.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolutionToken.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolvedAddress.cs create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResponseRoot.cs rename src/EasyKeys.Shipping.FedEx.AddressValidation/{WebServices => }/IFedExAddressValidationProvider.cs (51%) create mode 100644 src/EasyKeys.Shipping.FedEx.AddressValidation/RestApi/Impl/FedExAddressValidationProvider.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/IFedexRatesAndTransitTimesApiClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Impl/FedexRatesAndTransitTimesApiClient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AccountNumber.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AddTransportationChargesDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Address.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AlcoholDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BatteryDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker2.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BrokerAddress.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodCollectionAmount.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodRecipient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CommercialInvoice.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Commodity.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Contact.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Container.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ContentRecord.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsClearanceDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsValue.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DangerousGoodsDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeclaredValue.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeliveryOnInvoiceAcceptanceDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Description.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Dimensions.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DocumentReference.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DryIceWeight.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DutiesPayment.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailLabelDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailNotificationDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmergencyContactNumber.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ExpressFreightDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FinancialInstitutionContactAndAddress.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FixedValue.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HazardousCommodity.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HoldAtLocationDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HomeDeliveryPremiumDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InnerReceptacle.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalControlledExportDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalTrafficInArmsRegulationsDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Locale.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/LocationContactAndAddress.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Options.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/OptionsRequested.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageCODDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageSpecialServices.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Packaging.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackingDetails.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Payor.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PendingShipmentDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PhoneNumber.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PrintedReference.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ProcessingOptions.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Quantity.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RateRequestControlParameters.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient2.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RecommendedDocumentSpecification.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestRoot.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedPackageLineItem.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedShipment.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ResponsibleParty.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ReturnShipmentDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ServiceTypeDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentCODDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentDryIceDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentSpecialServices.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Shipper.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmartPostInfoDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmsDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/TotalWeight.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/UnitPrice.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/VariableHandlingChargeDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Weight.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Alert.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/BillingWeight.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Commit.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CurrencyExchangeRate.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CustomerMessage.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/DateDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Name.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/OperationalDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Output.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/PackageRateDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RateReplyDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedPackage.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedShipmentDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ResponseRoot.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ServiceDescription.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ShipmentRateDetail.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/SurCharge.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/TotalBillingWeight.cs create mode 100644 src/EasyKeys.Shipping.FedEx.Rates/RestApi/Impl/FedexRateProvider.cs rename src/EasyKeys.Shipping.FedEx.Rates/{ => WebServices}/Extensions/PackageExtensions.cs (96%) rename src/EasyKeys.Shipping.FedEx.Rates/{ => WebServices}/Extensions/RateAddressExtensions.cs (95%) rename src/EasyKeys.Shipping.FedEx.Rates/{ => WebServices}/Extensions/RateRequestedShipmentExtensions.cs (94%) rename src/EasyKeys.Shipping.FedEx.Rates/{ => WebServices/Impl}/FedExRateProvider.cs (99%) diff --git a/.editorconfig b/.editorconfig index 32a7ca5..be35dfb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,68 @@ dotnet_diagnostic.SA1300.severity = silent # SA1117: Parameters should be on same line or separate lines dotnet_diagnostic.SA1117.severity = suggestion +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:warning +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:warning +csharp_style_expression_bodied_constructors = false:warning +csharp_style_expression_bodied_operators = true:warning +csharp_indent_labels = no_change +csharp_style_expression_bodied_properties = true:warning +csharp_space_around_binary_operators = before_and_after + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = lf diff --git a/build/settings.props b/build/settings.props index 4752d16..1ce7b14 100644 --- a/build/settings.props +++ b/build/settings.props @@ -4,7 +4,7 @@ 3.0.0-preview1 false true - $(NoWarn);CS1591;NU1605;DS126858;DS137138 + $(NoWarn);CS1591;NU1605;DS126858;DS137138;SA1010;SA1011 diff --git a/src/EasyKeys.Shipping.Abstractions/IAddressValidationProvider.cs b/src/EasyKeys.Shipping.Abstractions/IAddressValidationProvider.cs index 3c0a4f0..a492a13 100644 --- a/src/EasyKeys.Shipping.Abstractions/IAddressValidationProvider.cs +++ b/src/EasyKeys.Shipping.Abstractions/IAddressValidationProvider.cs @@ -15,5 +15,5 @@ public interface IAddressValidationProvider /// /// /// - Task ValidateAddressAsync(ValidateAddress validateAddress, CancellationToken cancellationToken); + Task ValidateAddressAsync(ValidateAddress validateAddress, CancellationToken cancellationToken = default); } diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs deleted file mode 100644 index 5b8710b..0000000 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/IFedexAuthClient.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; - -namespace EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; - -public interface IFedExAuthClient -{ - Task GetTokenAsync(); -} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/IFedexAuthClient.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/IFedexAuthClient.cs new file mode 100644 index 0000000..a3a040c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/IFedexAuthClient.cs @@ -0,0 +1,15 @@ +namespace EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; + +/// +/// Implmentation of the FedEx Rates and Transit Times client. Can be used to get rates and transit times. +/// . +/// +public interface IFedExAuthClient +{ + /// + /// Gets the authentication token asynchronously. + /// + /// The cancellation token. + /// The authentication token. + Task GetTokenAsync(CancellationToken cancellationToken = default); +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/Impl/FedExAuthClient.cs similarity index 83% rename from src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs rename to src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/Impl/FedExAuthClient.cs index dd1d761..dac9220 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Impl/FedExAuthClient.cs +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/Impl/FedExAuthClient.cs @@ -1,7 +1,6 @@ using System.Collections.Concurrent; using System.Net.Http.Json; -using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Models; using EasyKeys.Shipping.FedEx.Abstractions.Options; @@ -28,7 +27,7 @@ public class FedExAuthClient : IFedExAuthClient _logger = logger; } - public async Task GetTokenAsync() + public async Task GetTokenAsync(CancellationToken cancellationToken = default) { try { @@ -43,16 +42,19 @@ public async Task GetTokenAsync() _logger.LogDebug("Token being requested."); // Send a POST request to FedEx's token endpoint - var response = await _httpClient.PostAsync($"{_options.Url}oauth/token", new FormUrlEncodedContent(new Dictionary + var response = await _httpClient.PostAsync( + $"{_options.Url}oauth/token", + new FormUrlEncodedContent(new Dictionary { { "client_id", _options.ClientId }, { "client_secret", _options.ClientSecret }, { "grant_type", "client_credentials" } - })); + }), + cancellationToken); response.EnsureSuccessStatusCode(); - var tokenObj = await response.Content.ReadFromJsonAsync(); + var tokenObj = await response.Content.ReadFromJsonAsync(cancellationToken); ArgumentNullException.ThrowIfNull(tokenObj, nameof(TokenResponse)); @@ -61,13 +63,13 @@ public async Task GetTokenAsync() _token.AddOrUpdate(nameof(TokenResponse), tokenObj.Token, (x, y) => tokenObj.Token); _expirationClock.AddOrUpdate(nameof(_expirationClock), (x) => DateTimeOffset.Now.AddSeconds(tokenObj.ExpiresIn - 5), (x, y) => y.AddSeconds(tokenObj.ExpiresIn - 5)); + + return tokenObj.Token; } catch (Exception ex) { _logger.LogError(ex.Message); + return string.Empty; } - - _token.TryGetValue(nameof(TokenResponse), out var token); - return token; } } diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/Models/TokenResponse.cs similarity index 100% rename from src/EasyKeys.Shipping.FedEx.Abstractions/Api/V1/Auth/Models/TokenResponse.cs rename to src/EasyKeys.Shipping.FedEx.Abstractions/Client/V1/Auth/Models/TokenResponse.cs diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs index 4f38eb7..ae707e1 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/DependencyInjection/FedExServiceCollectionExtensions.cs @@ -1,6 +1,6 @@ -using EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; -using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth.Impl; +using EasyKeys.Shipping.FedEx.Abstractions.Middleware; using EasyKeys.Shipping.FedEx.Abstractions.Options; using EasyKeys.Shipping.FedEx.Abstractions.Services; using EasyKeys.Shipping.FedEx.Abstractions.Services.Impl; @@ -31,7 +31,7 @@ public static class FedExServiceCollectionExtensions } /// - /// Adds FedEx Api Client Service with configuration options . + /// Adds and with configuration options . /// /// The DI services. /// The section name for the options. diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Middleware/AuthRequestMiddleware.cs similarity index 53% rename from src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs rename to src/EasyKeys.Shipping.FedEx.Abstractions/Middleware/AuthRequestMiddleware.cs index 6acde94..89bda9d 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/Api/Middleware/AuthRequestMiddleware.cs +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Middleware/AuthRequestMiddleware.cs @@ -1,15 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.IO.Compression; +using System.Net; using System.Text; -using System.Text.Json; -using System.Threading.Tasks; using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; using Microsoft.Extensions.Logging; -namespace EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; +namespace EasyKeys.Shipping.FedEx.Abstractions.Middleware; + +/// +/// Middleware class that intercepts fedex api HTTP requests and performs authentication before forwarding them to the server. +/// public class AuthRequestMiddleware : DelegatingHandler { private readonly IFedExAuthClient _authClient; @@ -31,18 +32,30 @@ protected override async Task SendAsync(HttpRequestMessage // Perform any custom logic here before the request is sent _logger.LogDebug($"Intercepted request to {request.RequestUri}"); - var token = await _authClient.GetTokenAsync(); + var token = await _authClient.GetTokenAsync(cancellationToken); request.Headers.Add("Authorization", token); // Call the base SendAsync method to continue processing the request response = await base.SendAsync(request, cancellationToken); - response.EnsureSuccessStatusCode(); + if (response.Content.Headers.ContentEncoding.Contains("gzip") && response.IsSuccessStatusCode is not true) + { + using var responseStream = await response.Content.ReadAsStreamAsync(); + using var decompressionStream = new GZipStream(responseStream, CompressionMode.Decompress); + using var decompressedStream = new StreamReader(decompressionStream); + var decompressedString = await decompressedStream.ReadToEndAsync(); + throw new Exception(decompressedString); + } } catch (Exception ex) { _logger.LogError(ex.Message); + return new HttpResponseMessage + { + Content = new StringContent(ex.Message, Encoding.UTF8, "application/json"), + StatusCode = HttpStatusCode.BadRequest + }; } return response; diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Models/ApiError.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Models/ApiError.cs new file mode 100644 index 0000000..34bf4f4 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Models/ApiError.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Models; +public class ApiError +{ + [JsonPropertyName("code")] + public string Code { get; set; } = string.Empty; + + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs b/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs index 16d0909..c3db705 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/Options/FedExApiOptions.cs @@ -1,12 +1,19 @@ -namespace EasyKeys.Shipping.FedEx.Abstractions.Options; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Abstractions.Options; public class FedExApiOptions { - public string Url => IsDevelopment ? "https://apis-sandbox.fedex.com/" : "https://apis-sandbox.fedex.com/"; + public string Url => IsDevelopment ? "https://apis-sandbox.fedex.com/" : "https://apis.fedex.com/"; public string ClientId { get; set; } = string.Empty; public string ClientSecret { get; set; } = string.Empty; - + + public string FedExAccountNumber { get; set; } = string.Empty; + public bool IsDevelopment { get; set; } + + public JsonSerializerOptions JsonSerializerOptions { get; set; } = new() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; } diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/README.md b/src/EasyKeys.Shipping.FedEx.Abstractions/README.md index f533be4..34d9bb3 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/README.md +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/README.md @@ -5,7 +5,7 @@ ![Nuget](https://img.shields.io/nuget/dt/EasyKeys.Shipping.FedEx.Abstractions) [![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https://f.feedz.io/easykeys/core/shield/EasyKeys.Shipping.FedEx.Abstractions/latest)](https://f.feedz.io/easykeys/core/packages/EasyKeys.Shipping.FedEx.Abstractions/latest/download) -This library provides abstractions for options, models and wsdls generated contracts. +This library provides abstractions for fedex options, models, fedex auth api client and wsdls generated contracts. ## Give a Star! :star: diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs deleted file mode 100644 index 7b145ad..0000000 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/IFedExAddressValidationApiClient.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using EasyKeys.Shipping.Abstractions.Models; - -namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; - -/// -/// This validates recipient address information and identifies it as either business or residential.Uses Fedex REST Api Address Validation Client V1. -/// -public interface IFedExAddressValidationApiClient -{ - /// - /// Validates USA based address and other countries, please refer to the manual. - /// - /// - /// - /// - Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken = default); -} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs deleted file mode 100644 index 36e16f6..0000000 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Impl/FedExAddressValidationApiClient.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System.Diagnostics; -using System.Net.Http.Json; - -using EasyKeys.Shipping.Abstractions; -using EasyKeys.Shipping.Abstractions.Models; -using EasyKeys.Shipping.FedEx.Abstractions.Options; -using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; -using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Impl; -public class FedExAddressValidationApiClient : IFedExAddressValidationApiClient, IAddressValidationProvider -{ - private readonly HttpClient _client; - private readonly FedExApiOptions _options; - private readonly ILogger _logger; - - public FedExAddressValidationApiClient( - HttpClient client, - IOptionsMonitor optionsMonitor, - ILogger logger) - { - _options = optionsMonitor.CurrentValue; - _client = client; - _logger = logger; - } - - public string Name => nameof(FedExAddressValidationApiClient); - - public async Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken) - { - var watch = ValueStopwatch.StartNew(); - - try - { - var apiRequest = new AddressValidationRequest - { - InEffectAsOfTimestamp = "2019-09-06", - ValidateAddressControlParameters = new ValidateAddressControlParameters - { - IncludeResolutionTokens = true - }, - AddressesToValidate = new List - { - new AddressToValidate - { - Address = new Models.Address - { - StreetLines = request.OriginalAddress.GetStreetLines(), - City = request.OriginalAddress.City, - StateOrProvinceCode = request.OriginalAddress.StateOrProvince, - PostalCode = request.OriginalAddress.PostalCode, - CountryCode = request.OriginalAddress.CountryCode - }, - ClientReferenceId = request.Id - } - } - }; - var result = await _client.PostAsJsonAsync($"{_options.Url}address/v1/addresses/resolve", apiRequest, cancellationToken); - - result.EnsureSuccessStatusCode(); - - var content = await result.Content.ReadAsStringAsync(cancellationToken); - - var response = await result.Content.ReadFromJsonAsync(cancellationToken); - - ArgumentNullException.ThrowIfNull(response); - - var lines = response.Output.ResolvedAddresses.FirstOrDefault()?.StreetLinesToken ?? [string.Empty]; - var address1 = lines.FirstOrDefault() ?? string.Empty; - var address2 = lines.Length > 1 ? lines[1] : string.Empty; - - request.ProposedAddress = new Shipping.Abstractions.Models.Address( - address1, - address2, - response.Output.ResolvedAddresses.FirstOrDefault()?.CityToken?.FirstOrDefault()?.Value ?? string.Empty, - response.Output.ResolvedAddresses.FirstOrDefault()?.StateOrProvinceCode ?? string.Empty, - response.Output.ResolvedAddresses.FirstOrDefault()?.PostalCodeToken.Value ?? string.Empty, - response.Output.ResolvedAddresses.FirstOrDefault()?.CountryCode ?? string.Empty, - response.Output.ResolvedAddresses.FirstOrDefault()?.Classification == "RESIDENTIAL"); - - if (lines.Length == 2) - { - request.ProposedAddress.StreetLine2 = lines[1]; - } - - foreach (var a in response.Output.ResolvedAddresses[0].Attributes) - { - if (!request.ValidationBag.ContainsKey(a.Key)) - { - request.ValidationBag.Add(a.Key, a.Value?.ToString() ?? string.Empty); - } - } - - if (response.Output.Alerts != null) - { - foreach (var notification in response.Output.Alerts) - { - request.Errors.Add(new Error - { - Source = notification.AlertType, - Number = notification.Code, - Description = notification.Message - }); - } - - _logger.LogWarning("{providerName} alerts: {errors} ", nameof(FedExAddressValidationApiClient), request.Errors.Select(x => x.Description).Flatten(",")); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "{providerName} failed", nameof(FedExAddressValidationApiClient)); - request.InternalErrors.Add(ex?.Message ?? $"{nameof(FedExAddressValidationApiClient)} failed"); - } - - _logger.LogDebug("[FedEx][ValidateAddressAsync] completed: {mil}", watch.GetElapsedTime().TotalMilliseconds); - return request; - } -} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs deleted file mode 100644 index d8f17d7..0000000 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; -internal class AddressValidationRequest -{ - public string InEffectAsOfTimestamp { get; set; } = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); - - public ValidateAddressControlParameters ValidateAddressControlParameters { get; set; } = new(); - - public List AddressesToValidate { get; set; } = new(); -} - -internal class ValidateAddressControlParameters -{ - public bool IncludeResolutionTokens { get; set; } = true; -} - -internal class AddressToValidate -{ - public Address Address { get; set; } = new(); - - public string ClientReferenceId { get; set; } = Guid.NewGuid().ToString(); -} - -internal class Address -{ - public string[] StreetLines { get; set; } = Array.Empty(); - - public string City { get; set; } = string.Empty; - - public string StateOrProvinceCode { get; set; } = string.Empty; - - public string PostalCode { get; set; } = string.Empty; - - public string CountryCode { get; set; } = string.Empty; -} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs deleted file mode 100644 index 59fc714..0000000 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/Api/V1/Models/AddressValidationResponse.cs +++ /dev/null @@ -1,113 +0,0 @@ -namespace EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Models; - -internal class AddressValidationResponse -{ - public string TransactionId { get; set; } - - public string CustomerTransactionId { get; set; } - - public Output Output { get; set; } - - public bool IsValidAddress() - { - if (Output == null || Output.ResolvedAddresses == null) - return false; - - foreach (var address in Output.ResolvedAddresses) - { - // Checking primary validation criteria - var isStandardized = address.Attributes.TryGetValue("AddressType", out var addressType) && addressType.ToString() == "STANDARDIZED"; - var isDPVTrue = address.Attributes.TryGetValue("DPV", out var dpv) && dpv.ToString() == "true"; - var isInterpolated = address.Attributes.TryGetValue("InterpolatedStreetAddress", out var interpolated) && interpolated.ToString() == "true"; - - // Check for specific customer message indicating invalidity - var hasInvalidCustomerMessage = address.CustomerMessage?.Any(cm => cm.Value == "INTERPOLATED.STREET.ADDRESS") ?? false; - - // Check if additional validation attributes meet the required conditions - var buildingValidated = address.Attributes.TryGetValue("BuildingValidated", out var buildingValid) && buildingValid.ToString() == "true"; - var postalValidated = address.Attributes.TryGetValue("PostalValidated", out var postalValid) && postalValid.ToString() == "true"; - - // Final validation logic - if (isStandardized && isDPVTrue && !isInterpolated && !hasInvalidCustomerMessage) - { - return true; - } - } - - return false; - } -} - -internal class Output -{ - public List ResolvedAddresses { get; set; } - - public List Alerts { get; set; } -} - -internal class ResolvedAddress -{ - public string[] StreetLinesToken { get; set; } - - public string City { get; set; } - - public string StateOrProvinceCode { get; set; } - - public string CountryCode { get; set; } - - public List? CustomerMessage { get; set; } - - public List CityToken { get; set; } - - public ResolutionToken PostalCodeToken { get; set; } - - public ParsedPostalCode ParsedPostalCode { get; set; } - - public string Classification { get; set; } - - public bool PostOfficeBox { get; set; } - - public bool NormalizedStatusNameDPV { get; set; } - - public string StandardizedStatusNameMatchSource { get; set; } - - public string ResolutionMethodName { get; set; } - - public bool RuralRouteHighwayContract { get; set; } - - public bool GeneralDelivery { get; set; } - - public Dictionary Attributes { get; set; } -} - -internal class CustomerMessage -{ - public bool Changed { get; set; } - - public string Value { get; set; } -} - -internal class ResolutionToken -{ - public bool Changed { get; set; } - - public string Value { get; set; } -} - -internal class ParsedPostalCode -{ - public string Base { get; set; } - - public string AddOn { get; set; } - - public string DeliveryPoint { get; set; } -} - -internal class Alert -{ - public string Code { get; set; } - - public string Message { get; set; } - - public string AlertType { get; set; } -} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/IFedexAddressValidationClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/IFedexAddressValidationClient.cs new file mode 100644 index 0000000..d367135 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/IFedexAddressValidationClient.cs @@ -0,0 +1,19 @@ +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1; + +/// +/// Implmentation of the FedEx Address Validation Client. +/// . +/// +public interface IFedexAddressValidationClient +{ + /// + /// Validates an address asynchronously. + /// + /// The address validation request. + /// The cancellation token. + /// The address validation response. + Task ValidateAddressAsync(RequestRoot request, CancellationToken cancellationToken = default); +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Impl/FedExAddressValidationClient.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Impl/FedExAddressValidationClient.cs new file mode 100644 index 0000000..d6cd3fd --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Impl/FedExAddressValidationClient.cs @@ -0,0 +1,47 @@ +using System.Net.Http.Json; +using EasyKeys.Shipping.FedEx.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Impl; + +public class FedExAddressValidationClient : IFedexAddressValidationClient +{ + private readonly HttpClient _client; + private readonly FedExApiOptions _options; + private ILogger _logger; + + public FedExAddressValidationClient( + IOptionsMonitor optionsMonitor, + ILogger logger, + HttpClient client) + { + _options = optionsMonitor.CurrentValue; + _logger = logger; + _client = client; + } + + public async Task ValidateAddressAsync(RequestRoot request, CancellationToken cancellationToken = default) + { + try + { + var result = await _client.PostAsJsonAsync($"{_options.Url}address/v1/addresses/resolve", request, _options.JsonSerializerOptions, cancellationToken); + + var content = await result.Content.ReadAsStringAsync(cancellationToken); + + var resultObject = await result.Content.ReadFromJsonAsync(_options.JsonSerializerOptions, cancellationToken); + + ArgumentNullException.ThrowIfNull(resultObject, nameof(ResponseRoot)); + + return resultObject; + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return new ResponseRoot { Errors = { new ApiError { Message = ex.Message } } }; + } + } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/Address.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/Address.cs new file mode 100644 index 0000000..a432004 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/Address.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; + +public class Address +{ + [JsonPropertyName("streetLines")] + public string[]? StreetLines { get; set; } + + [JsonPropertyName("city")] + public string? City { get; set; } + + [JsonPropertyName("stateOrProvinceCode")] + public string? StateOrProvinceCode { get; set; } + + [JsonPropertyName("postalCode")] + required public string PostalCode { get; set; } + + [JsonPropertyName("countryCode")] + required public string CountryCode { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/AddressToValidate.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/AddressToValidate.cs new file mode 100644 index 0000000..4ff686c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/AddressToValidate.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; + +public class AddressesToValidate +{ + [JsonPropertyName("address")] + required public Address Address { get; set; } + + [JsonPropertyName("clientReferenceId")] + public string? ClientReferenceId { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/RequestRoot.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/RequestRoot.cs new file mode 100644 index 0000000..73c5298 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/RequestRoot.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; +public class RequestRoot +{ + [JsonPropertyName("inEffectAsOfTimestamp")] + public string? InEffectAsOfTimestamp { get; set; } + + [JsonPropertyName("validateAddressControlParameters")] + public ValidateAddressControlParameters? ValidateAddressControlParameters { get; set; } + + [JsonPropertyName("addressesToValidate")] + required public List AddressesToValidate { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/ValidateAddressControlParameters.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/ValidateAddressControlParameters.cs new file mode 100644 index 0000000..79370fb --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Request/ValidateAddressControlParameters.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; + +public class ValidateAddressControlParameters +{ + [JsonPropertyName("includeResolutionTokens")] + public bool? IncludeResolutionTokens { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Alert.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Alert.cs new file mode 100644 index 0000000..e8a7632 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Alert.cs @@ -0,0 +1,10 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class Alert +{ + public string Code { get; set; } = string.Empty; + + public string Message { get; set; } = string.Empty; + + public string AlertType { get; set; } = string.Empty; +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/CustomerMessage.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/CustomerMessage.cs new file mode 100644 index 0000000..8d4b1cf --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/CustomerMessage.cs @@ -0,0 +1,8 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class CustomerMessage +{ + public bool Changed { get; set; } + + public string Value { get; set; } = string.Empty; +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Output.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Output.cs new file mode 100644 index 0000000..78c992f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/Output.cs @@ -0,0 +1,8 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class Output +{ + public List? ResolvedAddresses { get; set; } + + public List? Alerts { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ParsedPostalCode.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ParsedPostalCode.cs new file mode 100644 index 0000000..048139f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ParsedPostalCode.cs @@ -0,0 +1,10 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class ParsedPostalCode +{ + public string? Base { get; set; } + + public string? AddOn { get; set; } + + public string? DeliveryPoint { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolutionToken.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolutionToken.cs new file mode 100644 index 0000000..41f4956 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolutionToken.cs @@ -0,0 +1,8 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class ResolutionToken +{ + public bool Changed { get; set; } + + public string? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolvedAddress.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolvedAddress.cs new file mode 100644 index 0000000..49ee1fc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResolvedAddress.cs @@ -0,0 +1,36 @@ +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class ResolvedAddress +{ + public string[]? StreetLinesToken { get; set; } + + public string? City { get; set; } + + public string? StateOrProvinceCode { get; set; } + + public string? CountryCode { get; set; } + + public List? CustomerMessage { get; set; } + + public List? CityToken { get; set; } + + public ResolutionToken? PostalCodeToken { get; set; } + + public ParsedPostalCode? ParsedPostalCode { get; set; } + + public string? Classification { get; set; } + + public bool PostOfficeBox { get; set; } + + public bool NormalizedStatusNameDPV { get; set; } + + public string? StandardizedStatusNameMatchSource { get; set; } + + public string? ResolutionMethodName { get; set; } + + public bool RuralRouteHighwayContract { get; set; } + + public bool GeneralDelivery { get; set; } + + public Dictionary Attributes { get; set; } = new (); +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResponseRoot.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResponseRoot.cs new file mode 100644 index 0000000..fd4171c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/Client/V1/Models/Response/ResponseRoot.cs @@ -0,0 +1,51 @@ +using System.Text.Json.Serialization; + +using EasyKeys.Shipping.FedEx.Abstractions.Models; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Response; + +public class ResponseRoot +{ + [JsonPropertyName("transactionId")] + public string? TransactionId { get; set; } + + [JsonPropertyName("customerTransactionId")] + public string? CustomerTransactionId { get; set; } + + [JsonPropertyName("output")] + public Output? Output { get; set; } + + [JsonPropertyName("errors")] + public List Errors { get; set; } = new (); + + public bool IsValidAddress() + { + if (Output == null || Output.ResolvedAddresses == null) + { + return false; + } + + foreach (var address in Output.ResolvedAddresses) + { + // Checking primary validation criteria + var isStandardized = address.Attributes.TryGetValue("AddressType", out var addressType) && addressType.ToString() == "STANDARDIZED"; + var isDPVTrue = address.Attributes.TryGetValue("DPV", out var dpv) && dpv.ToString() == "true"; + var isInterpolated = address.Attributes.TryGetValue("InterpolatedStreetAddress", out var interpolated) && interpolated.ToString() == "true"; + + // Check for specific customer message indicating invalidity + var hasInvalidCustomerMessage = address.CustomerMessage?.Any(cm => cm.Value == "INTERPOLATED.STREET.ADDRESS") ?? false; + + // Check if additional validation attributes meet the required conditions + var buildingValidated = address.Attributes.TryGetValue("BuildingValidated", out var buildingValid) && buildingValid.ToString() == "true"; + var postalValidated = address.Attributes.TryGetValue("PostalValidated", out var postalValid) && postalValid.ToString() == "true"; + + // Final validation logic + if (isStandardized && isDPVTrue && !isInterpolated && !hasInvalidCustomerMessage) + { + return true; + } + } + + return false; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs index 5456b7e..9b6338c 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/DependencyInjection/AddressValidationServiceExtensions.cs @@ -1,10 +1,10 @@ using EasyKeys.Shipping.Abstractions; -using EasyKeys.Shipping.FedEx.Abstractions.Api.Middleware; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; +using EasyKeys.Shipping.FedEx.Abstractions.Middleware; using EasyKeys.Shipping.FedEx.Abstractions.Options; -using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; -using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1.Impl; -using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; -using EasyKeys.Shipping.FedEx.AddressValidation.WebServices.Impl; +using EasyKeys.Shipping.FedEx.AddressValidation; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Impl; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -13,14 +13,15 @@ namespace Microsoft.Extensions.DependencyInjection; public static class AddressValidationServiceExtensions { /// - /// Adds - /// and also instance to the DI container. + /// Adds that uses Web Services + /// and also instance to the DI container.
+ /// Caution: FedEx Web Services Tracking, Address Validation, and Validate Postal Codes WSDLS will be disabled on August 31, 2024. The SOAP based FedEx Web Services is in development containment and has been replaced with FedEx RESTful APIs. To learn more and upgrade your integration from Web Services to FedEx APIs, please visit the FedEx Developer Portal. ///
/// The DI services. /// The section name for the configuration. The default is . /// The configuration for the . The default is null. /// - public static IServiceCollection AddFedExAddressValidation( + public static IServiceCollection AddWebServicesFedExAddressValidation( this IServiceCollection services, string sectionName = nameof(FedExOptions), Action? configOptions = null) @@ -33,14 +34,22 @@ public static class AddressValidationServiceExtensions services.AddFedExClient(); - services.TryAddTransient(); + services.TryAddTransient(); - services.AddTransient(); + services.AddTransient(); return services; } - public static IServiceCollection AddFedExAddressValidationApiV1( + /// + /// Adds ,, + /// and with configuration options . + /// + /// + /// + /// + /// + public static IServiceCollection AddRestApiFedExAddressValidation( this IServiceCollection services, string sectionName = nameof(FedExApiOptions), Action? configOptions = null) @@ -53,10 +62,12 @@ public static class AddressValidationServiceExtensions services.AddFedExAuthApiClient(); - services.AddHttpClient() + services.AddHttpClient() .AddHttpMessageHandler(); - services.AddTransient(); + services.AddTransient(); + + services.AddTransient(); return services; } diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs similarity index 51% rename from src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs rename to src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs index 606adf0..6c8b514 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/IFedExAddressValidationProvider.cs +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/IFedExAddressValidationProvider.cs @@ -1,10 +1,7 @@ using EasyKeys.Shipping.Abstractions.Models; -namespace EasyKeys.Shipping.FedEx.AddressValidation.WebServices; +namespace EasyKeys.Shipping.FedEx.AddressValidation; -/// -/// Caution: FedEx Web Services Tracking, Address Validation, and Validate Postal Codes WSDLS will be disabled on August 31, 2024. The SOAP based FedEx Web Services is in development containment and has been replaced with FedEx RESTful APIs. To learn more and upgrade your integration from Web Services to FedEx APIs, please visit the FedEx Developer Portal. -/// public interface IFedExAddressValidationProvider { /// diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/RestApi/Impl/FedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/RestApi/Impl/FedExAddressValidationProvider.cs new file mode 100644 index 0000000..ec0f6ee --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/RestApi/Impl/FedExAddressValidationProvider.cs @@ -0,0 +1,132 @@ +using System.Diagnostics; + +using EasyKeys.Shipping.Abstractions; +using EasyKeys.Shipping.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1; +using EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +using Address = EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request.Address; +using AddressToValidate = EasyKeys.Shipping.FedEx.AddressValidation.Client.V1.Models.Request.AddressesToValidate; + +namespace EasyKeys.Shipping.FedEx.AddressValidation.RestApi.Impl; + +/// +/// This validates recipient address information and identifies it as either business or residential.Uses Fedex REST Api Address Validation Client V1. +/// +public class FedExAddressValidationProvider : IFedExAddressValidationProvider, IAddressValidationProvider +{ + private readonly IFedexAddressValidationClient _client; + private readonly FedExApiOptions _options; + private readonly ILogger _logger; + + public FedExAddressValidationProvider( + IFedexAddressValidationClient client, + IOptionsMonitor optionsMonitor, + ILogger logger) + { + _options = optionsMonitor.CurrentValue; + _client = client; + _logger = logger; + } + + public string Name => nameof(FedExAddressValidationProvider); + + public async Task ValidateAddressAsync(ValidateAddress request, CancellationToken cancellationToken = default) + { + var watch = ValueStopwatch.StartNew(); + + try + { + var apiRequest = new RequestRoot + { + InEffectAsOfTimestamp = "2019-09-06", + ValidateAddressControlParameters = new ValidateAddressControlParameters + { + IncludeResolutionTokens = true + }, + AddressesToValidate = new List + { + new AddressToValidate + { + Address = new Address + { + StreetLines = request.OriginalAddress.GetStreetLines(), + City = request.OriginalAddress.City, + StateOrProvinceCode = request.OriginalAddress.StateOrProvince, + PostalCode = request.OriginalAddress.PostalCode, + CountryCode = request.OriginalAddress.CountryCode + }, + ClientReferenceId = request.Id + } + } + }; + var response = await _client.ValidateAddressAsync(apiRequest, cancellationToken); + + foreach (var error in response.Errors) + { + request.Errors.Add(new Error + { + Description = error.Message + }); + } + + if (request.Errors.Any() || response.Output == null) + { + return request; + } + + var lines = response.Output.ResolvedAddresses?.FirstOrDefault()?.StreetLinesToken ?? [string.Empty]; + var address1 = lines.FirstOrDefault() ?? string.Empty; + var address2 = lines.Length > 1 ? lines[1] : string.Empty; + + request.ProposedAddress = new Shipping.Abstractions.Models.Address( + address1, + address2, + response.Output.ResolvedAddresses?.FirstOrDefault()?.CityToken?.FirstOrDefault()?.Value ?? string.Empty, + response.Output.ResolvedAddresses?.FirstOrDefault()?.StateOrProvinceCode ?? string.Empty, + response.Output.ResolvedAddresses?.FirstOrDefault()?.PostalCodeToken?.Value ?? string.Empty, + response.Output.ResolvedAddresses?.FirstOrDefault()?.CountryCode ?? string.Empty, + response.Output.ResolvedAddresses?.FirstOrDefault()?.Classification == "RESIDENTIAL"); + + if (lines.Length == 2) + { + request.ProposedAddress.StreetLine2 = lines[1]; + } + + foreach (var a in response.Output.ResolvedAddresses?.FirstOrDefault()?.Attributes ?? new ()) + { + if (!request.ValidationBag.ContainsKey(a.Key)) + { + request.ValidationBag.Add(a.Key, a.Value?.ToString() ?? string.Empty); + } + } + + if (response.Output.Alerts != null) + { + foreach (var notification in response.Output.Alerts) + { + request.Errors.Add(new Error + { + Source = notification.AlertType, + Number = notification.Code, + Description = notification.Message + }); + } + + _logger.LogWarning("{providerName} alerts: {errors} ", nameof(FedExAddressValidationProvider), request.Errors.Select(x => x.Description).Flatten(",")); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "{providerName} failed", nameof(FedExAddressValidationProvider)); + request.InternalErrors.Add(ex?.Message ?? $"{nameof(FedExAddressValidationProvider)} failed"); + } + + _logger.LogDebug("[FedEx][ValidateAddressAsync] completed: {mil}", watch.GetElapsedTime().TotalMilliseconds); + return request; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs index ac1d2fb..1f3426d 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/WebServices/Impl/FedExAddressValidationProvider.cs @@ -14,6 +14,9 @@ namespace EasyKeys.Shipping.FedEx.AddressValidation.WebServices.Impl; +/// +/// Caution: FedEx Web Services Tracking, Address Validation, and Validate Postal Codes WSDLS will be disabled on August 31, 2024. The SOAP based FedEx Web Services is in development containment and has been replaced with FedEx RESTful APIs. To learn more and upgrade your integration from Web Services to FedEx APIs, please visit the FedEx Developer Portal. +/// public class FedExAddressValidationProvider : IFedExAddressValidationProvider, IAddressValidationProvider { private readonly ILogger _logger; diff --git a/src/EasyKeys.Shipping.FedEx.Console/DependencyInjection/ConsoleServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.FedEx.Console/DependencyInjection/ConsoleServiceCollectionExtensions.cs index cce348e..fac6033 100644 --- a/src/EasyKeys.Shipping.FedEx.Console/DependencyInjection/ConsoleServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Console/DependencyInjection/ConsoleServiceCollectionExtensions.cs @@ -7,8 +7,8 @@ public static class ConsoleServiceCollectionExtensions public static void ConfigureServices(HostBuilderContext hostBuilder, IServiceCollection services) { services.AddScoped(); - services.AddFedExAddressValidation(); - services.AddFedExRateProvider(); + services.AddWebServicesFedExAddressValidation(); + services.AddWebServicesFedExRateProvider(); services.AddFedExShipmenProvider(); services.AddFedExTrackingProvider(); } diff --git a/src/EasyKeys.Shipping.FedEx.Console/Main.cs b/src/EasyKeys.Shipping.FedEx.Console/Main.cs index 2a3680f..490f769 100644 --- a/src/EasyKeys.Shipping.FedEx.Console/Main.cs +++ b/src/EasyKeys.Shipping.FedEx.Console/Main.cs @@ -4,7 +4,7 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; +using EasyKeys.Shipping.FedEx.AddressValidation; using EasyKeys.Shipping.FedEx.Rates; using EasyKeys.Shipping.FedEx.Shipment; using EasyKeys.Shipping.FedEx.Shipment.Models; diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/IFedexRatesAndTransitTimesApiClient.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/IFedexRatesAndTransitTimesApiClient.cs new file mode 100644 index 0000000..731bc97 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/IFedexRatesAndTransitTimesApiClient.cs @@ -0,0 +1,13 @@ +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1; + +/// +/// Implmentation of the FedEx Rates and Transit Times client. Can be used to get rates and transit times. +/// . +/// +public interface IFedexRatesAndTransitTimesClient +{ + Task GetRatesAsync(RequestRoot request, CancellationToken cancellationToken); +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Impl/FedexRatesAndTransitTimesApiClient.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Impl/FedexRatesAndTransitTimesApiClient.cs new file mode 100644 index 0000000..9c74eaa --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Impl/FedexRatesAndTransitTimesApiClient.cs @@ -0,0 +1,46 @@ +using System.Net.Http.Json; + +using EasyKeys.Shipping.FedEx.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Impl; +public class FedexRatesAndTransitTimesClient : IFedexRatesAndTransitTimesClient +{ + private readonly HttpClient _client; + private readonly FedExApiOptions _options; + private readonly ILogger _logger; + + public FedexRatesAndTransitTimesClient( + IOptionsMonitor optionsMonitor, + HttpClient client, + ILogger logger) + { + _options = optionsMonitor.CurrentValue; + _client = client; + _logger = logger; + } + + public async Task GetRatesAsync(RequestRoot request, CancellationToken cancellationToken = default) + { + try + { + var result = await _client.PostAsJsonAsync($"{_options.Url}rate/v1/rates/quotes", request, _options.JsonSerializerOptions, cancellationToken); + + var resultObject = await result.Content.ReadFromJsonAsync(_options.JsonSerializerOptions, cancellationToken); + + ArgumentNullException.ThrowIfNull(resultObject, nameof(ResponseRoot)); + + return resultObject; + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return new ResponseRoot { Errors = { new ApiError { Message = ex.Message } } }; + } + } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AccountNumber.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AccountNumber.cs new file mode 100644 index 0000000..f603270 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AccountNumber.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class AccountNumber +{ + [JsonPropertyName("value")] + public string? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AddTransportationChargesDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AddTransportationChargesDetail.cs new file mode 100644 index 0000000..c0dbcaf --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AddTransportationChargesDetail.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class AddTransportationChargesDetail +{ + [JsonPropertyName("rateType")] + public string? RateType { get; set; } + + [JsonPropertyName("rateLevelType")] + public string? RateLevelType { get; set; } + + [JsonPropertyName("chargeLevelType")] + public string? ChargeLevelType { get; set; } + + [JsonPropertyName("chargeType")] + public string? ChargeType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Address.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Address.cs new file mode 100644 index 0000000..c23e34e --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Address.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Address +{ + [JsonPropertyName("streetLines")] + public List? StreetLines { get; set; } + + [JsonPropertyName("city")] + public string? City { get; set; } + + [JsonPropertyName("stateOrProvinceCode")] + public string? StateOrProvinceCode { get; set; } + + [JsonPropertyName("postalCode")] + public string? PostalCode { get; set; } + + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } + + [JsonPropertyName("residential")] + public bool? Residential { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AlcoholDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AlcoholDetail.cs new file mode 100644 index 0000000..a9653fe --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/AlcoholDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class AlcoholDetail +{ + [JsonPropertyName("alcoholRecipientType")] + public string? AlcoholRecipientType { get; set; } + + [JsonPropertyName("shipperAgreementType")] + public string? ShipperAgreementType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BatteryDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BatteryDetail.cs new file mode 100644 index 0000000..0bb4e48 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BatteryDetail.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class BatteryDetail +{ + [JsonPropertyName("material")] + public string? Material { get; set; } + + [JsonPropertyName("regulatorySubType")] + public string? RegulatorySubType { get; set; } + + [JsonPropertyName("packing")] + public string? Packing { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker.cs new file mode 100644 index 0000000..5b49479 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Broker +{ + [JsonPropertyName("broker")] + public Broker? Broker2 { get; set; } + + [JsonPropertyName("type")] + public string? Type { get; set; } + + [JsonPropertyName("brokerCommitTimestamp")] + public string? BrokerCommitTimestamp { get; set; } + + [JsonPropertyName("brokerCommitDayOfWeek")] + public string? BrokerCommitDayOfWeek { get; set; } + + [JsonPropertyName("brokerLocationId")] + public string? BrokerLocationId { get; set; } + + [JsonPropertyName("brokerAddress")] + public BrokerAddress? BrokerAddress { get; set; } + + [JsonPropertyName("brokerToDestinationDays")] + public int? BrokerToDestinationDays { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker2.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker2.cs new file mode 100644 index 0000000..c72a19b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Broker2.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Broker2 +{ + [JsonPropertyName("accountNumber")] + public AccountNumber? AccountNumber { get; set; } + + [JsonPropertyName("address")] + public object? Address { get; set; } + + [JsonPropertyName("contact")] + public object? Contact { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BrokerAddress.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BrokerAddress.cs new file mode 100644 index 0000000..d0c9e74 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/BrokerAddress.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class BrokerAddress +{ + [JsonPropertyName("streetLines")] + public List? StreetLines { get; set; } + + [JsonPropertyName("city")] + public string? City { get; set; } + + [JsonPropertyName("stateOrProvinceCode")] + public string? StateOrProvinceCode { get; set; } + + [JsonPropertyName("postalCode")] + public string? PostalCode { get; set; } + + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } + + [JsonPropertyName("residential")] + public bool? Residential { get; set; } + + [JsonPropertyName("classification")] + public string? Classification { get; set; } + + [JsonPropertyName("geographicCoordinates")] + public string? GeographicCoordinates { get; set; } + + [JsonPropertyName("urbanizationCode")] + public string? UrbanizationCode { get; set; } + + [JsonPropertyName("countryName")] + public string? CountryName { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodCollectionAmount.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodCollectionAmount.cs new file mode 100644 index 0000000..30cdea5 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodCollectionAmount.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class CodCollectionAmount +{ + [JsonPropertyName("amount")] + public double? Amount { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodRecipient.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodRecipient.cs new file mode 100644 index 0000000..6eefc46 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CodRecipient.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class CodRecipient +{ + [JsonPropertyName("accountNumber")] + public AccountNumber? AccountNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CommercialInvoice.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CommercialInvoice.cs new file mode 100644 index 0000000..2d50afe --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CommercialInvoice.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class CommercialInvoice +{ + [JsonPropertyName("shipmentPurpose")] + public string? ShipmentPurpose { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Commodity.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Commodity.cs new file mode 100644 index 0000000..cd32883 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Commodity.cs @@ -0,0 +1,39 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Commodity +{ + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("weight")] + public Weight? Weight { get; set; } + + [JsonPropertyName("quantity")] + public int? Quantity { get; set; } + + [JsonPropertyName("customsValue")] + public CustomsValue? CustomsValue { get; set; } + + [JsonPropertyName("unitPrice")] + public UnitPrice? UnitPrice { get; set; } + + [JsonPropertyName("numberOfPieces")] + public int? NumberOfPieces { get; set; } + + [JsonPropertyName("countryOfManufacture")] + public string? CountryOfManufacture { get; set; } + + [JsonPropertyName("quantityUnits")] + public string? QuantityUnits { get; set; } + + [JsonPropertyName("name")] + public string? Name { get; set; } + + [JsonPropertyName("harmonizedCode")] + public string? HarmonizedCode { get; set; } + + [JsonPropertyName("partNumber")] + public string? PartNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Contact.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Contact.cs new file mode 100644 index 0000000..79984c9 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Contact.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Contact +{ + [JsonPropertyName("companyName")] + public string? CompanyName { get; set; } + + [JsonPropertyName("faxNumber")] + public string? FaxNumber { get; set; } + + [JsonPropertyName("personName")] + public string? PersonName { get; set; } + + [JsonPropertyName("phoneNumber")] + public string? PhoneNumber { get; set; } + + [JsonPropertyName("emailAddress")] + public string? EmailAddress { get; set; } + + [JsonPropertyName("phoneExtension")] + public string? PhoneExtension { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Container.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Container.cs new file mode 100644 index 0000000..8a0ef27 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Container.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Container +{ + [JsonPropertyName("offeror")] + public string? Offeror { get; set; } + + [JsonPropertyName("hazardousCommodities")] + public List? HazardousCommodities { get; set; } + + [JsonPropertyName("numberOfContainers")] + public int? NumberOfContainers { get; set; } + + [JsonPropertyName("containerType")] + public string? ContainerType { get; set; } + + [JsonPropertyName("emergencyContactNumber")] + public EmergencyContactNumber? EmergencyContactNumber { get; set; } + + [JsonPropertyName("packaging")] + public Packaging? Packaging { get; set; } + + [JsonPropertyName("packingType")] + public string? PackingType { get; set; } + + [JsonPropertyName("radioactiveContainerClass")] + public string? RadioactiveContainerClass { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ContentRecord.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ContentRecord.cs new file mode 100644 index 0000000..5094a31 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ContentRecord.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ContentRecord +{ + [JsonPropertyName("itemNumber")] + public string? ItemNumber { get; set; } + + [JsonPropertyName("receivedQuantity")] + public int? ReceivedQuantity { get; set; } + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("partNumber")] + public string? PartNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsClearanceDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsClearanceDetail.cs new file mode 100644 index 0000000..f9e1b52 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsClearanceDetail.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class CustomsClearanceDetail +{ + [JsonPropertyName("brokers")] + public List? Brokers { get; set; } + + [JsonPropertyName("commercialInvoice")] + public CommercialInvoice? CommercialInvoice { get; set; } + + [JsonPropertyName("freightOnValue")] + public string? FreightOnValue { get; set; } + + [JsonPropertyName("dutiesPayment")] + public DutiesPayment? DutiesPayment { get; set; } + + [JsonPropertyName("commodities")] + public List? Commodities { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsValue.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsValue.cs new file mode 100644 index 0000000..12c30e6 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/CustomsValue.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class CustomsValue +{ + [JsonPropertyName("amount")] + public string? Amount { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DangerousGoodsDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DangerousGoodsDetail.cs new file mode 100644 index 0000000..3487811 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DangerousGoodsDetail.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DangerousGoodsDetail +{ + [JsonPropertyName("offeror")] + public string? Offeror { get; set; } + + [JsonPropertyName("accessibility")] + public string? Accessibility { get; set; } + + [JsonPropertyName("emergencyContactNumber")] + public string? EmergencyContactNumber { get; set; } + + [JsonPropertyName("options")] + public List? Options { get; set; } + + [JsonPropertyName("containers")] + public List? Containers { get; set; } + + [JsonPropertyName("regulation")] + public string? Regulation { get; set; } + + [JsonPropertyName("packaging")] + public Packaging? Packaging { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeclaredValue.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeclaredValue.cs new file mode 100644 index 0000000..4985c81 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeclaredValue.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DeclaredValue +{ + [JsonPropertyName("amount")] + public string? Amount { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeliveryOnInvoiceAcceptanceDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeliveryOnInvoiceAcceptanceDetail.cs new file mode 100644 index 0000000..f95ef2f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DeliveryOnInvoiceAcceptanceDetail.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DeliveryOnInvoiceAcceptanceDetail +{ + [JsonPropertyName("recipient")] + public Recipient? Recipient { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Description.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Description.cs new file mode 100644 index 0000000..b13a642 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Description.cs @@ -0,0 +1,45 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Description +{ + [JsonPropertyName("sequenceNumber")] + public int? SequenceNumber { get; set; } + + [JsonPropertyName("processingOptions")] + public List? ProcessingOptions { get; set; } + + [JsonPropertyName("subsidiaryClasses")] + public string? SubsidiaryClasses { get; set; } + + [JsonPropertyName("labelText")] + public string? LabelText { get; set; } + + [JsonPropertyName("technicalName")] + public string? TechnicalName { get; set; } + + [JsonPropertyName("packingDetails")] + public PackingDetails? PackingDetails { get; set; } + + [JsonPropertyName("authorization")] + public string? Authorization { get; set; } + + [JsonPropertyName("reportableQuantity")] + public bool? ReportableQuantity { get; set; } + + [JsonPropertyName("percentage")] + public int? Percentage { get; set; } + + [JsonPropertyName("id")] + public string? Id { get; set; } + + [JsonPropertyName("packingGroup")] + public string? PackingGroup { get; set; } + + [JsonPropertyName("properShippingName")] + public string? ProperShippingName { get; set; } + + [JsonPropertyName("hazardClass")] + public string? HazardClass { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Dimensions.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Dimensions.cs new file mode 100644 index 0000000..9046d8c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Dimensions.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Dimensions +{ + [JsonPropertyName("length")] + public int? Length { get; set; } + + [JsonPropertyName("width")] + public int? Width { get; set; } + + [JsonPropertyName("height")] + public int? Height { get; set; } + + [JsonPropertyName("units")] + public string? Units { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DocumentReference.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DocumentReference.cs new file mode 100644 index 0000000..3b2cf48 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DocumentReference.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DocumentReference +{ + [JsonPropertyName("documentType")] + public string? DocumentType { get; set; } + + [JsonPropertyName("customerReference")] + public string? CustomerReference { get; set; } + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("documentId")] + public string? DocumentId { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DryIceWeight.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DryIceWeight.cs new file mode 100644 index 0000000..356e44f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DryIceWeight.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DryIceWeight +{ + [JsonPropertyName("units")] + public string? Units { get; set; } + + [JsonPropertyName("value")] + public int? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DutiesPayment.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DutiesPayment.cs new file mode 100644 index 0000000..19aa512 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/DutiesPayment.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class DutiesPayment +{ + [JsonPropertyName("payor")] + public Payor? Payor { get; set; } + + [JsonPropertyName("paymentType")] + public string? PaymentType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailLabelDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailLabelDetail.cs new file mode 100644 index 0000000..5f89f7c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailLabelDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class EmailLabelDetail +{ + [JsonPropertyName("recipients")] + public List? Recipients { get; set; } + + [JsonPropertyName("message")] + public string? Message { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailNotificationDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailNotificationDetail.cs new file mode 100644 index 0000000..1fcccac --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmailNotificationDetail.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class EmailNotificationDetail +{ + [JsonPropertyName("recipients")] + public List? Recipients { get; set; } + + [JsonPropertyName("personalMessage")] + public string? PersonalMessage { get; set; } + + [JsonPropertyName("PrintedReference")] + public PrintedReference? PrintedReference { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmergencyContactNumber.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmergencyContactNumber.cs new file mode 100644 index 0000000..8ff1797 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/EmergencyContactNumber.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class EmergencyContactNumber +{ + [JsonPropertyName("areaCode")] + public string? AreaCode { get; set; } + + [JsonPropertyName("extension")] + public string? Extension { get; set; } + + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } + + [JsonPropertyName("personalIdentificationNumber")] + public string? PersonalIdentificationNumber { get; set; } + + [JsonPropertyName("localNumber")] + public string? LocalNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ExpressFreightDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ExpressFreightDetail.cs new file mode 100644 index 0000000..37f7e5f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ExpressFreightDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ExpressFreightDetail +{ + [JsonPropertyName("bookingConfirmationNumber")] + public string? BookingConfirmationNumber { get; set; } + + [JsonPropertyName("shippersLoadAndCount")] + public int? ShippersLoadAndCount { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FinancialInstitutionContactAndAddress.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FinancialInstitutionContactAndAddress.cs new file mode 100644 index 0000000..f87b2f6 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FinancialInstitutionContactAndAddress.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class FinancialInstitutionContactAndAddress +{ + [JsonPropertyName("address")] + public Address? Address { get; set; } + + [JsonPropertyName("contact")] + public Contact? Contact { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FixedValue.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FixedValue.cs new file mode 100644 index 0000000..75d97d4 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/FixedValue.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class FixedValue +{ + [JsonPropertyName("amount")] + public string? Amount { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HazardousCommodity.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HazardousCommodity.cs new file mode 100644 index 0000000..40c0c72 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HazardousCommodity.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class HazardousCommodity +{ + [JsonPropertyName("quantity")] + public Quantity? Quantity { get; set; } + + [JsonPropertyName("innerReceptacles")] + public List? InnerReceptacles { get; set; } + + [JsonPropertyName("options")] + public Options? Options { get; set; } + + [JsonPropertyName("description")] + public Description? Description { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HoldAtLocationDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HoldAtLocationDetail.cs new file mode 100644 index 0000000..71b3692 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HoldAtLocationDetail.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class HoldAtLocationDetail +{ + [JsonPropertyName("locationId")] + public string? LocationId { get; set; } + + [JsonPropertyName("locationContactAndAddress")] + public LocationContactAndAddress? LocationContactAndAddress { get; set; } + + [JsonPropertyName("locationType")] + public string? LocationType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HomeDeliveryPremiumDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HomeDeliveryPremiumDetail.cs new file mode 100644 index 0000000..88ae6c7 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/HomeDeliveryPremiumDetail.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class HomeDeliveryPremiumDetail +{ + [JsonPropertyName("phoneNumber")] + public PhoneNumber? PhoneNumber { get; set; } + + [JsonPropertyName("shipTimestamp")] + public string? ShipTimestamp { get; set; } + + [JsonPropertyName("homedeliveryPremiumType")] + public string? HomedeliveryPremiumType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InnerReceptacle.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InnerReceptacle.cs new file mode 100644 index 0000000..ba27881 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InnerReceptacle.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class InnerReceptacle +{ + [JsonPropertyName("quantity")] + public Quantity? Quantity { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalControlledExportDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalControlledExportDetail.cs new file mode 100644 index 0000000..b82f254 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalControlledExportDetail.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class InternationalControlledExportDetail +{ + [JsonPropertyName("type")] + public string? Type { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalTrafficInArmsRegulationsDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalTrafficInArmsRegulationsDetail.cs new file mode 100644 index 0000000..64316c1 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/InternationalTrafficInArmsRegulationsDetail.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class InternationalTrafficInArmsRegulationsDetail +{ + [JsonPropertyName("licenseOrExemptionNumber")] + public string? LicenseOrExemptionNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Locale.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Locale.cs new file mode 100644 index 0000000..7732f54 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Locale.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Locale +{ + [JsonPropertyName("country")] + public string? Country { get; set; } + + [JsonPropertyName("language")] + public string? Language { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/LocationContactAndAddress.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/LocationContactAndAddress.cs new file mode 100644 index 0000000..7fa5cc0 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/LocationContactAndAddress.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class LocationContactAndAddress +{ + [JsonPropertyName("address")] + public Address? Address { get; set; } + + [JsonPropertyName("contact")] + public Contact? Contact { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Options.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Options.cs new file mode 100644 index 0000000..d843596 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Options.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Options +{ + [JsonPropertyName("labelTextOption")] + public string? LabelTextOption { get; set; } + + [JsonPropertyName("customerSuppliedLabelText")] + public string? CustomerSuppliedLabelText { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/OptionsRequested.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/OptionsRequested.cs new file mode 100644 index 0000000..e88077c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/OptionsRequested.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class OptionsRequested +{ + [JsonPropertyName("options")] + public List? Options { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageCODDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageCODDetail.cs new file mode 100644 index 0000000..25e7541 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageCODDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PackageCODDetail +{ + [JsonPropertyName("codCollectionAmount")] + public CodCollectionAmount? CodCollectionAmount { get; set; } + + [JsonPropertyName("codCollectionType")] + public string? CodCollectionType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageSpecialServices.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageSpecialServices.cs new file mode 100644 index 0000000..eb40a3b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackageSpecialServices.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PackageSpecialServices +{ + [JsonPropertyName("specialServiceTypes")] + public List? SpecialServiceTypes { get; set; } + + [JsonPropertyName("signatureOptionType")] + public List? SignatureOptionType { get; set; } + + [JsonPropertyName("alcoholDetail")] + public AlcoholDetail? AlcoholDetail { get; set; } + + [JsonPropertyName("dangerousGoodsDetail")] + public DangerousGoodsDetail? DangerousGoodsDetail { get; set; } + + [JsonPropertyName("packageCODDetail")] + public PackageCODDetail? PackageCODDetail { get; set; } + + [JsonPropertyName("pieceCountVerificationBoxCount")] + public int? PieceCountVerificationBoxCount { get; set; } + + [JsonPropertyName("batteryDetails")] + public List? BatteryDetails { get; set; } + + [JsonPropertyName("dryIceWeight")] + public DryIceWeight? DryIceWeight { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Packaging.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Packaging.cs new file mode 100644 index 0000000..5ea19e0 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Packaging.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Packaging +{ + [JsonPropertyName("count")] + public int? Count { get; set; } + + [JsonPropertyName("units")] + public string? Units { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackingDetails.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackingDetails.cs new file mode 100644 index 0000000..6a5481c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PackingDetails.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PackingDetails +{ + [JsonPropertyName("packingInstructions")] + public string? PackingInstructions { get; set; } + + [JsonPropertyName("cargoAircraftOnly")] + public bool? CargoAircraftOnly { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Payor.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Payor.cs new file mode 100644 index 0000000..ef7cedc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Payor.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Payor +{ + [JsonPropertyName("responsibleParty")] + public ResponsibleParty? ResponsibleParty { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PendingShipmentDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PendingShipmentDetail.cs new file mode 100644 index 0000000..105dcbc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PendingShipmentDetail.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PendingShipmentDetail +{ + [JsonPropertyName("pendingShipmentType")] + public string? PendingShipmentType { get; set; } + + [JsonPropertyName("processingOptions")] + public ProcessingOptions? ProcessingOptions { get; set; } + + [JsonPropertyName("recommendedDocumentSpecification")] + public RecommendedDocumentSpecification? RecommendedDocumentSpecification { get; set; } + + [JsonPropertyName("emailLabelDetail")] + public EmailLabelDetail? EmailLabelDetail { get; set; } + + [JsonPropertyName("documentReferences")] + public List? DocumentReferences { get; set; } + + [JsonPropertyName("expirationTimeStamp")] + public string? ExpirationTimeStamp { get; set; } + + [JsonPropertyName("shipmentDryIceDetail")] + public ShipmentDryIceDetail? ShipmentDryIceDetail { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PhoneNumber.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PhoneNumber.cs new file mode 100644 index 0000000..c1ffdbd --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PhoneNumber.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PhoneNumber +{ + [JsonPropertyName("areaCode")] + public string? AreaCode { get; set; } + + [JsonPropertyName("extension")] + public string? Extension { get; set; } + + [JsonPropertyName("countryCode")] + public string? CountryCode { get; set; } + + [JsonPropertyName("personalIdentificationNumber")] + public string? PersonalIdentificationNumber { get; set; } + + [JsonPropertyName("localNumber")] + public string? LocalNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PrintedReference.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PrintedReference.cs new file mode 100644 index 0000000..406c085 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/PrintedReference.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class PrintedReference +{ + [JsonPropertyName("printedReferenceType")] + public string? PrintedReferenceType { get; set; } + + [JsonPropertyName("value")] + public string? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ProcessingOptions.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ProcessingOptions.cs new file mode 100644 index 0000000..b5b6b90 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ProcessingOptions.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ProcessingOptions +{ + [JsonPropertyName("options")] + public List? Options { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Quantity.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Quantity.cs new file mode 100644 index 0000000..75dd3a1 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Quantity.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Quantity +{ + [JsonPropertyName("quantityType")] + public string? QuantityType { get; set; } + + [JsonPropertyName("amount")] + public int? Amount { get; set; } + + [JsonPropertyName("units")] + public string? Units { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RateRequestControlParameters.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RateRequestControlParameters.cs new file mode 100644 index 0000000..f01b371 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RateRequestControlParameters.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class RateRequestControlParameters +{ + [JsonPropertyName("returnTransitTimes")] + public bool? ReturnTransitTimes { get; set; } + + [JsonPropertyName("servicesNeededOnRateFailure")] + public bool? ServicesNeededOnRateFailure { get; set; } + + [JsonPropertyName("variableOptions")] + public string? VariableOptions { get; set; } + + [JsonPropertyName("rateSortOrder")] + public string? RateSortOrder { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient.cs new file mode 100644 index 0000000..d74b85b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Recipient +{ + [JsonPropertyName("address")] + public Address? Address { get; set; } + + [JsonPropertyName("accountNumber")] + public AccountNumber? AccountNumber { get; set; } + + [JsonPropertyName("contact")] + public Contact? Contact { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient2.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient2.cs new file mode 100644 index 0000000..66ee5bc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Recipient2.cs @@ -0,0 +1,33 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Recipient2 +{ + [JsonPropertyName("emailAddress")] + public string? EmailAddress { get; set; } + + [JsonPropertyName("notificationEventType")] + public List? NotificationEventType { get; set; } + + [JsonPropertyName("smsDetail")] + public SmsDetail? SmsDetail { get; set; } + + [JsonPropertyName("notificationFormatType")] + public string? NotificationFormatType { get; set; } + + [JsonPropertyName("emailNotificationRecipientType")] + public string? EmailNotificationRecipientType { get; set; } + + [JsonPropertyName("notificationType")] + public string? NotificationType { get; set; } + + [JsonPropertyName("locale")] + public string? Locale { get; set; } + + [JsonPropertyName("optionsRequested")] + public OptionsRequested? OptionsRequested { get; set; } + + [JsonPropertyName("role")] + public string? Role { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RecommendedDocumentSpecification.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RecommendedDocumentSpecification.cs new file mode 100644 index 0000000..453ad91 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RecommendedDocumentSpecification.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class RecommendedDocumentSpecification +{ + [JsonPropertyName("types")] + public List? Types { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestRoot.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestRoot.cs new file mode 100644 index 0000000..f4902ed --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestRoot.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class RequestRoot +{ + [JsonPropertyName("accountNumber")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public AccountNumber? AccountNumber { get; set; } + + [JsonPropertyName("rateRequestControlParameters")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public RateRequestControlParameters? RateRequestControlParameters { get; set; } + + [JsonPropertyName("requestedShipment")] + required public RequestedShipment RequestedShipment { get; set; } + + [JsonPropertyName("carrierCodes")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public List? CarrierCodes { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedPackageLineItem.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedPackageLineItem.cs new file mode 100644 index 0000000..4798073 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedPackageLineItem.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class RequestedPackageLineItem +{ + [JsonPropertyName("subPackagingType")] + public string? SubPackagingType { get; set; } + + [JsonPropertyName("groupPackageCount")] + public int? GroupPackageCount { get; set; } + + [JsonPropertyName("contentRecord")] + public List? ContentRecord { get; set; } + + [JsonPropertyName("declaredValue")] + public DeclaredValue? DeclaredValue { get; set; } + + [JsonPropertyName("weight")] + public Weight? Weight { get; set; } + + [JsonPropertyName("dimensions")] + public Dimensions? Dimensions { get; set; } + + [JsonPropertyName("variableHandlingChargeDetail")] + public VariableHandlingChargeDetail? VariableHandlingChargeDetail { get; set; } + + [JsonPropertyName("packageSpecialServices")] + public PackageSpecialServices? PackageSpecialServices { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedShipment.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedShipment.cs new file mode 100644 index 0000000..428a206 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/RequestedShipment.cs @@ -0,0 +1,69 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class RequestedShipment +{ + [JsonPropertyName("shipper")] + public Shipper? Shipper { get; set; } + + [JsonPropertyName("recipient")] + public Recipient? Recipient { get; set; } + + [JsonPropertyName("serviceType")] + public string? ServiceType { get; set; } + + [JsonPropertyName("emailNotificationDetail")] + public EmailNotificationDetail? EmailNotificationDetail { get; set; } + + [JsonPropertyName("preferredCurrency")] + public string? PreferredCurrency { get; set; } + + [JsonPropertyName("rateRequestType")] + public List? RateRequestType { get; set; } + + [JsonPropertyName("shipDateStamp")] + public string? ShipDateStamp { get; set; } + + [JsonPropertyName("pickupType")] + public string? PickupType { get; set; } + + [JsonPropertyName("requestedPackageLineItems")] + public List? RequestedPackageLineItems { get; set; } + + [JsonPropertyName("documentShipment")] + public bool? DocumentShipment { get; set; } + + [JsonPropertyName("variableHandlingChargeDetail")] + public VariableHandlingChargeDetail? VariableHandlingChargeDetail { get; set; } + + [JsonPropertyName("packagingType")] + public string? PackagingType { get; set; } + + [JsonPropertyName("totalPackageCount")] + public int? TotalPackageCount { get; set; } + + [JsonPropertyName("totalWeight")] + public double? TotalWeight { get; set; } + + [JsonPropertyName("shipmentSpecialServices")] + public ShipmentSpecialServices? ShipmentSpecialServices { get; set; } + + [JsonPropertyName("customsClearanceDetail")] + public CustomsClearanceDetail? CustomsClearanceDetail { get; set; } + + [JsonPropertyName("groupShipment")] + public bool? GroupShipment { get; set; } + + [JsonPropertyName("serviceTypeDetail")] + public ServiceTypeDetail? ServiceTypeDetail { get; set; } + + [JsonPropertyName("smartPostInfoDetail")] + public SmartPostInfoDetail? SmartPostInfoDetail { get; set; } + + [JsonPropertyName("expressFreightDetail")] + public ExpressFreightDetail? ExpressFreightDetail { get; set; } + + [JsonPropertyName("groundShipment")] + public bool? GroundShipment { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ResponsibleParty.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ResponsibleParty.cs new file mode 100644 index 0000000..db77981 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ResponsibleParty.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ResponsibleParty +{ + [JsonPropertyName("address")] + public Address? Address { get; set; } + + [JsonPropertyName("contact")] + public Contact? Contact { get; set; } + + [JsonPropertyName("accountNumber")] + public AccountNumber? AccountNumber { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ReturnShipmentDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ReturnShipmentDetail.cs new file mode 100644 index 0000000..ee533bc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ReturnShipmentDetail.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ReturnShipmentDetail +{ + [JsonPropertyName("returnType")] + public string? ReturnType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ServiceTypeDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ServiceTypeDetail.cs new file mode 100644 index 0000000..d219e2b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ServiceTypeDetail.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ServiceTypeDetail +{ + [JsonPropertyName("carrierCode")] + public string? CarrierCode { get; set; } + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("serviceName")] + public string? ServiceName { get; set; } + + [JsonPropertyName("serviceCategory")] + public string? ServiceCategory { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentCODDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentCODDetail.cs new file mode 100644 index 0000000..d9cca10 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentCODDetail.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ShipmentCODDetail +{ + [JsonPropertyName("addTransportationChargesDetail")] + public AddTransportationChargesDetail? AddTransportationChargesDetail { get; set; } + + [JsonPropertyName("codRecipient")] + public CodRecipient? CodRecipient { get; set; } + + [JsonPropertyName("remitToName")] + public string? RemitToName { get; set; } + + [JsonPropertyName("codCollectionType")] + public string? CodCollectionType { get; set; } + + [JsonPropertyName("financialInstitutionContactAndAddress")] + public FinancialInstitutionContactAndAddress? FinancialInstitutionContactAndAddress { get; set; } + + [JsonPropertyName("returnReferenceIndicatorType")] + public string? ReturnReferenceIndicatorType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentDryIceDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentDryIceDetail.cs new file mode 100644 index 0000000..57b41e1 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentDryIceDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ShipmentDryIceDetail +{ + [JsonPropertyName("totalWeight")] + public TotalWeight? TotalWeight { get; set; } + + [JsonPropertyName("packageCount")] + public int? PackageCount { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentSpecialServices.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentSpecialServices.cs new file mode 100644 index 0000000..747bb41 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/ShipmentSpecialServices.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class ShipmentSpecialServices +{ + [JsonPropertyName("returnShipmentDetail")] + public ReturnShipmentDetail? ReturnShipmentDetail { get; set; } + + [JsonPropertyName("deliveryOnInvoiceAcceptanceDetail")] + public DeliveryOnInvoiceAcceptanceDetail? DeliveryOnInvoiceAcceptanceDetail { get; set; } + + [JsonPropertyName("internationalTrafficInArmsRegulationsDetail")] + public InternationalTrafficInArmsRegulationsDetail? InternationalTrafficInArmsRegulationsDetail { get; set; } + + [JsonPropertyName("pendingShipmentDetail")] + public PendingShipmentDetail? PendingShipmentDetail { get; set; } + + [JsonPropertyName("holdAtLocationDetail")] + public HoldAtLocationDetail? HoldAtLocationDetail { get; set; } + + [JsonPropertyName("shipmentCODDetail")] + public ShipmentCODDetail? ShipmentCODDetail { get; set; } + + [JsonPropertyName("shipmentDryIceDetail")] + public ShipmentDryIceDetail? ShipmentDryIceDetail { get; set; } + + [JsonPropertyName("internationalControlledExportDetail")] + public InternationalControlledExportDetail? InternationalControlledExportDetail { get; set; } + + [JsonPropertyName("homeDeliveryPremiumDetail")] + public HomeDeliveryPremiumDetail? HomeDeliveryPremiumDetail { get; set; } + + [JsonPropertyName("specialServiceTypes")] + public List? SpecialServiceTypes { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Shipper.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Shipper.cs new file mode 100644 index 0000000..2dfd4b0 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Shipper.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Shipper +{ + [JsonPropertyName("address")] + public Address? Address { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmartPostInfoDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmartPostInfoDetail.cs new file mode 100644 index 0000000..ee1889d --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmartPostInfoDetail.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class SmartPostInfoDetail +{ + [JsonPropertyName("ancillaryEndorsement")] + public string? AncillaryEndorsement { get; set; } + + [JsonPropertyName("hubId")] + public string? HubId { get; set; } + + [JsonPropertyName("indicia")] + public string? Indicia { get; set; } + + [JsonPropertyName("specialServices")] + public string? SpecialServices { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmsDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmsDetail.cs new file mode 100644 index 0000000..f732c61 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/SmsDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class SmsDetail +{ + [JsonPropertyName("phoneNumber")] + public string? PhoneNumber { get; set; } + + [JsonPropertyName("phoneNumberCountryCode")] + public string? PhoneNumberCountryCode { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/TotalWeight.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/TotalWeight.cs new file mode 100644 index 0000000..22d34e9 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/TotalWeight.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class TotalWeight +{ + [JsonPropertyName("units")] + public string? Units { get; set; } + + [JsonPropertyName("value")] + public int? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/UnitPrice.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/UnitPrice.cs new file mode 100644 index 0000000..881b160 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/UnitPrice.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class UnitPrice +{ + [JsonPropertyName("amount")] + public string? Amount { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/VariableHandlingChargeDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/VariableHandlingChargeDetail.cs new file mode 100644 index 0000000..0826003 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/VariableHandlingChargeDetail.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class VariableHandlingChargeDetail +{ + [JsonPropertyName("rateType")] + public string? RateType { get; set; } + + [JsonPropertyName("percentValue")] + public int? PercentValue { get; set; } + + [JsonPropertyName("rateLevelType")] + public string? RateLevelType { get; set; } + + [JsonPropertyName("fixedValue")] + public FixedValue? FixedValue { get; set; } + + [JsonPropertyName("rateElementBasis")] + public string? RateElementBasis { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Weight.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Weight.cs new file mode 100644 index 0000000..be453bc --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Request/Weight.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +public class Weight +{ + [JsonPropertyName("units")] + public string? Units { get; set; } + + [JsonPropertyName("value")] + public int? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Alert.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Alert.cs new file mode 100644 index 0000000..8a4798b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Alert.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class Alert +{ + [JsonPropertyName("code")] + public string? Code { get; set; } + + [JsonPropertyName("message")] + public string? Message { get; set; } + + [JsonPropertyName("alertType")] + public string? AlertType { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/BillingWeight.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/BillingWeight.cs new file mode 100644 index 0000000..3e0f15e --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/BillingWeight.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class BillingWeight +{ + [JsonPropertyName("units")] + public string? Units { get; set; } + + [JsonPropertyName("value")] + public double? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Commit.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Commit.cs new file mode 100644 index 0000000..3c1f91e --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Commit.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class Commit +{ + [JsonPropertyName("dateDetail")] + public DateDetail? DateDetail { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CurrencyExchangeRate.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CurrencyExchangeRate.cs new file mode 100644 index 0000000..a6dffb8 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CurrencyExchangeRate.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class CurrencyExchangeRate +{ + [JsonPropertyName("fromCurrency")] + public string? FromCurrency { get; set; } + + [JsonPropertyName("doubleoCurrency")] + public string? DoubleoCurrency { get; set; } + + [JsonPropertyName("rate")] + public double? Rate { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CustomerMessage.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CustomerMessage.cs new file mode 100644 index 0000000..2ac973f --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/CustomerMessage.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class CustomerMessage +{ + [JsonPropertyName("code")] + public string? Code { get; set; } + + [JsonPropertyName("message")] + public string? Message { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/DateDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/DateDetail.cs new file mode 100644 index 0000000..e4732be --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/DateDetail.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class DateDetail +{ + [JsonPropertyName("dayOfWeek")] + public string? DayOfWeek { get; set; } + + [JsonPropertyName("dayCxsFormat")] + public DateTime? DayCxsFormat { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Name.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Name.cs new file mode 100644 index 0000000..ad0c474 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Name.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class Name +{ + [JsonPropertyName("type")] + public string? Type { get; set; } + + [JsonPropertyName("encoding")] + public string? Encoding { get; set; } + + [JsonPropertyName("value")] + public string? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/OperationalDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/OperationalDetail.cs new file mode 100644 index 0000000..d43e63b --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/OperationalDetail.cs @@ -0,0 +1,93 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class OperationalDetail +{ + [JsonPropertyName("ineligibleForMoneyBackGuarantee")] + public bool? IneligibleForMoneyBackGuarantee { get; set; } + + [JsonPropertyName("astraDescription")] + public string? AstraDescription { get; set; } + + [JsonPropertyName("airportId")] + public string? AirportId { get; set; } + + [JsonPropertyName("serviceCode")] + public string? ServiceCode { get; set; } + + [JsonPropertyName("originLocationIds")] + public string[]? OriginLocationIds { get; set; } + + [JsonPropertyName("commitDays")] + public string[]? CommitDays { get; set; } + + [JsonPropertyName("scac")] + public string? Scac { get; set; } + + [JsonPropertyName("originServiceAreas")] + public string[]? OriginServiceAreas { get; set; } + + [JsonPropertyName("deliveryDay")] + public string? DeliveryDay { get; set; } + + [JsonPropertyName("originLocationNumbers")] + public double[]? OriginLocationNumbers { get; set; } + + [JsonPropertyName("destinationPostalCode")] + public string? DestinationPostalCode { get; set; } + + [JsonPropertyName("commitDate")] + public DateTime? CommitDate { get; set; } + + [JsonPropertyName("deliveryDate")] + public string? DeliveryDate { get; set; } + + [JsonPropertyName("deliveryEligibilities")] + public string? DeliveryEligibilities { get; set; } + + [JsonPropertyName("maximumTransitTime")] + public string? MaximumTransitTime { get; set; } + + [JsonPropertyName("astraPlannedServiceLevel")] + public string? AstraPlannedServiceLevel { get; set; } + + [JsonPropertyName("destinationLocationIds")] + public string[]? DestinationLocationIds { get; set; } + + [JsonPropertyName("destinationLocationStateOrProvinceCodes")] + public string[]? DestinationLocationStateOrProvinceCodes { get; set; } + + [JsonPropertyName("transitTime")] + public string? TransitTime { get; set; } + + [JsonPropertyName("packagingCode")] + public string? PackagingCode { get; set; } + + [JsonPropertyName("destinationLocationNumbers")] + public double[]? DestinationLocationNumbers { get; set; } + + [JsonPropertyName("publishedDeliveryTime")] + public string? PublishedDeliveryTime { get; set; } + + [JsonPropertyName("countryCodes")] + public string[]? CountryCodes { get; set; } + + [JsonPropertyName("stateOrProvinceCodes")] + public string[]? StateOrProvinceCodes { get; set; } + + [JsonPropertyName("ursaPrefixCode")] + public string? UrsaPrefixCode { get; set; } + + [JsonPropertyName("ursaSuffixCode")] + public string? UrsaSuffixCode { get; set; } + + [JsonPropertyName("destinationServiceAreas")] + public string[]? DestinationServiceAreas { get; set; } + + [JsonPropertyName("originPostalCodes")] + public string[]? OriginPostalCodes { get; set; } + + [JsonPropertyName("customTransitTime")] + public string? CustomTransitTime { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Output.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Output.cs new file mode 100644 index 0000000..9be03b7 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/Output.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class Output +{ + [JsonPropertyName("rateReplyDetails")] + public List? RateReplyDetails { get; set; } + + [JsonPropertyName("quoteDate")] + public string? QuoteDate { get; set; } + + [JsonPropertyName("encoded")] + public bool? Encoded { get; set; } + + [JsonPropertyName("alerts")] + public List? Alerts { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/PackageRateDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/PackageRateDetail.cs new file mode 100644 index 0000000..de8e5fa --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/PackageRateDetail.cs @@ -0,0 +1,45 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class PackageRateDetail +{ + [JsonPropertyName("rateType")] + public string? RateType { get; set; } + + [JsonPropertyName("ratedWeightMethod")] + public string? RatedWeightMethod { get; set; } + + [JsonPropertyName("baseCharge")] + public double? BaseCharge { get; set; } + + [JsonPropertyName("netFreight")] + public double? NetFreight { get; set; } + + [JsonPropertyName("totalSurcharges")] + public double? TotalSurcharges { get; set; } + + [JsonPropertyName("netFedExCharge")] + public double? NetFedExCharge { get; set; } + + [JsonPropertyName("totalTaxes")] + public double? TotalTaxes { get; set; } + + [JsonPropertyName("netCharge")] + public double? NetCharge { get; set; } + + [JsonPropertyName("totalRebates")] + public double? TotalRebates { get; set; } + + [JsonPropertyName("billingWeight")] + public BillingWeight? BillingWeight { get; set; } + + [JsonPropertyName("totalFreightDiscounts")] + public double? TotalFreightDiscounts { get; set; } + + [JsonPropertyName("surcharges")] + public List? Surcharges { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RateReplyDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RateReplyDetail.cs new file mode 100644 index 0000000..22b0d3d --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RateReplyDetail.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class RateReplyDetail +{ + [JsonPropertyName("serviceType")] + public string ServiceType { get; set; } = string.Empty; + + [JsonPropertyName("serviceName")] + public string ServiceName { get; set; } = string.Empty; + + [JsonPropertyName("packagingType")] + public string PackagingType { get; set; } = string.Empty; + + [JsonPropertyName("customerMessages")] + public List? CustomerMessages { get; set; } + + [JsonPropertyName("ratedShipmentDetails")] + public List RatedShipmentDetails { get; set; } = new (); + + [JsonPropertyName("anonymouslyAllowable")] + public bool? AnonymouslyAllowable { get; set; } + + [JsonPropertyName("operationalDetail")] + public OperationalDetail OperationalDetail { get; set; } = new (); + + [JsonPropertyName("signatureOptionType")] + public string? SignatureOptionType { get; set; } + + [JsonPropertyName("serviceDescription")] + public ServiceDescription? ServiceDescription { get; set; } + + [JsonPropertyName("commit")] + public Commit Commit { get; set; } = new (); +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedPackage.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedPackage.cs new file mode 100644 index 0000000..50a0696 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedPackage.cs @@ -0,0 +1,58 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class RatedPackage +{ + [JsonPropertyName("groupNumber")] + public double? GroupNumber { get; set; } + + [JsonPropertyName("effectiveNetDiscount")] + public double? EffectiveNetDiscount { get; set; } + + [JsonPropertyName("packageRateDetail")] + public PackageRateDetail? PackageRateDetail { get; set; } + + [JsonPropertyName("rateType")] + public string? RateType { get; set; } + + [JsonPropertyName("ratedWeightMethod")] + public string? RatedWeightMethod { get; set; } + + [JsonPropertyName("baseCharge")] + public double? BaseCharge { get; set; } + + [JsonPropertyName("netFreight")] + public double? NetFreight { get; set; } + + [JsonPropertyName("totalSurcharges")] + public double? TotalSurcharges { get; set; } + + [JsonPropertyName("netFedExCharge")] + public double? NetFedExCharge { get; set; } + + [JsonPropertyName("totalTaxes")] + public double? TotalTaxes { get; set; } + + [JsonPropertyName("netCharge")] + public double? NetCharge { get; set; } + + [JsonPropertyName("totalRebates")] + public double? TotalRebates { get; set; } + + [JsonPropertyName("billingWeight")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public BillingWeight? BillingWeight { get; set; } + + [JsonPropertyName("totalFreightDiscounts")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public double? TotalFreightDiscounts { get; set; } + + [JsonPropertyName("surcharges")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public List? Surcharges { get; set; } + + [JsonPropertyName("currency")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedShipmentDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedShipmentDetail.cs new file mode 100644 index 0000000..a372699 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/RatedShipmentDetail.cs @@ -0,0 +1,64 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class RatedShipmentDetail +{ + [JsonPropertyName("rateType")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? RateType { get; set; } + + [JsonPropertyName("ratedWeightMethod")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? RatedWeightMethod { get; set; } + + [JsonPropertyName("totalDiscounts")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public double? TotalDiscounts { get; set; } + + [JsonPropertyName("totalBaseCharge")] + public double? TotalBaseCharge { get; set; } + + [JsonPropertyName("totalNetCharge")] + public double TotalNetCharge { get; set; } = 0; + + [JsonPropertyName("totalVatCharge")] + public double? TotalVatCharge { get; set; } + + [JsonPropertyName("totalNetFedExCharge")] + public double? TotalNetFedExCharge { get; set; } + + [JsonPropertyName("totalDutiesAndTaxes")] + public double? TotalDutiesAndTaxes { get; set; } + + [JsonPropertyName("totalNetChargeWithDutiesAndTaxes")] + public double? TotalNetChargeWithDutiesAndTaxes { get; set; } + + [JsonPropertyName("totalDutiesTaxesAndFees")] + public double? TotalDutiesTaxesAndFees { get; set; } + + [JsonPropertyName("totalAncillaryFeesAndTaxes")] + public double? TotalAncillaryFeesAndTaxes { get; set; } + + [JsonPropertyName("shipmentRateDetail")] + public ShipmentRateDetail? ShipmentRateDetail { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } + + [JsonPropertyName("ratedPackages")] + public List? RatedPackages { get; set; } + + [JsonPropertyName("anonymouslyAllowable")] + public bool? AnonymouslyAllowable { get; set; } + + [JsonPropertyName("operationalDetail")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public OperationalDetail? OperationalDetail { get; set; } + + [JsonPropertyName("signatureOptionType")] + public string? SignatureOptionType { get; set; } + + [JsonPropertyName("serviceDescription")] + public ServiceDescription? ServiceDescription { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ResponseRoot.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ResponseRoot.cs new file mode 100644 index 0000000..7c570ab --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ResponseRoot.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +using EasyKeys.Shipping.FedEx.Abstractions.Models; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class ResponseRoot +{ + [JsonPropertyName("transactionId")] + public string? TransactionId { get; set; } + + [JsonPropertyName("customerTransactionId")] + public string? CustomerTransactionId { get; set; } + + [JsonPropertyName("output")] + public Output? Output { get; set; } + + [JsonPropertyName("errors")] + public List Errors { get; set; } = new (); +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ServiceDescription.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ServiceDescription.cs new file mode 100644 index 0000000..9c6c2ca --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ServiceDescription.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class ServiceDescription +{ + [JsonPropertyName("serviceId")] + public string? ServiceId { get; set; } + + [JsonPropertyName("serviceType")] + public string? ServiceType { get; set; } + + [JsonPropertyName("code")] + public string? Code { get; set; } + + [JsonPropertyName("names")] + public List? Names { get; set; } + + [JsonPropertyName("operatingOrgCodes")] + public List? OperatingOrgCodes { get; set; } + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("astraDescription")] + public string? AstraDescription { get; set; } + + [JsonPropertyName("serviceCategory")] + public string? ServiceCategory { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ShipmentRateDetail.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ShipmentRateDetail.cs new file mode 100644 index 0000000..6f46eb1 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/ShipmentRateDetail.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class ShipmentRateDetail +{ + [JsonPropertyName("rateZone")] + public string? RateZone { get; set; } + + [JsonPropertyName("dimDivisor")] + public double? DimDivisor { get; set; } + + [JsonPropertyName("fuelSurchargePercent")] + public double? FuelSurchargePercent { get; set; } + + [JsonPropertyName("totalSurcharges")] + public double? TotalSurcharges { get; set; } + + [JsonPropertyName("totalFreightDiscount")] + public double? TotalFreightDiscount { get; set; } + + [JsonPropertyName("surCharges")] + public List? SurCharges { get; set; } + + [JsonPropertyName("pricingCode")] + public string? PricingCode { get; set; } + + [JsonPropertyName("currencyExchangeRate")] + public CurrencyExchangeRate? CurrencyExchangeRate { get; set; } + + [JsonPropertyName("totalBillingWeight")] + public TotalBillingWeight? TotalBillingWeight { get; set; } + + [JsonPropertyName("currency")] + public string? Currency { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/SurCharge.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/SurCharge.cs new file mode 100644 index 0000000..88a72e8 --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/SurCharge.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class SurCharge +{ + [JsonPropertyName("type")] + public string? Type { get; set; } + + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("amount")] + public double? Amount { get; set; } + + [JsonPropertyName("level")] + public string? Level { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/TotalBillingWeight.cs b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/TotalBillingWeight.cs new file mode 100644 index 0000000..f5dad2d --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/Client/V1/Models/Response/TotalBillingWeight.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Response; + +public class TotalBillingWeight +{ + [JsonPropertyName("units")] + public string? Units { get; set; } + + [JsonPropertyName("value")] + public double? Value { get; set; } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/DependencyInjection/FedExRatesServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.FedEx.Rates/DependencyInjection/FedExRatesServiceCollectionExtensions.cs index 178d583..002a90e 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/DependencyInjection/FedExRatesServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/DependencyInjection/FedExRatesServiceCollectionExtensions.cs @@ -1,5 +1,10 @@ -using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.Abstractions.Api.V1.Auth; +using EasyKeys.Shipping.FedEx.Abstractions.Middleware; +using EasyKeys.Shipping.FedEx.Abstractions.Options; using EasyKeys.Shipping.FedEx.Rates; +using EasyKeys.Shipping.FedEx.Rates.Client.V1; +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Impl; +using EasyKeys.Shipping.FedEx.Rates.WebServices.Impl; namespace Microsoft.Extensions.DependencyInjection; @@ -12,7 +17,7 @@ public static class FedExRatesServiceCollectionExtensions /// /// /// - public static IServiceCollection AddFedExRateProvider( + public static IServiceCollection AddWebServicesFedExRateProvider( this IServiceCollection services, string sectionName = nameof(FedExOptions), Action? configure = null) @@ -25,4 +30,33 @@ public static class FedExRatesServiceCollectionExtensions return services; } + + /// + /// Adds , + /// and with configuration options . + /// + /// + /// + /// + /// + public static IServiceCollection AddRestApiFedExRateProvider( + this IServiceCollection services, + string sectionName = nameof(FedExApiOptions), + Action? configOptions = null) + { + services.AddChangeTokenOptions( + sectionName: sectionName, + configureAction: (options, sp) => configOptions?.Invoke(options, sp)); + + services.AddLogging(); + + services.AddFedExAuthApiClient(); + + services.AddHttpClient() + .AddHttpMessageHandler(); + + services.AddTransient(); + + return services; + } } diff --git a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj index b38b2ab..0670284 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj +++ b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/EasyKeys.Shipping.FedEx.Rates/FedExRateConfigurator.cs b/src/EasyKeys.Shipping.FedEx.Rates/FedExRateConfigurator.cs index 8f6a2ec..0951a7a 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/FedExRateConfigurator.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/FedExRateConfigurator.cs @@ -1,6 +1,6 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.Rates.Extensions; +using EasyKeys.Shipping.FedEx.Rates.WebServices.Extensions; namespace EasyKeys.Shipping.FedEx.Rates; diff --git a/src/EasyKeys.Shipping.FedEx.Rates/RestApi/Impl/FedexRateProvider.cs b/src/EasyKeys.Shipping.FedEx.Rates/RestApi/Impl/FedexRateProvider.cs new file mode 100644 index 0000000..0d1220c --- /dev/null +++ b/src/EasyKeys.Shipping.FedEx.Rates/RestApi/Impl/FedexRateProvider.cs @@ -0,0 +1,145 @@ +using EasyKeys.Shipping.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Models; +using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.Rates.Client.V1; +using EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +using Address = EasyKeys.Shipping.FedEx.Rates.Client.V1.Models.Request.Address; + +namespace EasyKeys.Shipping.FedEx.Rates.RestApi.Impl; +public class FedexRateProvider : IFedExRateProvider +{ + private readonly IFedexRatesAndTransitTimesClient _client; + private readonly ILogger _logger; + private readonly FedExApiOptions _options; + + public FedexRateProvider( + IOptionsMonitor optionsMonitor, + IFedexRatesAndTransitTimesClient client, + ILogger logger) + { + _options = optionsMonitor.CurrentValue; + _client = client; + _logger = logger; + } + + public async Task GetRatesAsync(Shipment shipment, FedExServiceType? serviceType = null, CancellationToken cancellationToken = default) + { + var ratesRequest = new RequestRoot + { + AccountNumber = new AccountNumber { Value = shipment.Options.CustomerFedexAccountNumber ?? _options.FedExAccountNumber }, + CarrierCodes = new List { "FDXE", "FDXG" }, + RateRequestControlParameters = new RateRequestControlParameters + { + ReturnTransitTimes = true, + }, + RequestedShipment = new RequestedShipment + { + Shipper = new Shipper + { + Address = new Address + { + PostalCode = shipment.OriginAddress.PostalCode, + CountryCode = shipment.OriginAddress.CountryCode, + Residential = shipment.OriginAddress.IsResidential + } + }, + Recipient = new Recipient + { + Address = new Address + { + PostalCode = shipment.DestinationAddress.PostalCode, + CountryCode = shipment.DestinationAddress.CountryCode, + Residential = shipment.DestinationAddress.IsResidential + } + }, + ShipDateStamp = shipment.Options.ShippingDate.ToString("yyyy-MM-dd"), + PackagingType = shipment.Options.PackagingType, + PickupType = "USE_SCHEDULED_PICKUP", + RateRequestType = ["ACCOUNT", "LIST"], + RequestedPackageLineItems = shipment.Packages.Select(x => new RequestedPackageLineItem + { + Weight = new Weight + { + Units = "LB", + Value = (int)x.RoundedWeight + }, + DeclaredValue = new DeclaredValue + { + Currency = "USD", + Amount = x.InsuredValue.ToString() + } + }).ToList(), + } + }; + if (shipment.DestinationAddress.IsUnitedStatesAddress() is not true) + { + ratesRequest.RequestedShipment.CustomsClearanceDetail = new CustomsClearanceDetail + { + Commodities = shipment.Packages.Select(x => new Client.V1.Models.Request.Commodity + { + NumberOfPieces = 1, + Description = "keys and locks", + CountryOfManufacture = "US", + Weight = new Weight + { + Units = "LB", + Value = (int)x.RoundedWeight + }, + Quantity = 1, + QuantityUnits = "EA", + UnitPrice = new UnitPrice + { + Currency = "USD", + Amount = x.InsuredValue.ToString() + }, + CustomsValue = new CustomsValue + { + Currency = "USD", + Amount = x.InsuredValue.ToString() + } + }).ToList() + }; + } + + if (shipment.Options.PackagingType != FedExPackageType.YourPackaging.Name && shipment.DestinationAddress.IsUnitedStatesAddress()) + { + ratesRequest.RequestedShipment.ShipmentSpecialServices = new ShipmentSpecialServices + { + SpecialServiceTypes = new List { "FEDEX_ONE_RATE" } + }; + } + + var rates = await _client.GetRatesAsync(ratesRequest, cancellationToken); + + foreach (var error in rates.Errors) + { + shipment.Errors.Add(new Error + { + Description = error.Message + }); + } + + if (shipment.Errors.Any() || rates.Output?.RateReplyDetails == null) + { + return shipment; + } + + foreach (var rateDetail in rates.Output.RateReplyDetails) + { + var rate = new Rate( + rateDetail.ServiceType, + rateDetail.ServiceName, + rateDetail.PackagingType, + (decimal)rateDetail.RatedShipmentDetails.First(x => x.RateType == "ACCOUNT").TotalNetCharge, + (decimal)rateDetail.RatedShipmentDetails.First(x => x.RateType == "LIST").TotalNetCharge, + rateDetail.OperationalDetail.CommitDate); + shipment.Rates.Add(rate); + } + + return shipment; + } +} diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/PackageExtensions.cs b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/PackageExtensions.cs similarity index 96% rename from src/EasyKeys.Shipping.FedEx.Rates/Extensions/PackageExtensions.cs rename to src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/PackageExtensions.cs index e5d6d6a..792d3e0 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/PackageExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/PackageExtensions.cs @@ -1,7 +1,7 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -namespace EasyKeys.Shipping.FedEx.Rates.Extensions; +namespace EasyKeys.Shipping.FedEx.Rates.WebServices.Extensions; public static class PackageExtensions { diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateAddressExtensions.cs b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateAddressExtensions.cs similarity index 95% rename from src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateAddressExtensions.cs rename to src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateAddressExtensions.cs index e7785b1..32d868f 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateAddressExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateAddressExtensions.cs @@ -1,7 +1,7 @@ using EasyKeys.Shipping.Abstractions; using EasyKeys.Shipping.Abstractions.Models; -namespace EasyKeys.Shipping.FedEx.Rates.Extensions; +namespace EasyKeys.Shipping.FedEx.Rates.WebServices.Extensions; public static class RateAddressExtensions { diff --git a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateRequestedShipmentExtensions.cs b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateRequestedShipmentExtensions.cs similarity index 94% rename from src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateRequestedShipmentExtensions.cs rename to src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateRequestedShipmentExtensions.cs index 9134d43..8d91901 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/Extensions/RateRequestedShipmentExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Extensions/RateRequestedShipmentExtensions.cs @@ -1,6 +1,6 @@ using RateClient.v28; -namespace EasyKeys.Shipping.FedEx.Rates.Extensions; +namespace EasyKeys.Shipping.FedEx.Rates.WebServices.Extensions; /// /// Extension methods for RequestedShipment. diff --git a/src/EasyKeys.Shipping.FedEx.Rates/FedExRateProvider.cs b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Impl/FedExRateProvider.cs similarity index 99% rename from src/EasyKeys.Shipping.FedEx.Rates/FedExRateProvider.cs rename to src/EasyKeys.Shipping.FedEx.Rates/WebServices/Impl/FedExRateProvider.cs index 39b9566..174ad1b 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/FedExRateProvider.cs +++ b/src/EasyKeys.Shipping.FedEx.Rates/WebServices/Impl/FedExRateProvider.cs @@ -4,14 +4,14 @@ using EasyKeys.Shipping.FedEx.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Options; using EasyKeys.Shipping.FedEx.Abstractions.Services; -using EasyKeys.Shipping.FedEx.Rates.Extensions; +using EasyKeys.Shipping.FedEx.Rates.WebServices.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using RateClient.v28; -namespace EasyKeys.Shipping.FedEx.Rates; +namespace EasyKeys.Shipping.FedEx.Rates.WebServices.Impl; public class FedExRateProvider : IFedExRateProvider { diff --git a/src/EasyKeys.Shipping.FedEx.UploadDocument/DependencyInjection/FedExUploadDocumentServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.FedEx.UploadDocument/DependencyInjection/FedExUploadDocumentServiceCollectionExtensions.cs index 654c164..e1bf387 100644 --- a/src/EasyKeys.Shipping.FedEx.UploadDocument/DependencyInjection/FedExUploadDocumentServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.FedEx.UploadDocument/DependencyInjection/FedExUploadDocumentServiceCollectionExtensions.cs @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class FedExUploadDocumentServiceCollectionExtensions { /// - /// Adds implementation. + /// Adds implementation. /// /// /// diff --git a/src/EasyKeys.Shipping.FedEx.UploadDocument/FedExDocumentProvider.cs b/src/EasyKeys.Shipping.FedEx.UploadDocument/FedExDocumentProvider.cs index d6c735d..5bb141c 100644 --- a/src/EasyKeys.Shipping.FedEx.UploadDocument/FedExDocumentProvider.cs +++ b/src/EasyKeys.Shipping.FedEx.UploadDocument/FedExDocumentProvider.cs @@ -1,6 +1,4 @@ -using System.Xml.Serialization; - -using EasyKeys.Shipping.FedEx.Abstractions.Options; +using EasyKeys.Shipping.FedEx.Abstractions.Options; using EasyKeys.Shipping.FedEx.Abstractions.Services; using Microsoft.Extensions.Logging; diff --git a/src/EasyKeys.Shipping.Stamps.Abstractions/Services/Impl/StampsClientService.cs b/src/EasyKeys.Shipping.Stamps.Abstractions/Services/Impl/StampsClientService.cs index b43f967..c007c90 100644 --- a/src/EasyKeys.Shipping.Stamps.Abstractions/Services/Impl/StampsClientService.cs +++ b/src/EasyKeys.Shipping.Stamps.Abstractions/Services/Impl/StampsClientService.cs @@ -96,7 +96,6 @@ public async Task GetRatesAsync(GetRatesRequest request, Cance try { - request.Item = _options.UseAuthenticator ? _stampsClientAuthenticator.GetToken() : _credentials; var respo = await _client.GetRatesAsync(request); diff --git a/src/EasyKeys.Shipping.Stamps.Shipment/IStampsShipmentProvider.cs b/src/EasyKeys.Shipping.Stamps.Shipment/IStampsShipmentProvider.cs index c611c79..8a26da5 100644 --- a/src/EasyKeys.Shipping.Stamps.Shipment/IStampsShipmentProvider.cs +++ b/src/EasyKeys.Shipping.Stamps.Shipment/IStampsShipmentProvider.cs @@ -2,8 +2,6 @@ using EasyKeys.Shipping.Stamps.Rates.Models; using EasyKeys.Shipping.Stamps.Shipment.Models; -using StampsClient.v111; - namespace EasyKeys.Shipping.Stamps.Shipment; public interface IStampsShipmentProvider diff --git a/src/EasyKeys.Shipping.Usps.Rates/UspsRateProvider.cs b/src/EasyKeys.Shipping.Usps.Rates/UspsRateProvider.cs index 45f2f0c..75fb583 100644 --- a/src/EasyKeys.Shipping.Usps.Rates/UspsRateProvider.cs +++ b/src/EasyKeys.Shipping.Usps.Rates/UspsRateProvider.cs @@ -188,13 +188,13 @@ private string CreateDometicRequest(Shipment shipment, UspsRateOptions rateOptio var document = XElement.Parse(response, LoadOptions.None); var rates = from item in document.Descendants("Postage") - group item by (string)item.Element("MailService") ! + group item by (string)item.Element("MailService")! into g select new { Name = g.Key, - TotalCharges = g.Sum(x => decimal.Parse((string)x.Element("Rate") !)), - DeliveryDate = g.Select(x => (string)x.Element("CommitmentDate") !).FirstOrDefault(), + TotalCharges = g.Sum(x => decimal.Parse((string)x.Element("Rate")!)), + DeliveryDate = g.Select(x => (string)x.Element("CommitmentDate")!).FirstOrDefault(), SpecialServices = g.Select(x => x.Element("SpecialServices")).FirstOrDefault() }; @@ -210,8 +210,8 @@ select new { foreach (var specialService in specialServices) { - var serviceId = (string)specialService.Element("ServiceID") !; - var price = decimal.Parse((string)specialService.Element("Price") !); + var serviceId = (string)specialService.Element("ServiceID")!; + var price = decimal.Parse((string)specialService.Element("Price")!); if (includeSpecialServiceCodes.Contains(serviceId)) { @@ -339,12 +339,12 @@ private string CreateInternationalRequest(Shipment shipment) var rates = document .Descendants("Service") - .GroupBy(item => (string)item.Element("SvcDescription") !) + .GroupBy(item => (string)item.Element("SvcDescription")!) .Select(g => new { Name = g.Key, - DeliveryDate = g.Select(x => (string)x.Element("GuaranteeAvailability") !).FirstOrDefault(), - TotalCharges = g.Sum(x => decimal.Parse((string)x.Element("Postage") !)) + DeliveryDate = g.Select(x => (string)x.Element("GuaranteeAvailability")!).FirstOrDefault(), + TotalCharges = g.Sum(x => decimal.Parse((string)x.Element("Postage")!)) }); foreach (var r in rates) diff --git a/src/EasyKeys.Shipping.Usps.Tracking/DependencyInjection/UspsTrackingServiceCollectionExtensions.cs b/src/EasyKeys.Shipping.Usps.Tracking/DependencyInjection/UspsTrackingServiceCollectionExtensions.cs index eb3a6d7..b6b59a3 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/DependencyInjection/UspsTrackingServiceCollectionExtensions.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/DependencyInjection/UspsTrackingServiceCollectionExtensions.cs @@ -47,8 +47,8 @@ public static class UspsTrackingServiceCollectionExtensions { builder.AddTransientHttpErrorPolicy(p => { - return p.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))) - .WithPolicyKey($"{nameof(UspsTrackingClient)}-WaitAndRetryAsync"); + return p.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))) + .WithPolicyKey($"{nameof(UspsTrackingClient)}-WaitAndRetryAsync"); }); } diff --git a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackFieldRequest.cs b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackFieldRequest.cs index b62ba80..57663f7 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackFieldRequest.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackFieldRequest.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Xml.Serialization; +using System.Xml.Serialization; #nullable disable namespace EasyKeys.Shipping.Usps.Tracking.Models diff --git a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackInfo.cs b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackInfo.cs index 781e64a..b55b1bf 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackInfo.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackInfo.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Xml.Serialization; +using System.Xml.Serialization; #nullable disable diff --git a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackRequest.cs b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackRequest.cs index 2e496ad..3db0819 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackRequest.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackRequest.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Xml.Serialization; +using System.Xml.Serialization; #nullable disable namespace EasyKeys.Shipping.Usps.Tracking.Models diff --git a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackResponse.cs b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackResponse.cs index 4af5729..76ee64c 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackResponse.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/Models/TrackResponse.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Xml.Serialization; +using System.Xml.Serialization; #nullable disable namespace EasyKeys.Shipping.Usps.Tracking.Models diff --git a/src/EasyKeys.Shipping.Usps.Tracking/UspsTrackingClient.cs b/src/EasyKeys.Shipping.Usps.Tracking/UspsTrackingClient.cs index cd0474d..055bfc8 100644 --- a/src/EasyKeys.Shipping.Usps.Tracking/UspsTrackingClient.cs +++ b/src/EasyKeys.Shipping.Usps.Tracking/UspsTrackingClient.cs @@ -73,7 +73,7 @@ public async Task> GetTrackInfoAsync(List input, Cancel { XmlSerializer deserializer = new(typeof(TrackResponse)); var ms = new MemoryStream(Encoding.UTF8.GetBytes(content)); - var responseJson = (TrackResponse)deserializer.Deserialize(ms) !; + var responseJson = (TrackResponse)deserializer.Deserialize(ms)!; // todo: save response data to correct input data foreach (var trackInfo in responseJson.TrackInfo) @@ -108,7 +108,7 @@ public async Task GetTrackInfoAsync(string trackingNumber, Cancellati { List list = new() { new TrackID() { ID = trackingNumber } }; - return (await GetTrackInfoAsync(list, cancellationToken)).FirstOrDefault() !; + return (await GetTrackInfoAsync(list, cancellationToken)).FirstOrDefault()!; } public async Task> GetTrackInfoAsync(List trackingNumbers, CancellationToken cancellationToken) diff --git a/src/Minimal.Apis/Program.cs b/src/Minimal.Apis/Program.cs index 67b0467..e551407 100644 --- a/src/Minimal.Apis/Program.cs +++ b/src/Minimal.Apis/Program.cs @@ -2,7 +2,7 @@ using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; +using EasyKeys.Shipping.FedEx.AddressValidation; using EasyKeys.Shipping.FedEx.Rates; using EasyKeys.Shipping.FedEx.Shipment; using EasyKeys.Shipping.Stamps.Abstractions.Models; @@ -38,9 +38,9 @@ builder.Services.AddStampsTrackingProvider(); // add fedex libraries -builder.Services.AddFedExAddressValidation(); +builder.Services.AddWebServicesFedExAddressValidation(); -builder.Services.AddFedExRateProvider(); +builder.Services.AddWebServicesFedExRateProvider(); builder.Services.AddFedExShipmenProvider(); @@ -223,7 +223,7 @@ var rateOptions = new RateOptions { Sender = model.Sender, - Recipient = model!.Recipient, + Recipient = model!.Recipient!, ServiceType = StampsServiceType.FromName(serviceType) }; @@ -278,7 +278,7 @@ var shipmentDetails = new EasyKeys.Shipping.FedEx.Shipment.Models.ShipmentDetails { Sender = model.Sender, - Recipient = model!.Recipient, + Recipient = model!.Recipient!, TransactionId = orderId, diff --git a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs index 89eb688..b37c520 100644 --- a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExAddressValidationProviderTests.cs @@ -1,8 +1,7 @@ using Bet.Extensions.Testing.Logging; using EasyKeys.Shipping.Abstractions.Models; -using EasyKeys.Shipping.FedEx.AddressValidation.Api.V1; -using EasyKeys.Shipping.FedEx.AddressValidation.WebServices; +using EasyKeys.Shipping.FedEx.AddressValidation; using EasyKeysShipping.FuncTest.TestHelpers; @@ -14,16 +13,12 @@ namespace EasyKeysShipping.FuncTest.FedEx; public class FedExAddressValidationProviderTests { private readonly ITestOutputHelper _output; - private readonly IFedExAddressValidationProvider _validator; - private readonly IFedExAddressValidationApiClient _apiClient; + private readonly IEnumerable _validators; public FedExAddressValidationProviderTests(ITestOutputHelper output) { _output = output; - _validator = ServiceProviderInstance.GetFedExServices(output) - .GetRequiredService(); - _apiClient = ServiceProviderInstance.GetFedExServices(output) - .GetRequiredService(); + _validators = ServiceProviderInstance.GetFedExServices(output).GetServices(); } [Fact] @@ -40,27 +35,27 @@ public async Task NORMALIZED_Unknown_Address_Successfully() "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); - - var proposed = result.ProposedAddress; - - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); - Assert.Equal(string.Empty, proposed?.StreetLine); - Assert.Equal(string.Empty, proposed?.StreetLine2); - Assert.Equal("52722", proposed?.PostalCode); - - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("UNKNOWN", result.ValidationBag.GetValueOrDefault("Classification")); - - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("NORMALIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.False(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.False(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); + + var proposed = result.ProposedAddress; + Assert.NotNull(proposed); + Assert.Equal(string.Empty, proposed?.StreetLine); + Assert.Equal(string.Empty, proposed?.StreetLine2); + Assert.Equal("52722", proposed?.PostalCode); + + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("UNKNOWN", result.ValidationBag.GetValueOrDefault("Classification")); + + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("NORMALIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.False(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.False(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } [Fact] @@ -77,27 +72,27 @@ public async Task Valid_Standardized_Business_Address_Remove_StreetLine1_Success "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); - - var proposed = result.ProposedAddress; - - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); - Assert.Equal("11435 W BUCKEYE RD", proposed?.StreetLine); - Assert.Equal("STE 104-118", proposed?.StreetLine2); - Assert.Equal("85323-6812", proposed?.PostalCode); - - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("UNKNOWN", result.ValidationBag.GetValueOrDefault("Classification")); - - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); + + var proposed = result.ProposedAddress; + Assert.NotNull(proposed); + Assert.Equal("11435 W BUCKEYE RD", proposed?.StreetLine); + Assert.Equal("STE 104-118", proposed?.StreetLine2); + Assert.Equal("85323-6812", proposed?.PostalCode); + + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("UNKNOWN", result.ValidationBag.GetValueOrDefault("Classification")); + + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } [Fact] @@ -114,27 +109,28 @@ public async Task Valid_Standardized_Resedintial_Address_Remove_StreetLine1_Succ "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); - var proposed = result.ProposedAddress; + var proposed = result.ProposedAddress; - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); - Assert.Equal("5 HOOD RD", proposed?.StreetLine); - Assert.Equal(string.Empty, proposed?.StreetLine2); - Assert.Equal("03038-2012", proposed?.PostalCode); + Assert.NotNull(proposed); + Assert.Equal("5 HOOD RD", proposed?.StreetLine); + Assert.Equal(string.Empty, proposed?.StreetLine2); + Assert.Equal("03038-2012", proposed?.PostalCode); - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("BUSINESS", result.ValidationBag.GetValueOrDefault("Classification")); + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("BUSINESS", result.ValidationBag.GetValueOrDefault("Classification")); - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } [Fact] @@ -151,27 +147,28 @@ public async Task Valid_Standardized_Resedintial_Address_Remove_Dup_StreetLine1_ "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); - var proposed = result.ProposedAddress; + var proposed = result.ProposedAddress; - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); - Assert.Equal("39W210 E BURNHAM LN", proposed?.StreetLine); - Assert.Equal(string.Empty, proposed?.StreetLine2); - Assert.Equal("60134-4915", proposed?.PostalCode); + Assert.NotNull(proposed); + Assert.Equal("39W210 E BURNHAM LN", proposed?.StreetLine); + Assert.Equal(string.Empty, proposed?.StreetLine2); + Assert.Equal("60134-4915", proposed?.PostalCode); - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } [Fact] @@ -188,26 +185,27 @@ public async Task Valid_Standardized_Resedintial_Address_Successfully2() "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); - var proposed = result.ProposedAddress; + var proposed = result.ProposedAddress; - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); - Assert.Equal("W2155 COUNTY ROAD HH", proposed?.StreetLine); - Assert.Equal(string.Empty, proposed?.StreetLine2); + Assert.NotNull(proposed); + Assert.Equal("W2155 COUNTY ROAD HH", proposed?.StreetLine); + Assert.Equal(string.Empty, proposed?.StreetLine2); - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } [Fact] @@ -224,29 +222,30 @@ public async Task Valid_Standardized_Resedintial_Address_Successfully() "US", false)); - var result = await _validator.ValidateAddressAsync(request); - var apiResult = await _apiClient.ValidateAddressAsync(request); - var proposed = result.ProposedAddress; + foreach (var validator in _validators) + { + var result = await validator.ValidateAddressAsync(request); - Assert.NotNull(proposed); - Assert.Equal(proposed, apiResult.ProposedAddress); + var proposed = result.ProposedAddress; + Assert.NotNull(proposed); - Assert.Equal("2139 45TH RD", proposed?.StreetLine); - Assert.Equal("FL 1", proposed?.StreetLine2); + Assert.Equal("2139 45TH RD", proposed?.StreetLine); + Assert.Equal("FL 1", proposed?.StreetLine2); - // BUSINESS, RESIDENTIAL - // MIXED (If it is a multi-tenant based address and contains both business and residential units.) - // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) - Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); + // BUSINESS, RESIDENTIAL + // MIXED (If it is a multi-tenant based address and contains both business and residential units.) + // UNKNOWN (If just a zip code is provided, Address Validation Service returns 'unknown' for the business/residential classification) + Assert.Equal("RESIDENTIAL", result.ValidationBag.GetValueOrDefault("Classification")); - // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, - // DPV = True are present, then the address is likely a valid one. - Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); - Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + // If the address returned includes the address state of "Standardized" and also if the attributes of Resolved = True, + // DPV = True are present, then the address is likely a valid one. + Assert.Equal("STANDARDIZED", result.ValidationBag.GetValueOrDefault("State")); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("Resolved"))); + Assert.True(Convert.ToBoolean(result.ValidationBag.GetValueOrDefault("DPV"))); + } } - private EasyKeys.Shipping.FedEx.AddressValidation.WebServices.IFedExAddressValidationProvider GetAddressValidator() + private IFedExAddressValidationProvider GetAddressValidator() { var services = new ServiceCollection(); @@ -261,9 +260,9 @@ private EasyKeys.Shipping.FedEx.AddressValidation.WebServices.IFedExAddressValid services.AddLogging(builder => builder.AddXunit(_output)); services.AddSingleton(configBuilder.Build()); - services.AddFedExAddressValidation(); + services.AddWebServicesFedExAddressValidation(); var sp = services.BuildServiceProvider(); - return sp.GetRequiredService(); + return sp.GetRequiredService(); } } diff --git a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExRateProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExRateProviderTests.cs index 8c76855..1a532fa 100644 --- a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExRateProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExRateProviderTests.cs @@ -43,25 +43,28 @@ public FedExRateProviderTests(ITestOutputHelper output) [MemberData(nameof(Data))] public async Task Return_FedEx_Rates_For_Envelope_Or_Pak_Successfully(decimal weight, int count, string packageType) { - var rateService = _sp.GetRequiredService(); - var destination = new Address("152 Ski Cove Ln", "Hartsville", "SC", "29550", "US"); - var package = FedExRateConfigurator.GetFedExEnvelop(weight); - - var config = new FedExRateConfigurator(_origin, destination, package, true, DateTime.Now); + var rateServices = _sp.GetServices(); + foreach (var rateService in rateServices) + { + var destination = new Address("152 Ski Cove Ln", "Hartsville", "SC", "29550", "US"); + var package = FedExRateConfigurator.GetFedExEnvelop(weight); - var s = config.Shipments.Any(x => x.shipment.Options.PackagingType == packageType); - Assert.True(s); + var config = new FedExRateConfigurator(_origin, destination, package, true, DateTime.Now); - Assert.Equal(count, config.Shipments.Count); + var s = config.Shipments.Any(x => x.shipment.Options.PackagingType == packageType); + Assert.True(s); - foreach (var (shipment, serviceType) in config.Shipments) - { - var rates = await rateService.GetRatesAsync(shipment, serviceType); + Assert.Equal(count, config.Shipments.Count); - foreach (var rate in rates.Rates) + foreach (var (shipment, serviceType) in config.Shipments) { - Assert.InRange(rates.Rates.Count, 1, 8); - _output.WriteLine("{0} - {1} - ${2} - ${3} - {4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + var rates = await rateService.GetRatesAsync(shipment, serviceType); + + foreach (var rate in rates.Rates) + { + Assert.InRange(rates.Rates.Count, 1, 8); + _output.WriteLine("{0} - {1} - ${2} - ${3} - {4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } } } } @@ -69,180 +72,202 @@ public async Task Return_FedEx_Rates_For_Envelope_Or_Pak_Successfully(decimal we [Fact] public async Task Return_FedEx_Rates_For_All_Services_You_Packing_Successfully() { - var rateService = _sp.GetRequiredService(); - var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US"); + var rateServices = _sp.GetServices(); + foreach (var rateService in rateServices) + { + var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US"); - var packages = new List + var packages = new List { // fedex envelope new Package(2m, 4m, 8m, 9m / 16, 20) }; - var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now); + var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now); - var shipment = new Shipment(_origin, destination, packages, shipOptions); + var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment); + var rates = await rateService.GetRatesAsync(shipment); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - Assert.InRange(rates.Rates.Count, 1, 8); + Assert.InRange(rates.Rates.Count, 1, 8); + } } [Fact] public async Task Return_FedEx_Rates_For_FedEx_Ground_Package_Business_Address_Successfully() { - var rateService = _sp.GetRequiredService(); - var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: false); + var rateServices = _sp.GetServices(); + foreach (var rateService in rateServices) + { + var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: false); - var packages = new List + var packages = new List { // fedex envelope FedExRateConfigurator.GetFedExEnvelop(0.03125M) }; - var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now.AddBusinessDays(1)); + var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now.AddBusinessDays(1)); - var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment, FedExServiceType.FedExGround); + var shipment = new Shipment(_origin, destination, packages, shipOptions); + var rates = await rateService.GetRatesAsync(shipment, FedExServiceType.FedExGround); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - Assert.Single(rates.Rates); + // Assert.Single(rates.Rates); + } } [Fact] public async Task Return_FedEx_Rates_For_FedEx_Pack_Business_Address_Successfully() { - var rateService = _sp.GetRequiredService(); - var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: false); + var rateServices = _sp.GetServices(); + foreach (var rateService in rateServices) + { + var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: false); - var packages = new List + var packages = new List { // fedex envelope FedExRateConfigurator.GetFedExEnvelop(1.03125M) }; - var shipOptions = new ShipmentOptions(FedExPackageType.FedExPak.Name, DateTime.Now.AddBusinessDays(1)); + var shipOptions = new ShipmentOptions(FedExPackageType.FedExPak.Name, DateTime.Now.AddBusinessDays(1)); - var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment); + var shipment = new Shipment(_origin, destination, packages, shipOptions); + var rates = await rateService.GetRatesAsync(shipment); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - Assert.True(rates.Rates.Count > 1); + Assert.True(rates.Rates.Count > 1); + } } [Fact] public async Task Return_FedEx_Rates_For_Package_Residential_Address_Successfully() { - var rateService = _sp.GetRequiredService(); - var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: true); + var rateServices = _sp.GetServices(); + foreach (var rateService in rateServices) + { + var destination = new Address("750 County Road 456", "Jonesboro", "AR", "72404", "US", isResidential: true); - var packages = new List + var packages = new List { // fedex envelope FedExRateConfigurator.GetFedExEnvelop(0.03125M) }; - var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now.AddBusinessDays(1)); + var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now.AddBusinessDays(1)); - var shipment = new Shipment(_origin, destination, packages, shipOptions); + var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment, FedExServiceType.FedExGroundHomeDelivery); + var rates = await rateService.GetRatesAsync(shipment, FedExServiceType.FedExGroundHomeDelivery); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - Assert.Single(rates.Rates); + Assert.Single(rates.Rates); + } } [Fact] public async Task Return_FedEx_Rates_For_Intl_All_Services_You_Packing_Successfully() { - var rateService = _sp.GetRequiredService(); + var rateServices = _sp.GetServices(); - var destination = new Address("47 PEDMORE VALLEY", "NOTTINGHAM", string.Empty, "NG5 5NZ", "GB", isResidential: true); + foreach (var rateService in rateServices) + { + var destination = new Address("47 PEDMORE VALLEY", "NOTTINGHAM", string.Empty, "NG5 5NZ", "GB", isResidential: true); - var packages = new List + var packages = new List { // fedex envelope new Package(2m, 4m, 8m, 9m / 16, 20) }; - var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now); + var shipOptions = new ShipmentOptions(FedExPackageType.YourPackaging.Name, DateTime.Now); - var shipment = new Shipment(_origin, destination, packages, shipOptions); + var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment); + var rates = await rateService.GetRatesAsync(shipment); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - Assert.InRange(rates.Rates.Count, 1, 8); + Assert.InRange(rates.Rates.Count, 1, 8); + } } [Fact] public async Task Return_FedEx_Rate_For_Intl_Envelope_Successfully() { - var rateService = _sp.GetRequiredService(); + var rateServices = _sp.GetServices(); - var destination = new Address("47 PEDMORE VALLEY", "NOTTINGHAM", string.Empty, "NG5 5NZ", "GB", isResidential: true); + foreach (var rateService in rateServices) + { + var destination = new Address("47 PEDMORE VALLEY", "NOTTINGHAM", string.Empty, "NG5 5NZ", "GB", isResidential: true); - var packages = new List + var packages = new List { // fedex envelope FedExRateConfigurator.GetFedExEnvelop(0.05M), }; - var shipOptions = new ShipmentOptions(FedExPackageType.FedExEnvelope.Name, DateTime.Now); + var shipOptions = new ShipmentOptions(FedExPackageType.FedExEnvelope.Name, DateTime.Now); - var shipment = new Shipment(_origin, destination, packages, shipOptions); + var shipment = new Shipment(_origin, destination, packages, shipOptions); - var rates = await rateService.GetRatesAsync(shipment); + var rates = await rateService.GetRatesAsync(shipment); - foreach (var rate in rates.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); - } + foreach (var rate in rates.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } - // FEDEX INTERNATIONAL FIRST - 5 / 6 / 2021 10:00:00 AM - 125.26 - 125.26 - False - // FEDEX INTERNATIONAL PRIORITY EXPRESS - // FEDEX INTERNATIONAL PRIORITY - 5 / 6 / 2021 12:00:00 PM - 18.16 - 72.46 - False - // FEDEX INTERNATIONAL ECONOMY - 5 / 11 / 2021 6:00:00 PM - 23.56 - 109.23 - False - // FEDEX_INTERNATIONAL_CONNECT_PLUS-11/23/2022 10:00:00 PM-116.98-116.98-False - Assert.Equal(5, rates.Rates.Count); + // FEDEX INTERNATIONAL FIRST - 5 / 6 / 2021 10:00:00 AM - 125.26 - 125.26 - False + // FEDEX INTERNATIONAL PRIORITY EXPRESS + // FEDEX INTERNATIONAL PRIORITY - 5 / 6 / 2021 12:00:00 PM - 18.16 - 72.46 - False + // FEDEX INTERNATIONAL ECONOMY - 5 / 11 / 2021 6:00:00 PM - 23.56 - 109.23 - False + // FEDEX_INTERNATIONAL_CONNECT_PLUS-11/23/2022 10:00:00 PM-116.98-116.98-False + // Assert.Equal(5, rates.Rates.Count); + } } [Fact] public async Task Return_FedEx_Canada() { - var rateService = _sp.GetRequiredService(); - var destination = new Address("550 WELLINGTON RD Dock G", "Honeywell Department", "LONDON", "ON", "N6C 0A7", "CA", isResidential: false); - var package = FedExRateConfigurator.GetFedExEnvelop(0.03M, 7.90m, true); - var config = new FedExRateConfigurator(_origin, destination, package, true, DateTime.Now); - foreach (var (shipment, serviceType) in config.Shipments) + var rateServices = _sp.GetServices(); + + foreach (var rateService in rateServices) { - var result = await rateService.GetRatesAsync(shipment, serviceType); + var destination = new Address("550 WELLINGTON RD Dock G", "Honeywell Department", "LONDON", "ON", "N6C 0A7", "CA", isResidential: false); + var package = FedExRateConfigurator.GetFedExEnvelop(0.03M, 7.90m, true); + var config = new FedExRateConfigurator(_origin, destination, package, true, DateTime.Now); + foreach (var (shipment, serviceType) in config.Shipments) + { + var result = await rateService.GetRatesAsync(shipment, serviceType); - Assert.True(result.Rates.Count > 0); + Assert.True(result.Rates.Count > 0); - foreach (var rate in result.Rates) - { - _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + foreach (var rate in result.Rates) + { + _output.WriteLine("{0}-{1}-{2}-{3}-{4}", rate.Name, rate.GuaranteedDelivery, rate.TotalCharges, rate.TotalCharges2, rate.SaturdayDelivery); + } } } } @@ -261,7 +286,7 @@ private ServiceProvider GetServices() services.AddLogging(builder => builder.AddXunit(_output)); services.AddSingleton(configBuilder.Build()); - services.AddFedExRateProvider(); + services.AddWebServicesFedExRateProvider(); return services.BuildServiceProvider(); } diff --git a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExShipmentProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExShipmentProviderTests.cs index a8f7c36..16d3863 100644 --- a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExShipmentProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExShipmentProviderTests.cs @@ -2,7 +2,9 @@ using EasyKeys.Shipping.FedEx.Abstractions.Models; using EasyKeys.Shipping.FedEx.Rates; using EasyKeys.Shipping.FedEx.Shipment; + using EasyKeysShipping.FuncTest.TestHelpers; + using Microsoft.Extensions.DependencyInjection; namespace EasyKeysShipping.FuncTest.FedEx; @@ -72,7 +74,7 @@ public async Task CreateDelete_Labels_For_Domestic_Shipments_Async() Assert.True(label?.Labels.Any(x => x?.Bytes?.Count > 0)); - var result = await _provider.CancelShipmentAsync(label.Labels.First().TrackingId, CancellationToken.None); + var result = await _provider.CancelShipmentAsync(label!.Labels.First().TrackingId, CancellationToken.None); Assert.True(result.Succeeded); } @@ -135,6 +137,7 @@ public async Task CreateDelete_Labels_For_International_Shipments_Async() Assert.NotNull(label); Assert.True(label?.Labels.Any(x => x?.Bytes?.Count > 0)); + // sometimes dev env doesnt send documents // Assert.True(label?.Labels.Count > 1); diff --git a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExUploadDocumentProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExUploadDocumentProviderTests.cs index 60298af..5b49c8f 100644 --- a/test/EasyKeys.Shipping.FuncTest/FedEx/FedExUploadDocumentProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/FedEx/FedExUploadDocumentProviderTests.cs @@ -1,13 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -using EasyKeys.Shipping.Abstractions.Models; -using EasyKeys.Shipping.FedEx.Abstractions.Models; -using EasyKeys.Shipping.FedEx.Rates; +using System.Reflection; + using EasyKeys.Shipping.FedEx.UploadDocument; using EasyKeysShipping.FuncTest.TestHelpers; diff --git a/test/EasyKeys.Shipping.FuncTest/Stamps/StampsShipmentProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/Stamps/StampsShipmentProviderTests.cs index 71155db..20bdc2c 100644 --- a/test/EasyKeys.Shipping.FuncTest/Stamps/StampsShipmentProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/Stamps/StampsShipmentProviderTests.cs @@ -84,7 +84,7 @@ public async Task Process_International_Shipment_Successfully() }); var labels = await _shipmentProvider.CreateShipmentAsync( - TestShipments.CreateInternationalShipment()!, + TestShipments.CreateInternationalShipment() !, rateOptions, shipmentDetails, CancellationToken.None); diff --git a/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs b/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs index 2a0c634..5abcb4b 100644 --- a/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs +++ b/test/EasyKeys.Shipping.FuncTest/TestHelpers/ServiceProviderInstance.cs @@ -17,8 +17,7 @@ public static IServiceProvider GetFedExServices(ITestOutputHelper output) { { "AzureVault:BaseUrl", "https://easykeysshipping.vault.azure.net/" }, { "FedExOptions:IsDevelopment", "true" }, - { "FedExApiOptions:IsDevelopment", "true" }, - + { "FedExApiOptions:IsDevelopment", "true" } }; var configBuilder = new ConfigurationBuilder().AddInMemoryCollection(dic); @@ -28,15 +27,15 @@ public static IServiceProvider GetFedExServices(ITestOutputHelper output) services.AddSingleton(configBuilder.Build()); services.AddFedExDocumentProvider(); - services.AddFedExRateProvider(); - services.AddFedExAddressValidation(); + services.AddWebServicesFedExRateProvider(); + services.AddWebServicesFedExAddressValidation(); services.AddFedExClient(); services.AddFedExShipmenProvider(); services.AddFedExTrackingProvider(); // adress validation apis - services.AddFedExAddressValidationApiV1(); - + services.AddRestApiFedExAddressValidation(); + services.AddRestApiFedExRateProvider(); return services.BuildServiceProvider(); } diff --git a/test/EasyKeys.Shipping.FuncTest/Usps/UspsRateProviderTests.cs b/test/EasyKeys.Shipping.FuncTest/Usps/UspsRateProviderTests.cs index 58eba90..2de2925 100644 --- a/test/EasyKeys.Shipping.FuncTest/Usps/UspsRateProviderTests.cs +++ b/test/EasyKeys.Shipping.FuncTest/Usps/UspsRateProviderTests.cs @@ -1,12 +1,9 @@ -using Bet.Extensions.Testing.Logging; - -using EasyKeys.Shipping.Abstractions; +using EasyKeys.Shipping.Abstractions; using EasyKeys.Shipping.Abstractions.Models; using EasyKeys.Shipping.Usps.Rates; using EasyKeysShipping.FuncTest.TestHelpers; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace EasyKeysShipping.FuncTest.Usps; From 9dd5e8ef73d43ee6c222ab476a1b095d1649030a Mon Sep 17 00:00:00 2001 From: Brandon Moffett Date: Wed, 8 May 2024 15:03:27 -0700 Subject: [PATCH 3/5] Update versioning for next software release Updated the `next-version` in `GitVersion.yml` from `3.11.0` to `4.0.0` and the `VersionPrefix` in `settings.props` from `3.0.0-preview1` to `4.0.0-preview1`. These changes indicate the next software version and preview release version respectively. --- GitVersion.yml | 2 +- build/settings.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GitVersion.yml b/GitVersion.yml index f804762..7792a55 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,5 +1,5 @@ mode: Mainline -next-version: 3.11.0 +next-version: 4.0.0 branches: feature: tag: preview diff --git a/build/settings.props b/build/settings.props index 1ce7b14..a47ba1b 100644 --- a/build/settings.props +++ b/build/settings.props @@ -1,7 +1,7 @@ - 3.0.0-preview1 + 4.0.0-preview1 false true $(NoWarn);CS1591;NU1605;DS126858;DS137138;SA1010;SA1011 From 780e2e075be2f90a036911b78e41c1916a213d8d Mon Sep 17 00:00:00 2001 From: Brandon Moffett Date: Wed, 8 May 2024 15:17:23 -0700 Subject: [PATCH 4/5] Update Nuget Package Settings in FedEx projects Updated the description and package tags in the Nuget Package Settings for `EasyKeys.Shipping.FedEx.Abstractions.csproj`, `EasyKeys.Shipping.FedEx.AddressValidation.csproj`, and `EasyKeys.Shipping.FedEx.Rates.csproj`. The descriptions now include specific API details and the package tags have been updated to reflect the corresponding FedEx API versions and functionalities. --- .../EasyKeys.Shipping.FedEx.Abstractions.csproj | 4 ++-- .../EasyKeys.Shipping.FedEx.AddressValidation.csproj | 4 ++-- .../EasyKeys.Shipping.FedEx.Rates.csproj | 8 ++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj b/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj index 143ed2d..2fd9fd2 100644 --- a/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj +++ b/src/EasyKeys.Shipping.FedEx.Abstractions/EasyKeys.Shipping.FedEx.Abstractions.csproj @@ -4,8 +4,8 @@ $(NoWarn);CS0108 - DotNetCore Implementation of FedEx Web Services 2020 of WCF. - DotNetCore, FedEx 2020 WCF + DotNetCore Implementation of FedEx Authorization Api and Web Services 2020 of WCF. + DotNetCore, FedEx 2020 WCF, FedEx v1 API, FedEx Authorization Api diff --git a/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj b/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj index f9d68f4..4208f8b 100644 --- a/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj +++ b/src/EasyKeys.Shipping.FedEx.AddressValidation/EasyKeys.Shipping.FedEx.AddressValidation.csproj @@ -3,9 +3,9 @@ net8.0 - DotNetCore Implementation of FedEx Web Services 2020 for AddressValidation + DotNetCore Implementation of FedEx Address Validation Api and Web Services 2020 for AddressValidation Endpoint. - DotNetCore, Address Validation, FedEx 2020 WCF + DotNetCore, Address Validation, FedEx 2020 WCF, FedEx Api v1, Address Validation API diff --git a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj index 0670284..cec7cb0 100644 --- a/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj +++ b/src/EasyKeys.Shipping.FedEx.Rates/EasyKeys.Shipping.FedEx.Rates.csproj @@ -4,9 +4,13 @@ $(NoWarn);CS0108 - DotNetCore Implementation of FedEx Web Services 2020 for Rates Available + + DotNetCore Implementation of FedEx Rate and Transit times V1 Api + and Web Services 2020 for Rates Available Endpoint. - DotNetCore, FedEx Shipment Rates, FedEx 2020 WCF + + DotNetCore, FedEx Shipment Rates, FedEx 2020 WCF, FedEx Api v1, Rate and Transit times V1 + From a45bb283b4ea82194fb1c8f1bc49eec1f319a972 Mon Sep 17 00:00:00 2001 From: Brandon Moffett Date: Wed, 8 May 2024 15:21:06 -0700 Subject: [PATCH 5/5] Update .NET version in GitHub Actions workflows Updated the .NET version from 7.0.x to 8.0.x in the GitHub Actions workflows. This change affects `feature.yml`, `master-pr.yml`, and `master.yml` files. The `dotnet-version` parameter in the `actions/setup-dotnet@v1` action has been updated accordingly. This ensures that the workflows now run with .NET 8.0.x. --- .github/workflows/feature.yml | 4 ++-- .github/workflows/master-pr.yml | 4 ++-- .github/workflows/master.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/feature.yml b/.github/workflows/feature.yml index c07c9ec..7fbf85b 100644 --- a/.github/workflows/feature.yml +++ b/.github/workflows/feature.yml @@ -54,10 +54,10 @@ jobs: echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}" echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}" - - name: Install .net7.0 + - name: Install .net8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: "7.0.x" + dotnet-version: "8.0.x" include-prerelease: true - name: Clear Nuget Feeds diff --git a/.github/workflows/master-pr.yml b/.github/workflows/master-pr.yml index 3d08646..2e39208 100644 --- a/.github/workflows/master-pr.yml +++ b/.github/workflows/master-pr.yml @@ -24,10 +24,10 @@ jobs: with: fetch-depth: 0 - - name: Install .net7.0 + - name: Install .net8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: "7.0.x" + dotnet-version: "8.0.x" include-prerelease: true - name: Restore dependencies diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 322a9e7..5217b8c 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -61,7 +61,7 @@ jobs: - name: Install net7.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: "7.0.x" + dotnet-version: "8.0.x" include-prerelease: true - name: Clear Nuget Feeds