Merge branch 'amazon-min-max-repricing' into master

This commit is contained in:
2020-10-06 20:39:22 +01:00
committed by GitHub
2 changed files with 124 additions and 88 deletions

View File

@@ -23,6 +23,16 @@ namespace bnhtrade.Core.Data.Database
/// ///
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string GetMarginSchemeTaxCode()
{
return "T190";
}
public static string GetOrderChannelAmazonUk()
{
return "Amazon.co.uk";
}
public static int GetProductConditionIdNew() public static int GetProductConditionIdNew()
{ {
return 10; return 10;

View File

@@ -16,12 +16,12 @@ namespace bnhtrade.Core.Logic.Sku.Price
private string sqlConnectionString; private string sqlConnectionString;
private bnhtrade.Core.Logic.Log.LogEvent log = new Log.LogEvent(); private bnhtrade.Core.Logic.Log.LogEvent log = new Log.LogEvent();
string err = "FbaPricing Error: "; string err = "FbaPricing Error: ";
private string marginSchemeTaxCode = "T190"; private string marginSchemeTaxCode = Data.Database.Constants.GetMarginSchemeTaxCode();
int repriceHoldOnSalePeriod = 14; // days int repriceHoldOnSalePeriod = 14; // days
private int newConditionId = Data.Database.Constants.GetProductConditionIdNew(); private int newConditionId = Data.Database.Constants.GetProductConditionIdNew();
private List<Model.Sku.Price.SkuPriceParameter> skuInfo; private List<Model.Sku.Price.SkuPriceParameter> skuInfo;
private Dictionary<string, Model.Product.CompetitivePrice> competitivePrices; private Dictionary<string, Model.Product.CompetitivePrice> competitivePrices;
DateTime crTimeStamp = DateTime.UtcNow; DateTime newTimeStamp = DateTime.UtcNow;
private int repriceIncrementDivisor = 60; private int repriceIncrementDivisor = 60;
private Dictionary<string, int> saleCountInPeriod = new Dictionary<string, int>(); private Dictionary<string, int> saleCountInPeriod = new Dictionary<string, int>();
private Logic.Account.TaxCalculation taxCalc; private Logic.Account.TaxCalculation taxCalc;
@@ -31,28 +31,25 @@ namespace bnhtrade.Core.Logic.Sku.Price
{ {
this.sqlConnectionString = sqlConnectionString; this.sqlConnectionString = sqlConnectionString;
taxCalc = new Account.TaxCalculation(); taxCalc = new Account.TaxCalculation();
crTimeStamp = DateTime.UtcNow; newTimeStamp = DateTime.UtcNow;
marginSchemeMargin = taxCalc.GetMarginMultiplier(crTimeStamp); marginSchemeMargin = taxCalc.GetMarginMultiplier(newTimeStamp);
} }
public void Update(bool overrideDayCheck = false) public void Update(bool overrideDayCheck = false)
{ {
UpdatePrecheck();
using (var scope = new TransactionScope()) using (var scope = new TransactionScope())
{ {
string orderChannel = "Amazon.co.uk"; // may in future enable other order channels string orderChannel = Data.Database.Constants.GetOrderChannelAmazonUk(); ; // may in future enable other order channels
// need to add some cheks up here for last stock reconcilliation
// get current sku base pricing details (stock quantity, competative price, VAT info, etc.) // get current sku base pricing details (stock quantity, competative price, VAT info, etc.)
skuInfo = new Data.Database.Sku.Price.ReadParameter(sqlConnectionString).Execute(); skuInfo = new Data.Database.Sku.Price.ReadParameter(sqlConnectionString).Execute();
if (skuInfo == null || !skuInfo.Any()) if (skuInfo == null || !skuInfo.Any())
{ {
throw new Exception("Querying the database returned no records."); err += "Querying the database returned no records.";
log.LogError(err);
throw new Exception(err);
} }
// create lists that we'll add to during lopp // create lists that we'll add to during lopp
@@ -73,6 +70,8 @@ namespace bnhtrade.Core.Logic.Sku.Price
// loop through skus returnd from stock query // loop through skus returnd from stock query
for (int i = 0; i < skuInfo.Count(); i++) for (int i = 0; i < skuInfo.Count(); i++)
{ {
var existing = skuInfo[i];
string skuNumber = skuInfo[i].SkuNumber; string skuNumber = skuInfo[i].SkuNumber;
var cr = new Model.Sku.Price.PriceInfo(); var cr = new Model.Sku.Price.PriceInfo();
@@ -85,7 +84,7 @@ namespace bnhtrade.Core.Logic.Sku.Price
cr.ReviewRequired = false; cr.ReviewRequired = false;
cr.OrderChannel = orderChannel; cr.OrderChannel = orderChannel;
cr.OrderChannelQuantity = skuInfo[i].TotalQuantity; cr.OrderChannelQuantity = skuInfo[i].TotalQuantity;
cr.PriceInfoTimeStamp = crTimeStamp; cr.PriceInfoTimeStamp = newTimeStamp;
cr.SkuNumber = skuInfo[i].SkuNumber; cr.SkuNumber = skuInfo[i].SkuNumber;
// get inventory age range // get inventory age range
@@ -191,87 +190,18 @@ namespace bnhtrade.Core.Logic.Sku.Price
} }
// finish loop // finish loop
// validate and save values to database // save values to database
var validate = new Core.Logic.Validate.SkuPriceInfo(); SaveToDatabase(crDictionary);
if (!validate.IsValidDatabaseCreate(crDictionary.Values.ToList()))
{
err += "Database object create validation failed";
log.LogError(err, validate.ValidationResultListToString());
throw new Exception(err);
}
new Data.Database.Sku.Price.CreatePricingDetail(sqlConnectionString).Executue(crDictionary.Values.ToList()); // upload to amazon
UploadToAmazon(crDictionary);
// create and upload inventory loader file to amazon return; // remove after testing
var exportList = new List<Model.Export.AmazonIventoryLoaderFile>();
foreach (var item in crDictionary.Values)
{
var listItem = new Model.Export.AmazonIventoryLoaderFile();
listItem.Sku = item.SkuNumber;
listItem.MinimumAllowedPrice = item.MinPrice;
listItem.MaximumAllowedPrice = item.MaxPrice;
listItem.Price = item.MaxPrice;
listItem.SetFulfillmentCenterId(true);
exportList.Add(listItem);
}
// validate
var vaildateInvLoader = new Validate.AmazonIventoryLoaderFile();
if (!vaildateInvLoader.IsValidFbaPricing(exportList))
{
err += "Inventory loader object validation failed";
log.LogError(err, vaildateInvLoader.ValidationResultListToString());
throw new Exception(err);
}
// create file stream
var config = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.CurrentCulture);
config.Delimiter = "\t";
config.Encoding = Encoding.UTF8;
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, Encoding.UTF8))
using (var csv = new CsvWriter(writer, config))
{
csv.WriteRecords(exportList);
}
// submit file to database and amazon mws
var submit = new Logic.Export.AmazonSubmitFile(sqlConnectionString);
return;
submit.SubmitInventoryLoader(stream);
scope.Complete(); scope.Complete();
} }
} }
private bool OkayToReprice(DateTime lastPriceUpdate)
{
if (lastPriceUpdate == default(DateTime))
{
err += "Invalid, datetime is default.";
log.LogError(err);
throw new Exception(err);
}
bool update = false;
lastPriceUpdate = new DateTime(lastPriceUpdate.Year, lastPriceUpdate.Month, lastPriceUpdate.Day);
DateTime today = new DateTime(crTimeStamp.Year, crTimeStamp.Month, crTimeStamp.Day);
// will only update once on tue, wed or thurs each week.
if (today.DayOfWeek == DayOfWeek.Tuesday || today.DayOfWeek == DayOfWeek.Wednesday || today.DayOfWeek == DayOfWeek.Thursday)
{
if (today > lastPriceUpdate.AddDays(3))
{
update = true;
}
}
return update;
}
/// <summary> /// <summary>
/// Get the minimum sale price to break even. /// Get the minimum sale price to break even.
/// </summary> /// </summary>
@@ -382,5 +312,101 @@ namespace bnhtrade.Core.Logic.Sku.Price
return 0; return 0;
} }
} }
private bool OkayToReprice(DateTime lastPriceUpdate)
{
if (lastPriceUpdate == default(DateTime))
{
err += "Invalid, datetime is default.";
log.LogError(err);
throw new Exception(err);
}
bool update = false;
lastPriceUpdate = new DateTime(lastPriceUpdate.Year, lastPriceUpdate.Month, lastPriceUpdate.Day);
DateTime today = new DateTime(newTimeStamp.Year, newTimeStamp.Month, newTimeStamp.Day);
// will only update once on tue, wed or thurs each week.
if (today.DayOfWeek == DayOfWeek.Tuesday || today.DayOfWeek == DayOfWeek.Wednesday || today.DayOfWeek == DayOfWeek.Thursday)
{
if (today > lastPriceUpdate.AddDays(3))
{
update = true;
}
}
return update;
}
private void SaveToDatabase(Dictionary<string, Model.Sku.Price.PriceInfo> crDictionary)
{
var validate = new Core.Logic.Validate.SkuPriceInfo();
if (!validate.IsValidDatabaseCreate(crDictionary.Values.ToList()))
{
err += "Database object create validation failed";
log.LogError(err, validate.ValidationResultListToString());
throw new Exception(err);
}
new Data.Database.Sku.Price.CreatePricingDetail(sqlConnectionString).Executue(crDictionary.Values.ToList());
}
/// <summary>
/// Before running reprice update, this method ensures that the relevant data needed is up to date.
/// </summary>
private void UpdatePrecheck()
{
throw new NotImplementedException();
// check last FBA sale import
err += "Querying the database returned no records.";
log.LogError(err);
throw new Exception(err);
// check last amazon sku fees updates
}
private void UploadToAmazon(Dictionary<string, Model.Sku.Price.PriceInfo> crDictionary)
{
var exportList = new List<Model.Export.AmazonIventoryLoaderFile>();
foreach (var item in crDictionary.Values)
{
var listItem = new Model.Export.AmazonIventoryLoaderFile();
listItem.Sku = item.SkuNumber;
listItem.MinimumAllowedPrice = item.MinPrice;
listItem.MaximumAllowedPrice = item.MaxPrice;
listItem.Price = item.MaxPrice;
listItem.SetFulfillmentCenterId(true);
exportList.Add(listItem);
}
// validate
var vaildateInvLoader = new Validate.AmazonIventoryLoaderFile();
if (!vaildateInvLoader.IsValidFbaPricing(exportList))
{
err += "Inventory loader object validation failed";
log.LogError(err, vaildateInvLoader.ValidationResultListToString());
throw new Exception(err);
}
// create file stream
var config = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.CurrentCulture);
config.Delimiter = "\t";
config.Encoding = Encoding.UTF8;
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, Encoding.UTF8))
using (var csv = new CsvWriter(writer, config))
{
csv.WriteRecords(exportList);
}
// submit file to database and amazon mws
var submit = new Logic.Export.AmazonSubmitFile(sqlConnectionString);
return; // remove after testing
submit.SubmitInventoryLoader(stream);
}
} }
} }