public EnvironmentSeedCommand( AppSettings settings, IPortalService portal, IHSSupplierCommand supplierCommand, IHSBuyerCommand buyerCommand, IHSBuyerLocationCommand buyerLocationCommand, IOrderCloudClient oc, IExchangeRatesCommand exhangeRates ) { _settings = settings; _portal = portal; _supplierCommand = supplierCommand; _buyerCommand = buyerCommand; _buyerLocationCommand = buyerLocationCommand; _oc = oc; _exhangeRates = exhangeRates; var translationsConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = _settings.BlobSettings.ContainerNameTranslations }; _translationsBlob = new OrderCloudIntegrationsBlobService(translationsConfig); }
public async Task UpdateTranslations(string connectionString, string containerName) { var englishTranslationsPath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "Assets", "english-translations.json")); var translationsConfig = new BlobServiceConfig() { ConnectionString = connectionString, Container = containerName, AccessType = BlobContainerPublicAccessType.Container }; var translationsBlob = new OrderCloudIntegrationsBlobService(translationsConfig); await translationsBlob.Save("i18n/en.json", File.ReadAllText(englishTranslationsPath)); }
public async Task <EnvironmentSeedResponse> Seed(EnvironmentSeed seed) { OcEnv requestedEnv = validateEnvironment(seed.OrderCloudSettings.Environment); if (requestedEnv.environmentName == OrderCloudEnvironments.Production.environmentName && seed.SellerOrgID == null) { throw new Exception("Cannot create a production environment via the environment seed endpoint. Please contact an OrderCloud Developer to create a production org."); } // lets us handle requests to multiple api environments _oc = new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = requestedEnv.apiUrl, AuthUrl = requestedEnv.apiUrl }); var portalUserToken = await _portal.Login(seed.PortalUsername, seed.PortalPassword); var sellerOrg = await GetOrCreateOrg(portalUserToken, requestedEnv.environmentName, seed.SellerOrgName, seed.SellerOrgID); var orgToken = await _portal.GetOrgToken(sellerOrg.Id, portalUserToken); await CreateDefaultSellerUsers(seed, orgToken); await CreateIncrementors(orgToken); // must be before CreateBuyers await CreateMessageSenders(seed, orgToken); // must be before CreateBuyers and CreateSuppliers await CreateSecurityProfiles(orgToken); await CreateBuyers(seed, orgToken); await CreateConfigureAnonBuyer(seed, orgToken); await CreateApiClients(orgToken); await AssignSecurityProfiles(seed, orgToken); var apiClients = await GetApiClients(orgToken); await CreateXPIndices(orgToken); await CreateAndAssignIntegrationEvents(new string[] { apiClients.BuyerUiApiClient.ID }, apiClients.BuyerLocalUiApiClient.ID, orgToken, seed); await CreateSuppliers(seed, orgToken); // populate default english translations into blob container name: settings.BlobSettings.ContainerNameTranslations or "ngx-translate" if setting is not defined // provide other language files to support multiple languages var englishTranslationsPath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "Assets", "english-translations.json")); if (seed?.BlobSettings?.ConnectionString != null && seed?.BlobSettings?.ContainerNameTranslations != null) { var translationsConfig = new BlobServiceConfig() { ConnectionString = seed.BlobSettings.ConnectionString, Container = seed.BlobSettings.ContainerNameTranslations, AccessType = BlobContainerPublicAccessType.Container }; var translationsBlob = new OrderCloudIntegrationsBlobService(translationsConfig); await translationsBlob.Save("i18n/en.json", File.ReadAllText(englishTranslationsPath)); } return(new EnvironmentSeedResponse { Comments = "Success! Your environment is now seeded. The following clientIDs & secrets should be used to finalize the configuration of your application. The initial admin username and password can be used to sign into your admin application", OrganizationName = sellerOrg.Name, OrganizationID = sellerOrg.Id, OrderCloudEnvironment = requestedEnv.environmentName, ApiClients = new Dictionary <string, dynamic> { ["Middleware"] = new { ClientID = apiClients.MiddlewareApiClient.ID, ClientSecret = apiClients.MiddlewareApiClient.ClientSecret }, ["Seller"] = new { ClientID = apiClients.AdminUiApiClient.ID }, ["Buyer"] = new { ClientID = apiClients.BuyerUiApiClient.ID } } }); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { var cosmosConfig = new CosmosConfig( _settings.CosmosSettings.DatabaseName, _settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.RequestTimeoutInSeconds ); var cosmosContainers = new List <ContainerInfo>() { new ContainerInfo() { Name = "rmas", PartitionKey = "PartitionKey" } }; var avalaraConfig = new AvalaraConfig() { BaseApiUrl = _settings.AvalaraSettings.BaseApiUrl, AccountID = _settings.AvalaraSettings.AccountID, LicenseKey = _settings.AvalaraSettings.LicenseKey, CompanyCode = _settings.AvalaraSettings.CompanyCode, CompanyID = _settings.AvalaraSettings.CompanyID }; var currencyConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = _settings.BlobSettings.ContainerNameExchangeRates }; var assetConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = "assets", AccessType = BlobContainerPublicAccessType.Container }; var flurlClientFactory = new PerBaseUrlFlurlClientFactory(); var smartyStreetsUsClient = new ClientBuilder(_settings.SmartyStreetSettings.AuthID, _settings.SmartyStreetSettings.AuthToken).BuildUsStreetApiClient(); services .Configure <KestrelServerOptions>(options => { options.AllowSynchronousIO = true; }) .Configure <IISServerOptions>(options => { options.AllowSynchronousIO = true; }) .AddSingleton <ISimpleCache, OrderCloud.Common.Services.LazyCacheService>() // Replace LazyCacheService with RedisService if you have multiple server instances. .ConfigureServices() .AddOrderCloudUserAuth() .AddOrderCloudWebhookAuth(opts => opts.HashKey = _settings.OrderCloudSettings.WebhookHashKey) .InjectCosmosStore <LogQuery, OrchestrationLog>(cosmosConfig) .InjectCosmosStore <ReportTemplateQuery, ReportTemplate>(cosmosConfig) .AddCosmosDb(_settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.DatabaseName, cosmosContainers) .Inject <IPortalService>() .Inject <ISmartyStreetsCommand>() .Inject <ICheckoutIntegrationCommand>() .Inject <IShipmentCommand>() .Inject <IOrderCommand>() .Inject <IPaymentCommand>() .Inject <IOrderSubmitCommand>() .Inject <IEnvironmentSeedCommand>() .Inject <IHSProductCommand>() .Inject <ILineItemCommand>() .Inject <IMeProductCommand>() .Inject <IHSCatalogCommand>() .Inject <ISendgridService>() .Inject <IHSSupplierCommand>() .Inject <ICreditCardCommand>() .Inject <ISupportAlertService>() .Inject <IUserContextProvider>() .Inject <ISupplierApiClientHelper>() .AddSingleton <ISendGridClient>(x => new SendGridClient(_settings.SendgridSettings.ApiKey)) .AddSingleton <IFlurlClientFactory>(x => flurlClientFactory) .AddSingleton <DownloadReportCommand>() .Inject <IRMARepo>() .Inject <IZohoClient>() .AddSingleton <IZohoCommand>(z => new ZohoCommand(new ZohoClient( new ZohoClientConfig() { ApiUrl = "https://books.zoho.com/api/v3", AccessToken = _settings.ZohoSettings.AccessToken, ClientId = _settings.ZohoSettings.ClientId, ClientSecret = _settings.ZohoSettings.ClientSecret, OrganizationID = _settings.ZohoSettings.OrgID }, flurlClientFactory), new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } }))) .AddSingleton <IOrderCloudIntegrationsExchangeRatesClient, OrderCloudIntegrationsExchangeRatesClient>() .AddSingleton <IAssetClient>(provider => new AssetClient(new OrderCloudIntegrationsBlobService(assetConfig), _settings)) .AddSingleton <IExchangeRatesCommand>(provider => new ExchangeRatesCommand(new OrderCloudIntegrationsBlobService(currencyConfig), flurlClientFactory, provider.GetService <ISimpleCache>())) .AddSingleton <IAvalaraCommand>(x => new AvalaraCommand( avalaraConfig, new AvaTaxClient("four51_headstart", "v1", "four51_headstart", new Uri(avalaraConfig.BaseApiUrl) ).WithSecurity(_settings.AvalaraSettings.AccountID, _settings.AvalaraSettings.LicenseKey), _settings.EnvironmentSettings.Environment.ToString())) .AddSingleton <IEasyPostShippingService>(x => new EasyPostShippingService(new EasyPostConfig() { APIKey = _settings.EasyPostSettings.APIKey })) .AddSingleton <ISmartyStreetsService>(x => new SmartyStreetsService(_settings.SmartyStreetSettings, smartyStreetsUsClient)) .AddSingleton <IOrderCloudIntegrationsCardConnectService>(x => new OrderCloudIntegrationsCardConnectService(_settings.CardConnectSettings, _settings.EnvironmentSettings.Environment.ToString(), flurlClientFactory)) .AddSingleton <IOrderCloudClient>(provider => new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } })) .AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Headstart API", Version = "v1" }); c.CustomSchemaIds(x => x.FullName); }); var serviceProvider = services.BuildServiceProvider(); services .AddApplicationInsightsTelemetry(new ApplicationInsightsServiceOptions { EnableAdaptiveSampling = false, // retain all data InstrumentationKey = _settings.ApplicationInsightsSettings.InstrumentationKey }); ServicePointManager.DefaultConnectionLimit = int.MaxValue; FlurlHttp.Configure(settings => settings.Timeout = TimeSpan.FromSeconds(_settings.FlurlSettings.TimeoutInSeconds == 0 ? 30 : _settings.FlurlSettings.TimeoutInSeconds)); // This adds retry logic for any api call that fails with a transient error (server errors, timeouts, or rate limiting requests) // Will retry up to 3 times using exponential backoff and jitter, a mean of 3 seconds wait time in between retries // https://github.com/App-vNext/Polly/wiki/Retry-with-jitter#more-complex-jitter var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(3), retryCount: 3); var policy = HttpPolicyExtensions .HandleTransientHttpError() .OrResult(response => response.StatusCode == HttpStatusCode.TooManyRequests) .WaitAndRetryAsync(delay); FlurlHttp.Configure(settings => settings.HttpClientFactory = new PollyFactory(policy)); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { var cosmosConfig = new CosmosConfig( _settings.CosmosSettings.DatabaseName, _settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.RequestTimeoutInSeconds ); var cosmosContainers = new List <ContainerInfo>() { new ContainerInfo() { Name = "rmas", PartitionKey = "PartitionKey" } }; var avalaraConfig = new AvalaraConfig() { BaseApiUrl = _settings.AvalaraSettings.BaseApiUrl, AccountID = _settings.AvalaraSettings.AccountID, LicenseKey = _settings.AvalaraSettings.LicenseKey, CompanyCode = _settings.AvalaraSettings.CompanyCode, CompanyID = _settings.AvalaraSettings.CompanyID }; var currencyConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = _settings.BlobSettings.ContainerNameExchangeRates }; var middlewareErrorsConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = "unhandled-errors-log" }; var flurlClientFactory = new PerBaseUrlFlurlClientFactory(); var smartyStreetsUsClient = new ClientBuilder(_settings.SmartyStreetSettings.AuthID, _settings.SmartyStreetSettings.AuthToken).BuildUsStreetApiClient(); services .AddLazyCache() .OrderCloudIntegrationsConfigureWebApiServices(_settings, middlewareErrorsConfig, corsPolicyName: "headstarcors") .InjectCosmosStore <LogQuery, OrchestrationLog>(cosmosConfig) .InjectCosmosStore <ReportTemplateQuery, ReportTemplate>(cosmosConfig) .AddCosmosDb(_settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.DatabaseName, cosmosContainers) .Inject <IPortalService>() .Inject <ISmartyStreetsCommand>() .Inject <ICheckoutIntegrationCommand>() .Inject <IShipmentCommand>() .Inject <IOrderCommand>() .Inject <IPaymentCommand>() .Inject <IOrderSubmitCommand>() .Inject <IEnvironmentSeedCommand>() .Inject <IHSProductCommand>() .Inject <ILineItemCommand>() .Inject <IMeProductCommand>() .Inject <IHSCatalogCommand>() .Inject <ISendgridService>() .Inject <IHSSupplierCommand>() .Inject <ICreditCardCommand>() .Inject <ISupportAlertService>() .Inject <IOrderCalcService>() .Inject <ISupplierApiClientHelper>() .AddSingleton <ICMSClient>(new CMSClient(new CMSClientConfig() { BaseUrl = _settings.CMSSettings.BaseUrl })) .AddSingleton <ISendGridClient>(x => new SendGridClient(_settings.SendgridSettings.ApiKey)) .AddSingleton <IFlurlClientFactory>(x => flurlClientFactory) .AddSingleton <DownloadReportCommand>() .Inject <IRMARepo>() .Inject <IZohoClient>() .AddSingleton <IZohoCommand>(z => new ZohoCommand(new ZohoClient( new ZohoClientConfig() { ApiUrl = "https://books.zoho.com/api/v3", AccessToken = _settings.ZohoSettings.AccessToken, ClientId = _settings.ZohoSettings.ClientId, ClientSecret = _settings.ZohoSettings.ClientSecret, OrganizationID = _settings.ZohoSettings.OrgID }, flurlClientFactory), new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } }))) .AddSingleton <IOrderCloudIntegrationsExchangeRatesClient, OrderCloudIntegrationsExchangeRatesClient>() .AddSingleton <IExchangeRatesCommand>(provider => new ExchangeRatesCommand(currencyConfig, flurlClientFactory, provider.GetService <IAppCache>())) .AddSingleton <IAvalaraCommand>(x => new AvalaraCommand( avalaraConfig, new AvaTaxClient("four51_headstart", "v1", "four51_headstart", new Uri(avalaraConfig.BaseApiUrl) ).WithSecurity(_settings.AvalaraSettings.AccountID, _settings.AvalaraSettings.LicenseKey))) .AddSingleton <IEasyPostShippingService>(x => new EasyPostShippingService(new EasyPostConfig() { APIKey = _settings.EasyPostSettings.APIKey })) .AddSingleton <ISmartyStreetsService>(x => new SmartyStreetsService(_settings.SmartyStreetSettings, smartyStreetsUsClient)) .AddSingleton <IOrderCloudIntegrationsCardConnectService>(x => new OrderCloudIntegrationsCardConnectService(_settings.CardConnectSettings, flurlClientFactory)) .AddSingleton <IOrderCloudClient>(provider => new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } })) .AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Headstart API", Version = "v1" }); c.CustomSchemaIds(x => x.FullName); }) .AddAuthentication(); var serviceProvider = services.BuildServiceProvider(); services .AddAuthenticationScheme <OrderCloudIntegrationsAuthOptions, OrderCloudIntegrationsAuthHandler>("OrderCloudIntegrations", opts => opts.OrderCloudClient = serviceProvider.GetService <IOrderCloudClient>()) .AddAuthenticationScheme <OrderCloudWebhookAuthOptions, OrderCloudWebhookAuthHandler>("OrderCloudWebhook", opts => opts.HashKey = _settings.OrderCloudSettings.WebhookHashKey) .AddApplicationInsightsTelemetry(new ApplicationInsightsServiceOptions { EnableAdaptiveSampling = false, // retain all data InstrumentationKey = _settings.ApplicationInsightsSettings.InstrumentationKey }); ServicePointManager.DefaultConnectionLimit = int.MaxValue; FlurlHttp.Configure(settings => settings.Timeout = TimeSpan.FromSeconds(_settings.FlurlSettings.TimeoutInSeconds)); }
public ExchangeRatesCommand(BlobServiceConfig config, IFlurlClientFactory flurlFactory, IAppCache cache) { _client = new OrderCloudIntegrationsExchangeRatesClient(flurlFactory); _blob = new OrderCloudIntegrationsBlobService(config); _cache = cache; }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { var cosmosConfig = new CosmosConfig( _settings.CosmosSettings.DatabaseName, _settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.RequestTimeoutInSeconds ); var cosmosContainers = new List <ContainerInfo>() { new ContainerInfo() { Name = "salesorderdetail", PartitionKey = "/PartitionKey" }, new ContainerInfo() { Name = "purchaseorderdetail", PartitionKey = "/PartitionKey" }, new ContainerInfo() { Name = "lineitemdetail", PartitionKey = "/PartitionKey" }, new ContainerInfo() { Name = "rmas", PartitionKey = "/PartitionKey" }, new ContainerInfo() { Name = "shipmentdetail", PartitionKey = "/PartitionKey" }, new ContainerInfo() { Name = "productdetail", PartitionKey = "/PartitionKey" } }; var avalaraConfig = new AvalaraConfig() { BaseApiUrl = _settings.AvalaraSettings.BaseApiUrl, AccountID = _settings.AvalaraSettings.AccountID, LicenseKey = _settings.AvalaraSettings.LicenseKey, CompanyCode = _settings.AvalaraSettings.CompanyCode, CompanyID = _settings.AvalaraSettings.CompanyID }; var currencyConfig = new BlobServiceConfig() { ConnectionString = _settings.StorageAccountSettings.ConnectionString, Container = _settings.StorageAccountSettings.BlobContainerNameExchangeRates }; var assetConfig = new BlobServiceConfig() { ConnectionString = _settings.StorageAccountSettings.ConnectionString, Container = "assets", AccessType = BlobContainerPublicAccessType.Container }; var flurlClientFactory = new PerBaseUrlFlurlClientFactory(); var smartyStreetsUsClient = new ClientBuilder(_settings.SmartyStreetSettings.AuthID, _settings.SmartyStreetSettings.AuthToken).BuildUsStreetApiClient(); var orderCloudClient = new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } }); AvalaraCommand avalaraCommand = null; VertexCommand vertexCommand = null; TaxJarCommand taxJarCommand = null; switch (_settings.EnvironmentSettings.TaxProvider) { case TaxProvider.Avalara: avalaraCommand = new AvalaraCommand(avalaraConfig, _settings.EnvironmentSettings.Environment.ToString()); break; case TaxProvider.Taxjar: taxJarCommand = new TaxJarCommand(_settings.TaxJarSettings); break; case TaxProvider.Vertex: vertexCommand = new VertexCommand(_settings.VertexSettings); break; default: break; } services.AddMvc(o => { o.Filters.Add(new ordercloud.integrations.library.ValidateModelAttribute()); o.EnableEndpointRouting = false; }) .ConfigureApiBehaviorOptions(o => o.SuppressModelStateInvalidFilter = true) .SetCompatibilityVersion(CompatibilityVersion.Version_3_0) .AddNewtonsoftJson(options => { options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver(); options.SerializerSettings.Converters.Add(new StringEnumConverter()); }); services .AddCors(o => o.AddPolicy("integrationcors", builder => { builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); })) .AddSingleton <ISimpleCache, LazyCacheService>() // Replace LazyCacheService with RedisService if you have multiple server instances. .AddOrderCloudUserAuth() .AddOrderCloudWebhookAuth(opts => opts.HashKey = _settings.OrderCloudSettings.WebhookHashKey) .InjectCosmosStore <LogQuery, OrchestrationLog>(cosmosConfig) .InjectCosmosStore <ReportTemplateQuery, ReportTemplate>(cosmosConfig) .AddCosmosDb(_settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.DatabaseName, cosmosContainers) .Inject <IPortalService>() .Inject <ISmartyStreetsCommand>() .Inject <ICheckoutIntegrationCommand>() .Inject <IShipmentCommand>() .Inject <IOrderCommand>() .Inject <IPaymentCommand>() .Inject <IOrderSubmitCommand>() .Inject <IEnvironmentSeedCommand>() .Inject <IHSProductCommand>() .Inject <ILineItemCommand>() .Inject <IMeProductCommand>() .Inject <IDiscountDistributionService>() .Inject <IHSCatalogCommand>() .Inject <ISendgridService>() .Inject <IHSSupplierCommand>() .Inject <ICreditCardCommand>() .Inject <ISupportAlertService>() .Inject <ISupplierApiClientHelper>() .AddSingleton <ISendGridClient>(x => new SendGridClient(_settings.SendgridSettings.ApiKey)) .AddSingleton <IFlurlClientFactory>(x => flurlClientFactory) .AddSingleton <DownloadReportCommand>() .Inject <IRMARepo>() .Inject <IZohoClient>() .AddSingleton <IZohoCommand>(z => new ZohoCommand(new ZohoClient( new ZohoClientConfig() { ApiUrl = "https://books.zoho.com/api/v3", AccessToken = _settings.ZohoSettings.AccessToken, ClientId = _settings.ZohoSettings.ClientId, ClientSecret = _settings.ZohoSettings.ClientSecret, OrganizationID = _settings.ZohoSettings.OrgID }, flurlClientFactory), orderCloudClient)) .AddSingleton <IOrderCloudIntegrationsExchangeRatesClient, OrderCloudIntegrationsExchangeRatesClient>() .AddSingleton <IAssetClient>(provider => new AssetClient(new OrderCloudIntegrationsBlobService(assetConfig), _settings)) .AddSingleton <IExchangeRatesCommand>(provider => new ExchangeRatesCommand(new OrderCloudIntegrationsBlobService(currencyConfig), flurlClientFactory, provider.GetService <ISimpleCache>())) .AddSingleton <ITaxCodesProvider>(provider => { return(_settings.EnvironmentSettings.TaxProvider switch { TaxProvider.Avalara => avalaraCommand, TaxProvider.Taxjar => taxJarCommand, TaxProvider.Vertex => new NotImplementedTaxCodesProvider(), _ => avalaraCommand // Avalara is default }); })