mirror of
https://github.com/stokebob/bnhtrade.git
synced 2026-03-19 14:37:16 +00:00
feature exchange rate update automation
Automated downloading exchange rates from HMRC and updating the database. Added function call to the console and form applications. Also added a form to show the console output in form application.
This commit is contained in:
@@ -1,23 +1,200 @@
|
||||
using System;
|
||||
using FikaAmazonAPI.ConstructFeed.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Account
|
||||
{
|
||||
public class Currency
|
||||
{
|
||||
Log.LogEvent log = new Log.LogEvent();
|
||||
|
||||
public decimal CurrencyConvertToGbp(string currencyCode, decimal amount, DateTime conversionDate)
|
||||
{
|
||||
return new Data.Database.Account.Currency().CurrencyConvertToGbp(currencyCode, amount, conversionDate);
|
||||
if (currencyCode == "GBP" || amount == 0M)
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
if (currencyCode.Length != 3)
|
||||
{
|
||||
throw new Exception("Invalid currency code '" + currencyCode + "'");
|
||||
}
|
||||
|
||||
var db = new Data.Database.Account.Currency();
|
||||
var exchageRate = db.ReadExchangeRate(currencyCode, conversionDate);
|
||||
|
||||
if (exchageRate != null)
|
||||
{
|
||||
return amount / Convert.ToDecimal(exchageRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Currency code '" + currencyCode + "' or date " + conversionDate.ToShortDateString() + " " + conversionDate.ToLongTimeString() + "' does not exist in the Exchange Rate table");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int CurrencyExchangeRateInsert(int exchangeRateSource, string currencyCode,
|
||||
decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false)
|
||||
private DateTime GetHmrcMaxPeriodAvaible()
|
||||
{
|
||||
return new Data.Database.Account.Currency().CurrencyExchangeRateInsert(exchangeRateSource, currencyCode,
|
||||
currencyUnitsPerGbp, periodStart, periodEnd, checkOverride);
|
||||
// HMRC monthly sxchange rates are published on the penultimate Thursday of the month before
|
||||
// For some leeway we'll use the penultimate Friday
|
||||
|
||||
// find penultimate Friday for current month
|
||||
var ukTimeNow = new Logic.Utilities.DateTime().ConvertUtcToUk(DateTime.UtcNow);
|
||||
var monthDayCount = DateTime.DaysInMonth(ukTimeNow.Year, ukTimeNow.Month);
|
||||
var thisMonthPenultimateFriday = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, monthDayCount), DateTimeKind.Unspecified);
|
||||
int count = 0;
|
||||
int fridayCount = 0;
|
||||
while (count != 15)
|
||||
{
|
||||
if (thisMonthPenultimateFriday.DayOfWeek == DayOfWeek.Friday)
|
||||
{
|
||||
fridayCount++;
|
||||
if (fridayCount == 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
thisMonthPenultimateFriday = thisMonthPenultimateFriday.AddDays(-1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 15)
|
||||
{
|
||||
throw new Exception("Something went wrong here ErrorID:ef7f5d8f-0f7b-4014-aa65-421ecd5d7367");
|
||||
}
|
||||
|
||||
var mostRecentPeriodAvaible = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, 1), DateTimeKind.Unspecified); ;
|
||||
if (ukTimeNow >= thisMonthPenultimateFriday)
|
||||
{
|
||||
mostRecentPeriodAvaible = mostRecentPeriodAvaible.AddMonths(1);
|
||||
}
|
||||
|
||||
return mostRecentPeriodAvaible;
|
||||
}
|
||||
|
||||
public void UpdateHmrcExchageRates()
|
||||
{
|
||||
log.LogInformation("Starting update database HMRC exchange rates");
|
||||
|
||||
int exchangeRateSourceId = 1; // id for hmrc
|
||||
|
||||
// retrive most recent data from db
|
||||
var db = new Data.Database.Account.Currency();
|
||||
var dbLatestRates = db.ReadExchangeRateLatest();
|
||||
|
||||
// sanity check, make sure there are no duplicates
|
||||
int count = 0;
|
||||
foreach (var exchageRate in dbLatestRates)
|
||||
{
|
||||
count = 0;
|
||||
var currency = exchageRate.CurrencyCode;
|
||||
foreach (var subExchageRate in dbLatestRates)
|
||||
{
|
||||
if (exchageRate.CurrencyCode == subExchageRate.CurrencyCode)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
if (count > 1)
|
||||
{
|
||||
throw new FormatException("Datebase returned duplicate information");
|
||||
}
|
||||
}
|
||||
|
||||
// test for no data (first time running)
|
||||
var hmrcMonthToRetrive = new DateTime();
|
||||
if (dbLatestRates.Any() == false)
|
||||
{
|
||||
hmrcMonthToRetrive = Data.Database.Constants.GetBusinessStartUk();
|
||||
}
|
||||
|
||||
// set first/earliest month to retrive from hmrc website
|
||||
foreach (var exchageRate in dbLatestRates)
|
||||
{
|
||||
var dbEndDateTime = exchageRate.DateTimeEndUk;
|
||||
|
||||
if (hmrcMonthToRetrive == default(DateTime))
|
||||
{
|
||||
hmrcMonthToRetrive = dbEndDateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbEndDateTime < hmrcMonthToRetrive)
|
||||
{
|
||||
hmrcMonthToRetrive = dbEndDateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check - more coding required to retrive periods before 2021-01-01
|
||||
if (hmrcMonthToRetrive < DateTime.SpecifyKind(new DateTime(2021, 1, 1), DateTimeKind.Unspecified))
|
||||
{
|
||||
throw new Exception("This function does not currently retirve exchange rates from HMRC for dates before 2021-01-01");
|
||||
}
|
||||
|
||||
// check if retrival from hmrc is required
|
||||
var hmrcMaxMonthAvaible = GetHmrcMaxPeriodAvaible();
|
||||
if (hmrcMonthToRetrive.Year == hmrcMaxMonthAvaible.Year && hmrcMonthToRetrive.Month > hmrcMaxMonthAvaible.Month)
|
||||
{
|
||||
// nothing to retrive
|
||||
log.LogInformation("Exchange rates curretly up to date, exiting.");
|
||||
return;
|
||||
}
|
||||
|
||||
// get info from hmrc and insert data in db
|
||||
while (hmrcMonthToRetrive <= hmrcMaxMonthAvaible)
|
||||
{
|
||||
count = 0;
|
||||
|
||||
var url = new string(
|
||||
"https://www.trade-tariff.service.gov.uk/api/v2/exchange_rates/files/monthly_xml_"
|
||||
+ hmrcMonthToRetrive.Year.ToString()
|
||||
+ "-"
|
||||
+ hmrcMonthToRetrive.Month.ToString()
|
||||
+ ".xml"
|
||||
);
|
||||
var xd = new XDocument();
|
||||
xd = XDocument.Load(url);
|
||||
|
||||
foreach (var exchageRate in dbLatestRates)
|
||||
{
|
||||
if (exchageRate.DateTimeStartUtc < hmrcMonthToRetrive)
|
||||
{
|
||||
//retrive exchange rate from xml
|
||||
XElement node = xd.Root.Elements("exchangeRate").Where(e => e.Element("currencyCode").Value == exchageRate.CurrencyCode.ToString()).FirstOrDefault();
|
||||
decimal rate = decimal.Parse(node.Element("rateNew").Value);
|
||||
rate = decimal.Round(rate, 4);
|
||||
|
||||
// insert into db
|
||||
new Data.Database.Account.Currency().InsertExchangeRate(
|
||||
exchangeRateSourceId
|
||||
, exchageRate.CurrencyCode
|
||||
, rate
|
||||
, new Utilities.DateTime().ConvertUkToUtc(hmrcMonthToRetrive)
|
||||
, new Utilities.DateTime().ConvertUkToUtc(hmrcMonthToRetrive.AddMonths(1))
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
log.LogInformation(
|
||||
count + " new exchange rate(s) added to database for " + hmrcMonthToRetrive.ToString("MMMM") + " " + hmrcMonthToRetrive.Year.ToString()
|
||||
);
|
||||
|
||||
hmrcMonthToRetrive = hmrcMonthToRetrive.AddMonths(1);
|
||||
}
|
||||
|
||||
log.LogInformation("Updating database currency exchange rates complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
src/bnhtrade.Core/Logic/Utilities/DateTime.cs
Normal file
51
src/bnhtrade.Core/Logic/Utilities/DateTime.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Utilities
|
||||
{
|
||||
public class DateTime
|
||||
{
|
||||
public System.DateTime ConvertUkToUtc(System.DateTime ukDateTime)
|
||||
{
|
||||
if (ukDateTime.Kind == DateTimeKind.Local && TimeZoneInfo.Local.Id != "GMT Standard Time")
|
||||
{
|
||||
throw new System.ArgumentException("DateTime kind set to local, local is not set to 'GMT Standard Time'");
|
||||
}
|
||||
else if (ukDateTime.Kind == DateTimeKind.Utc)
|
||||
{
|
||||
throw new System.ArgumentException("DateTime kind is UTC");
|
||||
}
|
||||
|
||||
TimeZoneInfo ukZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
|
||||
System.DateTime ukTime = TimeZoneInfo.ConvertTimeToUtc(ukDateTime, ukZone);
|
||||
return ukTime; // is returned as DateTimeKind 'unspecified'
|
||||
}
|
||||
|
||||
public System.DateTime ConvertUtcToUk(System.DateTime utcDateTime)
|
||||
{
|
||||
if (utcDateTime.Kind != DateTimeKind.Utc)
|
||||
{
|
||||
throw new System.ArgumentException("DateTime kind is not UTC");
|
||||
}
|
||||
|
||||
TimeZoneInfo ukZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
|
||||
System.DateTime ukTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, ukZone);
|
||||
return ukTime; // is returned as DateTimeKind 'unspecified'
|
||||
}
|
||||
|
||||
public System.DateTime ParseIsoDateTimeString(string reportDateTime)
|
||||
{
|
||||
string isoDateTime =
|
||||
reportDateTime.Substring(6, 4) + "-" +
|
||||
reportDateTime.Substring(3, 2) + "-" +
|
||||
reportDateTime.Substring(0, 2) + "T" +
|
||||
reportDateTime.Substring(11, 2) + ":" +
|
||||
reportDateTime.Substring(14, 2) + ":" +
|
||||
reportDateTime.Substring(17, 2) + "Z";
|
||||
return System.DateTime.Parse(isoDateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ namespace bnhtrade.Core.Logic.Utilities
|
||||
{
|
||||
public class DateTimeCheck : Validate.Validate
|
||||
{
|
||||
public bool IsUtc(DateTime dateTimeToCheck)
|
||||
public bool IsUtc(System.DateTime dateTimeToCheck)
|
||||
{
|
||||
if (dateTimeToCheck == default(DateTime))
|
||||
if (dateTimeToCheck == default(System.DateTime))
|
||||
{
|
||||
ValidationResultAdd( "DateTime value set to default.");
|
||||
return false;
|
||||
@@ -22,9 +22,9 @@ namespace bnhtrade.Core.Logic.Utilities
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool IsLocal(DateTime dateTimeToCheck)
|
||||
public bool IsLocal(System.DateTime dateTimeToCheck)
|
||||
{
|
||||
if (dateTimeToCheck == default(DateTime))
|
||||
if (dateTimeToCheck == default(System.DateTime))
|
||||
{
|
||||
ValidationResultAdd("DateTime value set to default.");
|
||||
return false;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Utilities
|
||||
{
|
||||
public class DateTimeParse
|
||||
{
|
||||
public DateTime ParseMwsReportDateTime(string reportDateTime)
|
||||
{
|
||||
string isoDateTime =
|
||||
reportDateTime.Substring(6, 4) + "-" +
|
||||
reportDateTime.Substring(3, 2) + "-" +
|
||||
reportDateTime.Substring(0, 2) + "T" +
|
||||
reportDateTime.Substring(11, 2) + ":" +
|
||||
reportDateTime.Substring(14, 2) + ":" +
|
||||
reportDateTime.Substring(17, 2) + "Z";
|
||||
return DateTime.Parse(isoDateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/bnhtrade.Core/Logic/Utilities/ListFunction.cs
Normal file
59
src/bnhtrade.Core/Logic/Utilities/ListFunction.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Utilities
|
||||
{
|
||||
public class ListFunction
|
||||
{
|
||||
public ListFunction() { }
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a unique list from an input list
|
||||
/// </summary>
|
||||
/// <param name="inputList"></param>
|
||||
/// <param name="includeWhiteSpace"></param>
|
||||
/// <returns>Unique list</returns>
|
||||
public List<string> UniqueList(List<string> inputList, bool removeNullorWhitespace = true)
|
||||
{
|
||||
List<string> outputList = new List<string>();
|
||||
|
||||
foreach (string input in inputList)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input) && removeNullorWhitespace)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bool stringExists = false;
|
||||
foreach (string output in outputList)
|
||||
{
|
||||
if (output == input)
|
||||
{
|
||||
stringExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stringExists == false)
|
||||
{
|
||||
outputList.Add(input);
|
||||
}
|
||||
}
|
||||
|
||||
return outputList;
|
||||
}
|
||||
|
||||
public List<string> UniqueList(List<Enum> inputList, bool removeNullorWhitespace = true)
|
||||
{
|
||||
List<string> stringList = new List<string>();
|
||||
foreach (Enum input in inputList)
|
||||
{
|
||||
stringList.Add(input.ToString());
|
||||
}
|
||||
return UniqueList(stringList, removeNullorWhitespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ namespace bnhtrade.Core.Logic.Utilities
|
||||
var export = new bnhtrade.Core.Logic.Export.AmazonSettlement();
|
||||
|
||||
bool stockUpdate = false;
|
||||
bool exchangeRate = false;
|
||||
bool accountProcess = false;
|
||||
|
||||
while (true)
|
||||
@@ -28,6 +29,7 @@ namespace bnhtrade.Core.Logic.Utilities
|
||||
try
|
||||
{
|
||||
if (stockUpdate == false) { stockUpdate = true; new bnhtrade.Core.Logic.Import.Amazon().SyncAllWithDatabase(); ; }
|
||||
if (exchangeRate == false) { exchangeRate = true; new Logic.Account.Currency().UpdateHmrcExchageRates(); }
|
||||
if (accountProcess == false) { accountProcess = true; export.ToInvoice(); }
|
||||
|
||||
// if (stockProcess == false) { stockProcess = true; stock.ProcessFbaStockImportData(); }
|
||||
|
||||
Reference in New Issue
Block a user