Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AvaTax.TaxModule.Core/AvaTax.TaxModule.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="VirtoCommerce.CoreModule.Data" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.OrdersModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.0.0-rc5" />
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.0.0-rc6-preview002" />
<PackageReference Include="VirtoCommerce.SearchModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.TaxModule.Core" Version="3.0.1" />
</ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion src/AvaTax.TaxModule.Data/AvaTax.TaxModule.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalara.AvaTax" Version="18.9.0.234" />
<PackageReference Include="Hangfire" Version="1.7.9" />
<PackageReference Include="VirtoCommerce.InventoryModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.OrdersModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.0.0-rc5" />
<PackageReference Include="VirtoCommerce.SearchModule.Data" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.ShippingModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.StoreModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.TaxModule.Core" Version="3.0.1" />
Expand Down
31 changes: 31 additions & 0 deletions src/AvaTax.TaxModule.Data/BackgroundJobs/BackgroundJobsRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Hangfire;
using VirtoCommerce.Platform.Core.Settings;
using static AvaTax.TaxModule.Core.ModuleConstants.Settings;

namespace AvaTax.TaxModule.Data.BackgroundJobs
{
public class BackgroundJobsRunner
{
private readonly ISettingsManager _settingsManager;

public BackgroundJobsRunner(ISettingsManager settingsManager)
{
_settingsManager = settingsManager;
}

public async Task StartStopOrdersSynchronizationJob()
{
var processJobEnabled = await _settingsManager.GetValueAsync(ScheduledOrdersSynchronization.SynchronizationIsEnabled.Name, (bool)ScheduledOrdersSynchronization.SynchronizationIsEnabled.DefaultValue);
if (processJobEnabled)
{
var cronExpression = _settingsManager.GetValue(ScheduledOrdersSynchronization.SynchronizationCronExpression.Name, (string)ScheduledOrdersSynchronization.SynchronizationCronExpression.DefaultValue);
RecurringJob.AddOrUpdate<OrdersSynchronizationJob>("SendOrdersToAvaTaxJob", x => x.RunScheduled(JobCancellationToken.Null, null), cronExpression);
}
else
{
RecurringJob.RemoveIfExists("SendOrdersToAvaTaxJob");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Hangfire;
using Hangfire;
using VirtoCommerce.Platform.Core.Common;

namespace AvaTax.TaxModule.Web.BackgroundJobs
namespace AvaTax.TaxModule.Data.BackgroundJobs
{
/// <summary>
/// Wrapper for Hangfire's IJobCancellationToken
Expand All @@ -24,4 +24,4 @@ public void ThrowIfCancellationRequested()

#endregion
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System;
using System.Linq;
using System.Threading.Tasks;
using AvaTax.TaxModule.Core;
using AvaTax.TaxModule.Core.Models;
using AvaTax.TaxModule.Core.Services;
using AvaTax.TaxModule.Data.Model.PushNotifications;
using AvaTax.TaxModule.Data.Services;
using AvaTax.TaxModule.Web.Models.PushNotifications;
using Hangfire;
using Hangfire.Server;
using VirtoCommerce.OrdersModule.Core.Services;
Expand All @@ -16,8 +16,7 @@
using VirtoCommerce.SearchModule.Core.Services;
using VirtoCommerce.SearchModule.Data.Services;


namespace AvaTax.TaxModule.Web.BackgroundJobs
namespace AvaTax.TaxModule.Data.BackgroundJobs
{
[CLSCompliant(false)]
public class OrdersSynchronizationJob
Expand All @@ -42,11 +41,11 @@ public OrdersSynchronizationJob(IOrdersSynchronizationService ordersSynchronizat

[DisableConcurrentExecution(10)]
// "DisableConcurrentExecutionAttribute" prevents to start simultaneous job payloads.
// Should have short timeout, because this attribute implemented by following manner: newly started job falls into "processing" state immediately.
// Should have short timeout, because this attribute implemented by following manner: newly started job falls into "processing" state immediately.
// Then it tries to receive job lock during timeout. If the lock received, the job starts payload.
// When the job is awaiting desired timeout for lock release, it stucks in "processing" anyway. (Therefore, you should not to set long timeouts (like 24*60*60), this will cause a lot of stucked jobs and performance degradation.)
// Then, if timeout is over and the lock NOT acquired, the job falls into "scheduled" state (this is default fail-retry scenario).
// Failed job goes to "Failed" state (by default) after retries exhausted.
// Failed job goes to "Failed" state (by default) after retries exhausted.
public async Task RunScheduled(IJobCancellationToken cancellationToken, PerformContext context)
{
var currentTime = DateTime.UtcNow;
Expand All @@ -68,7 +67,7 @@ void ProgressCallback(AvaTaxOrdersSynchronizationProgress progress)
}

[DisableConcurrentExecution(10)]
public async Task RunManually(string[] orderIds, OrdersSynchronizationPushNotification notification,
public async Task RunManually(string[] orderIds, OrdersSynchronizationPushNotification notification,
IJobCancellationToken cancellationToken, PerformContext context)
{
var ordersFeed = new InMemoryIndexDocumentChangeFeed(orderIds, IndexDocumentChangeType.Modified, BatchSize);
Expand Down Expand Up @@ -113,4 +112,4 @@ private async Task PerformOrderSynchronization(IIndexDocumentChangeFeed ordersFe
await _ordersSynchronizationService.SynchronizeOrdersAsync(ordersFeed, progressCallback, cancellationTokenWrapper);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Linq;
using System.Threading.Tasks;
using AvaTax.TaxModule.Data.BackgroundJobs;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.Events;
using VirtoCommerce.Platform.Core.Settings.Events;
using static AvaTax.TaxModule.Core.ModuleConstants.Settings;

namespace AvaTax.TaxModule.Data.Handlers
{
public class ObjectSettingEntryChangedEventHandler : IEventHandler<ObjectSettingChangedEvent>
{
private readonly BackgroundJobsRunner _backgroundJobsRunner;

public ObjectSettingEntryChangedEventHandler(BackgroundJobsRunner backgroundJobsRunner)
{
_backgroundJobsRunner = backgroundJobsRunner;
}

public virtual async Task Handle(ObjectSettingChangedEvent message)
{
if (message.ChangedEntries.Any(x => (x.EntryState == EntryState.Modified
|| x.EntryState == EntryState.Added)
&& (x.NewEntry.Name == ScheduledOrdersSynchronization.SynchronizationIsEnabled.Name
|| x.NewEntry.Name == ScheduledOrdersSynchronization.SynchronizationCronExpression.Name)))
{
await _backgroundJobsRunner.StartStopOrdersSynchronizationJob();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using VirtoCommerce.Platform.Core.PushNotifications;

namespace AvaTax.TaxModule.Web.Models.PushNotifications
namespace AvaTax.TaxModule.Data.Model.PushNotifications
{
public class OrdersSynchronizationPushNotification : PushNotification
{
public OrdersSynchronizationPushNotification(string creator)
public OrdersSynchronizationPushNotification(string creator)
: base(creator)
{
NotifyType = "AvaTaxOrdersSynchronization";
Expand All @@ -30,4 +30,4 @@ public OrdersSynchronizationPushNotification(string creator)
[JsonProperty("errors")]
public ICollection<string> Errors { get; set; }
}
}
}
2 changes: 1 addition & 1 deletion src/AvaTax.TaxModule.Web/AvaTax.TaxModule.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Hangfire" Version="1.7.9" />
<PackageReference Include="VirtoCommerce.BuildWebpack" Version="1.0.0" />
<PackageReference Include="VirtoCommerce.OrdersModule.Core" Version="3.0.1" />
<PackageReference Include="VirtoCommerce.Platform.Core" Version="3.0.0-rc5" />
<PackageReference Include="VirtoCommerce.SearchModule.Data" Version="3.0.1" />
</ItemGroup>
<ItemGroup>
Expand Down
12 changes: 6 additions & 6 deletions src/AvaTax.TaxModule.Web/Controller/AvaTaxController.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
using System;
using System.Threading.Tasks;
using Avalara.AvaTax.RestClient;
using AvaTax.TaxModule.Core;
using AvaTax.TaxModule.Core.Models;
using AvaTax.TaxModule.Core.Services;
using AvaTax.TaxModule.Data.BackgroundJobs;
using AvaTax.TaxModule.Data.Logging;
using AvaTax.TaxModule.Web.BackgroundJobs;
using AvaTax.TaxModule.Data.Model.PushNotifications;
using AvaTax.TaxModule.Web.Models;
using AvaTax.TaxModule.Web.Models.PushNotifications;
using AvaTax.TaxModule.Web.Services;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using VirtoCommerce.Platform.Core.PushNotifications;
using VirtoCommerce.Platform.Core.Security;
using Microsoft.Extensions.Options;

namespace AvaTax.TaxModule.Web.Controller
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@
},
"ScheduledOrdersSynchronization": {
"IsEnabled": {
"description": "Enable scheduled synchronization of VC Platform orders with AvaTax (requires restart)",
"description": "Enable scheduled synchronization of VC Platform orders with AvaTax",
"title": "Send orders to AvaTax automatically"
},
"CronExpression": {
"description":
" x minutes use '0/x * * * *', x hours use '0 */x * * *', you can set minutes also '15 */x * * *', x days '0 0 */x * *' ",
"title": "Schedule of automatic order synchronization (requires restart)"
"title": "Schedule of automatic order synchronization"
}
}
},
Expand Down
41 changes: 20 additions & 21 deletions src/AvaTax.TaxModule.Web/Module.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
using Avalara.AvaTax.RestClient;
using AvaTax.TaxModule.Core;
using AvaTax.TaxModule.Core.Services;
using AvaTax.TaxModule.Data;
using AvaTax.TaxModule.Data.Services;
using AvaTax.TaxModule.Web.BackgroundJobs;
using Hangfire;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalara.AvaTax.RestClient;
using AvaTax.TaxModule.Core;
using AvaTax.TaxModule.Core.Services;
using AvaTax.TaxModule.Data.BackgroundJobs;
using AvaTax.TaxModule.Data.Handlers;
using AvaTax.TaxModule.Data.Providers;
using AvaTax.TaxModule.Data.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using VirtoCommerce.Platform.Core.Bus;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.ExportImport;
using VirtoCommerce.Platform.Core.Modularity;
using VirtoCommerce.Platform.Core.Security;
using VirtoCommerce.Platform.Core.Settings;
using VirtoCommerce.Platform.Core.Settings.Events;
using VirtoCommerce.TaxModule.Core.Model;
using ModuleConstants = AvaTax.TaxModule.Core.ModuleConstants;

Expand Down Expand Up @@ -56,6 +57,8 @@ public void Initialize(IServiceCollection serviceCollection)
serviceCollection.AddTransient<IAddressValidationService, AddressValidationService>();
serviceCollection.AddTransient<IOrdersSynchronizationService, OrdersSynchronizationService>();
serviceCollection.AddTransient<IOrderTaxTypeResolver, OrderTaxTypeResolver>();
serviceCollection.AddTransient<ObjectSettingEntryChangedEventHandler>();
serviceCollection.AddTransient<BackgroundJobsRunner>();

serviceCollection.AddOptions<AvaTaxSecureOptions>().Bind(configuration.GetSection("Tax:Avalara")).ValidateDataAnnotations();
}
Expand All @@ -73,26 +76,22 @@ public void PostInitialize(IApplicationBuilder appBuilder)
var avalaraOptions = appBuilder.ApplicationServices.GetRequiredService<IOptions<AvaTaxSecureOptions>>();
var logger = appBuilder.ApplicationServices.GetRequiredService<ILogger<AvaTaxRateProvider>>();
var avaTaxClientFactory = appBuilder.ApplicationServices.GetRequiredService<Func<IAvaTaxSettings, AvaTaxClient>>();
return new AvaTaxRateProvider(logger,avaTaxClientFactory, avalaraOptions);
return new AvaTaxRateProvider(logger, avaTaxClientFactory, avalaraOptions);

});
settingsRegistrar.RegisterSettingsForType(ModuleConstants.Settings.Credentials.Settings, nameof(AvaTaxRateProvider));

var permissionsProvider = appBuilder.ApplicationServices.GetRequiredService<IPermissionsRegistrar>();
permissionsProvider.RegisterPermissions(ModuleConstants.Security.Permissions.AllPermissions.Select(x => new Permission() { GroupName = "Avalara Tax", Name = x }).ToArray());

var settingManager = appBuilder.ApplicationServices.GetRequiredService<ISettingsManager>();
//Subscribe for Orders Synchronization job configuration changes
var inProcessBus = appBuilder.ApplicationServices.GetService<IHandlerRegistrar>();
inProcessBus.RegisterHandler<ObjectSettingChangedEvent>(async (message, token) => await appBuilder.ApplicationServices.GetService<ObjectSettingEntryChangedEventHandler>().Handle(message));

var processJobEnabled = settingManager.GetValue(ModuleConstants.Settings.ScheduledOrdersSynchronization.SynchronizationIsEnabled.Name, false);
if (processJobEnabled)
{
var cronExpression = settingManager.GetValue(ModuleConstants.Settings.ScheduledOrdersSynchronization.SynchronizationCronExpression.Name, "0 0 * * *");
RecurringJob.AddOrUpdate<OrdersSynchronizationJob>("SendOrdersToAvaTaxJob", x => x.RunScheduled(JobCancellationToken.Null, null), cronExpression);
}
else
{
RecurringJob.RemoveIfExists("SendOrdersToAvaTaxJob");
}
//Schedule periodic Orders Synchronization job
appBuilder.ApplicationServices.GetService<BackgroundJobsRunner>().StartStopOrdersSynchronizationJob();
var jobsRunner = appBuilder.ApplicationServices.GetService<BackgroundJobsRunner>();
jobsRunner.StartStopOrdersSynchronizationJob().GetAwaiter().GetResult();
}

public Task ExportAsync(Stream outStream, ExportImportOptions options, Action<ExportImportProgressInfo> progressCallback,
Expand Down
Loading