diff --git a/README.md b/README.md index db65ccd5..4f9608b7 100644 --- a/README.md +++ b/README.md @@ -498,6 +498,13 @@ var result = amazonConnection.Notification.CreateSubscription( > **Tip:** if your subscriptions include `APPLICATION_OAUTH_CLIENT_NEW_SECRET`, wrap your `IMessageReceiver` with [`RotationApplyingMessageReceiver`](#application-management-v2023-11-30--rotate-the-lwa-client-secret) so a rotated client secret is applied to `amazonConnection.Credentials.ClientSecret` automatically before your receiver sees the message. +How the receive loop behaves: + +- **Long polling is on by default** (20 seconds). Leave `WaitTimeSeconds` unset unless you have a reason to change it; passing `0` forces short polling, which returns fewer messages per call and adds a 5 second pause between empty receives. +- **Up to 10 messages are received per call**, handed to your receiver one by one, then deleted with a single batch call. +- **Deletion** is controlled by `isDeleteNotificationAfterRead` (default `true` for `IMessageReceiver`). Implement `IMessageReceiverWithResult` instead and pass `false` if you want to decide per message - return `true` to delete, `false` to leave the message for redelivery after its visibility timeout. +- **One loop per call.** To drain a queue that has built up a backlog, start several `StartReceivingNotificationMessagesAsync` tasks against the same queue - SQS hands each receive call a different set of messages. + ```CSharp var SQS_URL = Environment.GetEnvironmentVariable("SQS_URL"); @@ -506,7 +513,7 @@ var param = new ParameterMessageReceiver( Environment.GetEnvironmentVariable("SecretKey"), SQS_URL, Amazon.RegionEndpoint.USEast2, - WaitTimeSeconds: 20); // Enable SQS long polling to reduce empty receives and cost + WaitTimeSeconds: 20); // Optional - long polling (20s) is the default; pass 0 for short polling var messageReceiver = new CustomMessageReceiver(); diff --git a/Source/FikaAmazonAPI.SampleCode/ApplicationManagementSample.cs b/Source/FikaAmazonAPI.SampleCode/ApplicationManagementSample.cs index 419de286..c4453ef3 100644 --- a/Source/FikaAmazonAPI.SampleCode/ApplicationManagementSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/ApplicationManagementSample.cs @@ -69,13 +69,13 @@ public Task StartReceivingWithRotationApplyAsync( string awsAccessKeyId, string awsSecretAccessKey, RegionEndpoint region, - IClientSecretStore store = null) + IClientSecretStore? store = null) { // The onRotated callback fires AFTER the secret has been applied to the live // AmazonCredential, so the running connection already uses the new secret by // the time we persist. Wrap the IO call so a DB outage doesn't kill the SQS // consumer loop — the SDK has already kept the in-memory credential current. - Action persist = null; + Action? persist = null; if (store != null) { persist = payload => diff --git a/Source/FikaAmazonAPI.SampleCode/FikaAmazonAPI.SampleCode.csproj b/Source/FikaAmazonAPI.SampleCode/FikaAmazonAPI.SampleCode.csproj index 8b759749..0ddcfc15 100644 --- a/Source/FikaAmazonAPI.SampleCode/FikaAmazonAPI.SampleCode.csproj +++ b/Source/FikaAmazonAPI.SampleCode/FikaAmazonAPI.SampleCode.csproj @@ -19,8 +19,6 @@ - - diff --git a/Source/FikaAmazonAPI.SampleCode/LoggingExamples.cs b/Source/FikaAmazonAPI.SampleCode/LoggingExamples.cs index 2ac214f7..9b414349 100644 --- a/Source/FikaAmazonAPI.SampleCode/LoggingExamples.cs +++ b/Source/FikaAmazonAPI.SampleCode/LoggingExamples.cs @@ -17,11 +17,11 @@ public LoggingExamples(IConfigurationRoot config) //AccessKey = config.GetSection("FikaAmazonAPI:AccessKey").Value, //SecretKey = config.GetSection("FikaAmazonAPI:SecretKey").Value, //RoleArn = config.GetSection("FikaAmazonAPI:RoleArn").Value, - ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value, - ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value, - RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value, - MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value, - SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value, + ClientId = config.Required("FikaAmazonAPI:ClientId"), + ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"), + RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"), + MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"), + SellerID = config.Required("FikaAmazonAPI:SellerId"), IsDebugMode = true, Environment = Constants.Environments.Sandbox }, loggerFactory: factory); diff --git a/Source/FikaAmazonAPI.SampleCode/NotificationsSample.cs b/Source/FikaAmazonAPI.SampleCode/NotificationsSample.cs index 7d8573dd..114228ff 100644 --- a/Source/FikaAmazonAPI.SampleCode/NotificationsSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/NotificationsSample.cs @@ -175,21 +175,19 @@ public void SetUpSqsNotifications() public async Task StartReceivingNotificationMessagesAsync(CancellationToken cancellationToken) { // Prevent unobserved task exceptions from crashing the process. - // The library fires off ProcessAnyOfferChangedMessage without await, - // so any exception in that path becomes an unobserved task exception. TaskScheduler.UnobservedTaskException += (sender, e) => { Console.WriteLine($"Unobserved task exception caught: {e.Exception?.Message}"); e.SetObserved(); }; - var SQS_URL = Environment.GetEnvironmentVariable("SQS_URL"); + var SQS_URL = SampleConfiguration.RequiredEnv("SQS_URL"); var param = new ParameterMessageReceiver( - Environment.GetEnvironmentVariable("AccessKey"), - Environment.GetEnvironmentVariable("SecretKey"), + SampleConfiguration.RequiredEnv("AccessKey"), + SampleConfiguration.RequiredEnv("SecretKey"), SQS_URL, Amazon.RegionEndpoint.USEast2, - WaitTimeSeconds: 20); // Enable SQS long polling to reduce empty receives and cost + WaitTimeSeconds: 20); // Optional - long polling (20s) is the default; pass 0 for short polling var messageReceiver = new CustomMessageReceiver(); diff --git a/Source/FikaAmazonAPI.SampleCode/Program.cs b/Source/FikaAmazonAPI.SampleCode/Program.cs index 8a7adee5..c696ed55 100644 --- a/Source/FikaAmazonAPI.SampleCode/Program.cs +++ b/Source/FikaAmazonAPI.SampleCode/Program.cs @@ -20,11 +20,11 @@ static async Task Main(string[] args) AmazonConnection amazonConnection = new AmazonConnection(new AmazonCredential() { - ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value, - ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value, - RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value, - MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value, - SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value, + ClientId = config.Required("FikaAmazonAPI:ClientId"), + ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"), + RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"), + MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"), + SellerID = config.Required("FikaAmazonAPI:SellerId"), IsDebugMode = true, }); diff --git a/Source/FikaAmazonAPI.SampleCode/ReportsSample.cs b/Source/FikaAmazonAPI.SampleCode/ReportsSample.cs index 94cc05ef..7d2fc5f7 100644 --- a/Source/FikaAmazonAPI.SampleCode/ReportsSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/ReportsSample.cs @@ -187,7 +187,7 @@ public string CreateReport_GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE() } - public string CreateReportAndDawnload(ReportTypes reportTypes, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null) + public string CreateReportAndDawnload(ReportTypes reportTypes, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null) { return amazonConnection.Reports.CreateReportAndDownloadFile(reportTypes, dataStartTime, dataEndTime, reportOptions); } diff --git a/Source/FikaAmazonAPI.SampleCode/SampleConfiguration.cs b/Source/FikaAmazonAPI.SampleCode/SampleConfiguration.cs new file mode 100644 index 00000000..c06ff7ec --- /dev/null +++ b/Source/FikaAmazonAPI.SampleCode/SampleConfiguration.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Configuration; + +namespace FikaAmazonAPI.SampleCode +{ + /// + /// Helpers for reading the credentials the samples need. + /// + /// requires ClientId, ClientSecret and RefreshToken — + /// AmazonConnection.ValidateCredentials throws when any of them is missing. + /// Reading them through these helpers fails at the point of the missing setting and + /// names the key, instead of letting a null travel into the SDK. + /// + public static class SampleConfiguration + { + /// Reads a required setting from configuration (appsettings.json / user secrets). + public static string Required(this IConfiguration config, string key) => + config.GetSection(key).Value + ?? throw new InvalidOperationException( + $"Missing configuration value '{key}'. Add it to appsettings.json or user secrets."); + + /// Reads a required environment variable. + public static string RequiredEnv(string name) => + Environment.GetEnvironmentVariable(name) + ?? throw new InvalidOperationException( + $"Missing environment variable '{name}'."); + } +} diff --git a/Source/FikaAmazonAPI.SampleCode/SerilogLoggingExamples.cs b/Source/FikaAmazonAPI.SampleCode/SerilogLoggingExamples.cs index 885b23b9..b9661efb 100644 --- a/Source/FikaAmazonAPI.SampleCode/SerilogLoggingExamples.cs +++ b/Source/FikaAmazonAPI.SampleCode/SerilogLoggingExamples.cs @@ -21,11 +21,11 @@ public SerilogLoggingExamples(IConfigurationRoot config) //AccessKey = config.GetSection("FikaAmazonAPI:AccessKey").Value, //SecretKey = config.GetSection("FikaAmazonAPI:SecretKey").Value, //RoleArn = config.GetSection("FikaAmazonAPI:RoleArn").Value, - ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value, - ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value, - RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value, - MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value, - SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value, + ClientId = config.Required("FikaAmazonAPI:ClientId"), + ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"), + RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"), + MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"), + SellerID = config.Required("FikaAmazonAPI:SellerId"), IsDebugMode = true, Environment = Constants.Environments.Sandbox }, loggerFactory: factory); diff --git a/Source/FikaAmazonAPI/.editorconfig b/Source/FikaAmazonAPI/.editorconfig new file mode 100644 index 00000000..b360fa04 --- /dev/null +++ b/Source/FikaAmazonAPI/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig for the FikaAmazonAPI library. +# https://editorconfig.org + +root = false + +# AmazonSpApiSDK/Models/** is swagger-generated from Amazon's OpenAPI specs +# (https://github.com/amzn/selling-partner-api-models) and is overwritten whenever +# the specs are regenerated. The generator emits required-property null guards and +# generated Equals/GetHashCode bodies that test non-nullable value types (enums, +# decimal, int) against null: +# +# if (unit == null) throw new InvalidDataException("unit is a required property..."); +# +# That produces ~400 CS0472 "expression is always true/false" warnings which are +# harmless, cannot be fixed without hand-editing generated code, and would come +# straight back on the next regeneration. Silence CS0472 for the generated models +# only, so the warning stays live for hand-written code under Services/, Parameter/ +# and ReportGeneration/. +# CS0109 comes from the same source: generated collection wrappers declare +# "public new string ToJson()" on a class deriving from List, which has no ToJson +# to hide. Also generator noise, also regenerated on every refresh. +[AmazonSpApiSDK/Models/**.cs] +dotnet_diagnostic.CS0472.severity = none +dotnet_diagnostic.CS0109.severity = none diff --git a/Source/FikaAmazonAPI/AmazonConnection.cs b/Source/FikaAmazonAPI/AmazonConnection.cs index 3b78bafc..5bbcaa02 100644 --- a/Source/FikaAmazonAPI/AmazonConnection.cs +++ b/Source/FikaAmazonAPI/AmazonConnection.cs @@ -124,7 +124,7 @@ public class AmazonConnection private UnauthorizedAccessException _NoCredentials = new UnauthorizedAccessException($"Error, you cannot make calls to Amazon without credentials!"); public string RefNumber { get; set; } - public AmazonConnection(AmazonCredential Credentials, string RefNumber = null, CultureInfo? cultureInfo = null, ILoggerFactory? loggerFactory = null) + public AmazonConnection(AmazonCredential Credentials, string? RefNumber = null, CultureInfo? cultureInfo = null, ILoggerFactory? loggerFactory = null) { _loggerFactory = loggerFactory; this.Authenticate(Credentials); diff --git a/Source/FikaAmazonAPI/AmazonCredential.cs b/Source/FikaAmazonAPI/AmazonCredential.cs index f0e91d39..3c264f92 100644 --- a/Source/FikaAmazonAPI/AmazonCredential.cs +++ b/Source/FikaAmazonAPI/AmazonCredential.cs @@ -41,7 +41,7 @@ public AmazonCredential() } public AmazonCredential(string AccessKey, string SecretKey, string RoleArn, string ClientId, - string ClientSecret, string RefreshToken, string ProxyAddress = null) + string ClientSecret, string RefreshToken, string? ProxyAddress = null) { this.AccessKey = AccessKey; this.SecretKey = SecretKey; diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributor.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributor.cs index a08a798c..7351c850 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributor.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributor.cs @@ -21,7 +21,8 @@ protected ItemContributor() { } /// The role of the contributor public ItemContributor(string value = default(string), ItemContributorRole itemContributorRole = default) { - Role = new ItemContributorRole(); + this.Value = value; + this.Role = itemContributorRole; } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributorRole.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributorRole.cs index 795d6e24..7b0c3895 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributorRole.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributorRole.cs @@ -61,7 +61,7 @@ public virtual string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as ItemImage); + return this.Equals(input as ItemContributorRole); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributors.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributors.cs index 87ec0b4b..097d1386 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributors.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/CatalogItems/V20220401/ItemContributors.cs @@ -38,7 +38,7 @@ public override string ToString() /// Boolean public override bool Equals(object input) { - return this.Equals(input as ItemImages); + return this.Equals(input as ItemContributors); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Exceptions/AmazonException.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Exceptions/AmazonException.cs index 3712944e..bea0fafb 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Exceptions/AmazonException.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Exceptions/AmazonException.cs @@ -8,7 +8,7 @@ public class AmazonException : Exception { public ExceptionResponse Response { get; set; } - public AmazonException(string msg, RestResponse response = null) : base(msg) + public AmazonException(string msg, RestResponse? response = null) : base(msg) { if (response != null) { @@ -22,7 +22,7 @@ public AmazonException(string msg, RestResponse response = null) : base(msg) public class AmazonNotFoundException : AmazonException { - public AmazonNotFoundException(string msg, RestResponse response = null) : base(msg, response) + public AmazonNotFoundException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -30,7 +30,7 @@ public AmazonNotFoundException(string msg, RestResponse response = null) : base( public class AmazonUnauthorizedException : AmazonException { - public AmazonUnauthorizedException(string msg, RestResponse response = null) : base(msg, response) + public AmazonUnauthorizedException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -40,7 +40,7 @@ public class AmazonInvalidInputException : AmazonException { public string Details { get; set; } - public AmazonInvalidInputException(string msg, string details = null, RestResponse response = null) : base(msg, response) + public AmazonInvalidInputException(string msg, string? details = null, RestResponse? response = null) : base(msg, response) { this.Details = details; //this.Data["Details"] = details; @@ -49,7 +49,7 @@ public AmazonInvalidInputException(string msg, string details = null, RestRespon public class AmazonQuotaExceededException : AmazonException { - public AmazonQuotaExceededException(string msg, RestResponse response = null) : base(msg, response) + public AmazonQuotaExceededException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -57,7 +57,7 @@ public AmazonQuotaExceededException(string msg, RestResponse response = null) : public class AmazonInvalidSignatureException : AmazonException { - public AmazonInvalidSignatureException(string msg, RestResponse response = null) : base(msg, response) + public AmazonInvalidSignatureException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -65,7 +65,7 @@ public AmazonInvalidSignatureException(string msg, RestResponse response = null) public class AmazonInternalErrorException : AmazonException { - public AmazonInternalErrorException(string msg, RestResponse response = null) : base(msg, response) + public AmazonInternalErrorException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -73,7 +73,7 @@ public AmazonInternalErrorException(string msg, RestResponse response = null) : public class AmazonBadRequestException : AmazonException { - public AmazonBadRequestException(string msg, RestResponse response = null) : base(msg, response) + public AmazonBadRequestException(string msg, RestResponse? response = null) : base(msg, response) { } @@ -82,7 +82,7 @@ public AmazonBadRequestException(string msg, RestResponse response = null) : bas public class AmazonProcessingReportDeserializeException : AmazonException { public string ReportContent { get; set; } - public AmazonProcessingReportDeserializeException(string msg, string reportContent, RestResponse response = null) : base(msg, response) + public AmazonProcessingReportDeserializeException(string msg, string reportContent, RestResponse? response = null) : base(msg, response) { ReportContent = reportContent; } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Feeds/GetFeedsResponseV00.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Feeds/GetFeedsResponseV00.cs index e66d81b3..ddb2f3ff 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Feeds/GetFeedsResponseV00.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Feeds/GetFeedsResponseV00.cs @@ -84,7 +84,7 @@ public string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as GetFeedsResponse); + return this.Equals(input as GetFeedsResponseV00); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Filters/AmazonFilter.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Filters/AmazonFilter.cs index a1919957..e8f6e488 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Filters/AmazonFilter.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Filters/AmazonFilter.cs @@ -5,7 +5,7 @@ public class AmazonFilter public int Limit { get; set; } public string NextPage { get; set; } - public AmazonFilter(int limit, string href = null) + public AmazonFilter(int limit, string? href = null) { Limit = limit; NextPage = href; diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Financesv20240619/RelatedIdentifier.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Financesv20240619/RelatedIdentifier.cs index 73e9446f..2baaa2c1 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Financesv20240619/RelatedIdentifier.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Financesv20240619/RelatedIdentifier.cs @@ -98,7 +98,13 @@ public enum RelatedIdentifierNameEnum [EnumMember(Value = "SETTLEMENT_ID")] SETTLEMENTID = 11, [EnumMember(Value = "SAFET_CLAIM_ID")] - SAFETCLAIMID = 12 + SAFETCLAIMID = 12, + + /// + /// Enum OBFUSCATEDSHIPMENTID for value: OBFUSCATED_SHIPMENT_ID + /// + [EnumMember(Value = "OBFUSCATED_SHIPMENT_ID")] + OBFUSCATEDSHIPMENTID = 13 } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/FulfillmentOutbound/FulfillmentPreviewShipment.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/FulfillmentOutbound/FulfillmentPreviewShipment.cs index cd1121ac..6eac7bd1 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/FulfillmentOutbound/FulfillmentPreviewShipment.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/FulfillmentOutbound/FulfillmentPreviewShipment.cs @@ -217,14 +217,10 @@ public override int GetHashCode() unchecked // Overflow is fine, just wrap { int hashCode = 41; - if (this.EarliestShipDate != null) - hashCode = hashCode * 59 + this.EarliestShipDate.GetHashCode(); - if (this.LatestShipDate != null) - hashCode = hashCode * 59 + this.LatestShipDate.GetHashCode(); - if (this.EarliestArrivalDate != null) - hashCode = hashCode * 59 + this.EarliestArrivalDate.GetHashCode(); - if (this.LatestArrivalDate != null) - hashCode = hashCode * 59 + this.LatestArrivalDate.GetHashCode(); + hashCode = hashCode * 59 + this.EarliestShipDateTime.GetHashCode(); + hashCode = hashCode * 59 + this.LatestShipDateTime.GetHashCode(); + hashCode = hashCode * 59 + this.EarliestArrivalDateTime.GetHashCode(); + hashCode = hashCode * 59 + this.LatestArrivalDateTime.GetHashCode(); if (this.FulfillmentPreviewItems != null) hashCode = hashCode * 59 + this.FulfillmentPreviewItems.GetHashCode(); return hashCode; diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/AsinIdentifier.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/AsinIdentifier.cs index 2d95ce62..b0f7a3a0 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/AsinIdentifier.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/AsinIdentifier.cs @@ -36,7 +36,8 @@ public AsinIdentifier() { } /// Amazon Standard Identification Number (ASIN) of the listings item. public AsinIdentifier(string marketplaceId = default(string), string asin = default(string)) { - + this.MarketplaceId = marketplaceId; + this.Asin = asin; } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/Audience.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/Audience.cs index 860058ae..9fc6f1de 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/Audience.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/Audience.cs @@ -36,7 +36,8 @@ protected Audience() { } /// Localized display name for the audience. public Audience(OfferAudienceEnum? value = default(OfferAudienceEnum?), string displayName = default(string)) { - + this.Value = value; + this.DisplayName = displayName; } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/IssueCategoryEnum.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/IssueCategoryEnum.cs index cb9d4d65..6b050fb1 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/IssueCategoryEnum.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ListingsItems/IssueCategoryEnum.cs @@ -71,5 +71,17 @@ public enum IssueCategory /// [EnumMember(Value = "QUALIFICATION_REQUIRED")] QUALIFICATION_REQUIRED = 8, + + /// + /// Enum PRODUCT for value: PRODUCT + /// + [EnumMember(Value = "PRODUCT")] + PRODUCT = 9, + + /// + /// Enum LISTING for value: LISTING + /// + [EnumMember(Value = "LISTING")] + LISTING = 10, } } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Messaging/GetMessagingActionsForOrderResponseLinks.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Messaging/GetMessagingActionsForOrderResponseLinks.cs index a63e5dfc..e3f90089 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Messaging/GetMessagingActionsForOrderResponseLinks.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Messaging/GetMessagingActionsForOrderResponseLinks.cs @@ -1,6 +1,7 @@  using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; using System.ComponentModel.DataAnnotations; @@ -48,7 +49,7 @@ public virtual string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as GetMessagingActionsForOrderResponse); + return this.Equals(input as GetMessagingActionsForOrderResponseLinks); } @@ -83,7 +84,21 @@ public override int GetHashCode() public bool Equals(GetMessagingActionsForOrderResponseLinks input) { - return this.Equals(input); + if (input == null) + return false; + + return + ( + this.Self == input.Self || + this.Self != null && + this.Self.Equals(input.Self) + ) && + ( + this.Actions == input.Actions || + this.Actions != null && + input.Actions != null && + this.Actions.SequenceEqual(input.Actions) + ); } } } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Reports/GetReportsResponseV00.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Reports/GetReportsResponseV00.cs index 4e379d67..b0d411f2 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Reports/GetReportsResponseV00.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Reports/GetReportsResponseV00.cs @@ -92,7 +92,7 @@ public string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as GetReportsResponse); + return this.Equals(input as GetReportsResponseV00); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Sales/Money.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Sales/Money.cs index 0ef994a2..bc43ba20 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Sales/Money.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Sales/Money.cs @@ -45,6 +45,7 @@ public Money() { } { this.CurrencyCode = CurrencyCode; } + this.Amount = Amount; } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ShipmentInvoicing/ShipmentDetail.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ShipmentInvoicing/ShipmentDetail.cs index 6cb000dc..7cb6cca5 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ShipmentInvoicing/ShipmentDetail.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/ShipmentInvoicing/ShipmentDetail.cs @@ -29,7 +29,18 @@ public ShipmentDetail() public override bool Equals(object input) { - return this.Equals(input as GetShipmentDetailsResponse); + return this.Equals(input as ShipmentDetail); + } + + /// + /// Gets the hash code, kept consistent with Equals(ShipmentDetail). + /// + public override int GetHashCode() + { + unchecked + { + return this.WarehouseId == null ? 0 : this.WarehouseId.GetHashCode(); + } } public bool Equals(ShipmentDetail input) { diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderAcknowledgementItem.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderAcknowledgementItem.cs index b939e867..25b2c607 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderAcknowledgementItem.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderAcknowledgementItem.cs @@ -30,6 +30,7 @@ public OrderAcknowledgementItem() { } } ItemSequenceNumber = itemSequenceNumber; AmazonProductIdentifier = amazonProductIdentifier; + VendorProductIdentifier = vendorProductIdentifier; NetCost = netCost; ListPrice = listPrice; DiscountMultiplier = discountMultiplier; diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderStatus.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderStatus.cs index b922d462..4b6d71bc 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderStatus.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderStatus.cs @@ -131,7 +131,7 @@ public virtual string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as Order); + return this.Equals(input as OrderStatus); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderedQuantityDetails.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderedQuantityDetails.cs index f57c57cc..d2d97301 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderedQuantityDetails.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/VendorOrders/OrderedQuantityDetails.cs @@ -61,7 +61,7 @@ public virtual string ToJson() /// Boolean public override bool Equals(object input) { - return this.Equals(input as orderedQuantity); + return this.Equals(input as OrderedQuantityDetails); } /// diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAAccessTokenRequestMeta.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAAccessTokenRequestMeta.cs index 53e27dcc..f0403ff8 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAAccessTokenRequestMeta.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAAccessTokenRequestMeta.cs @@ -30,5 +30,19 @@ public override bool Equals(object obj) ClientSecret == other.ClientSecret && Scope == other.Scope; } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 31) + (GrantType == null ? 0 : GrantType.GetHashCode()); + hash = (hash * 31) + (RefreshToken == null ? 0 : RefreshToken.GetHashCode()); + hash = (hash * 31) + (ClientId == null ? 0 : ClientId.GetHashCode()); + hash = (hash * 31) + (ClientSecret == null ? 0 : ClientSecret.GetHashCode()); + hash = (hash * 31) + (Scope == null ? 0 : Scope.GetHashCode()); + return hash; + } + } } } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAClient.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAClient.cs index a84967fc..4fc294a6 100644 --- a/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAClient.cs +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Runtime/LWAClient.cs @@ -20,7 +20,7 @@ public class LWAClient public LWAAuthorizationCredentials LWAAuthorizationCredentials { get; private set; } - public LWAClient(LWAAuthorizationCredentials lwaAuthorizationCredentials, IWebProxy proxy = null) + public LWAClient(LWAAuthorizationCredentials lwaAuthorizationCredentials, IWebProxy? proxy = null) { LWAAuthorizationCredentials = lwaAuthorizationCredentials; diff --git a/Source/FikaAmazonAPI/ConstructFeed/Messages/InventoryMessage.cs b/Source/FikaAmazonAPI/ConstructFeed/Messages/InventoryMessage.cs index 23e18ea0..d010eaef 100644 --- a/Source/FikaAmazonAPI/ConstructFeed/Messages/InventoryMessage.cs +++ b/Source/FikaAmazonAPI/ConstructFeed/Messages/InventoryMessage.cs @@ -15,7 +15,7 @@ public class InventoryMessage [XmlElement(DataType = "date")] public DateTime? RestockDate { get; set; } - public string FulfillmentLatency { get; set; } + public string? FulfillmentLatency { get; set; } public InventorySwitchFulfillmentTo? SwitchFulfillmentTo { get; set; } diff --git a/Source/FikaAmazonAPI/FikaAmazonAPI.csproj b/Source/FikaAmazonAPI/FikaAmazonAPI.csproj index 30c8ffdf..a9e4535b 100644 --- a/Source/FikaAmazonAPI/FikaAmazonAPI.csproj +++ b/Source/FikaAmazonAPI/FikaAmazonAPI.csproj @@ -7,9 +7,12 @@ CSharp Amazon Sp API true 8.0 - 1.9.31 - 1.9.31 - 1.9.31 + + annotations + 1.9.33 + 1.9.33 + 1.9.33 true https://github.com/abuzuhri/Amazon-SP-API-CSharp https://github.com/abuzuhri/Amazon-SP-API-CSharp @@ -33,13 +36,13 @@ - - + + - - + + - + diff --git a/Source/FikaAmazonAPI/Parameter/DataKiosk/ParameterGetQueries.cs b/Source/FikaAmazonAPI/Parameter/DataKiosk/ParameterGetQueries.cs index e820cd1c..375ff9fa 100644 --- a/Source/FikaAmazonAPI/Parameter/DataKiosk/ParameterGetQueries.cs +++ b/Source/FikaAmazonAPI/Parameter/DataKiosk/ParameterGetQueries.cs @@ -34,6 +34,6 @@ public class ParameterGetQueries : ParameterBased /// /// A token to fetch a certain page of results when there are multiple pages. /// - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/ExternalFulfillmentShipment/ParameterGetShipments.cs b/Source/FikaAmazonAPI/Parameter/ExternalFulfillmentShipment/ParameterGetShipments.cs index 5b91f88c..fdfa0feb 100644 --- a/Source/FikaAmazonAPI/Parameter/ExternalFulfillmentShipment/ParameterGetShipments.cs +++ b/Source/FikaAmazonAPI/Parameter/ExternalFulfillmentShipment/ParameterGetShipments.cs @@ -45,7 +45,7 @@ public class ParameterGetShipments : ParameterBased /// /// A token that you use to retrieve the next page of results. The response includes nextToken when there are multiple pages of results. /// - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } /// /// Maximum number of pages to return. When null, all pages are fetched. diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlanBase.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlanBase.cs index 700faf5f..0ac9ddff 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlanBase.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlanBase.cs @@ -4,6 +4,6 @@ public class ParameterListInboundPlanBase : PaginationParameter { public string InboundPlanId { get; set; } - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlans.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlans.cs index bfe9cdd0..90bf88f6 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlans.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListInboundPlans.cs @@ -6,7 +6,7 @@ namespace FikaAmazonAPI.Parameter.FulFillmentInbound.v20240320 [CamelCase] public class ParameterListInboundPlans : PaginationParameter { - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } public InboundPlanStatus? Status { get; set; } public SortBy? SortBy { get; set; } public SortOrderEnum? SortOrder { get; set; } diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupBoxes.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupBoxes.cs index 37b577c9..7cca3cd8 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupBoxes.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupBoxes.cs @@ -5,6 +5,6 @@ public class ParameterListPackingGroupBoxes : PaginationParameter { public string InboundPlanId { get; set; } public string PackingGroupId { get; set; } - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupItems.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupItems.cs index 0f55e068..d3b17d2b 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupItems.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListPackingGroupItems.cs @@ -5,6 +5,6 @@ public class ParameterListPackingGroupItems : PaginationParameter { public string InboundPlanId { get; set; } public string PackingGroupId { get; set; } - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListShipmentBase.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListShipmentBase.cs index 53e541ed..ea0a3dbf 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListShipmentBase.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListShipmentBase.cs @@ -5,6 +5,6 @@ public class ParameterListShipmentBase : PaginationParameter { public string InboundPlanId { get; set; } public string ShipmentId { get; set; } - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListTransportationOptions.cs b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListTransportationOptions.cs index 8a2d02fe..59c0ad62 100644 --- a/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListTransportationOptions.cs +++ b/Source/FikaAmazonAPI/Parameter/FulFillmentInbound/v20240320/ParameterListTransportationOptions.cs @@ -5,6 +5,6 @@ public class ParameterListTransportationOptions : PaginationParameter { public string PlacementOptionId { get; set; } public string ShipmentId { get; set; } - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } } } diff --git a/Source/FikaAmazonAPI/Parameter/Notification/RotationApplyingMessageReceiver.cs b/Source/FikaAmazonAPI/Parameter/Notification/RotationApplyingMessageReceiver.cs index 83f7bbac..22523229 100644 --- a/Source/FikaAmazonAPI/Parameter/Notification/RotationApplyingMessageReceiver.cs +++ b/Source/FikaAmazonAPI/Parameter/Notification/RotationApplyingMessageReceiver.cs @@ -33,7 +33,7 @@ public class RotationApplyingMessageReceiver : IMessageReceiverWithResult public RotationApplyingMessageReceiver( IMessageReceiverWithResult inner, AmazonCredential credentials, - Action onRotated = null) + Action? onRotated = null) { _inner = inner ?? throw new ArgumentNullException(nameof(inner)); _credentials = credentials ?? throw new ArgumentNullException(nameof(credentials)); @@ -48,7 +48,7 @@ public RotationApplyingMessageReceiver( public RotationApplyingMessageReceiver( IMessageReceiver inner, AmazonCredential credentials, - Action onRotated = null) + Action? onRotated = null) : this(new VoidToBoolAdapter(inner), credentials, onRotated) { } diff --git a/Source/FikaAmazonAPI/Parameter/Order/V20260101/ParameterSearchOrders.cs b/Source/FikaAmazonAPI/Parameter/Order/V20260101/ParameterSearchOrders.cs index a840dd04..700584bb 100644 --- a/Source/FikaAmazonAPI/Parameter/Order/V20260101/ParameterSearchOrders.cs +++ b/Source/FikaAmazonAPI/Parameter/Order/V20260101/ParameterSearchOrders.cs @@ -69,7 +69,7 @@ public ParameterSearchOrders() /// /// Pagination occurs when a request produces a response that exceeds the maxResultsPerPage. This means that the response is divided into individual pages. To retrieve the next page, you must pass the nextToken value as the paginationToken query parameter in the next request. You will not receive a nextToken value on the last page. /// - public string PaginationToken { get; set; } + public string? PaginationToken { get; set; } /// /// Maximum number of pages to return diff --git a/Source/FikaAmazonAPI/ReportGeneration/ReportManager.cs b/Source/FikaAmazonAPI/ReportGeneration/ReportManager.cs index c4a87750..4a78deb6 100644 --- a/Source/FikaAmazonAPI/ReportGeneration/ReportManager.cs +++ b/Source/FikaAmazonAPI/ReportGeneration/ReportManager.cs @@ -109,11 +109,11 @@ private async Task GetReimbursementsOrderAsync(AmazonConnection am #region ReturnFBAOrder - public List GetReturnFBAOrder(int days, List marketplaces = null) => + public List GetReturnFBAOrder(int days, List? marketplaces = null) => Task.Run(() => GetReturnFBAOrderAsync(days, marketplaces)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task> GetReturnFBAOrderAsync(int days, - List marketplaces = null, CancellationToken cancellationToken = default) + List? marketplaces = null, CancellationToken cancellationToken = default) { DateTime fromDate = DateTime.UtcNow.AddDays(-1 * days); DateTime toDate = DateTime.UtcNow; @@ -121,12 +121,12 @@ public async Task> GetReturnFBAOrderAsync(int days, } public List GetReturnFBAOrder(DateTime fromDate, DateTime toDate, - List marketplaces = null) => + List? marketplaces = null) => Task.Run(() => GetReturnFBAOrderAsync(fromDate, toDate, marketplaces)).ConfigureAwait(false).GetAwaiter() .GetResult(); public async Task> GetReturnFBAOrderAsync(DateTime fromDate, DateTime toDate, - List marketplaces = null, CancellationToken cancellationToken = default) + List? marketplaces = null, CancellationToken cancellationToken = default) { using var stream = await GetReturnFBAOrderAsync(_amazonConnection, fromDate, toDate, marketplaces, cancellationToken); @@ -136,7 +136,7 @@ public async Task> GetReturnFBAOrderAsync(DateTime fromD } private async Task GetReturnFBAOrderAsync(AmazonConnection amazonConnection, DateTime fromDate, - DateTime toDate, List marketplaces = null, CancellationToken cancellationToken = default) + DateTime toDate, List? marketplaces = null, CancellationToken cancellationToken = default) { return await amazonConnection.Reports.CreateReportAndDownloadFileStreamAsync( ReportTypes.GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA, fromDate, toDate, marketplaces: marketplaces, @@ -278,10 +278,10 @@ private async Task GetInventoryAgingAsync(AmazonConnection amazonC #region Products - public List GetProducts(List marketplaces = null) => + public List GetProducts(List? marketplaces = null) => Task.Run(() => GetProductsAsync(marketplaces)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task> GetProductsAsync(List marketplaces = null, + public async Task> GetProductsAsync(List? marketplaces = null, CancellationToken cancellationToken = default) { using var stream = await GetProductsAsync(_amazonConnection, marketplaces, cancellationToken); @@ -289,7 +289,7 @@ public async Task> GetProductsAsync(List marketpl return report.Data; } - private Task GetProductsAsync(AmazonConnection amazonConnection, List marketplaces = null, + private Task GetProductsAsync(AmazonConnection amazonConnection, List? marketplaces = null, CancellationToken cancellationToken = default) { return amazonConnection.Reports.CreateReportAndDownloadFileStreamAsync(ReportTypes.GET_MERCHANT_LISTINGS_ALL_DATA, @@ -419,12 +419,12 @@ private async Task GetOrdersByOrderDateAsync(AmazonConnection amaz } public List GetOrderInvoicingData(DateTime fromDate, DateTime toDate, - List marketplaces = null) => + List? marketplaces = null) => Task.Run(() => GetOrderInvoicingDataAsync(fromDate, toDate, marketplaces)).ConfigureAwait(false) .GetAwaiter().GetResult(); public async Task> GetOrderInvoicingDataAsync(DateTime fromDate, DateTime toDate, - List marketplaces = null) + List? marketplaces = null) { List list = new List(); var dateList = ReportDateRange.GetDateRange(fromDate, toDate, DAY_30); @@ -440,7 +440,7 @@ public async Task> GetOrderInvoicingDataAsync(Date } private async Task GetOrderInvoicingDataAsync(AmazonConnection amazonConnection, DateTime fromDate, - DateTime toDate, List marketplaces = null) + DateTime toDate, List? marketplaces = null) { var options = new AmazonSpApiSDK.Models.Reports.ReportOptions(); options.Add("ShowSalesChannel", "true"); @@ -453,12 +453,12 @@ private async Task GetOrderInvoicingDataAsync(AmazonConnection ama #region VatInvoicing public List GetVATInvoicingData(DateTime fromDate, DateTime toDate, - List marketplaces = null) => + List? marketplaces = null) => Task.Run(() => GetVATInvoicingDataAsync(fromDate, toDate, marketplaces)).ConfigureAwait(false) .GetAwaiter().GetResult(); public async Task> GetVATInvoicingDataAsync(DateTime fromDate, DateTime toDate, - List marketplaces = null) + List? marketplaces = null) { List list = new List(); var dateList = ReportDateRange.GetDateRange(fromDate, toDate, DAY_30); @@ -474,7 +474,7 @@ public async Task> GetVATInvoicingDataAsync(DateTime } private async Task GetVATInvoicingDataAsync(AmazonConnection amazonConnection, DateTime fromDate, - DateTime toDate, List marketplaces = null) + DateTime toDate, List? marketplaces = null) { var options = new ReportOptions(); options.Add("ReportOption=All", "true"); diff --git a/Source/FikaAmazonAPI/ReportGeneration/ReportParser.cs b/Source/FikaAmazonAPI/ReportGeneration/ReportParser.cs index 508901fd..b5e0ec56 100644 --- a/Source/FikaAmazonAPI/ReportGeneration/ReportParser.cs +++ b/Source/FikaAmazonAPI/ReportGeneration/ReportParser.cs @@ -9,7 +9,7 @@ namespace FikaAmazonAPI.ReportGeneration { internal static class ReportParser { - internal static List ParseTableRows(Stream stream, Func map, string refNumber, Encoding encoding = null) + internal static List ParseTableRows(Stream stream, Func map, string refNumber, Encoding? encoding = null) { if (stream == null || stream.Length == 0) return new List(); @@ -25,7 +25,7 @@ internal static List ParseTableRows(Stream stream, Func ParseTableRows(Stream stream, Func map, Encoding encoding = null) + internal static List ParseTableRows(Stream stream, Func map, Encoding? encoding = null) { if (stream == null || stream.Length == 0) return new List(); @@ -41,7 +41,7 @@ internal static List ParseTableRows(Stream stream, Func map, return values; } - internal static List ParseCsvLines(Stream stream, Func map, string refNumber, Encoding encoding = null) + internal static List ParseCsvLines(Stream stream, Func map, string refNumber, Encoding? encoding = null) { if (stream == null || stream.Length == 0) return new List(); diff --git a/Source/FikaAmazonAPI/ReportGeneration/VatInvoicingReport.cs b/Source/FikaAmazonAPI/ReportGeneration/VatInvoicingReport.cs index e185be90..68f3763d 100644 --- a/Source/FikaAmazonAPI/ReportGeneration/VatInvoicingReport.cs +++ b/Source/FikaAmazonAPI/ReportGeneration/VatInvoicingReport.cs @@ -222,8 +222,6 @@ public static VatInvoicingReportRow FromRow(TableRow rowData, string refNumber) row.refNumber = refNumber; return row; - - return row; } } } diff --git a/Source/FikaAmazonAPI/Services/ApiUrls.cs b/Source/FikaAmazonAPI/Services/ApiUrls.cs index cae5c997..00b50710 100644 --- a/Source/FikaAmazonAPI/Services/ApiUrls.cs +++ b/Source/FikaAmazonAPI/Services/ApiUrls.cs @@ -596,6 +596,7 @@ public static string ListFinancialEventGroups } public static string ListFinancialEventsByGroupId(string eventGroupId) => $"{_resourceBaseUrl}/financialEventGroups/{eventGroupId}/financialEvents"; public static string ListFinancialEventsByOrderId(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/financialEvents"; + public static string ListFinancialEventsByShipmentId(string shipmentId) => $"{_resourceBaseUrl}/financialEvents/shipment/{shipmentId}"; public static string ListFinancialEvents { get => $"{_resourceBaseUrl}/financialEvents"; @@ -778,8 +779,6 @@ protected class ProductTypeDefinitionsApi protected class AppIntegrationsApiUrls { - private readonly static string _resourceBaseUrl = "appIntegrations"; - #region V20240401 private readonly static string _resourceBaseUrl_V20240401 = "appIntegrations/2024-04-01"; diff --git a/Source/FikaAmazonAPI/Services/AplusContentService.cs b/Source/FikaAmazonAPI/Services/AplusContentService.cs index 85e430aa..b15c0b1d 100644 --- a/Source/FikaAmazonAPI/Services/AplusContentService.cs +++ b/Source/FikaAmazonAPI/Services/AplusContentService.cs @@ -21,10 +21,10 @@ public AplusContentService(AmazonCredential amazonCredential, ILoggerFactory? lo // -- searchContentDocuments --------------------------------------------------- - public IList SearchContentDocuments(string marketplaceId = null) => + public IList SearchContentDocuments(string? marketplaceId = null) => Task.Run(() => SearchContentDocumentsAsync(marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task> SearchContentDocumentsAsync(string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task> SearchContentDocumentsAsync(string? marketplaceId = null, CancellationToken cancellationToken = default) { var marketplace = string.IsNullOrEmpty(marketplaceId) ? AmazonCredential.MarketPlace.ID : marketplaceId; var records = new List(); @@ -50,10 +50,10 @@ public async Task> SearchContentDocumentsAsync(stri // -- createContentDocument ---------------------------------------------------- - public PostContentDocumentResponse CreateContentDocument(PostContentDocumentRequest request, string marketplaceId = null) => + public PostContentDocumentResponse CreateContentDocument(PostContentDocumentRequest request, string? marketplaceId = null) => Task.Run(() => CreateContentDocumentAsync(request, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CreateContentDocumentAsync(PostContentDocumentRequest request, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task CreateContentDocumentAsync(PostContentDocumentRequest request, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (request?.ContentDocument == null) throw new InvalidDataException("request.ContentDocument is required"); @@ -68,10 +68,10 @@ public async Task CreateContentDocumentAsync(PostCo // -- getContentDocument ------------------------------------------------------- - public GetContentDocumentResponse GetContentDocument(string contentReferenceKey, IList includedDataSet, string marketplaceId = null) => + public GetContentDocumentResponse GetContentDocument(string contentReferenceKey, IList includedDataSet, string? marketplaceId = null) => Task.Run(() => GetContentDocumentAsync(contentReferenceKey, includedDataSet, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetContentDocumentAsync(string contentReferenceKey, IList includedDataSet, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task GetContentDocumentAsync(string contentReferenceKey, IList includedDataSet, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); @@ -89,10 +89,10 @@ public async Task GetContentDocumentAsync(string con // -- updateContentDocument ---------------------------------------------------- - public PostContentDocumentResponse UpdateContentDocument(string contentReferenceKey, PostContentDocumentRequest request, string marketplaceId = null) => + public PostContentDocumentResponse UpdateContentDocument(string contentReferenceKey, PostContentDocumentRequest request, string? marketplaceId = null) => Task.Run(() => UpdateContentDocumentAsync(contentReferenceKey, request, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task UpdateContentDocumentAsync(string contentReferenceKey, PostContentDocumentRequest request, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task UpdateContentDocumentAsync(string contentReferenceKey, PostContentDocumentRequest request, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); @@ -109,10 +109,10 @@ public async Task UpdateContentDocumentAsync(string // -- listContentDocumentAsinRelations ---------------------------------------- - public IList ListContentDocumentAsinRelations(string contentReferenceKey, IList includedDataSet = null, IList asins = null, string marketplaceId = null) => + public IList ListContentDocumentAsinRelations(string contentReferenceKey, IList? includedDataSet = null, IList? asins = null, string? marketplaceId = null) => Task.Run(() => ListContentDocumentAsinRelationsAsync(contentReferenceKey, includedDataSet, asins, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task> ListContentDocumentAsinRelationsAsync(string contentReferenceKey, IList includedDataSet = null, IList asins = null, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task> ListContentDocumentAsinRelationsAsync(string contentReferenceKey, IList? includedDataSet = null, IList? asins = null, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); @@ -145,10 +145,10 @@ public async Task> ListContentDocumentAsinRelationsAsync(str // -- postContentDocumentAsinRelations ----------------------------------------- - public PostContentDocumentAsinRelationsResponse PostContentDocumentAsinRelations(string contentReferenceKey, PostContentDocumentAsinRelationsRequest request, string marketplaceId = null) => + public PostContentDocumentAsinRelationsResponse PostContentDocumentAsinRelations(string contentReferenceKey, PostContentDocumentAsinRelationsRequest request, string? marketplaceId = null) => Task.Run(() => PostContentDocumentAsinRelationsAsync(contentReferenceKey, request, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task PostContentDocumentAsinRelationsAsync(string contentReferenceKey, PostContentDocumentAsinRelationsRequest request, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task PostContentDocumentAsinRelationsAsync(string contentReferenceKey, PostContentDocumentAsinRelationsRequest request, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); @@ -165,10 +165,10 @@ public async Task PostContentDocumentA // -- validateContentDocumentAsinRelations ------------------------------------- - public ValidateContentDocumentAsinRelationsResponse ValidateContentDocumentAsinRelations(PostContentDocumentRequest request, IList asins = null, string marketplaceId = null) => + public ValidateContentDocumentAsinRelationsResponse ValidateContentDocumentAsinRelations(PostContentDocumentRequest request, IList? asins = null, string? marketplaceId = null) => Task.Run(() => ValidateContentDocumentAsinRelationsAsync(request, asins, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task ValidateContentDocumentAsinRelationsAsync(PostContentDocumentRequest request, IList asins = null, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task ValidateContentDocumentAsinRelationsAsync(PostContentDocumentRequest request, IList? asins = null, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (request?.ContentDocument == null) throw new InvalidDataException("request.ContentDocument is required"); @@ -186,10 +186,10 @@ public async Task ValidateContentD // -- searchContentPublishRecords ---------------------------------------------- - public IList SearchContentPublishRecords(string asin, string marketplaceId = null) => + public IList SearchContentPublishRecords(string asin, string? marketplaceId = null) => Task.Run(() => SearchContentPublishRecordsAsync(asin, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task> SearchContentPublishRecordsAsync(string asin, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task> SearchContentPublishRecordsAsync(string asin, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(asin)) throw new InvalidDataException("asin is required"); @@ -219,10 +219,10 @@ public async Task> SearchContentPublishRecordsAsync(string // -- postContentDocumentApprovalSubmission ------------------------------------ - public PostContentDocumentApprovalSubmissionResponse PostContentDocumentApprovalSubmission(string contentReferenceKey, string marketplaceId = null) => + public PostContentDocumentApprovalSubmissionResponse PostContentDocumentApprovalSubmission(string contentReferenceKey, string? marketplaceId = null) => Task.Run(() => PostContentDocumentApprovalSubmissionAsync(contentReferenceKey, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task PostContentDocumentApprovalSubmissionAsync(string contentReferenceKey, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task PostContentDocumentApprovalSubmissionAsync(string contentReferenceKey, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); @@ -237,10 +237,10 @@ public async Task PostContentDocu // -- postContentDocumentSuspendSubmission ------------------------------------- - public PostContentDocumentSuspendSubmissionResponse PostContentDocumentSuspendSubmission(string contentReferenceKey, string marketplaceId = null) => + public PostContentDocumentSuspendSubmissionResponse PostContentDocumentSuspendSubmission(string contentReferenceKey, string? marketplaceId = null) => Task.Run(() => PostContentDocumentSuspendSubmissionAsync(contentReferenceKey, marketplaceId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task PostContentDocumentSuspendSubmissionAsync(string contentReferenceKey, string marketplaceId = null, CancellationToken cancellationToken = default) + public async Task PostContentDocumentSuspendSubmissionAsync(string contentReferenceKey, string? marketplaceId = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(contentReferenceKey)) throw new InvalidDataException("contentReferenceKey is required"); diff --git a/Source/FikaAmazonAPI/Services/CatalogItemService.cs b/Source/FikaAmazonAPI/Services/CatalogItemService.cs index 65bbb629..626f7bdb 100644 --- a/Source/FikaAmazonAPI/Services/CatalogItemService.cs +++ b/Source/FikaAmazonAPI/Services/CatalogItemService.cs @@ -105,12 +105,12 @@ public async Task GetCatalogItemAsync(string asin) [Obsolete("Catalog Items API v0 was removed by Amazon on 2025-03-31; this call will fail at runtime. The 2022-04-01 version of the API does not expose a categories endpoint.", false)] [EditorBrowsable(EditorBrowsableState.Never)] - public IList ListCatalogCategories(string ASIN, string SellerSKU = null, string MarketPlaceID = null) => + public IList ListCatalogCategories(string ASIN, string? SellerSKU = null, string? MarketPlaceID = null) => Task.Run(() => ListCatalogCategoriesAsync(ASIN, SellerSKU, MarketPlaceID)).ConfigureAwait(false).GetAwaiter().GetResult(); [Obsolete("Catalog Items API v0 was removed by Amazon on 2025-03-31; this call will fail at runtime. The 2022-04-01 version of the API does not expose a categories endpoint.", false)] [EditorBrowsable(EditorBrowsableState.Never)] - public async Task> ListCatalogCategoriesAsync(string ASIN, string SellerSKU = null, string MarketPlaceID = null, CancellationToken cancellationToken = default) + public async Task> ListCatalogCategoriesAsync(string ASIN, string? SellerSKU = null, string? MarketPlaceID = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(ASIN)) throw new InvalidDataException("ASIN is a required property and cannot be null or empty"); diff --git a/Source/FikaAmazonAPI/Services/ExternalFulfillmentShipmentService.cs b/Source/FikaAmazonAPI/Services/ExternalFulfillmentShipmentService.cs index 206d9f43..324bf547 100644 --- a/Source/FikaAmazonAPI/Services/ExternalFulfillmentShipmentService.cs +++ b/Source/FikaAmazonAPI/Services/ExternalFulfillmentShipmentService.cs @@ -126,10 +126,10 @@ public async Task RetrieveShippingOptionsAsync(string s return await ExecuteRequestAsync(RateLimitType.ExternalFulfillmentShipment_RetrieveShippingOptions, ct); } - public ShipLabelsResponse GenerateShipLabels(string shipmentId, GenerateShipLabelsOperation operation, ShipLabelsInput body, string shippingOptionId = null) => + public ShipLabelsResponse GenerateShipLabels(string shipmentId, GenerateShipLabelsOperation operation, ShipLabelsInput body, string? shippingOptionId = null) => Task.Run(() => GenerateShipLabelsAsync(shipmentId, operation, body, shippingOptionId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GenerateShipLabelsAsync(string shipmentId, GenerateShipLabelsOperation operation, ShipLabelsInput body, string shippingOptionId = null, CancellationToken ct = default) + public async Task GenerateShipLabelsAsync(string shipmentId, GenerateShipLabelsOperation operation, ShipLabelsInput body, string? shippingOptionId = null, CancellationToken ct = default) { var query = new List> { new KeyValuePair("operation", operation.ToString()) }; diff --git a/Source/FikaAmazonAPI/Services/FeedService.cs b/Source/FikaAmazonAPI/Services/FeedService.cs index aa1d435f..9fc03b73 100644 --- a/Source/FikaAmazonAPI/Services/FeedService.cs +++ b/Source/FikaAmazonAPI/Services/FeedService.cs @@ -137,7 +137,7 @@ public async Task GetFeedDocumentProcessingReportAsync( { response = (FeedAmazonEnvelope)xmlSerializer.Deserialize(stream); } - catch (Exception e) + catch (Exception) { StreamReader reader = new StreamReader(stream); responseContent = reader.ReadToEnd(); @@ -147,7 +147,7 @@ public async Task GetFeedDocumentProcessingReportAsync( processingReport = response.Message[0].ProcessingReport; } - catch (AmazonProcessingReportDeserializeException ex) + catch (AmazonProcessingReportDeserializeException) { throw; } @@ -173,7 +173,7 @@ public async Task GetFeedDocumentProcessingReportAsync( { response = (FeedAmazonEnvelope)xmlSerializer.Deserialize(stream); } - catch (Exception e) + catch (Exception) { StreamReader reader = new StreamReader(stream); responseContent = await reader.ReadToEndAsync(); @@ -183,7 +183,7 @@ public async Task GetFeedDocumentProcessingReportAsync( processingReport = response.Message[0].ProcessingReport; } - catch (AmazonProcessingReportDeserializeException ex) + catch (AmazonProcessingReportDeserializeException) { throw; } @@ -226,19 +226,19 @@ public async Task CreateFeedDocumentAsync(ContentType return null; } - public string SubmitFeedFile(string FilePath, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML) => + public string SubmitFeedFile(string FilePath, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML) => Task.Run(() => SubmitFeedAsync(FilePath, feedType, marketPlaceIds, feedOptions, contentType, ContentFormate.File)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task SubmitFeedFileAsync(string FilePath, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML, CancellationToken cancellationToken = default) => + public async Task SubmitFeedFileAsync(string FilePath, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML, CancellationToken cancellationToken = default) => await SubmitFeedAsync(FilePath, feedType, marketPlaceIds, feedOptions, contentType, ContentFormate.File, cancellationToken); - public string SubmitFeedContent(string Content, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML) => + public string SubmitFeedContent(string Content, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML) => Task.Run(() => SubmitFeedAsync(Content, feedType, marketPlaceIds, feedOptions, contentType, ContentFormate.Text)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task SubmitFeedContentAsync(string Content, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML, CancellationToken cancellationToken = default) => + public async Task SubmitFeedContentAsync(string Content, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML, CancellationToken cancellationToken = default) => await SubmitFeedAsync(Content, feedType, marketPlaceIds, feedOptions, contentType, ContentFormate.Text, cancellationToken); - public string SubmitFeed(string XmlContentOrFilePath, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML, ContentFormate contentFormate = ContentFormate.AutoDetect) => + public string SubmitFeed(string XmlContentOrFilePath, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML, ContentFormate contentFormate = ContentFormate.AutoDetect) => Task.Run(() => SubmitFeedAsync(XmlContentOrFilePath, feedType, marketPlaceIds, feedOptions, contentType, contentFormate)).ConfigureAwait(false).GetAwaiter().GetResult(); /// @@ -247,7 +247,7 @@ public string SubmitFeed(string XmlContentOrFilePath, FeedType feedType, List /// /// - public async Task SubmitFeedAsync(string feedContentOrFilePath, FeedType feedType, List marketPlaceIds = null, FeedOptions feedOptions = null, ContentType contentType = ContentType.XML, ContentFormate contentFormate = ContentFormate.AutoDetect, CancellationToken cancellationToken = default) + public async Task SubmitFeedAsync(string feedContentOrFilePath, FeedType feedType, List? marketPlaceIds = null, FeedOptions? feedOptions = null, ContentType contentType = ContentType.XML, ContentFormate contentFormate = ContentFormate.AutoDetect, CancellationToken cancellationToken = default) { //We are creating Feed Document var feedCreate = await CreateFeedDocumentAsync(contentType, cancellationToken); diff --git a/Source/FikaAmazonAPI/Services/FinancialService.cs b/Source/FikaAmazonAPI/Services/FinancialService.cs index 05874307..e77d5109 100644 --- a/Source/FikaAmazonAPI/Services/FinancialService.cs +++ b/Source/FikaAmazonAPI/Services/FinancialService.cs @@ -54,9 +54,9 @@ public async Task GetFinancialEventGroupListByN return response.Payload; } - public List ListFinancialEventsByGroupId(string eventGroupId, ParameterListFinancialEventsByGroupId parameterListFinancialEventsByGroupId = null) => + public List ListFinancialEventsByGroupId(string eventGroupId, ParameterListFinancialEventsByGroupId? parameterListFinancialEventsByGroupId = null) => Task.Run(() => ListFinancialEventsByGroupIdAsync(eventGroupId, parameterListFinancialEventsByGroupId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task> ListFinancialEventsByGroupIdAsync(string eventGroupId, ParameterListFinancialEventsByGroupId parameterListFinancialEventsByGroupId = null, + public async Task> ListFinancialEventsByGroupIdAsync(string eventGroupId, ParameterListFinancialEventsByGroupId? parameterListFinancialEventsByGroupId = null, CancellationToken cancellationToken = default) { var parameters = parameterListFinancialEventsByGroupId?.getParameters() ?? new List>(); @@ -99,6 +99,49 @@ public async Task ListFinancialEventsByOrderIdAsync(string orde return response.Payload.FinancialEvents; } + public List ListFinancialEventsByShipmentId(string shipmentId) => + Task.Run(() => GetFinancialEventsByShipmentIdAsync(shipmentId)).ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Returns all financial events for the specified FBA inbound shipment. + /// Wraps GET /finances/v0/financialEvents/shipment/{shipmentId} and follows + /// NextToken pagination until the response no longer carries a token. + /// + public async Task> GetFinancialEventsByShipmentIdAsync(string shipmentId, CancellationToken cancellationToken = default) + { + await CreateAuthorizedRequestAsync(FinanceApiUrls.ListFinancialEventsByShipmentId(shipmentId), RestSharp.Method.Get, cancellationToken: cancellationToken); + var response = await ExecuteRequestAsync(RateLimitType.Financial_ListFinancialEventsByShipmentId, cancellationToken); + + var list = new List(); + if (response?.Payload?.FinancialEvents != null) + list.Add(response.Payload.FinancialEvents); + + var nextToken = response?.Payload?.NextToken; + + while (!string.IsNullOrEmpty(nextToken)) + { + var data = await ListFinancialEventsByShipmentIdByNextTokenAsync(shipmentId, nextToken, cancellationToken); + if (data?.Payload?.FinancialEvents != null) + { + list.Add(data.Payload.FinancialEvents); + } + nextToken = data?.Payload?.NextToken; + } + + return list; + } + + private async Task ListFinancialEventsByShipmentIdByNextTokenAsync(string shipmentId, string nextToken, CancellationToken cancellationToken = default) + { + var queryParameters = new List> + { + new KeyValuePair("NextToken", nextToken) + }; + + await CreateAuthorizedRequestAsync(FinanceApiUrls.ListFinancialEventsByShipmentId(shipmentId), RestSharp.Method.Get, queryParameters, cancellationToken: cancellationToken); + return await ExecuteRequestAsync(RateLimitType.Financial_ListFinancialEventsByShipmentId, cancellationToken); + } + public FinancialEvents ListFinancialEvents() => Task.Run(() => ListFinancialEventsAsync()).ConfigureAwait(false).GetAwaiter().GetResult(); diff --git a/Source/FikaAmazonAPI/Services/MerchantFulfillmentService.cs b/Source/FikaAmazonAPI/Services/MerchantFulfillmentService.cs index 61bfbdbf..a6c5e6a1 100644 --- a/Source/FikaAmazonAPI/Services/MerchantFulfillmentService.cs +++ b/Source/FikaAmazonAPI/Services/MerchantFulfillmentService.cs @@ -43,9 +43,9 @@ public async Task GetEligibleShipmentServices return null; } - public Shipment GetShipment(string shipmentId, IParameterBasedPII ParameterBasedPII = null) => + public Shipment GetShipment(string shipmentId, IParameterBasedPII? ParameterBasedPII = null) => Task.Run(() => GetShipmentAsync(shipmentId, ParameterBasedPII = null)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetShipmentAsync(string shipmentId, IParameterBasedPII ParameterBasedPII = null, CancellationToken cancellationToken = default) + public async Task GetShipmentAsync(string shipmentId, IParameterBasedPII? ParameterBasedPII = null, CancellationToken cancellationToken = default) { if (ParameterBasedPII != null && ParameterBasedPII.IsNeedRestrictedDataToken && ParameterBasedPII.RestrictedDataTokenRequest == null) { @@ -67,9 +67,9 @@ public async Task GetShipmentAsync(string shipmentId, IParameterBasedP return response.Payload; return null; } - public Shipment CancelShipment(string shipmentId, IParameterBasedPII parameterBasedPII = null) => + public Shipment CancelShipment(string shipmentId, IParameterBasedPII? parameterBasedPII = null) => Task.Run(() => CancelShipmentAsync(shipmentId, parameterBasedPII)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CancelShipmentAsync(string shipmentId, IParameterBasedPII parameterBasedPII = null, CancellationToken cancellationToken = default) + public async Task CancelShipmentAsync(string shipmentId, IParameterBasedPII? parameterBasedPII = null, CancellationToken cancellationToken = default) { if (parameterBasedPII != null && parameterBasedPII.IsNeedRestrictedDataToken && parameterBasedPII.RestrictedDataTokenRequest == null) { @@ -92,9 +92,9 @@ public async Task CancelShipmentAsync(string shipmentId, IParameterBas return null; } - public Shipment CancelShipmentOld(string shipmentId, IParameterBasedPII parameterBasedPII = null) => + public Shipment CancelShipmentOld(string shipmentId, IParameterBasedPII? parameterBasedPII = null) => Task.Run(() => CancelShipmentOldAsync(shipmentId, parameterBasedPII)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CancelShipmentOldAsync(string shipmentId, IParameterBasedPII parameterBasedPII = null, CancellationToken cancellationToken = default) + public async Task CancelShipmentOldAsync(string shipmentId, IParameterBasedPII? parameterBasedPII = null, CancellationToken cancellationToken = default) { if (parameterBasedPII != null && parameterBasedPII.IsNeedRestrictedDataToken && parameterBasedPII.RestrictedDataTokenRequest == null) { @@ -117,9 +117,9 @@ public async Task CancelShipmentOldAsync(string shipmentId, IParameter return null; } - public Shipment CreateShipment(CreateShipmentRequest createShipmentRequest, IParameterBasedPII parameterBasedPII = null) => + public Shipment CreateShipment(CreateShipmentRequest createShipmentRequest, IParameterBasedPII? parameterBasedPII = null) => Task.Run(() => CreateShipmentAsync(createShipmentRequest, parameterBasedPII)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CreateShipmentAsync(CreateShipmentRequest createShipmentRequest, IParameterBasedPII parameterBasedPII = null, CancellationToken cancellationToken = default) + public async Task CreateShipmentAsync(CreateShipmentRequest createShipmentRequest, IParameterBasedPII? parameterBasedPII = null, CancellationToken cancellationToken = default) { if (parameterBasedPII != null && parameterBasedPII.IsNeedRestrictedDataToken && parameterBasedPII.RestrictedDataTokenRequest == null) { diff --git a/Source/FikaAmazonAPI/Services/NotificationService.cs b/Source/FikaAmazonAPI/Services/NotificationService.cs index f534e6c8..ea0927ec 100644 --- a/Source/FikaAmazonAPI/Services/NotificationService.cs +++ b/Source/FikaAmazonAPI/Services/NotificationService.cs @@ -126,6 +126,16 @@ public static Task StartReceivingNotificationMessagesAsync(ParameterMessageRecei return StartReceivingNotificationMessagesAsync(param, new MessageReceiverAdapter(messageReceiver), isDeleteNotificationAfterRead, cancellationToken); } + /// + /// Wait time used when the caller does not set ParameterMessageReceiver.WaitTimeSeconds. + /// Long polling returns as soon as a message arrives and lets a single receive call fill + /// up to MaxNumberOfMessages; short polling only samples a subset of the SQS servers and + /// often returns one or two messages even when the queue holds thousands. + /// + private const int DefaultWaitTimeSeconds = 20; + + private const int MaxNumberOfMessagesPerReceive = 10; + public static async Task StartReceivingNotificationMessagesAsync(ParameterMessageReceiver param, IMessageReceiverWithResult messageReceiver, bool isDeleteNotificationAfterRead = false, CancellationToken cancellationToken = default) { var awsAccessKeyId = param.awsAccessKeyId; @@ -135,28 +145,39 @@ public static async Task StartReceivingNotificationMessagesAsync(ParameterMessag using (var amazonSQSClient = new AmazonSQSClient(awsAccessKeyId, awsSecretAccessKey, Region)) { + var waitTimeSeconds = param.WaitTimeSeconds ?? DefaultWaitTimeSeconds; + ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(SQS_URL); - receiveMessageRequest.MaxNumberOfMessages = 10; - if (param.WaitTimeSeconds.HasValue) - receiveMessageRequest.WaitTimeSeconds = param.WaitTimeSeconds.Value; + receiveMessageRequest.MaxNumberOfMessages = MaxNumberOfMessagesPerReceive; + receiveMessageRequest.WaitTimeSeconds = waitTimeSeconds; - while (true) + while (!cancellationToken.IsCancellationRequested) { try { var result = await amazonSQSClient.ReceiveMessageAsync(receiveMessageRequest, cancellationToken); var Messages = result.Messages ?? new List(); - if (Messages.Count > 0) + + var messagesToDelete = new List(Messages.Count); + foreach (var msg in Messages) { - foreach (var msg in Messages) - { - await ProcessAnyOfferChangedMessage(msg, messageReceiver, amazonSQSClient, SQS_URL, isDeleteNotificationAfterRead, cancellationToken).ConfigureAwait(false); - } + if (ProcessNotificationMessage(msg, messageReceiver, isDeleteNotificationAfterRead)) + messagesToDelete.Add(msg); } - if (Messages.Count < 10) + await DeleteMessagesFromQueueAsync(amazonSQSClient, SQS_URL, messagesToDelete, messageReceiver, cancellationToken).ConfigureAwait(false); + + // Only back off on an empty queue, and only when the caller turned long + // polling off - otherwise the receive call above already did the waiting. + // Sleeping on any partial batch throttles exactly the case we care about, + // a queue that has a backlog. + if (Messages.Count == 0 && waitTimeSeconds <= 0) await Task.Delay(1000 * 5, cancellationToken).ConfigureAwait(false); } + catch (OperationCanceledException) + { + return; + } catch (Exception ex) { messageReceiver.ErrorCatch(ex); @@ -165,7 +186,10 @@ public static async Task StartReceivingNotificationMessagesAsync(ParameterMessag } } - private static async Task ProcessAnyOfferChangedMessage(Message msg, IMessageReceiverWithResult messageReceiver, AmazonSQSClient amazonSQSClient, string SQS_URL, bool isDeleteNotificationAfterRead = true, CancellationToken cancellationToken = default) + /// + /// Hands one message to the receiver and reports whether it should be deleted. + /// + private static bool ProcessNotificationMessage(Message msg, IMessageReceiverWithResult messageReceiver, bool isDeleteNotificationAfterRead) { var deleteMessage = isDeleteNotificationAfterRead; try @@ -173,22 +197,39 @@ private static async Task ProcessAnyOfferChangedMessage(Message msg, IMessageRec var data = DeserializeNotification(msg); deleteMessage = messageReceiver.NewMessageRevicedTriger(data) || isDeleteNotificationAfterRead; - - if (deleteMessage) - await DeleteMessageFromQueueAsync(amazonSQSClient, SQS_URL, msg.ReceiptHandle, cancellationToken); } catch (Exception ex) { messageReceiver.ErrorCatch(ex); - - if (deleteMessage) - await DeleteMessageFromQueueAsync(amazonSQSClient, SQS_URL, msg.ReceiptHandle, cancellationToken); } + + return deleteMessage; } - private static async Task DeleteMessageFromQueueAsync(AmazonSQSClient sqsClient, string QueueUrl, string ReceiptHandle, CancellationToken cancellationToken = default) + + /// + /// Deletes a whole receive batch with one API call instead of one call per message. + /// + private static async Task DeleteMessagesFromQueueAsync(AmazonSQSClient sqsClient, string QueueUrl, IList messages, IMessageReceiverWithResult messageReceiver, CancellationToken cancellationToken = default) { - var deleteMessageRequest = new DeleteMessageRequest() { QueueUrl = QueueUrl, ReceiptHandle = ReceiptHandle }; - _ = await sqsClient.DeleteMessageAsync(deleteMessageRequest, cancellationToken); + if (messages == null || messages.Count == 0) + return; + + var entries = new List(messages.Count); + for (var i = 0; i < messages.Count; i++) + entries.Add(new DeleteMessageBatchRequestEntry(i.ToString(), messages[i].ReceiptHandle)); + + var response = await sqsClient.DeleteMessageBatchAsync( + new DeleteMessageBatchRequest(QueueUrl, entries), cancellationToken).ConfigureAwait(false); + + // A message that fails to delete stays invisible until its visibility timeout runs + // out and is then redelivered, so the caller needs to know about it. + if (response.Failed != null && response.Failed.Count > 0) + { + var failed = response.Failed[0]; + messageReceiver.ErrorCatch(new AmazonSQSException( + "Failed to delete " + response.Failed.Count + " of " + messages.Count + + " message(s) from " + QueueUrl + ". First failure: " + failed.Code + " " + failed.Message)); + } } private static NotificationMessageResponce DeserializeNotification(Message message) { diff --git a/Source/FikaAmazonAPI/Services/OrderService.cs b/Source/FikaAmazonAPI/Services/OrderService.cs index 0d50f25f..fb2072c5 100644 --- a/Source/FikaAmazonAPI/Services/OrderService.cs +++ b/Source/FikaAmazonAPI/Services/OrderService.cs @@ -199,9 +199,9 @@ public async Task GetOrderAsync(ParameterGetOrder parameter, Cancellation return response.Payload; else return null; } - public OrderItemList GetOrderItems(string orderId, IParameterBasedPII parameterBasedPII = null) => + public OrderItemList GetOrderItems(string orderId, IParameterBasedPII? parameterBasedPII = null) => Task.Run(() => GetOrderItemsAsync(orderId, parameterBasedPII)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderItemsAsync(string orderId, IParameterBasedPII ParameterBasedPII = null, CancellationToken cancellationToken = default) + public async Task GetOrderItemsAsync(string orderId, IParameterBasedPII? ParameterBasedPII = null, CancellationToken cancellationToken = default) { var orderItemList = new OrderItemList(); @@ -247,9 +247,9 @@ public async Task GetOrderItemsNextTokenAsync(string orderId, st return response.Payload; } - public OrderBuyerInfo GetOrderBuyerInfo(string orderId, List> queryParameters = null) => + public OrderBuyerInfo GetOrderBuyerInfo(string orderId, List>? queryParameters = null) => Task.Run(() => GetOrderBuyerInfoAsync(orderId, queryParameters)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderBuyerInfoAsync(string orderId, List> queryParameters = null, CancellationToken cancellationToken = default) + public async Task GetOrderBuyerInfoAsync(string orderId, List>? queryParameters = null, CancellationToken cancellationToken = default) { await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderBuyerInfo(orderId), RestSharp.Method.Get, queryParameters, cancellationToken: cancellationToken); var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderBuyerInfo, cancellationToken); diff --git a/Source/FikaAmazonAPI/Services/ReportService.cs b/Source/FikaAmazonAPI/Services/ReportService.cs index 11cffd2d..d54ce17d 100644 --- a/Source/FikaAmazonAPI/Services/ReportService.cs +++ b/Source/FikaAmazonAPI/Services/ReportService.cs @@ -351,9 +351,9 @@ public async Task CancelReportScheduleAsync(string reportScheduleId, Cance #endregion - public string CreateReportAndDownloadFile(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null, bool isRestrictedReport = false, List marketplaces = null, int millisecondsDelay = 500) => + public string CreateReportAndDownloadFile(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null, bool isRestrictedReport = false, List? marketplaces = null, int millisecondsDelay = 500) => Task.Run(() => CreateReportAndDownloadFileAsync(reportType, dataStartTime, dataEndTime, reportOptions, isRestrictedReport, marketplaces, millisecondsDelay)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CreateReportAndDownloadFileAsync(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null, bool isRestrictedReport = false, List marketplaces = null, int millisecondsDelay = 500, CancellationToken cancellationToken = default) + public async Task CreateReportAndDownloadFileAsync(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null, bool isRestrictedReport = false, List? marketplaces = null, int millisecondsDelay = 500, CancellationToken cancellationToken = default) { if (!isRestrictedReport && Enum.TryParse(reportType.ToString(), out _)) { @@ -387,10 +387,10 @@ public async Task CreateReportAndDownloadFileAsync(ReportTypes reportTyp } - public MemoryStream CreateReportAndDownloadFileStream(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null, bool isRestrictedReport = false, List marketplaces = null, int millisecondsDelay = 500) => + public MemoryStream CreateReportAndDownloadFileStream(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null, bool isRestrictedReport = false, List? marketplaces = null, int millisecondsDelay = 500) => Task.Run(() => CreateReportAndDownloadFileStreamAsync(reportType, dataStartTime, dataEndTime, reportOptions, isRestrictedReport, marketplaces, millisecondsDelay)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CreateReportAndDownloadFileStreamAsync(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null, bool isRestrictedReport = false, List marketplaces = null, int millisecondsDelay = 500, CancellationToken cancellationToken = default) + public async Task CreateReportAndDownloadFileStreamAsync(ReportTypes reportType, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null, bool isRestrictedReport = false, List? marketplaces = null, int millisecondsDelay = 500, CancellationToken cancellationToken = default) { if (!isRestrictedReport && Enum.TryParse(reportType.ToString(), out _)) { diff --git a/Source/FikaAmazonAPI/Services/RequestService.cs b/Source/FikaAmazonAPI/Services/RequestService.cs index 34e63f84..9e4fc289 100644 --- a/Source/FikaAmazonAPI/Services/RequestService.cs +++ b/Source/FikaAmazonAPI/Services/RequestService.cs @@ -71,8 +71,8 @@ private void CreateRequest(string url, RestSharp.Method method) } protected async Task CreateAuthorizedRequestAsync(string url, RestSharp.Method method, - List> queryParameters = null, object postJsonObj = null, - TokenDataType tokenDataType = TokenDataType.Normal, object parameter = null, + List>? queryParameters = null, object? postJsonObj = null, + TokenDataType tokenDataType = TokenDataType.Normal, object? parameter = null, CancellationToken cancellationToken = default) { var PiiObject = parameter as IParameterBasedPII; @@ -271,7 +271,7 @@ public async Task ExecuteRequestAsync(RateLimitType rateLimitType = RateLi { return await ExecuteRequestTry(rateLimitType, cancellationToken); } - catch (AmazonQuotaExceededException ex) + catch (AmazonQuotaExceededException) { if (tryCount >= AmazonCredential.MaxThrottledRetryCount) { @@ -323,8 +323,10 @@ private async Task SleepForRateLimit(IReadOnlyCollection he } } } - catch (Exception e) + catch (Exception ex) { + // Rate-limit bookkeeping is best-effort: never fail the caller's request over it. + _logger?.LogDebug(ex, "Failed to apply rate limit for {RateLimitType}", rateLimitType); } } @@ -406,7 +408,7 @@ protected void AddShippingBusinessId() } protected async Task RefreshToken(TokenDataType tokenDataType = TokenDataType.Normal, - CreateRestrictedDataTokenRequest requestPII = null) + CreateRestrictedDataTokenRequest? requestPII = null) { var token = AmazonCredential.GetToken(tokenDataType); if (token == null) @@ -440,7 +442,7 @@ protected async Task RefreshToken(TokenDataType tokenDataType = TokenDataType.No } protected async Task RefreshTokenAsync(TokenDataType tokenDataType = TokenDataType.Normal, - CreateRestrictedDataTokenRequest requestPII = null, CancellationToken cancellationToken = default) + CreateRestrictedDataTokenRequest? requestPII = null, CancellationToken cancellationToken = default) { var token = AmazonCredential.GetToken(tokenDataType); if (token == null) diff --git a/Source/FikaAmazonAPI/Services/SolicitationService.cs b/Source/FikaAmazonAPI/Services/SolicitationService.cs index fe163267..a7b48f12 100644 --- a/Source/FikaAmazonAPI/Services/SolicitationService.cs +++ b/Source/FikaAmazonAPI/Services/SolicitationService.cs @@ -15,18 +15,18 @@ public SolicitationService(AmazonCredential amazonCredential, ILoggerFactory? lo } - public GetSolicitationActionsForOrderResponseEmbedded GetSolicitationActionsForOrder(string orderId, List> queryParameters = null) => + public GetSolicitationActionsForOrderResponseEmbedded GetSolicitationActionsForOrder(string orderId, List>? queryParameters = null) => Task.Run(() => GetSolicitationActionsForOrderAsync(orderId, queryParameters)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetSolicitationActionsForOrderAsync(string orderId, List> queryParameters = null, CancellationToken cancellationToken = default) + public async Task GetSolicitationActionsForOrderAsync(string orderId, List>? queryParameters = null, CancellationToken cancellationToken = default) { await CreateAuthorizedRequestAsync(SolicitationsApiUrls.GetSolicitationActionsForOrder(orderId), RestSharp.Method.Get, queryParameters, cancellationToken: cancellationToken); var response = await ExecuteRequestAsync(RateLimitType.Solicitations_GetSolicitationActionsForOrder, cancellationToken); return response.Embedded; } - public GetSolicitationActionsForOrderResponseEmbedded CreateProductReviewAndSellerFeedbackSolicitation(string orderId, List> queryParameters = null) => + public GetSolicitationActionsForOrderResponseEmbedded CreateProductReviewAndSellerFeedbackSolicitation(string orderId, List>? queryParameters = null) => Task.Run(() => CreateProductReviewAndSellerFeedbackSolicitationAsync(orderId, queryParameters)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task CreateProductReviewAndSellerFeedbackSolicitationAsync(string orderId, List> queryParameters = null, CancellationToken cancellationToken = default) + public async Task CreateProductReviewAndSellerFeedbackSolicitationAsync(string orderId, List>? queryParameters = null, CancellationToken cancellationToken = default) { await CreateAuthorizedRequestAsync(SolicitationsApiUrls.CreateProductReviewAndSellerFeedbackSolicitation(orderId), RestSharp.Method.Post, queryParameters, cancellationToken: cancellationToken); var response = await ExecuteRequestAsync(RateLimitType.Solicitations_CreateProductReviewAndSellerFeedbackSolicitation, cancellationToken); diff --git a/Source/FikaAmazonAPI/Utils/RateLimitType.cs b/Source/FikaAmazonAPI/Utils/RateLimitType.cs index f56c81d1..fe58086c 100644 --- a/Source/FikaAmazonAPI/Utils/RateLimitType.cs +++ b/Source/FikaAmazonAPI/Utils/RateLimitType.cs @@ -35,6 +35,7 @@ public enum RateLimitType Financial_ListFinancialEventGroups, Financial_ListFinancialEventsByGroupId, Financial_ListFinancialEventsByOrderId, + Financial_ListFinancialEventsByShipmentId, Financial_ListFinancialEvents, FinancialV20240619_Transactions, diff --git a/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs b/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs index 38cc8364..3f028f58 100644 --- a/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs +++ b/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs @@ -40,6 +40,7 @@ internal static Dictionary RateLimitsTime() { RateLimitType.Financial_ListFinancialEventGroups, new RateLimits(0.5M, 30) }, { RateLimitType.Financial_ListFinancialEventsByGroupId, new RateLimits(0.5M, 30) }, { RateLimitType.Financial_ListFinancialEventsByOrderId, new RateLimits(0.5M, 30) }, + { RateLimitType.Financial_ListFinancialEventsByShipmentId, new RateLimits(0.5M, 30) }, { RateLimitType.Financial_ListFinancialEvents, new RateLimits(0.5M, 30) }, { RateLimitType.FinancialV20240619_Transactions, new RateLimits(0.5M, 10) },