diff --git a/bnhtrade Database Client.sln b/bnhtrade Database Client.sln new file mode 100644 index 0000000..127ef96 --- /dev/null +++ b/bnhtrade Database Client.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2037 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bnhtradeDatabaseClient", "bnhtrade Database Client\bnhtradeDatabaseClient.csproj", "{339D7413-3DA7-46EA-A55C-255A9A6B95EB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bnhtradeScheduledTasks", "bnhtrade Scheduled Tasks\bnhtradeScheduledTasks.csproj", "{5D6E1D66-3901-4340-95C6-EE65051AB623}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CF330C30-8231-4D54-B60C-FF0644713502}" + ProjectSection(SolutionItems) = preProject + bnhtradeRegasmInstall.bat = bnhtradeRegasmInstall.bat + bnhtradeRegasmRefresh.bat = bnhtradeRegasmRefresh.bat + bnhtradeRegasmUninstall.bat = bnhtradeRegasmUninstall.bat + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {339D7413-3DA7-46EA-A55C-255A9A6B95EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {339D7413-3DA7-46EA-A55C-255A9A6B95EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {339D7413-3DA7-46EA-A55C-255A9A6B95EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {339D7413-3DA7-46EA-A55C-255A9A6B95EB}.Release|Any CPU.Build.0 = Release|Any CPU + {5D6E1D66-3901-4340-95C6-EE65051AB623}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D6E1D66-3901-4340-95C6-EE65051AB623}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D6E1D66-3901-4340-95C6-EE65051AB623}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D6E1D66-3901-4340-95C6-EE65051AB623}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9CE53A62-9E0C-460F-9C09-B7DDB3B7F0EA} + EndGlobalSection +EndGlobal diff --git a/bnhtrade Database Client/App.config b/bnhtrade Database Client/App.config new file mode 100644 index 0000000..affa224 --- /dev/null +++ b/bnhtrade Database Client/App.config @@ -0,0 +1,24 @@ + + + + +
+ + + + + + + + + + + + %USERPROFILE%\Desktop\e2A_Client\Archive\ + + + %USERPROFILE%\Desktop\e2A_Client\Processing\ + + + + diff --git a/bnhtrade Database Client/Program.cs b/bnhtrade Database Client/Program.cs new file mode 100644 index 0000000..840ee79 --- /dev/null +++ b/bnhtrade Database Client/Program.cs @@ -0,0 +1,9669 @@ +using MarketplaceWebService; +using MarketplaceWebService.Model; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MWSFinancesService; +using MWSFinancesService.Model; +using System.Xml.Linq; +using System.IO.Compression; +using System.Threading; +using System.Transactions; +using System.Text.RegularExpressions; +using MarketplaceWebServiceProducts.Model; +using MarketplaceWebServiceProducts; +using System.Data.SqlTypes; +using System.Security.Cryptography; +using bnhtradeDatabaseClient.AmazonMWS; + +namespace bnhtradeDatabaseClient +{ + namespace Database + { + public class Connection + { + public class DatabaseConnectionDetail + { + public string DataSource { get; } = "SQL-Server"; + public string InitialCatalogue { get; } = "e2A"; + public string UserId { get; set; } + public string Password { get; set; } + public bool PersistSecurityInfo { get; set; } = true; + public bool MultipleActiveResults { get; set; } = true; + public string ConnectionString + { + get + { + return "Data Source=" + DataSource + ";Initial Catalog=" + InitialCatalogue + ";Persist Security Info=" + PersistSecurityInfo.ToString() + + ";User ID=" + UserId + ";Password=" + Password + ";MultipleActiveResultSets=" + MultipleActiveResults.ToString(); + } + } + } + public SqlConnection DatabaseConnection(DatabaseConnectionDetail connDetails) + { + if (connDetails.InitialCatalogue == "" || connDetails.DataSource == "" || connDetails.UserId == "" || connDetails.Password == "") + { + throw new Exception("Insuficent info supplied for sql connection string"); + } + SqlConnection sqlConn = new SqlConnection(connDetails.ConnectionString); + + return sqlConn; + } + } + + public class Consistancy + { + // add some database consistancy checkes here as and when needed + + public static void ConsistancyCheckRunAll(string sqlConnectionString) + { + + } + } + } + + namespace EbayQuery + { + public class Ebay + { + /// + /// Function returns records ID if a matching listing is found, 0 if not + /// + /// 12 digit number string + /// Allows for an error of +/- 2 days in supplied end datetime -- function will accept date with no time + /// + /// + public int EbayListingItemGet(string sqlConnectionString, string itemNumber, DateTime listingEnd) + { + if (itemNumber.Length != 12) + { throw new Exception("Error, eBay item number must consist of a 12 charater numeric string."); } + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT EbayListingItemID + FROM tblEbayListingItem + WHERE EbayItemNumber=@itemNumber + AND ListingEndDateTime > DATEADD(day, -2, @listingEnd) AND ListingEndDateTime < DATEADD(day, +2, @listingEnd)" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@itemNumber", itemNumber); + cmd.Parameters.AddWithValue("@listingEnd", listingEnd.ToUniversalTime()); + + object result = cmd.ExecuteScalar(); + if (result == null) + { + return 0; + } + else + { + return Convert.ToInt32(result); + } + } + } + } + + public (int listingId, bool isNewListingItem, bool isNewListing) EbayListingItemInsert + ( + string sqlConnectionString, string itemNumber, DateTime listingEnd, string listingTitle, string listingDescription, string ebayUser, + bool isAuction, decimal price, DateTime priceTime, decimal shipping, string itemLocation, string category, + FileStream imageFile, string imageFileExtension + ) + { + // first off, check if listing-item already exists, return id if it does + int listingItemId = EbayListingItemGet(sqlConnectionString, itemNumber, listingEnd); + if (listingItemId > 0) + { return (listingItemId, false, false); } + + // continue if there is no listing + bool newListing = false; + + // settings/checks + if (listingTitle.Length == 0 || ebayUser.Length == 0 || itemLocation.Length == 0 || category.Length == 0) + { throw new Exception("Required parameter(s) missing."); } + + if (string.IsNullOrWhiteSpace(listingDescription)) + { listingDescription = ""; } + + int imageFileSize; + if (imageFile == null) + { imageFileSize = 0; } + else + { imageFileSize = Convert.ToInt32(imageFile.Length); } // long to int -- good for files up to 2.14 GB + + byte[] md5ByteArray = new byte[0]; + if (imageFileSize > 0) + { + using (var md5 = MD5.Create()) + { + md5ByteArray = md5.ComputeHash(imageFile); + } + } + + // file extention checks + if (imageFileExtension.Length > 0) + { + if (imageFileExtension.Substring(0, 1) == ".") + { imageFileExtension = imageFileExtension.Substring(1, imageFileExtension.Length - 1); } + if (imageFileExtension.Length < 3 & imageFileSize > 0) + { throw new Exception("Image file extension required if image file is present."); } + } + + listingEnd = DateTime.SpecifyKind(listingEnd, DateTimeKind.Utc); + priceTime = DateTime.SpecifyKind(priceTime, DateTimeKind.Utc); + + // if listing-item does not exist, look for matching 'Listing' + // for speed, do this in two stages as description field on sql server cannot be indexed + // >> first stage + int listingId = 0; + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "SELECT EbayListingID " + + "FROM tblEbayListing " + + "WHERE ListingTitle=@listingTitle AND EbayUser=@ebayUser AND ItemLocation=@itemLocation AND Category=@category " + + "AND ListingImageHashMD5=@listingImageHashMD5" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@listingTitle", listingTitle); + cmd.Parameters.AddWithValue("@ebayUser", ebayUser); + cmd.Parameters.AddWithValue("@itemLocation", itemLocation); + cmd.Parameters.AddWithValue("@category", category); + //cmd.Parameters.Add("@listingImageHashMD5", SqlDbType.VarBinary).Value = md5ByteArray; + cmd.Parameters.AddWithValue("@listingImageHashMD5", md5ByteArray); + if (imageFileSize > 0) + { + //cmd.Parameters.AddWithValue("@listingImageHashMD5", md5ByteArray); + //cmd.Parameters.AddWithValue("@listingImageFileExtension", imageFileExtension); + } + else + { + //cmd.Parameters.AddWithValue("@listingImageHashMD5", DBNull.Value); + //cmd.Parameters.AddWithValue("@listingImageFileExtension", DBNull.Value); + } + + object result = cmd.ExecuteScalar(); + if (result != null) + { + listingId = Convert.ToInt32(result); + } + } + + // >> second stage + if (listingId > 0) + { + using (SqlCommand cmd = new SqlCommand(@" + SELECT EbayListingID + FROM tblEbayListing + WHERE EbayListingID=@ebayListingID AND ListingDescription=@listingDescription + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@ebayListingID", listingId); + cmd.Parameters.AddWithValue("@listingDescription", listingDescription); + + object result = cmd.ExecuteScalar(); + if (result == null) + { + // match not found, set variable to 0 and add listing to db + listingId = 0; + } + } + } + } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + // add listing if not + if (listingId == 0) + { + newListing = true; + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblEbayListing (ListingTitle, ListingDescription, EbayUser, ItemLocation, Category, " + + " ListingImage, ListingImageSizeByte, ListingImageFileExtension, ListingImageHashMD5) " + + "OUTPUT INSERTED.EbayListingID " + + "VALUES (@listingTitle, @listingDescription, @ebayUser, @itemLocation, @category, " + + " @listingImage, @listingImageSizeByte, @listingImageFileExtension, @listingImageHashMD5)" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@listingTitle", listingTitle); + cmd.Parameters.AddWithValue("@listingDescription", listingDescription); + cmd.Parameters.AddWithValue("@ebayUser", ebayUser); + cmd.Parameters.AddWithValue("@itemLocation", itemLocation); + cmd.Parameters.AddWithValue("@category", category); + cmd.Parameters.AddWithValue("@listingImageSizeByte", imageFileSize); + cmd.Parameters.AddWithValue("@listingImageHashMD5", md5ByteArray); + cmd.Parameters.AddWithValue("@listingImageFileExtension", imageFileExtension); + if (imageFileSize > 0) + { + // open the file and map it to an SqlBytes instance that we use as the parameter value. + SqlBytes bytesImageFile = new SqlBytes(imageFile); + cmd.Parameters.AddWithValue("@listingImage", bytesImageFile); + } + else + { + cmd.Parameters.AddWithValue("@listingImage", new byte[0]); + } + + listingId = (int)cmd.ExecuteScalar(); + } + } + + // add listing-item + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblEbayListingItem (EbayListingID, EbayItemNumber, ListingEndDateTime, IsAuction, Price, PriceDateTime, Shipping) " + + "OUTPUT INSERTED.EbayListingItemID " + + "VALUES (@listingId, @itemNumber, @listingEnd, @isAuction, @price, @priceTime, @shipping)" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@listingId", listingId); + cmd.Parameters.AddWithValue("@itemNumber", itemNumber); + cmd.Parameters.AddWithValue("@listingEnd", listingEnd); + cmd.Parameters.AddWithValue("@isAuction", isAuction); + cmd.Parameters.AddWithValue("@price", price); + cmd.Parameters.AddWithValue("@priceTime", priceTime); + cmd.Parameters.AddWithValue("@shipping", shipping); + + listingItemId = (int)cmd.ExecuteScalar(); + } + scope.Complete(); + } + } + return (listingItemId, true, newListing); + } + } + } + namespace Export + { + public class ExportQuery + { + public static int WIP_ExportAccountInvoiceInsert(string sqlConnectionString, int invoiceTypeId, string contact, DateTime invoiceDate, + DateTime invoiceDueDate, string reference, string currencyCode, string invoiceNumber = "", bool markComplete = false) + { + //checks + if (currencyCode.Length != 3) + { + throw new Exception("Incorrect currency code"); + } + + // onto business + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblExportAccountInvoice + (ExportAccountInvoiceTypeID, Contact, InvoiceDate, InvoiceDueDate, InvoiceNumber, Reference, CurrencyCode, IsComplete) + OUTPUT + INSERTED.ExportAccountInvoiceID + VALUES + (@invoiceTypeId, @contact, @invoiceDate, @invoiceDueDate, @invoiceNumber, @reference, @currencyCode, @markComplete); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@invoiceTypeId", invoiceTypeId); + cmd.Parameters.AddWithValue("@contact", contact); + cmd.Parameters.AddWithValue("@invoiceDate", invoiceDate); + cmd.Parameters.AddWithValue("@invoiceDueDate", invoiceDueDate); + cmd.Parameters.AddWithValue("@reference", reference); + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + //cmd.Parameters.AddWithValue("@invoiceTotal", invoiceTotal); + cmd.Parameters.AddWithValue("@markComplete", markComplete); + if (invoiceNumber == "") + { cmd.Parameters.AddWithValue("@invoiceNumber", DBNull.Value); } + else + { cmd.Parameters.AddWithValue("@invoiceNumber", invoiceNumber); } + + return (int)cmd.ExecuteScalar(); + } + } + } + + // function returns Id of inserted line, 0 for lineInsert disabled, exception for IsNew + public static int WIP_ExportAccountInvoiceLineInsert(string sqlConnectionString, int invoiceId, int invoiceLineTypeId, + decimal netAmount, decimal taxAmount) + { + int netAccountId; + int taxAccountId; + + // get default net and tax account IDs + // suppress any ambient transactions, can cause locks on table inserts + using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress)) + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT + IsNewReviewRequired, InvoiceLineEntryEnable, AccountChartOfID_Default, AccountTaxCodeID_Default + FROM + tblExportAccountInvoiceLineType + WHERE + ExportAccountInvoiceLineTypeID=@invoiceLineTypeId; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@invoiceLineTypeId", invoiceLineTypeId); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + // checks + if (reader.GetBoolean(0) == true) + { + throw new Exception("New Type requires review where ExportAccountInvoiceLineTypeID=" + invoiceLineTypeId); + } + //// any invoice lines that shouldn't be entered will be taken out after the fact + //if (reader.GetBoolean(1) == false) + //{ + // return 0; + //} + if (reader.IsDBNull(2) || reader.IsDBNull(3)) + { + throw new Exception("Default account values missing where ExportAccountInvoiceLineTypeID=" + invoiceLineTypeId); + } + + netAccountId = reader.GetInt32(2); + taxAccountId = reader.GetInt32(3); + } + else + { + throw new Exception("Supplied TypeId does not exist in table, where ExportAccountInvoiceLineTypeID=" + invoiceLineTypeId); + } + } + } + scope.Complete(); + } + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + // insert record + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblExportAccountInvoiceLine + (ExportAccountInvoiceID, ExportAccountInvoiceLineTypeID, NetAmount, AccountChartOfID, TaxAmount, AccountTaxCodeID) + OUTPUT + INSERTED.ExportAccountInvoiceLineID + VALUES + (@invoiceId, @invoiceLineTypeId, @netAmount, @netAccountId, @taxAmount, @taxAccountId); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@invoiceID", invoiceId); + cmd.Parameters.AddWithValue("@invoiceLineTypeID", invoiceLineTypeId); + cmd.Parameters.AddWithValue("@netAmount", netAmount); + cmd.Parameters.AddWithValue("@netAccountId", netAccountId); + cmd.Parameters.AddWithValue("@taxAmount", taxAmount); + cmd.Parameters.AddWithValue("@taxAccountId", taxAccountId); + + return (int)cmd.ExecuteScalar(); + } + } + + } + + public static int WIP_GetImportInvoiceLineTypeId(string sqlConnectionString, string matchString) + { + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type is new or has not been reviewed yet */ + + if (matchString.Length == 0) + { + throw new Exception("Matchstring is of zero lenth"); + } + + bool insertNew = false; + using (TransactionScope scopeSupress = new TransactionScope(TransactionScopeOption.Suppress)) + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT ExportAccountInvoiceLineTypeID, IsNewReviewRequired, InvoiceLineEntryEnable + FROM tblExportAccountInvoiceLineType + WHERE MatchString=@matchString; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@matchString", matchString); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + int transactionTypeId = reader.GetInt32(0); + bool isNew = reader.GetBoolean(1); + bool? importEnabled = reader.GetBoolean(2); + + if (isNew == true) + { + // return null and 'skip' item + return 0; + } + //else if (importEnabled == false) + //{ + // // mark IsProcessed=true and leave transactionId=null + // return -1; + //} + else if (transactionTypeId > 0) + { + return transactionTypeId; + } + else + { + throw new Exception("Account TransactionTypeId lookup method went wrong, is one of the 'enabled' boolean on table set to null?"); + } + } + else + { + insertNew = true; + } + } + } + + // insert new and retrive new value, if required + if (insertNew) + { + + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblExportAccountInvoiceLineType ( TypeTitle, MatchString ) " + + "OUTPUT INSERTED.ExportAccountInvoiceLineTypeID " + + "VALUES ( @typeTitle, @matchString );" + , sqlConn)) + { + insertCmd.Parameters.AddWithValue("@typeTitle", "NEW TYPE"); + insertCmd.Parameters.AddWithValue("@matchString", matchString); + + int transactionTypeId = (int)insertCmd.ExecuteScalar(); + + scopeSupress.Complete(); + } + return 0; + } + else + { + throw new Exception("This is only here so 'all code paths return a value', this can never be reached!"); + } + } + } + } + } + namespace Purchase + { + public class PurchaseQuery + { + private static int accountJournalTypeIdNet = 1; + private static int accountJournalTypeIdTax = 2; + private static int stockJournalTypeId = 1; + private static int creditAccountId = 59; + private static int creditStatusId = 13; + private static int defaultAccountId = 138; + + public static void WIP_PurchaseLineTransactionNetInsert(string sqlConnectionString, int purchaseLineId, + string currencyCode, decimal amountNet, DateTime entryDate, int debitAccountId = 0) + { + // default to 'Inventory, Receivable/Processing' + if (debitAccountId < 1) + { + debitAccountId = defaultAccountId; + } + + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // create account journal entry + int journalId = Account.AccountQuery.AccountJournalInsert( + sqlConnectionString, accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId); + + // add transaction to purchase line transaction table + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO + tblPurchaseLineTransaction + ( PurchaseLineID, AccountJournalID ) + VALUES + ( @purchaseLineID, @accountJournalID ); + ", conn)) + { + cmd.Parameters.AddWithValue("@purchaseLineID", purchaseLineId); + cmd.Parameters.AddWithValue("@accountJournalID", journalId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 1) + { + throw new Exception("Operation cancelled, failed to update tblPurchaseLineTransaction!"); + } + } + + //commit the transaction and return value + scope.Complete(); + } + } + + public static void WIP_PurchaseLineTransactionNetUpdate(string sqlConnectionString, int accountJouranlId, + string currencyCode, decimal amountNet, int debitAccountId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // stock accountId check + if (debitAccountId == 86) + { + int count = 0; + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Count(tblStock.StockID) AS CountOfStockID + FROM tblStock + WHERE (((tblStock.AccountJournalID)=@accountJouranlId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJouranlId", accountJouranlId); + + count = (int)cmd.ExecuteScalar(); + } + + if (count == 0) + { + throw new Exception("Add account journal entry to stock before attempting this operation."); + } + else if(count > 1) + { + throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines."); + } + } + + // make the update + bool result = bnhtradeDatabaseClient.Account.AccountQuery.AccountJournalPostUpdate(sqlConnectionString, + accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId); + + scope.Complete(); + } + } + + // delete after testing.... + + //public static void WIP_PurchaseLineTransactionStockDelete(string sqlConnectionString, int accountJournalId, int stockId) + //{ + // using (TransactionScope scope = new TransactionScope()) + // using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + // { + // conn.Open(); + + // // get stock cost + // (int quantity, decimal totalCost) result = Stock.StockJournal.StockGetTotalQuantityAndCost(sqlConnectionString, stockId); + // decimal amount = result.totalCost; + + // // delete accountJournalId from stock table + // using (SqlCommand cmd = new SqlCommand(@" + // UPDATE tblStock + // SET AccountJournalID=Null + // WHERE StockID=@stockId AND AccountJournalID=@accountJournalId; + // ", conn)) + // { + // cmd.Parameters.AddWithValue("@stockId", stockId); + // cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + // int count = cmd.ExecuteNonQuery(); + + // if (count != 1) + // { + // throw new Exception("Integrity check failure! StockID=" + stockId + ", AccountJournalID=" + accountJournalId + + // " combination not found on stock table."); + // } + // } + + // // reset the account journal to default + // Account.AccountQuery.AccountJournalPostUpdate(sqlConnectionString, accountJournalId, "GBP", amount, defaultAccountId, creditAccountId); + + // // delete the stock entry + // Stock.StockCreate.WIP_StockDeleteSub(sqlConnectionString, stockId); + + // scope.Complete(); + // } + //} + + public static void WIP_PurchaseLineTransactionDelete(string sqlConnectionString, int purchaseLineId, int accountJournalId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // check accountJournalId does not exist in stock table + using (SqlCommand cmd = new SqlCommand(@" + SELECT StockID + FROM tblStock + WHERE AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + if (reader.Read()) + { + throw new Exception("Integrity check failure! AccountJournalID=" + accountJournalId + " exists multiple time in stock table!"); + } + else + { + throw new Exception("Delete stock first before proceeding, AccountJournalID=" + accountJournalId ); + } + } + } + } + + // delete line in purchase line transaction table + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblPurchaseLineTransaction + WHERE AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 1) + { + throw new Exception("Operation cancelled, failed to delete entry in tblPurchaseLineTransaction WHERE AccountJournalID=" + accountJournalId); + } + } + + // delete account journal entry + Account.AccountQuery.AccountJournalDelete(sqlConnectionString, accountJournalId); + + scope.Complete(); + } + } + } + } + namespace Account + { + public class AccountQuery + { + public static int GetCurrencyId(string sqlConnectionString, string currencyCode) + { + if (currencyCode == "GBP") + { + return 53; + } + if (currencyCode == "EUR") + { + return 50; + } + + try + { + if (currencyCode.Length == 3) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand sqlCommand = new SqlCommand( + "SELECT AccountCurrencyID FROM tblAccountCurrency WHERE CurrencyCode=@currencyCode;" + , sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@currencyCode", currencyCode); + object obj = sqlCommand.ExecuteScalar(); + if (!(obj == null)) + { + return (int)sqlCommand.ExecuteScalar(); + } + else + { + return -1; + } + } + } + } + else + { + return -1; + } + } + catch (Exception ex) + { + throw ex; + } + } + + public static decimal CurrencyConvertToGbp(string sqlConnectionString, string currencyCode, decimal amount, DateTime conversionDate) + { + if (currencyCode == "GBP" || amount == 0M) + { + return amount; + } + + if (currencyCode.Length != 3) + { + throw new Exception("Invalid currency code '" + currencyCode + "'"); + } + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT CurrencyUnitsPerGBP + FROM tblAccountExchangeRate + WHERE CurrencyCode=@currencyCode AND StartDate<=@conversionDate AND EndDate>@conversionDate + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + cmd.Parameters.AddWithValue("@conversionDate", conversionDate); + + object result = cmd.ExecuteScalar(); + if (result != null) + { + return amount / Convert.ToDecimal(result); + } + } + + // return reason for no record found + using (SqlCommand cmd = new SqlCommand(@" + SELECT CurrencyUnitsPerGBP + FROM tblAccountExchangeRate + WHERE CurrencyCode=@currencyCode + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + + object result = cmd.ExecuteScalar(); + if (result == null) + { + throw new Exception("Currency code '" + currencyCode + "' does not exist in Exchange Rate table"); + } + else + { + throw new Exception("Date range for " + currencyCode + " " + conversionDate.ToShortDateString() + " " + + conversionDate.ToLongTimeString() + "' does not exist in Exchange Rate table"); + } + } + } + } + public static int CurrencyExchangeRateInsert(string sqlConnectionString, int exchangeRateSource, string currencyCode, + decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false) + { + currencyUnitsPerGbp = decimal.Round(currencyUnitsPerGbp, 4); + periodStart = DateTime.SpecifyKind(periodStart, DateTimeKind.Utc); + periodEnd = DateTime.SpecifyKind(periodEnd, DateTimeKind.Utc); + + // CHECKS + // HMRC source only + if (exchangeRateSource != 1) + { + throw new Exception("Function does not currently accept exchange rates from sources other than HMRC"); + } + // currency code upper case only + currencyCode = currencyCode.ToUpper(); + if (currencyCode.Length != 3) + { + throw new Exception("Invalid currency code '" + currencyCode +"'"); + } + + if (periodEnd <= periodStart) + { + throw new Exception("Invalid date period."); + } + + if (checkOverride == false && (periodEnd - periodStart).Days > 31) + { + throw new Exception("Date period is greater than 31 days."); + } + + // retirve previous data + DateTime? periodEndLast = null; + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Max(tblAccountExchangeRate.EndDate) AS MaxOfEndDate + FROM tblAccountExchangeRate + WHERE (((tblAccountExchangeRate.CurrencyCode) = @currencyCode)) + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + + object obj = cmd.ExecuteScalar(); + + // currency code not existing + if (obj == DBNull.Value && checkOverride == false) + { + throw new Exception("Currency code '" + currencyCode + "' does not exist in table"); + } + // currency code exists + else + { + periodEndLast = DateTime.SpecifyKind(Convert.ToDateTime(obj), DateTimeKind.Utc); + + if (periodStart != periodEndLast) + { + throw new Exception("Invalid period start date -- must equal previous period end-date."); + } + } + } + + // retrive previous exchange rate and check + decimal currencyUnitsPerGbpLast = 0; + if (periodEndLast != null) + { + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblAccountExchangeRate.AccountExchangeRateID, tblAccountExchangeRate.CurrencyUnitsPerGBP + FROM tblAccountExchangeRate + WHERE (tblAccountExchangeRate.EndDate = @periodEndLast) + AND (CurrencyCode = @currencyCode); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@periodEndLast", periodEndLast); + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + currencyUnitsPerGbpLast = reader.GetDecimal(1); + } + else + { + throw new Exception("Error that shouldn't happen! Check code @ 5129f3e6-2f7e-4883-bc73-b317d8fa4050"); + } + // error if >1 line + if (reader.Read()) + { + string errText = "Multiple lines in currency exchange table for '" + currencyCode + "' where [EndDate]=" + periodEndLast.ToString(); + MiscFunction.EventLogInsert(errText, 1); + throw new Exception(errText); + } + } + } + } + + // check difference between current and previous exchange rates isn't too great + if (checkOverride == false && + (currencyUnitsPerGbpLast > (currencyUnitsPerGbp * 1.05m) || currencyUnitsPerGbpLast < (currencyUnitsPerGbp * 0.95m)) + ) + { + throw new Exception("Difference between supplied and previous exchange rates is greater than 5%"); + } + + // MAKE THE INSERT + int recordId = 0; + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAccountExchangeRate (ExchangeRateSource, CurrencyCode, CurrencyUnitsPerGBP, StartDate, EndDate) + OUTPUT INSERTED.AccountExchangeRateID + VALUES (@exchangeRateSource, @currencyCode, @currencyUnitsPerGbp, @periodStart, @periodEnd); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@exchangeRateSource", exchangeRateSource); + cmd.Parameters.AddWithValue("@currencyCode", currencyCode); + cmd.Parameters.AddWithValue("@currencyUnitsPerGbp", currencyUnitsPerGbp); + cmd.Parameters.AddWithValue("@periodStart", periodStart); + cmd.Parameters.AddWithValue("@periodEnd", periodEnd); + + recordId = (int)cmd.ExecuteScalar(); + + if (recordId < 1) + { + throw new Exception("Error inserting record, did not retrive new record ID."); + } + } + + return recordId; + } + } + + public static int WIP_GetAccountTransactionTypeId(string sqlConnectionString, string matchString, bool onNewReturnId = false, bool onNewDisableInsert = false) + { + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + + if (matchString.Length == 0) + { + throw new Exception("matchstring is of zero lenth"); + } + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT AccountTransactionTypeID, IsNewReviewRequired, TransactionImportEnabled FROM tblAccountTransactionType WHERE MatchString=@matchString;" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@matchString", matchString); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + int index01 = reader.GetOrdinal("AccountTransactionTypeID"); + int index02 = reader.GetOrdinal("IsNewReviewRequired"); + int index03 = reader.GetOrdinal("TransactionImportEnabled"); + + int transactionTypeId = reader.GetInt32(index01); + bool isNew = reader.GetBoolean(index02); + bool? importEnabled = reader.GetBoolean(index03); + + if (isNew == true || importEnabled == null) + { + // return null and 'skip' item + return 0; + } + else if (importEnabled == false) + { + // mark IsProcessed=true and leave transactionId=null + return -1; + } + else if (transactionTypeId > 0) + { + return transactionTypeId; + } + else + { + throw new Exception("Account TransactionTypeId lookup method went wrong, is one of the 'enabled' boolean on table set to null?"); + } + } + else if (onNewDisableInsert == false) + { + // insert new and retrive new value + using (SqlConnection scopeConn = new SqlConnection(sqlConnectionString)) + using (TransactionScope scopeSupress = new TransactionScope(TransactionScopeOption.Suppress)) + { + scopeConn.Open(); + + using (SqlCommand insertCmd = new SqlCommand(@" + INSERT INTO tblAccountTransactionType ( MatchString ) + OUTPUT INSERTED.AccountTransactionTypeID + VALUES ( @matchString ); + ", scopeConn)) + { + insertCmd.Parameters.AddWithValue("@matchString", matchString); + int transactionTypeId = (int)insertCmd.ExecuteScalar(); + scopeSupress.Complete(); + + if (onNewReturnId == true) + { + return transactionTypeId; + } + else + { + return 0; + } + } + } + } + else + { + return 0; + } + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + // function returns tuple with debit and credit Id or 0,0 if none present + public static (int debitId, int creditId) WIP_GetAccountTransactionTypeDebitIdCreditId(string sqlConnectionString, int accountTransactionTypeId) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblAccountTransactionTypeGroup.DebitAccountChartOfID, + tblAccountTransactionTypeGroup.CreditAccountChartOfID + FROM + tblAccountTransactionType + INNER JOIN tblAccountTransactionTypeGroup + ON tblAccountTransactionType.AccountTransactionTypeGroupID = tblAccountTransactionTypeGroup.AccountTransactionTypeGroupID + WHERE (((tblAccountTransactionType.AccountTransactionTypeID)=@accountTransactionTypeId)); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@accountTransactionTypeId", accountTransactionTypeId); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + (int debitId, int creditId) returnTuple; + + if (reader.Read()) + { + + returnTuple.debitId = reader.GetInt32(0); + returnTuple.creditId = reader.GetInt32(1); + + return returnTuple; + } + else + { + returnTuple.debitId = 0; + returnTuple.creditId = 0; + + return returnTuple; + } + } + } + } + } + + public static int AccountTransactionInsert(string sqlConnectionString, DateTime transactionUtcDate, int transactionTypeId, + string currencyCode, decimal amount, int foreignKey = 0, string reference = "", string detail = "", + int accountJournalId = 0, bool isProcessed = false, int stockId = 0) + { + transactionUtcDate = DateTime.SpecifyKind(transactionUtcDate, DateTimeKind.Utc); + + // checks + if (currencyCode.Length != 3) + { + if (currencyCode.Length == 0) + { + MiscFunction.EventLogInsert("No CurrencyCode string passed to InsertAccountTransaction(), item insert skipped.", 1); + } + else + { + MiscFunction.EventLogInsert("CurrencyCode '" + currencyCode + "' passed to InsertAccountTransaction() is incorrect length, item insert skipped.", 1); + } + return -1; + } + + // onto business.... + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblAccountTransaction ( TransactionDate, AccountTransactionTypeID, CurrencyCode, Amount, ForeignKey, Reference, Detail, AccountJournalID, IsProcessed, StockID ) " + + "OUTPUT INSERTED.AccountTransactionID " + + "VALUES (@transactionDate, @transactionTypeId, @currencyCode, @amount, @foreignKey, @reference, @detail, @AccountJournalId, @isProcessed, @stockId);", + sqlConn)) + { + cmd.Parameters.AddWithValue("@transactionDate", transactionUtcDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); + cmd.Parameters.AddWithValue("@currencyCode", currencyCode.ToUpper()); + cmd.Parameters.AddWithValue("@amount", amount); + if (foreignKey == 0) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@foreignKey", foreignKey); } + if (reference == "") { cmd.Parameters.AddWithValue("@reference", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reference", reference); } + if (detail == "") { cmd.Parameters.AddWithValue("@detail", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@detail", detail); } + if (accountJournalId == 0) { cmd.Parameters.AddWithValue("@AccountJournalId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@AccountJournalId", accountJournalId); } + cmd.Parameters.AddWithValue("@isProcessed", isProcessed); + if (stockId < 1) { cmd.Parameters.AddWithValue("@stockId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@stockId", stockId); } + + int transactionId = Convert.ToInt32(cmd.ExecuteScalar()); + return transactionId; + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + // return 0 if no journal id is attached + public static int AccountTransactionGetJournalId(string sqlConnectionString, int transactionId) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT + AccountJournalID + FROM + tblAccountTransaction + WHERE + AccountTransactionID=@transactionId + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@transactionId", transactionId); + + object obj = cmd.ExecuteScalar(); + if (obj == null) + { + throw new Exception("AccountTransactionID=" + transactionId + " does not exist in tblAccountTransaction."); + } + else if (obj == DBNull.Value) + { + return 0; + } + else + { + return (int)obj; + } + } + } + } + + public static bool AccountJournalEntryIsLocked(string sqlConnectionString, int journalId) + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblAccountJournal.IsLocked + FROM + tblAccountJournal + WHERE + tblAccountJournal.AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", journalId); + + object obj = cmd.ExecuteScalar(); + if (obj == null) + { + throw new Exception("Journal entry not found for AccountJournalID=" + journalId); + } + else + { + return (bool)obj; + } + } + } + } + + // returns total of debits + public static decimal WIP_AccountJournalDebitBalance(string sqlConnectionString, int accountJournalId) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT + Sum(tblAccountJournalPost.AmountGbp) AS SumOfAmountGbp + FROM + tblAccountJournalPost + WHERE + (((tblAccountJournalPost.AccountJournalID)=@AccountJournalId) + AND ((tblAccountJournalPost.AmountGbp)>=0)); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@AccountJournalId", accountJournalId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("No records found for AccountJournalID=" + accountJournalId); + } + + return (decimal)obj; + } + } + } + + public static int DEPRECIATED_AccountJournalInsert(string sqlConnectionString, int journalTypeId, List<(int accountId, decimal Amount)> journalPosts, + DateTime entryDate, string currencyCode) + { + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + //disable split transactions + if (journalPosts.Count > 2) + { + throw new Exception("Split transactions not supported."); + } + + // checks + + // number of posts + if (journalPosts.Count < 2) + { + // list not long enough + throw new Exception("Method requires an minumum of two posts in any one journal entry."); + } + + // equal debits to credits + if (journalPosts.Sum(item => item.Amount) != 0) + { + // credits and debits do not match + throw new Exception("Sum of debits and credits do not match."); + } + + // convert currency, if required + if (currencyCode != "GBP") + { + List<(int accountId, decimal Amount)> tempList = new List<(int accountId, decimal Amount)>(); + + foreach ((int accountId, decimal Amount) item in journalPosts) + { + (int accountId, decimal Amount) tempTuple; + + tempTuple.accountId = item.accountId; + tempTuple.Amount = Math.Round(Account.AccountQuery.CurrencyConvertToGbp(sqlConnectionString, currencyCode, item.Amount, entryDate), 2); + + tempList.Add(tempTuple); + } + journalPosts.Clear(); + journalPosts = new List<(int accountId, decimal Amount)>(tempList); + tempList.Clear(); + + // check and, if required, correct for rounding differences + decimal diff = journalPosts.Sum(item => item.Amount); + if (diff != 0) + { + // get largest amount to apply difference to (wether + or -) + decimal maxDebit = journalPosts.Where(item => item.Amount >= 0).Max(item => item.Amount); + decimal maxCredit = journalPosts.Where(item => item.Amount <= 0).Min(item => item.Amount); + + decimal maxValue = maxCredit; + if (maxDebit > (maxCredit * -1)) + { + maxValue = maxDebit; + } + + // rebuild the post list with difference +/- from the max debit/credit value + bool valueUpdated = false; + foreach ((int accountId, decimal Amount) item in journalPosts) + { + (int accountId, decimal Amount) tempTuple; + + tempTuple.accountId = item.accountId; + + if (valueUpdated == false && maxValue == item.Amount) + { + tempTuple.Amount = item.Amount - diff; + valueUpdated = true; + } + else + { + tempTuple.Amount = item.Amount; + } + + tempList.Add(tempTuple); + } + journalPosts.Clear(); + journalPosts = new List<(int accountId, decimal Amount)>(tempList); + tempList.Clear(); + } + } + + // last fail-safe check before database insert + if (journalPosts.Sum(item => item.Amount) != 0) + { + // credits and debits do not match + throw new Exception("Sum of debits and credits do not match (after attempting to convert currency)."); + } + + //write entry to database + int accountJournalId = new int(); + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand sqlCommand = new SqlCommand( + "INSERT INTO tblAccountJournal ( EntryDate ) " + + "OUTPUT INSERTED.AccountJournalID " + + "VALUES ( @EntryDate );" + , sqlConn)) + { + // add parameters + sqlCommand.Parameters.AddWithValue("@EntryDate", entryDate.ToUniversalTime()); + + //execute + accountJournalId = (int)sqlCommand.ExecuteScalar(); + } + + // insert journal posts into database + foreach (var post in journalPosts) + { + using (SqlCommand sqlCommand = new SqlCommand( + "INSERT INTO tblAccountJournalPost ( AccountJournalID, AccountChartOfID, AmountGbp ) " + + "VALUES ( @AccountJournalID, @AccountChartOfID, @AmountGbp );" + , sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@AccountJournalID", accountJournalId); + sqlCommand.Parameters.AddWithValue("@AccountChartOfID", post.accountId); + sqlCommand.Parameters.AddWithValue("@AmountGbp", post.Amount); + + // execute + sqlCommand.ExecuteNonQuery(); + } + } + } + //commit the transaction + scope.Complete(); + } + return accountJournalId; + } + + public static int AccountJournalInsert(string sqlConnectionString, int journalTypeId, DateTime entryDate, string currencyCode, + decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false) + { + int defaultDebit = 0; + int defaultCredit = 0; + + // ensure date is UTC + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + // debit and credit locks are checked in journal post method + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // insert the journal entry + int journalId; + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAccountJournal + (AccountJournalTypeID, EntryDate, IsLocked) + OUTPUT INSERTED.AccountJournalID + VALUES + (@journalTypeId, @entryDate, @lockEntry) + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId); + cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@lockEntry", lockEntry); + + //execute + journalId = (int)cmd.ExecuteScalar(); + } + + // insert journal entries + bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId); + + scope.Complete(); + return journalId; + } + } + + // return false on locked journal entry + public static bool AccountJournalDelete(string sqlConnectionString, int accountJournalId) + { + // check if journal entry is locked + using (TransactionScope scope = new TransactionScope()) + { + bool IsLocked = Account.AccountQuery.AccountJournalEntryIsLocked(sqlConnectionString, accountJournalId); + if (IsLocked == true) + { + return false; + } + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // make the delete + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblAccountJournalPost + WHERE AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + int rows = cmd.ExecuteNonQuery(); + + if (rows == 0) + { + throw new Exception("Journal entry and/or entry posts do not exist for AccountJournalId=" + accountJournalId); + } + } + + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblAccountJournal + WHERE AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + cmd.ExecuteNonQuery(); + } + + scope.Complete(); + return true; + } + } + } + + private static bool AccountJournalPostInsert(string sqlConnectionString, int journalId, DateTime entryDate, + string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0) + { + int defaultDebit; + int defaultCredit; + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // ensure their are no other entries + using (SqlCommand cmd = new SqlCommand(@" + SELECT + Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID + FROM + tblAccountJournalPost + WHERE + (((tblAccountJournalPost.AccountJournalID)=@AccountJournalID)); + ", conn)) + { + cmd.Parameters.AddWithValue("@AccountJournalID", journalId); + + int count = (int)cmd.ExecuteScalar(); + + if (count > 0) + { + throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId); + } + } + + //checks + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit + FROM + tblAccountJournal + INNER JOIN tblAccountJournalType + ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID + WHERE + (((tblAccountJournal.AccountJournalID)=@journalId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@journalId", journalId); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + // debit check + if (reader.IsDBNull(0)) + { + if (debitAccountId == 0) + { + throw new Exception("Debit Account ID required, default not set for journal type"); + } + } + else + { + defaultDebit = reader.GetInt32(0); + if (debitAccountId == 0) + { + debitAccountId = defaultDebit; + } + else if (debitAccountId != defaultDebit) + { + throw new Exception("Debit Account ID supplied does not match default set for journal type"); + } + + } + // credit check + if (reader.IsDBNull(1)) + { + if (creditAccountId == 0) + { + throw new Exception("Credit Account ID required, default not set for journal type"); + } + } + else + { + defaultCredit = reader.GetInt32(1); + if (creditAccountId == 0) + { + creditAccountId = defaultCredit; + } + else if (creditAccountId != defaultCredit) + { + throw new Exception("Credit Account ID supplied does not match default set for journal type"); + } + } + } + else + { + throw new Exception("AccountJournalID '" + journalId + "' does not exist."); + } + } + } + + // currency conversion + if (currencyCode != "GBP") + { + amount = bnhtradeDatabaseClient.Account.AccountQuery.CurrencyConvertToGbp(sqlConnectionString, currencyCode, amount, entryDate); + } + + // ensure decimal is rounded + amount = Math.Round(amount, 2); + + // insert debit post + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAccountJournalPost + (AccountJournalID, AccountChartOfID, AmountGbp) + VALUES + (@AccountJournalId, @AccountChartOfId, @AmountGbp) + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@AccountJournalId", journalId); + cmd.Parameters.AddWithValue("@AccountChartOfId", debitAccountId); + cmd.Parameters.AddWithValue("@AmountGbp", amount); + + cmd.ExecuteNonQuery(); + } + + // insert credit post + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAccountJournalPost + (AccountJournalID, AccountChartOfID, AmountGbp) + VALUES + (@AccountJournalId, @AccountChartOfId, @AmountGbp) + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@AccountJournalId", journalId); + cmd.Parameters.AddWithValue("@AccountChartOfId", creditAccountId); + cmd.Parameters.AddWithValue("@AmountGbp", (amount * -1)); + + cmd.ExecuteNonQuery(); + } + + scope.Complete(); + return true; + } + } + + public static bool AccountJournalPostUpdate(string sqlConnectionString, int journalId, string currencyCode, decimal amount, + int debitAccountId = 0, int creditAccountId = 0) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // retrive journal entry date + DateTime entryDate; + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblAccountJournal.EntryDate + FROM + tblAccountJournal + WHERE + (((tblAccountJournal.AccountJournalID)=@accountJournalId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", journalId); + + entryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc); + } + + // delete the original posts + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM + tblAccountJournalPost + WHERE + (((tblAccountJournalPost.AccountJournalID)=@accountJournalId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", journalId); + + cmd.ExecuteNonQuery(); + } + + //insert new posts + bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId); + + // update modified date on journal + using (SqlCommand cmd = new SqlCommand(@" + UPDATE + tblAccountJournal + SET + tblAccountJournal.LastModified=@utcNow + WHERE + (((tblAccountJournal.AccountJournalID)=@accountJournalId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", journalId); + cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow); + + cmd.ExecuteNonQuery(); + } + + scope.Complete(); + } + return true; + } + } + } + + namespace Product + { + public class ProductQuery + { + public static void ProductUpdateAmazonEstimateFee(string sqlConnectionString, List<(string asin, decimal PriceToEstimate)> inputList) + { + // add product id to list + List<(string asin, string productRef, decimal PriceToEstimate)> outputList = new List<(string asin, string productRef, decimal PriceToEstimate)>(); + foreach ((string asin, decimal PriceToEstimate) item in inputList) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT prdProductID FROM tblProduct WHERE prdAmazonAsin=@asin + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@asin", item.asin); + + object obj = sqlCommand.ExecuteScalar(); + if (!(obj == null)) + { + int productId = (int)sqlCommand.ExecuteScalar(); + (string asin, string productRef, decimal PriceToEstimate) tempTuple = (item.asin, productId.ToString(), item.PriceToEstimate); + outputList.Add(tempTuple); + } + else + { + (string asin, string productRef, decimal PriceToEstimate) tempTuple = (item.asin, "0", item.PriceToEstimate); + outputList.Add(tempTuple); + } + } + } + } + + // request info from MWS and import + int i = 0; + int count = 0; + int total = inputList.Count; + FeesEstimateRequestList requestList = new FeesEstimateRequestList(); + + foreach (var item in outputList) + { + i++; + count++; + + // build and (after 20 iterations) send the mws request + if (i == 1 && count != 1) + { + requestList = new FeesEstimateRequestList(); + } + requestList.FeesEstimateRequest.Add(new FeesEstimateRequest + { + MarketplaceId = "A1F83G8C2ARO7P", // .co.uk + IdType = "ASIN", + IdValue = item.asin, + PriceToEstimateFees = new PriceToEstimateFees + { + ListingPrice = new MoneyType { Amount = item.PriceToEstimate, CurrencyCode = "GBP" }, + //Shipping = new MoneyType { Amount = 0M, CurrencyCode = "GBP" }, + //Points = new Points { PointsNumber = 0 } + }, + Identifier = item.productRef, + IsAmazonFulfilled = true + }); + + // request data and import into database + if (i == 20 || count == total) + { + AmazonMwsProduct mws = new AmazonMwsProduct(); + List returnList = mws.WIP_GetProductEstimateFee(requestList); + foreach (FeesEstimateResult returnItem in returnList) + { + // get me values + string asin = returnItem.FeesEstimateIdentifier.IdValue; + int productId = int.Parse(returnItem.FeesEstimateIdentifier.SellerInputIdentifier); + //int productId; + //try + //{ productId = int.Parse(returnItem.FeesEstimateIdentifier.SellerInputIdentifier); } + //catch + //{ throw new Exception("Could not parse the return ProductID string '" + returnItem.FeesEstimateIdentifier.SellerInputIdentifier + "'"); } + + // test for error + if (returnItem.Error != null) + { + var sb = new StringBuilder(); + sb.AppendLine("ASIN: " + asin); + sb.AppendLine("Error Code: " + returnItem.Error.Code); + if (returnItem.Error.Detail != null) + { sb.AppendLine("Detail: " + returnItem.Error.Detail); } + if (returnItem.Error.Message != null) + { sb.AppendLine("Message: " + returnItem.Error.Message); } + if (returnItem.Error.Type != null) + { sb.AppendLine("Type: " + returnItem.Error.Type); } + + MiscFunction.EventLogInsert("Error running GetProductEstimateFee for ASIN:" + asin + ", further details attached.", 1, sb.ToString()); + + continue; + } + + bool isAmazonFulfilled = returnItem.FeesEstimateIdentifier.IsAmazonFulfilled; + DateTime timeOfFeeEstimation = returnItem.FeesEstimate.TimeOfFeesEstimation; + decimal totalFeeEstimate = returnItem.FeesEstimate.TotalFeesEstimate.Amount; + string currencyCode = returnItem.FeesEstimate.TotalFeesEstimate.CurrencyCode; + decimal priceToEstimateFeeListingPrice = returnItem.FeesEstimateIdentifier.PriceToEstimateFees.ListingPrice.Amount; + decimal priceToEstimateFeeShipping = 0; + if (returnItem.FeesEstimateIdentifier.PriceToEstimateFees.Shipping != null) + { priceToEstimateFeeShipping = returnItem.FeesEstimateIdentifier.PriceToEstimateFees.Shipping.Amount; } + decimal priceToEstimateFeePoints = 0; + if (returnItem.FeesEstimateIdentifier.PriceToEstimateFees.Points != null) + { priceToEstimateFeePoints = returnItem.FeesEstimateIdentifier.PriceToEstimateFees.Points.PointsMonetaryValue.Amount; } + + decimal referralFee = 0m; + decimal variableClosingFee = 0m; + decimal fulfillmentFees = 0m; + decimal perItemFee = 0m; + decimal otherFee_Exception = 0m; + + FeeDetailList feeDetailList = returnItem.FeesEstimate.FeeDetailList; + List feeDetail = feeDetailList.FeeDetail; + foreach (FeeDetail feeDetailItem in feeDetail) + { + if (feeDetailItem.FeeType == "AmazonReferralFee" || feeDetailItem.FeeType == "ReferralFee") + { referralFee = feeDetailItem.FinalFee.Amount; } + else if (feeDetailItem.FeeType == "VariableClosingFee") + { variableClosingFee = feeDetailItem.FinalFee.Amount; } + else if (feeDetailItem.FeeType == "PerItemFee") + { perItemFee = feeDetailItem.FinalFee.Amount; } + else if (feeDetailItem.FeeType == "FBAFees" || feeDetailItem.FeeType == "FulfillmentFees") + { fulfillmentFees = feeDetailItem.FinalFee.Amount; } + else + { otherFee_Exception = otherFee_Exception + feeDetailItem.FinalFee.Amount; } + + } + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand sqlCommand = new SqlCommand(@" + UPDATE tblAmazonFeeEstimate SET + ProductIdentifier=@productIdentifier, IsAmazonFulfilled=@isAmazonFulfilled, TimeOfFeeEstimation=@timeOfFeeEstimation, + TotalFeeEstimate=@totalFeeEstimate, PriceToEstimateFeeListingPrice=@priceToEstimateFeeListingPrice, + PriceToEstimateFeeShipping=@priceToEstimateFeeShipping, PriceToEstimateFeePoints=@priceToEstimateFeePoints, + ReferralFee=@referralFee, VariableClosingFee=@variableClosingFee, PerItemFee=@perItemFee, FBAFee=@fbaFee, + OtherFee_Exception=@otherFee_Exception, currencyCode=CurrencyCode + WHERE AmazonASIN=@asin + IF @@ROWCOUNT = 0 + INSERT INTO tblAmazonFeeEstimate ( AmazonASIN, + ProductIdentifier, IsAmazonFulfilled, TimeOfFeeEstimation, TotalFeeEstimate, PriceToEstimateFeeListingPrice, + PriceToEstimateFeeShipping, PriceToEstimateFeePoints, ReferralFee, VariableClosingFee, PerItemFee, FBAFee, + OtherFee_Exception, CurrencyCode + ) VALUES ( @asin, + @productIdentifier, @isAmazonFulfilled, @timeOfFeeEstimation, @totalFeeEstimate, @priceToEstimateFeeListingPrice, + @priceToEstimateFeeShipping, @priceToEstimateFeePoints, @referralFee, @variableClosingFee, @perItemFee, @fbaFee, + @otherFee_Exception, @currencyCode + ) + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@asin", asin); + sqlCommand.Parameters.AddWithValue("@productIdentifier", productId); + sqlCommand.Parameters.AddWithValue("@isAmazonFulfilled", isAmazonFulfilled); + sqlCommand.Parameters.AddWithValue("@timeOfFeeEstimation", timeOfFeeEstimation); + sqlCommand.Parameters.AddWithValue("@totalFeeEstimate", totalFeeEstimate); + sqlCommand.Parameters.AddWithValue("@priceToEstimateFeeListingPrice", priceToEstimateFeeListingPrice); + sqlCommand.Parameters.AddWithValue("@priceToEstimateFeeShipping", priceToEstimateFeeShipping); + sqlCommand.Parameters.AddWithValue("@priceToEstimateFeePoints", priceToEstimateFeePoints); + sqlCommand.Parameters.AddWithValue("@referralFee", referralFee); + sqlCommand.Parameters.AddWithValue("@variableClosingFee", variableClosingFee); + sqlCommand.Parameters.AddWithValue("@perItemFee", perItemFee); + sqlCommand.Parameters.AddWithValue("@fbaFee", fulfillmentFees); + sqlCommand.Parameters.AddWithValue("@otherFee_Exception", otherFee_Exception); + sqlCommand.Parameters.AddWithValue("@currencyCode", currencyCode); + + sqlCommand.ExecuteNonQuery(); + } + } + } + i = 0; + } + + } + } + + public int? ProductGetProductIdByCatId(string sqlConnectionString, int catId) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "SELECT prdProductID " + + "FROM tblProduct " + + "WHERE CatId=@catId" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@catId", catId); + + object result = cmd.ExecuteScalar(); + if (result != null) + { + return Convert.ToInt32(result); + } + else + { + return null; + } + } + } + } + + public (decimal? price, DateTime? priceDate) ProductCompetitivePriceGet(string sqlConnectionString, int productId, int conditionId) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "SELECT t.CompetitivePrice, t.PriceDate " + + "FROM tblProductPriceCompetitive AS t INNER JOIN (SELECT ProductID, Max(PriceDate) AS MaxOfPriceDate " + + "FROM tblProductPriceCompetitive " + + "WHERE ProductID=" + productId + " AND SkuConditionID=" + conditionId + + "GROUP BY ProductID) AS a ON (t.PriceDate = a.MaxOfPriceDate) AND (t.ProductID = a.ProductID)" + , sqlConn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + DateTime dt = reader.GetDateTime(1); + dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); + return (reader.GetDecimal(0), dt); + } + else + { + return (null, null); + } + } + } + } + } + + public int ProductCompetitivePriceSet(string sqlConnectionString, int productId, int conditionId, decimal price, bool isBuyBoxPrice, DateTime? priceDate = null) + { + if (priceDate == null) + { + priceDate = DateTime.UtcNow; + } + DateTime dt = DateTime.SpecifyKind(priceDate.Value, DateTimeKind.Utc); + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblProductPriceCompetitive (ProductID, SkuConditionID, CompetitivePrice, PriceDate, IsBuyBoxPrice) " + + "OUTPUT INSERTED.ProductPriceCompetitiveID " + + "VALUES (@productId, @conditionId, @price, @priceDate, @isBuyBoxPrice)" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@price", price); + cmd.Parameters.AddWithValue("@priceDate", dt.ToUniversalTime()); + cmd.Parameters.AddWithValue("@isBuyBoxPrice", isBuyBoxPrice); + + return (int)cmd.ExecuteScalar(); + } + } + } + catch (Exception e) + { + throw e; + } + } + + public int testing(string sqlConnectionString) + { + int id = 0; + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand sqlCommand = new SqlCommand( + "SELECT skuSkuID " + + "FROM tblSku " + + "WHERE skuSkuNumber='006449-10'" + , sqlConn)) + { + //execute sql + id = (int)sqlCommand.ExecuteScalar(); + } + } + return id; + } + } + } + namespace Stock + { + public class StockCreate + { + private static int WIP_StockInsert(string sqlConnectionString, int accountJournalType, int stockJournalType, string currencyCode, decimal amount, + int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // add account journal entry + int accountJournalId = Account.AccountQuery.AccountJournalInsert(sqlConnectionString, accountJournalType, entryDate, currencyCode, amount); + + // make the stock insert + int stockId = StockCreate.WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId, + accountJournalId, stockJournalType, entryDate, quantity, debitStatusId); + + scope.Complete(); + return stockId; + } + } + + private static int WIP_StockInsertSub(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, + int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId) + { + stockJournalEntryDate = DateTime.SpecifyKind(stockJournalEntryDate, DateTimeKind.Utc); + + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // ensure account journal id hasn't already been added to stock table + int count = 0; + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Count(tblStock.StockID) AS CountOfID + FROM tblStock + WHERE (((tblStock.AccountJournalID)=@accountJouranlId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJouranlId", accountJournalId); + + count = (int)cmd.ExecuteScalar(); + } + + if (count == 1) + { + throw new Exception("Add account journal entry already assigned to stock line."); + } + else if (count > 1) + { + throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines."); + } + + // ensure the debit for the account journal transaction is to an 'Asset' account type + using (SqlCommand cmd = new SqlCommand(@" + SELECT + Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID + FROM + (tblAccountJournalPost + INNER JOIN tblAccountChartOf + ON tblAccountJournalPost.AccountChartOfID = tblAccountChartOf.AccountChartOfID) + INNER JOIN tblAccountChartOfType + ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID + WHERE + tblAccountJournalPost.AmountGbp>=0 + AND tblAccountChartOfType.BasicType='Asset' + AND tblAccountJournalPost.AccountJournalID=@accountJournalId; + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + if ((int)cmd.ExecuteScalar() < 1) + { + throw new Exception("Supplied AccountJournal entry must debit an 'Asset' account type."); + } + } + + // get statusCreditId for stock journal type + int statusCreditId; + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblStockJournalType.StockStatusID_Credit + FROM + tblStockJournalType + WHERE + tblStockJournalType.StockJournalTypeID=@stockJournalTypeId + AND tblStockJournalType.StockStatusID_Credit Is Not Null; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("Default credit status not set for StockJournalTypeID=" + stockJournalTypeId); + } + else + { + statusCreditId = (int)obj; + } + } + + // get/set an skuId + int skuId = bnhtradeDatabaseClient.Sku.SkuQuery.WIP_SkuGetSet(sqlConnectionString, productId, conditionId, accountTaxCodeId, true); + + // add the entry to the stock table (minus stockJournalId) + int stockId = 0; + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblStock + (SkuID, AccountJournalID) + OUTPUT INSERTED.StockID + VALUES + (@skuId, @accountJournalId); + ", conn)) + { + cmd.Parameters.AddWithValue("@skuId", skuId); + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + stockId = (int)cmd.ExecuteScalar(); + } + + // insert stock journal entry + var journalPosts = new List<(int statusId, int quantity)>(); + journalPosts.Add((statusDebitId, quantity)); + journalPosts.Add((statusCreditId, (quantity * -1))); + int stockJournalId = Stock.StockJournal.StockJournalInsert(sqlConnectionString, stockJournalTypeId, stockId, journalPosts, stockJournalEntryDate, true); + + // update the stock table + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblStock + SET StockJournalID=@stockJournalId + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId); + cmd.Parameters.AddWithValue("@stockId", stockId); + + count = cmd.ExecuteNonQuery(); + + if (count < 1) + { + throw new Exception("New stock insert cancelled, failed to update StockJournalID"); + } + } + + scope.Complete(); + return stockId; + } + } + + private static void WIP_StockDelete(string sqlConnectionString, int stockId) + { + int accountJournalType = 0; + int stockJournalType = 0; + + // get stock and account types + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // ensure stockId is owner-introduced + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblStockJournal.StockJournalTypeID, tblAccountJournal.AccountJournalTypeID + FROM + (tblStock INNER JOIN tblAccountJournal + ON tblStock.AccountJournalID = tblAccountJournal.AccountJournalID) + INNER JOIN tblStockJournal + ON tblStock.StockJournalID = tblStockJournal.StockJournalID + WHERE + (((tblStock.StockID)=@stockId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + accountJournalType = reader.GetInt32(1); + stockJournalType = reader.GetInt32(0); + } + else + { + throw new Exception("Integrity check failed, cancelling StockDeleteOwnerIntroduced"); + } + } + } + + // check stock journal type is not restricted + // owner inventory introduced + if (stockJournalType == 2) + { + // no dramas + } + else + { + throw new Exception("Manual delete of this stock type is not supported, use the moethod that created it!"); + } + + // check there is only one stock journal entry for stock item + using (SqlCommand cmd = new SqlCommand(@" + SELECT Count(tblStockJournal.StockJournalID) AS CountOfStockJournalID + FROM tblStockJournal + WHERE (((tblStockJournal.StockID)=@stockId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + int count = (int)cmd.ExecuteScalar(); + + if (count > 1) + { + throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation."); + } + } + + // remove account journal entry + Stock.StockCreate.WIP_StockDeleteSubAccountJournalEntry(sqlConnectionString, stockId); + + // remove stock + Stock.StockCreate.WIP_StockDeleteSub(sqlConnectionString, stockId); + + scope.Complete(); + } + } + + + + private static void WIP_StockDeleteSub(string sqlConnectionString, int stockId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // check for accountJournalId on stock table + using (SqlCommand cmd = new SqlCommand(@" + SELECT AccountJournalID + FROM tblStock + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("StockID=" + stockId + " does not exist."); + } + else if (obj == DBNull.Value) + { + // nothing to do all is good + } + else + { + int id = (int)obj; + if (id > 0) + { + throw new Exception("StockID=" + stockId + " remove account journal entry using method that created it first."); + } + } + } + + // get stockJournalId + int stockJournalId; + using (SqlCommand cmd = new SqlCommand(@" + SELECT StockJournalID + FROM tblStock + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + try + { + stockJournalId = (int)cmd.ExecuteScalar(); + } + catch + { + throw new Exception("Could not retrive StockJournalID for StockID=" + stockId); + } + } + + // remove stockJournalId from stock table + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblStock + SET StockJournalID=NULL + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 2) // we need to count the LastUpdated trigger! + { + throw new Exception("Failed to remove StockJournalID from stock table StockID=" + stockId); + } + } + + // delete stock journal entry + Stock.StockJournal.StockJournalDelete(sqlConnectionString, stockJournalId); + + // delete stock table entry + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblStock + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 1) + { + throw new Exception("StockID = " + stockId + " delete failed"); + } + else + { + scope.Complete(); + } + } + } + } + + // to be used by other methods within a transaction scope + private static void WIP_StockDeleteSubAccountJournalEntry(string sqlConnectionString, int stockId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // get the account journal id + int accountJournalId = 0; + using (SqlCommand cmd = new SqlCommand(@" + SELECT AccountJournalID + FROM tblStock + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("StockID=" + stockId + " does not exist."); + } + else if (obj == DBNull.Value) + { + throw new Exception("AccountJournalID not found for StockID=" + stockId); + } + else + { + accountJournalId = (int)obj; + } + } + + // remove entry from stock table + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblStock + SET AccountJournalID=NULL + WHERE StockID=@stockId; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 2) // must include last modified trigger + { + throw new Exception("Failed to set AccountJournalID to NULL on stock table for StockID=" + stockId); + } + } + + // delete account journal entry + Account.AccountQuery.AccountJournalDelete(sqlConnectionString, accountJournalId); + + scope.Complete(); + } + } + + public static int WIP_StockInsertPurchase(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId) + { + DateTime stockJournalEntryDate; + int stockJournalTypeId = 1; + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // retrive info from purchase invoice line/transaction + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblAccountJournal.EntryDate + FROM tblAccountJournal + WHERE (((tblAccountJournal.AccountJournalID)=@accountJournalId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId); + + stockJournalEntryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc); + } + } + + return WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId); + } + + public static int WIP_StockInsertOwnerIntroduced(string sqlConnectionString, decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) + { + int accountJournalType = 3; + int stockJournalType = 2; + string currencyCode = "GBP"; + + return WIP_StockInsert(sqlConnectionString, accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId); + } + + public static void WIP_StockDeletePurchase(string sqlConnectionString, int stockId) + { + WIP_StockDeleteSub(sqlConnectionString, stockId); + } + + public static void WIP_StockDeleteOwnerIntroduced(string sqlConnectionString, int stockId) + { + WIP_StockDelete(sqlConnectionString, stockId); + } + + } + + public class StockJournal + { + // only to be assessable via code, use stock relocate to move stock bewtween status' + public static int StockJournalInsert(string sqlConnectionString, int journalTypeId, int stockId, List<(int statusId, int quantity)> journalPosts, + DateTime entryDate, bool isNewStock = false) + { + // balance and status IsCredit checks made by post insert function + + // make entrydate utc + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + // create the journal entry + int stockJournalId; + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + //consitancy check is required? + bool consistencyRequired = true; + // get date of most recent debit for status' that I will be crediting + if (isNewStock == false) + { + // build sql string + string stringSql = @" + SELECT + tblStockJournal.EntryDate + FROM + tblStockJournal + INNER JOIN tblStockJournalPost + ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE + tblStockJournal.StockID=@stockId + AND EntryDate>=@entryDate + AND tblStockJournalPost.Quantity>0 + AND ("; + + bool firstDone = false; + foreach (var item in journalPosts) + { + if (item.quantity < 0) + { + if (firstDone) + { + stringSql = stringSql + " OR "; + } + stringSql = stringSql + "tblStockJournalPost.StockStatusID=" + item.statusId; + firstDone = true; + } + } + stringSql = stringSql + ");"; + + using (SqlCommand cmd = new SqlCommand(stringSql, conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime()); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + consistencyRequired = true; + } + else + { + consistencyRequired = false; + } + } + } + } + + // create journal entry + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblStockJournal ( EntryDate, StockJournalTypeID, StockID, IsLocked ) + OUTPUT INSERTED.StockJournalID + VALUES ( @EntryDate, @journalTypeId, @stockID, @isLocked ); + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@stockID", stockId); + cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId); + cmd.Parameters.AddWithValue("@EntryDate", entryDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@isLocked", isNewStock); + + //execute + stockJournalId = (int)cmd.ExecuteScalar(); + } + + // insert journal posts into database + bnhtradeDatabaseClient.Stock.StockJournal.StockJournalPostInsert(conn, stockId, stockJournalId, journalPosts, isNewStock); + + // consistency check + bool consistencyResult = true; + if (consistencyRequired) + { + // build list of effected status' + var statusIdEffected = new List(); + foreach (var item in journalPosts) + { + if (item.quantity < 0) + { + statusIdEffected.Add(item.statusId); + } + } + // run check + consistencyResult = Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnectionString, stockId, statusIdEffected); + } + + if (consistencyResult) + { + // commit + scope.Complete(); + return stockJournalId; + } + else + { + throw new Exception("Unable to insert stock journal entry, consistancy check failed."); + } + } + } + + public static void StockJournalDelete(string sqlConnectionString, int stockJournalId) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // get date for journal entry + DateTime entryDate; + int stockId; + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblStockJournal.EntryDate, StockID + FROM tblStockJournal + WHERE (((tblStockJournal.StockJournalID)=@stockJournalId)); + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + entryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc); + stockId = reader.GetInt32(1); + } + else + { + throw new Exception("StockJournalID=" + stockJournalId + " does not exist!"); + } + } + + } + + // is consistancy check required + bool consistancyCheck; + // build list of debits that are to be deleted + var debitList = new List(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblStockJournalPost.StockStatusID + FROM tblStockJournalPost + WHERE (((tblStockJournalPost.StockJournalID)=@stockJournalId) AND ((tblStockJournalPost.Quantity)>0)); + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + while (reader.Read()) + { + debitList.Add(reader.GetInt32(0)); + } + } + else + { + throw new Exception("StockJournalID=" + stockJournalId + " has no debits with quantity greater than zero!"); + } + } + } + + // check no credits for stockId & debit combination have been made since delete entry + string stringSql = @" + SELECT + tblStockJournal.EntryDate + FROM + tblStockJournal + INNER JOIN tblStockJournalPost + ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE + tblStockJournal.StockID=@stockId + AND tblStockJournalPost.Quantity<0 + AND EntryDate>=@entryDate + AND ("; + + bool firstDone = false; + foreach (var item in debitList) + { + if (firstDone) + { + stringSql = stringSql + " OR "; + } + stringSql = stringSql + "tblStockJournalPost.StockStatusID=" + item; + firstDone = true; + } + stringSql = stringSql + ");"; + + using (SqlCommand cmd = new SqlCommand(stringSql, conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime()); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + consistancyCheck = true; + } + else + { + consistancyCheck = false; + } + } + } + + // delete the posts + StockJournalPostDelete(conn, stockJournalId); + + // delete journal entry + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblStockJournal + WHERE StockJournalID=@stockJournalId; + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId); + + int count = cmd.ExecuteNonQuery(); + + if (count != 1) + { + throw new Exception("Failed to delete stock journal header."); + } + } + + // consistanct check + bool consistencyResult = true; + if (consistancyCheck) + { + // run check + consistencyResult = Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnectionString, stockId, debitList); + } + + if (consistencyResult) + { + // commit + scope.Complete(); + } + else + { + throw new Exception("Unable to delete stock journal entry, consistancy check failed."); + } + } + } + + + private static void StockJournalPostInsert(SqlConnection conn, int stockId, int stockJournalId, + List<(int statusId, int quantity)> journalPosts, bool isNewStock = false) + { + //checks + if (journalPosts.Count > 2) + { + // I have purposely made the code to accept split transaction incase of future requirements, however, db design is simpler this way. + throw new Exception("Stock journal does not currently support split transactions (greater than two posts)." + journalPosts.Count + " number posts attempted."); + } + else if (journalPosts.Count < 2) + { + // list not long enough + throw new Exception("Stock journal entry requires minium of two posts, entry of " + journalPosts.Count + " number posts attempted."); + } + + if (journalPosts.Sum(item => item.quantity) != 0) + { + // credits and debits do not match + throw new Exception("Sum of credits and debits do not resolve to zero."); + } + + // group credits and debits by status + var dicStatusQty = new Dictionary(); + foreach (var post in journalPosts) + { + if (dicStatusQty.ContainsKey(post.statusId) == false) + { + dicStatusQty.Add(post.statusId, post.quantity); + } + else + { + dicStatusQty[post.statusId] = dicStatusQty[post.statusId] + post.quantity; + } + } + + // get isCreditOnly for each status + var dicStatusIsCreditOnly = new Dictionary(); + foreach (var item in dicStatusQty) + { + using (SqlCommand cmd = new SqlCommand(@" + SELECT IsCreditOnly FROM tblStockStatus WHERE StockStatusID=@statusId; + ", conn)) + { + cmd.Parameters.AddWithValue("@statusId", item.Key); + + dicStatusIsCreditOnly.Add(item.Key, (bool)cmd.ExecuteScalar()); + } + } + + // check there is only one IsCreditOnly in list and it is allowed in this instance + int isCreditOnlyCount = 0; + foreach (var item in dicStatusIsCreditOnly) + { + if (item.Value) + { + isCreditOnlyCount = isCreditOnlyCount + 1; + } + } + if (isNewStock == false && isCreditOnlyCount > 0) + { + throw new Exception("Attempted credit or debit to 'Is Credit Only' status not allowed, in this instance."); + } + if (isNewStock == true && isCreditOnlyCount != 1) + { + throw new Exception("StockID=" + stockId + ", each stock line must have only have one IsCreditOnly=True status assigned to it."); + } + + // ensure debit (or zero credit) isn't made to credit only status + // need to do this check via original post list (i.e. journalPosts) + foreach (var post in journalPosts) + { + // debit check + if (post.quantity >= 0) + { + if (dicStatusIsCreditOnly[post.statusId] == true) + { + throw new Exception("Cannot make debit, or zero quantity credit, to credit only status. StatusID=" + post.statusId); + } + } + } + + // balance check for any credits (that are not isCreditOnly=true) + foreach (var item in dicStatusQty) + { + if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false) + { + int quantity = Stock.StockJournal.StockStatusBalanceByStockId(conn.ConnectionString, stockId, item.Key); + + if (quantity + item.Value < 0) + { + throw new Exception("Credit status balance check failed. Available balance " + quantity + ", attempted credit " + item.Value * -1 + "."); + } + } + } + + // get this far... + // insert journal posts into database + foreach (var post in journalPosts) + { + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblStockJournalPost ( StockJournalID, StockStatusID, Quantity ) + VALUES ( @StockJournalId, @stockStatudId, @quantity ); + ", conn)) + { + cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId); + cmd.Parameters.AddWithValue("@stockStatudId", post.statusId); + cmd.Parameters.AddWithValue("@quantity", post.quantity); + + // execute + cmd.ExecuteNonQuery(); + } + } + } + + private static void StockJournalPostDelete(SqlConnection conn, int stockJournalId) + { + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblStockJournalPost + WHERE StockJournalID=@stockJournalId + ", conn)) + { + cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId); + + // execute + cmd.ExecuteNonQuery(); + + // the calling method must compete any transaction-scope on the connection + } + } + + // can be used before commiting an sql insert, update or delete to the stock journal to ensure a status does not fall below 0 + // (unless the status is enabled to do so) + // set empty list or statusIdEffected to null to check entier stock entries for consistency + public static bool WIP_StockJournalConsistencyCheck(string sqlConnectionString, int stockId, List statusIdEffected = null) + { + if (statusIdEffected == null) + { + statusIdEffected = new List(); + } + + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // if no list supplied, build list of all used status' for stockId + if (statusIdEffected.Count == 0) + { + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblStockJournalPost.StockStatusID + FROM + tblStockJournal + INNER JOIN tblStockJournalPost + ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE + tblStockJournal.StockID=@stockId + GROUP BY + tblStockJournalPost.StockStatusID; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + while (reader.Read()) + { + statusIdEffected.Add(reader.GetInt32(0)); + } + } + else + { + throw new Exception("No stock journal entries exist for StockID=" + stockId); + } + } + } + } + + // build the sql string to build creditCreate bool + var dicStatusCreditOnly = new Dictionary(); + string sqlString = @" + SELECT + tblStockStatus.StockStatusID, tblStockStatus.IsCreditOnly + FROM + tblStockStatus "; + + for (var i = 0; i < statusIdEffected.Count; i++) + { + if (i == 0) + { + sqlString = sqlString + " WHERE tblStockStatus.StockStatusID=" + statusIdEffected[i]; + } + else + { + sqlString = sqlString + " OR tblStockStatus.StockStatusID=" + statusIdEffected[i]; + } + + //if (i == (statusIdEffected.Count - 1)) + //{ + // sqlString = sqlString + ";"; + //} + } + sqlString = sqlString + " GROUP BY tblStockStatus.StockStatusID, tblStockStatus.IsCreditOnly;"; + + // run query & build dictionaries + using (SqlCommand cmd = new SqlCommand(sqlString, conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + dicStatusCreditOnly.Add(reader.GetInt32(0), reader.GetBoolean(1)); + + while (reader.Read()) + { + dicStatusCreditOnly.Add(reader.GetInt32(0), reader.GetBoolean(1)); + } + } + else + { + throw new Exception("Error, no journal entries found for StockID=" + stockId); + } + } + } + + // check integrity of supplied statusIds + foreach (int statusId in statusIdEffected) + { + if (!dicStatusCreditOnly.ContainsKey(statusId)) + { + throw new Exception("Supplied StatusId (" + statusId + ") doesn't exist for StockId=" + stockId); + } + } + + // loop through each statudId and check integrity, if createdEnabled=false + foreach (int statudId in statusIdEffected) + { + if (dicStatusCreditOnly[statudId] == false) + { + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblStockJournal.EntryDate, tblStockJournalPost.Quantity + FROM + tblStockJournal + INNER JOIN tblStockJournalPost + ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE + tblStockJournal.StockID=@stockId + AND tblStockJournalPost.StockStatusID=@statudId + ORDER BY + tblStockJournal.EntryDate; + ", conn)) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + cmd.Parameters.AddWithValue("@statudId", statudId); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + // read first line into variables + reader.Read(); + int quantity = reader.GetInt32(1); + DateTime entryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc); + + while (true) + { + // compare to next values + if (reader.Read()) + { + DateTime nextEntryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc); + // don't check quantites for transactions on same date + if (entryDate == nextEntryDate) + { + entryDate = nextEntryDate; + quantity = quantity + reader.GetInt32(1); + } + // check if dates are different + else + { + if (quantity < 0) + { + return false; + } + else + { + entryDate = nextEntryDate; + quantity = quantity + reader.GetInt32(1); + } + } + } + // end if no records, check quantity + else + { + if (quantity < 0) + { + return false; + } + break; + } + } + } + } + } + } + } + // get this far, all good + return true; + } + + public static int StockStatusBalanceByStockId(string sqlConnectionString, int stockId, int statusId) + { + int statusBalance = new int(); + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT + SUM(tblStockJournalPost.Quantity) AS Balance + FROM + tblStockJournal + INNER JOIN tblStockJournalPost + ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE + (tblStockJournal.StockID = @stockId ) + AND (tblStockJournalPost.StockStatusID = @statusId ) + ", conn)) + { + // add parameters + cmd.Parameters.AddWithValue("@stockId", stockId); + cmd.Parameters.AddWithValue("@statusId", statusId); + + // execute + object obj = cmd.ExecuteScalar(); + if (obj == null || obj == DBNull.Value) + { + statusBalance = 0; + } + else + { + statusBalance = (int)obj; + } + } + } + return statusBalance; + } + + // Function returns a list with balance of stock avaiable by individual stockId ordered by earliest added to status (stock journal entrydate) + // beforeDate - used to filter results, useful when reallocating stock retrospectivly (i.e. avoid case were stock is + // moved out of status, ahead of it being moved into that status) -- really this should be the calling function that does this!! + public static List> GetStockStatusBalanceBySkuId + (string sqlConnectionString, int skuId, int stockStatusId, DateTime? maxDateUtc = null, bool sortAgeAscending = true) + { + + //build sql statement + string strSQL = @" + SELECT a.JournalDate, a.balance, a.stockID + FROM ( + SELECT MIN(tblStockJournal.EntryDate) AS JournalDate, SUM(tblStockJournalPost.Quantity) AS Balance, tblStock.StockID + FROM tblStockJournal INNER JOIN + tblStock ON tblStockJournal.StockID = tblStock.StockID INNER JOIN + tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + WHERE (tblStock.SkuID = @skuId ) AND (tblStockJournalPost.StockStatusID = @stockStatusId ) + GROUP BY tblStock.StockID + HAVING (SUM(tblStockJournalPost.Quantity)) > 0 + ) a + "; + if (maxDateUtc != null) + { + strSQL = strSQL + @" + WHERE a.JournalDate <= @beforeDateUtc + "; + } + strSQL = strSQL + @" + ORDER BY a.JournalDate; + "; + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(strSQL, sqlConn)) + { + // add parameters + cmd.Parameters.AddWithValue("@skuId", skuId); + cmd.Parameters.AddWithValue("@stockStatusId", stockStatusId); + if (maxDateUtc != null) + { cmd.Parameters.AddWithValue("@beforeDateUtc", maxDateUtc.Value.ToUniversalTime()); } + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + List> list = new List>(); + + int index01 = reader.GetOrdinal("StockID"); + int index02 = reader.GetOrdinal("JournalDate"); + int index03 = reader.GetOrdinal("Balance"); + + while (reader.Read()) + { + int stockId = reader.GetInt32(index01); + DateTime journalDate = reader.GetDateTime(index02); + int balance = reader.GetInt32(index03); + journalDate = DateTime.SpecifyKind(journalDate, DateTimeKind.Utc); + + list.Add(new Tuple(stockId, journalDate, balance)); + } + if (sortAgeAscending == false) + { + list.Reverse(); + } + + return list; + } + else + { + return null; + } + } + } + } + } + catch (Exception) + { + throw; + } + } + + public static int StockReallocateByStockId(string sqlConnectionString, int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId, + DateTime entryDate = default(DateTime)) + { + if (entryDate == default(DateTime)) + { + entryDate = DateTime.UtcNow; + } + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + // create the list + var posts = new List<(int statusId, int quantity)>(); + posts.Add((debitStatusId, quantity)); + posts.Add((creditStatusId, (quantity * -1))); + + // execute + return StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false); + } + + public static List> StockReallocateBySkuId(string sqlConnectionString, int journalTypeId, int skuId, int quantity, int debitStatusId, int creditStatusId, + bool moveOldestFirst = true, DateTime entryDate = default(DateTime), bool reallocatePartialQuantity = false) + { + // feed an skuId and quantity into function and the stock will be reallocated + // return tuple list + // Item1 = StockJournalId + // Item2 = Quantity + + List> list = GetStockStatusBalanceBySkuId(sqlConnectionString, skuId, creditStatusId, entryDate, moveOldestFirst); + if (list == null) + { + return null; + } + + List> returnList = new List>(); + + // quantity check + int avaiableQuantity = 0; + foreach (Tuple item in list) + { + avaiableQuantity = avaiableQuantity + item.Item3; + } + if (avaiableQuantity < quantity && reallocatePartialQuantity == false) + { + return null; + } + + // make the changes + try + { + using (TransactionScope scope = new TransactionScope()) + { + foreach (Tuple item in list) + { + if (quantity > item.Item3) + { + int tempInt = StockReallocateByStockId(sqlConnectionString, journalTypeId, item.Item1, item.Item3, debitStatusId, creditStatusId, entryDate); + quantity = quantity - item.Item3; + returnList.Add(new Tuple(tempInt, item.Item3)); + } + else + { + int tempInt = StockReallocateByStockId(sqlConnectionString, journalTypeId, item.Item1, quantity, debitStatusId, creditStatusId, entryDate); + returnList.Add(new Tuple(tempInt, quantity)); + break; + } + } + scope.Complete(); + return returnList; + } + } + catch (Exception) + { + throw; + } + } + public static int GetStockIdByStockJournalId(string sqlConnectionString, int stockJournalId) + { + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT StockID FROM tblStockJournal WHERE StockJournalID=@StockJournalId + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId); + + object obj = cmd.ExecuteScalar(); + if (obj == null) + { + return -1; + } + else + { + return Convert.ToInt32(obj); + } + } + } + + } + catch (Exception) + { + throw; + } + } + + public static int StockTransactionTypeIdSelect(string sqlConnectionString, string matchString) + { + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type doesn't exist or is new (not reviewed yet) + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + + // old optional parameters + // , bool onNewReturnId = false, bool onNewDisableInsert = false + + if (matchString.Length == 0) + { + throw new Exception("Empty match string passed to method"); + } + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT + StockTransactionTypeID, + IsNewReviewRequired, + TransactionImportEnabled + FROM + tblStockTransactionType + WHERE + MatchString=@matchString; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@matchString", matchString); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + int index01 = reader.GetOrdinal("StockTransactionTypeID"); + int index02 = reader.GetOrdinal("IsNewReviewRequired"); + int index03 = reader.GetOrdinal("TransactionImportEnabled"); + + int transactionTypeId = reader.GetInt32(index01); + bool isNew = reader.GetBoolean(index02); + bool? importEnabled = reader[index03] as bool? ?? null; // column can be null + + if (isNew == true || importEnabled == null) + { + // return 0 and 'skip' item + return 0; + } + else if (importEnabled == false) + { + // mark IsProcessed=true and leave transactionId=null + return -1; + } + else if (transactionTypeId > 0) + { + + return transactionTypeId; + } + else + { + throw new Exception("Stock TransactionTypeId lookup method went wrong, is one of the 'enabled' boolean on table set to null?"); + } + } + else + { + return 0; + } + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + public static int StockTransactionTypeIdInsert(string sqlConnectionString, int stockJournalTypeId, string matchString, bool transScopeSuppress = true) + { + int transactionTypeId; + var scopeOption = new TransactionScopeOption(); + if (transScopeSuppress) + { + scopeOption = TransactionScopeOption.Suppress; + } + else + { + scopeOption = TransactionScopeOption.Required; + } + + using (TransactionScope scope = new TransactionScope(scopeOption)) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + //check to see if type already exists, return id of that if it does + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblStockTransactionType.StockTransactionTypeID + FROM + tblStockTransactionType + WHERE + tblStockTransactionType.StockJournalTypeID=@stockJournalTypeId + AND tblStockTransactionType.MatchString=@matchString; + ", conn)) + { + cmd.Parameters.AddWithValue("@matchString", matchString); + cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId); + + object obj = cmd.ExecuteScalar(); + + if (!(obj == null || obj == DBNull.Value)) + { + return (int)obj; + } + } + + // insert new and retrive new value + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblStockTransactionType + ( StockJournalTypeID, MatchString ) + OUTPUT + INSERTED.StockTransactionTypeID + VALUES + ( @stockJournalTypeId, @matchString ); + ", conn)) + { + cmd.Parameters.AddWithValue("@matchString", matchString); + cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId); + + transactionTypeId = (int)cmd.ExecuteScalar(); + } + + scope.Complete(); + } + return transactionTypeId; + } + + public static (int quantity, decimal totalAmount) StockGetTotalQuantityAndCost(string sqlConnectionString, int stockId) + { + (int quantity, decimal totalAmount) result; + + using (var conn = new SqlConnection()) + { + conn.Open(); + + using (var cmd = new SqlCommand(@" + SELECT tblAccountStockCost.Quantity, tblAccountStockCost.AmountTotal + FROM tblAccountStockCost + WHERE tblAccountStockCost.StockID=@stockId; + ")) + { + cmd.Parameters.AddWithValue("@stockId", stockId); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + result = (reader.GetInt32(0), reader.GetDecimal(1)); + if (reader.Read()) + { + throw new Exception("StockID=" + stockId + " found more than once in tblAccountStockCost!"); + } + } + else + { + throw new Exception("StockID=" + stockId + " not found in tblAccountStockCost!"); + } + } + } + } + return result; + } + + public void TMP_AddAccountJournalEntriesToStockMovement(string sqlConnectionString) + { + // redundant code + // going to track stock costing by adding quanity and total cost to stock table + // each stock status will be assigned an accountId, from this I can calculate account balance from stock balance and value + // + // the way below would be far too complex for the only added gain of being able to reduce the value of a stock line + // at a given point in time. + // going with sending stock to a write-down status and creating new a stock line from that status. + + return; + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + // load list to iterate through + using (SqlCommand cmdSelect = new SqlCommand(@" + SELECT + tblStockJournal.StockJournalID, tblStockJournal.EntryDate, tblStockJournal.StockID + FROM + tblStockJournal + WHERE + (((tblStockJournal.AccountIsProcessed)=@false)) + ORDER BY + tblStockJournal.EntryDate, tblStockJournal.StockJournalID; + ", sqlConn)) + { + cmdSelect.Parameters.AddWithValue("@false", false); + + using (SqlDataReader reader = cmdSelect.ExecuteReader()) + { + while (reader.Read()) + { + int StockJournalId = reader.GetInt32(0); + DateTime entryDate = DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc); + int stockId = reader.GetInt32(2); + + // get credit and debits + int qtyDebit = 0; + int qtyCredit = 0; + int statusDebit = 0; + int statusCredit = 0; + int i = 0; + + using (SqlCommand cmdSelectPost = new SqlCommand(@" + SELECT + tblStockJournalPost.StockStatusID, tblStockJournalPost.Quantity + FROM + tblStockJournalPost + WHERE + (((tblStockJournalPost.StockJournalID)=@StockJournalId)); + ", sqlConn)) + { + using (SqlDataReader readerPost = cmdSelect.ExecuteReader()) + { + while (readerPost.Read()) + { + i = i + 1; + int qty = readerPost.GetInt32(1); + int statusId = readerPost.GetInt32(0); + + if (qty > 0) + { + qtyDebit = qty; + statusDebit = statusId; + } + else + { + qtyCredit = qty; + statusCredit = statusId; + } + } + if (i > 2) + { + throw new Exception("more than two post for journal entry StockJournalId=" + StockJournalId + "."); + } + } + } + + // get account chart id for each status and compare + int accountIdDebitId; + int accountIdCreditId; + + //debit + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblStockStatusType.AccountChartOfID + FROM tblStockStatus INNER JOIN tblStockStatusType ON tblStockStatus.StockStatusTypeID = tblStockStatusType.StockStatusTypeID + WHERE (((tblStockStatus.StockStatusID)=@stockStatusId)); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("stockStatusId", statusDebit); + + accountIdDebitId = (int)cmd.ExecuteScalar(); + } + + //credit + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblStockStatusType.AccountChartOfID + FROM tblStockStatus INNER JOIN tblStockStatusType ON tblStockStatus.StockStatusTypeID = tblStockStatusType.StockStatusTypeID + WHERE (((tblStockStatus.StockStatusID)=@stockStatusId)); + ", sqlConn)) + { + cmd.Parameters.AddWithValue("stockStatusId", statusCredit); + + accountIdCreditId = (int)cmd.ExecuteScalar(); + } + + using (SqlConnection connScope = new SqlConnection(sqlConnectionString)) + using (TransactionScope scope = new TransactionScope()) + { + connScope.Open(); + + // add account journal entry if they are different + if (accountIdDebitId != accountIdCreditId) + { + // get stock value and balance by account Id + + + + + // insert account journal entry + + + + // do something with the account journal id + + + + } + + // finish up, mark stock journal entry as done + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblStockJournal SET tblStockJournal.AccountIsProcessed = True + WHERE (((tblStockJournal.StockJournalID)=@StockJournalId)); + ", connScope)) + { + cmd.Parameters.AddWithValue("StockJournalId", StockJournalId); + + cmd.ExecuteNonQuery(); + } + scope.Complete(); + } + } + } + } + } + } + } + + public class StockReconciliation + { + public class ReconcileStockTransactionsResult + { + public bool ReconciliationComplete { get; set; } = false; + public int StockTransactionId { get; set; } + public int StockTransactionTypeId { get; set; } + public string ProgressMessage { get; set; } + public int ItemsCompleted { get; set; } + public int ItemsRemaining { get; set; } + public DateTime LastItemDateTime { get; set; } + } + + // downloads new inventory data from mws and updates stock import tables + public void UpdateFbaStockImportData(string sqlConnectionString) + { + + bool inventoryReceiptUpdate = false; + bool fbaShipmentsUpdate = false; + bool fbaReturnsUpdate = false; + bool fbaAdjustmentUpdate = false; + bool fbaReimbursementUpdate = false; + bool fbaRemovalOrderUpdate = false; + bool fbaInventoryAgeUpdate = false; + + while (true) + { + try + { + var mwsReports = new AmazonReport(); + + if (inventoryReceiptUpdate == false) { inventoryReceiptUpdate = true; mwsReports.UpdateFbaInventoryReceiptData(sqlConnectionString); } + if (fbaShipmentsUpdate == false) { fbaShipmentsUpdate = true; mwsReports.UpdateFbaSaleShipmentData(sqlConnectionString); } + if (fbaReturnsUpdate == false) { fbaReturnsUpdate = true; mwsReports.UpdateFbaReturnData(sqlConnectionString); } + if (fbaAdjustmentUpdate == false) { fbaAdjustmentUpdate = true; mwsReports.UpdateFbaAdustmentData(sqlConnectionString); } + if (fbaReimbursementUpdate == false) { fbaReimbursementUpdate = true; mwsReports.UpdateFbaReimbursementData(sqlConnectionString); } + if (fbaRemovalOrderUpdate == false) { fbaRemovalOrderUpdate = true; mwsReports.UpdateFbaRemovalOrderReport(sqlConnectionString); } + if (fbaInventoryAgeUpdate == false) { fbaInventoryAgeUpdate = true; mwsReports.UpdateFbaInventoryAgeData(sqlConnectionString); } + + break; + } + catch (Exception ex) + { + MiscFunction.EventLogInsert( + "Exception caught running UpdateFbaStockImportData, see for further details", + 1, + ex.ToString() + ); + } + } + } + + // transposes data from report import tables to stock transaction table + public void ProcessFbaStockImportData(string sqlConnectionString) + { + bool inventoryReceiptProcess = false; + bool fbaShipmentsProcess = false; + bool fbaReturnsProcess = false; + bool fbaAdjustmentProcess = false; + bool fbaReimbursementProcess = false; + bool fbaRemovalOrderProcess = false; + + while (true) + { + try + { + var mwsReports = new Stock.StockReconciliation(); + + if (inventoryReceiptProcess == false) { inventoryReceiptProcess = true; mwsReports.ProcessFbaInventoryReceiptData(sqlConnectionString); } + if (fbaShipmentsProcess == false) { fbaShipmentsProcess = true; mwsReports.ProcessFbaSaleShipmentData(sqlConnectionString); } + if (fbaReturnsProcess == false) { fbaReturnsProcess = true; mwsReports.ProcessFbaReturnsData(sqlConnectionString); } + if (fbaAdjustmentProcess == false) { fbaAdjustmentProcess = true; mwsReports.ProcessFbaAdustmentData(sqlConnectionString); } + if (fbaReimbursementProcess == false) { fbaReimbursementProcess = true; mwsReports.WIP_ProcessFbaReimbursementData(sqlConnectionString); } + if (fbaRemovalOrderProcess == false) { fbaRemovalOrderProcess = true; mwsReports.ProcessReportFbaRemovalOrder(sqlConnectionString); } + + break; + } + catch (Exception ex) + { + MiscFunction.EventLogInsert( + "Exception caught running ProcessFbaStockImportData, see for further details", + 1, + ex.ToString() + ); + } + } + } + + public void WIP_ProcessAmazonSettlementData(string sqlConnectionString) + { + + MiscFunction.EventLogInsert("Starting import of Amazon settlement data into account transaction table..."); + int reportCount = 0; + int reportLineCount = 0; + int lineCount = 0; + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + try + { + // test wether there are records to process + using (SqlCommand cmd = new SqlCommand(@" + SELECT + Count(ImportAmazonSettlementReportID) AS CountOfID + FROM + tblImportAmazonSettlementReport + WHERE + (((tblImportAmazonSettlementReport.IsProcessed)=0)); + ", sqlConn)) + { + int records = (int)cmd.ExecuteScalar(); + + if (records == 0) + { + MiscFunction.EventLogInsert("No new settlements to process, exiting import..."); + return; + } + } + + // ensure settlement lines have not been processed or had transactions added + using (SqlCommand cmd = new SqlCommand(@" + SELECT + Count(tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportLineID) AS CountOfID + FROM + tblImportAmazonSettlementReportLine + INNER JOIN tblImportAmazonSettlementReport + ON tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportID = tblImportAmazonSettlementReport.ImportAmazonSettlementReportID + WHERE + (((tblImportAmazonSettlementReport.IsProcessed)=0) AND ((tblImportAmazonSettlementReportLine.AccountTransactionID) Is Not Null)) + OR (((tblImportAmazonSettlementReport.IsProcessed)=0) AND ((tblImportAmazonSettlementReportLine.IsProcessed)=1)); + ", sqlConn)) + { + int count = Convert.ToInt32(cmd.ExecuteScalar()); + if (count != 0) + { + throw new Exception("Error, " + count + " settlement report lines have transactionId/IsProcessed set on an unprocessed settlement"); + } + } + + // build dictionary of SKU's and Vat type + var dicSkuToTaxCodeId = new Dictionary(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblImportAmazonSettlementReportLine.sku, + tblSku.AccountTaxCodeID + FROM + (tblImportAmazonSettlementReport INNER JOIN tblImportAmazonSettlementReportLine + ON tblImportAmazonSettlementReport.ImportAmazonSettlementReportID = tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportID) + INNER JOIN tblSku ON tblImportAmazonSettlementReportLine.sku = tblSku.skuSkuNumber + WHERE + (((tblImportAmazonSettlementReport.IsProcessed)=0)) + GROUP BY + tblImportAmazonSettlementReportLine.sku, + tblSku.AccountTaxCodeID; + ", sqlConn)) + { + int i = 0; + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + i = i + 1; + Console.Write("\rBuilding SKU list... " + i); + dicSkuToTaxCodeId.Add(reader.GetString(0), reader.GetInt32(1)); + } + } + } + + // get list of unprocessed settlements to loop thorugh + using (SqlCommand selectCmd = new SqlCommand(@" + SELECT * FROM tblImportAmazonSettlementReport + WHERE IsProcessed=0 + ORDER BY [settlement-end-date] + ", sqlConn)) + using (var reader = selectCmd.ExecuteReader()) + { + int index01 = reader.GetOrdinal("ImportAmazonSettlementReportID"); + int index02 = reader.GetOrdinal("settlement-id"); + int index03 = reader.GetOrdinal("settlement-end-date"); + int index04 = reader.GetOrdinal("total-amount"); + int index05 = reader.GetOrdinal("currency"); + int index06 = reader.GetOrdinal("marketplace-name"); + int index07 = reader.GetOrdinal("deposit-date"); + + while (reader.Read()) + { + reportCount = reportCount + 1; + string consoleLine = "\rProcessing report #" + reportCount + " "; + Console.Write("\r "); + Console.Write(consoleLine); + + int settlementId = reader.GetInt32(index01); + string settlementRef = reader.GetString(index02); + DateTime settlementEndDate = DateTime.SpecifyKind(reader.GetDateTime(index03), DateTimeKind.Utc); + decimal settlementAmount = reader.GetDecimal(index04); + string currency = reader.GetString(index05); + DateTime depositDate = DateTime.SpecifyKind(reader.GetDateTime(index07), DateTimeKind.Utc); + string marketPlace = ""; + List insertedInvoiceIds = new List(); + + // test marketplace-name has been sucsessfully entered into settlement table -- + // this is not supplied in the original report from Amazon and has to be inferred from settlement line data + if (!reader.IsDBNull(index06)) + { + marketPlace = reader.GetString(index06); + } + else + { + MiscFunction.EventLogInsert( + "Action required: Enter market place name for settlelment report (ImportAmazonSettlementReportID=" + settlementId + ")." + , 1 + , "Unable to process settlement data from one settlement report '"+ settlementRef + + "'. Report header table requires a market place name, which is not supplied in original " + + "report from Amazon. This is useually inferred from settlement lines. " + + "However, in this case it was not not possible. Manual edit/entry for database table required." + ); + reportCount = reportCount - 1; + continue; + } + + // build list of cut off dates (multiple when date range straddles two months) + DateTime maxDate; + DateTime minDate; + List dateList = new List(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Max([posted-date-time]) AS ReturnDate + FROM tblImportAmazonSettlementReportLine + WHERE ImportAmazonSettlementReportID=@settlementReportId; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@settlementReportId", settlementId); + + maxDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc); + } + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Min([posted-date-time]) AS ReturnDate + FROM tblImportAmazonSettlementReportLine + WHERE ImportAmazonSettlementReportID=@settlementReportId; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@settlementReportId", settlementId); + + minDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc); + } + + for (int i = 1; true; i++) + { + DateTime splitDate = new DateTime(minDate.Year, minDate.Month, 1, 0, 0, 0, DateTimeKind.Utc); + splitDate = splitDate.AddMonths(i); + splitDate = splitDate.AddSeconds(-1); + if (splitDate < maxDate) + { + dateList.Add(splitDate); + } + else + { + dateList.Add(maxDate); + break; + } + if (i > 10) + { + throw new Exception("Error when building Date list, too many loops."); + } + } + + // shouldn't normally be more than 2 date ranges + if (dateList.Count > 2 || dateList.Count == 0) + { + MiscFunction.EventLogInsert( + dateList.Count + " total numner of items in date list (ImportAmazonSettlementReportID=" + settlementId + ")." + , 1, + "Settlement period appears to span more 3 months or more. Whilst this is possible, it is unsual. Confirm his is correct."); + } + + // loop through settlement lines + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + using (TransactionScope scope = new TransactionScope()) + { + transConn.Open(); + + decimal settlementLineTotal = 0; + + for (int i = 0; i < dateList.Count; i++) + { + Console.Write("\r "); + Console.Write(consoleLine + "- creating export invoice and invoice lines..."); + + //setup dictionaries for this round + var dicMatchToLineType = new Dictionary(); + var dicSettlementLineToLineType = new Dictionary(); + var dicLineTypeTotal = new Dictionary(); + //var dicTransTypeToJournal = new Dictionary(); + var dicLineTypeToLineId = new Dictionary(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportLineID, + tblImportAmazonSettlementReportLine.[transaction-type], + tblImportAmazonSettlementReportLine.[amount-type], + tblImportAmazonSettlementReportLine.[amount-description], + tblImportAmazonSettlementReportLine.amount, + tblImportAmazonSettlementReportLine.currency, + tblImportAmazonSettlementReportLine.sku + FROM + tblImportAmazonSettlementReportLine + WHERE + (((tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportID)=@settlementReportId) + AND ((tblImportAmazonSettlementReportLine.[posted-date-time])<=@maxDate) + AND tblImportAmazonSettlementReportLine.IsProcessed=0); + ", transConn)) + { + cmd.Parameters.AddWithValue("@settlementReportId", settlementId); + cmd.Parameters.AddWithValue("@maxDate", dateList[i].ToUniversalTime()); + + using (var readerLine = cmd.ExecuteReader()) + { + // settlement period can, on occasion, span multiple months. Some months having no transactions + // account for this here + if (!readerLine.HasRows) + { continue; } + + while (readerLine.Read()) + { + reportLineCount = reportLineCount + 1; + + int settlementLineId = readerLine.GetInt32(0); + string match01 = readerLine.GetString(1); + string match02 = readerLine.GetString(2); + string match03 = readerLine.GetString(3); + decimal lineAmount = readerLine.GetDecimal(4); + string lineCurrency = readerLine.GetString(5); + string lineSku = ""; + if (!readerLine.IsDBNull(6)) + { + lineSku = readerLine.GetString(6); + } + + // double check currency matches settlement parent table + if (lineCurrency != currency) + { + throw new Exception("Currency code of settlement-line does not match parent settlement (ImportAmazonReportSettlementID=" + settlementId + ")."); + } + + // get transaction type id for line + // build the match string + // NB special case for global accounting sale and refunds (also note Goodlwill is included) + string matchString = "<" + match01 + "><" + match02 + ">"; + if ((match01 == "Order" || match01 == "Refund") && match02 == "ItemPrice" && (match03 == "Principal" || match03 == "Goodwill")) + { + if (lineSku == "") + { + throw new Exception("Could not retrive Sku from SettleLineId=" + settlementLineId); + } + matchString = matchString + ""; + if (dicSkuToTaxCodeId.ContainsKey(lineSku)) + { + matchString = matchString + ""; + } + else + { + throw new Exception("Sku '" + lineSku + "' not found in dictionary list."); + } + } + else + { + matchString = matchString + "<" + match03 + ">"; + } + + // get/set linetypeid + int lineTypeId = 0; + if (dicMatchToLineType.ContainsKey(matchString)) + { + lineTypeId = dicMatchToLineType[matchString]; + } + else + { + lineTypeId = Export.ExportQuery.WIP_GetImportInvoiceLineTypeId(sqlConnectionString, matchString); + // new type item, requires review before continue + if (lineTypeId == 0) + { + MiscFunction.EventLogInsert("New type found for Export Invoice Line Type. Update table!", 1, matchString, + DateTime.UtcNow, true); + return; + } + + dicMatchToLineType.Add(matchString, lineTypeId); + } + + // line type amount total & invoice total + if (dicLineTypeTotal.ContainsKey(lineTypeId)) + { + dicLineTypeTotal[lineTypeId] = dicLineTypeTotal[lineTypeId] + lineAmount; + } + else + { + dicLineTypeTotal.Add(lineTypeId, lineAmount); + } + + // set line type for settlement report line + dicSettlementLineToLineType.Add(settlementLineId, lineTypeId); + } + } + } + + // finish looping though settlement records (building dictionaries) + + // build info for invoice header + + // set transaction/journal entry date, if last in dateList use settlement end date (minus 1 second) + DateTime invoiceDate; + if ((i + 1) == dateList.Count) + { + invoiceDate = DateTime.SpecifyKind(settlementEndDate, DateTimeKind.Utc); + invoiceDate = invoiceDate.AddSeconds(-1); + } + else + { + invoiceDate = DateTime.SpecifyKind(dateList[i], DateTimeKind.Utc); + } + + //// set invoice total + //decimal invoiceTotal = 0; + //foreach (KeyValuePair entry in dicLineTypeTotal) + //{ + // invoiceTotal = invoiceTotal + entry.Value; + //} + + + // insert invoice header details + int invoiceId = bnhtradeDatabaseClient.Export.ExportQuery.WIP_ExportAccountInvoiceInsert(sqlConnectionString, + 2, marketPlace, invoiceDate, depositDate, settlementRef, currency, ""); + insertedInvoiceIds.Add(invoiceId); + + // insert invoice lines + foreach (KeyValuePair entry in dicLineTypeTotal) + { + int lineId = bnhtradeDatabaseClient.Export.ExportQuery.WIP_ExportAccountInvoiceLineInsert(sqlConnectionString, + invoiceId, entry.Key, entry.Value, 0); + if (lineId < 1) + { + throw new Exception("Error inserting invoice line"); + } + lineCount = lineCount + 1; + + // add lineId to transtypeId dictionary + dicLineTypeToLineId.Add(entry.Key, lineId); + } + + // update settlement lines with lineIds (if required) and IsProcessed + Console.Write("\r "); + Console.Write(consoleLine + "- Updating settlement report tables..."); + + foreach (KeyValuePair entry in dicSettlementLineToLineType) + { + using (SqlCommand cmd = new SqlCommand(@" + UPDATE + tblImportAmazonSettlementReportLine + SET + tblImportAmazonSettlementReportLine.ExportAccountInvoiceLineID=@lineId, + tblImportAmazonSettlementReportLine.IsProcessed=1 + WHERE + (((tblImportAmazonSettlementReportLine.ImportAmazonSettlementReportLineID)=@reportLineId)); + ", transConn)) + { + cmd.Parameters.AddWithValue("@reportLineId", entry.Key); + + int lineId = dicLineTypeToLineId[entry.Value]; + if (lineId == -1) { cmd.Parameters.AddWithValue("@lineId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@lineId", lineId); } + + cmd.ExecuteNonQuery(); + } + } + + // total for settlement check (total of commited transactions) + foreach (KeyValuePair entry in dicLineTypeTotal) + { + settlementLineTotal = settlementLineTotal + entry.Value; + } + } + // finish looping through settlement date splits + + // set settlement report to IsProcessed + + using (SqlCommand cmd = new SqlCommand(@" + UPDATE + tblImportAmazonSettlementReport + SET + tblImportAmazonSettlementReport.IsProcessed=1 + WHERE + (((tblImportAmazonSettlementReport.ImportAmazonSettlementReportID)=@settlementId)); + ", transConn)) + { + cmd.Parameters.AddWithValue("@settlementId", settlementId); + + cmd.ExecuteNonQuery(); + } + + // checks before commiting transactions for settlement + if (settlementLineTotal != settlementAmount) + { + throw new Exception("Totals of inserted transactions do not match settlement amount"); + } + + // Final stage, invoice post processing + // + // remove invoice lines with LineType invoice entry disabled + int invoiceRemoved = 0; + int invoiceLinesRemoved = 0; + + // build sqlPostfix + string sqlPostfix = ""; + foreach (int invoiceId in insertedInvoiceIds) + { + sqlPostfix = sqlPostfix + @" + OR (ExportAccountInvoiceID = " + invoiceId + ")"; + } + sqlPostfix = sqlPostfix + ")"; + + // remove invoice line id from settlement line table + string sql = @" + UPDATE tblImportAmazonSettlementReportLine + SET ExportAccountInvoiceLineID = NULL + FROM tblImportAmazonSettlementReportLine + INNER JOIN tblExportAccountInvoiceLine ON tblImportAmazonSettlementReportLine.ExportAccountInvoiceLineID = tblExportAccountInvoiceLine.ExportAccountInvoiceLineID + INNER JOIN tblExportAccountInvoiceLineType ON tblExportAccountInvoiceLine.ExportAccountInvoiceLineTypeID = tblExportAccountInvoiceLineType.ExportAccountInvoiceLineTypeID + WHERE (tblExportAccountInvoiceLineType.InvoiceLineEntryEnable = 0) + AND ( + (1 = 2)"; + sql = sql + sqlPostfix; + + using (SqlCommand cmd = new SqlCommand(sql, transConn)) + { + cmd.ExecuteNonQuery(); + } + + // remove invoice lines + sql = @" + DELETE + FROM tblExportAccountInvoiceLine + FROM tblExportAccountInvoiceLine + INNER JOIN tblExportAccountInvoiceLineType ON tblExportAccountInvoiceLine.ExportAccountInvoiceLineTypeID = tblExportAccountInvoiceLineType.ExportAccountInvoiceLineTypeID + WHERE (tblExportAccountInvoiceLineType.IsNewReviewRequired = 0) + AND (tblExportAccountInvoiceLineType.InvoiceLineEntryEnable = 0) + AND ( + (1 = 2)"; + sql = sql + sqlPostfix; + + using (SqlCommand cmd = new SqlCommand(sql, transConn)) + { + invoiceLinesRemoved = cmd.ExecuteNonQuery(); + } + + // remove any invoices with no lines + sql = @" + DELETE + FROM tblExportAccountInvoice + WHERE + not exists + ( + select 1 from tblExportAccountInvoiceLine where tblExportAccountInvoice.ExportAccountInvoiceID = tblExportAccountInvoiceLine.ExportAccountInvoiceID + ) + AND ( + (1 = 2)"; + sql = sql + sqlPostfix; + + using (SqlCommand cmd = new SqlCommand(sql, transConn)) + { + invoiceRemoved = cmd.ExecuteNonQuery(); + } + + // add postfix to invoice ref, if required + var dicInvoiceIdToRef = new Dictionary(); + sql = @" + SELECT ExportAccountInvoiceID + FROM tblExportAccountInvoice + WHERE ((1 = 2) "; + sql = sql + sqlPostfix + " ORDER BY InvoiceDate"; + using (SqlCommand readerCmd = new SqlCommand(sql, transConn)) + { + using (var readerInvRef = readerCmd.ExecuteReader()) + { + while (readerInvRef.Read()) + { + dicInvoiceIdToRef.Add(readerInvRef.GetInt32(0), settlementRef); + } + } + } + if (dicInvoiceIdToRef.Count > 1) + { + int i = 0; + foreach (var item in dicInvoiceIdToRef) + { + i = i + 1; + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblExportAccountInvoice + SET Reference = @reference + WHERE tblExportAccountInvoice.ExportAccountInvoiceID = @invoiceId + ", transConn)) + { + cmd.Parameters.AddWithValue("@reference", item.Value + "-" + i); + cmd.Parameters.AddWithValue("@invoiceId", item.Key); + + cmd.ExecuteNonQuery(); + } + } + } + + // complete the transaction and move to next settlement report + scope.Complete(); + } + } + Console.Write("\r"); + MiscFunction.EventLogInsert( + "Settlement report import complete. " + reportCount + " reports imported, " + lineCount + " transactions inserted, " + + reportLineCount + " report lines processed."); + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert( + "Import of Amazon settlement table data into transaction table and journal failed", + 1, + ex.ToString()); + } + } + } + public void ProcessFbaInventoryReceiptData(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Starting TransposeFbaInventoryReceiptReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int transactionTypeIdPos; + int transactionTypeIdNeg; + int stockJournalTypeId = 6; + string matchStringPos = "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>"; + string matchStringNeg = "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><-ve>"; + + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + + try + { + transactionTypeIdPos = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringPos); + transactionTypeIdNeg = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("TransposeFbaInventoryReceiptReport() failed to retrive 'TransactionTypeID from method, cancelling operation. More details available.", 1, ex.ToString()); + return; + } + + if (!(transactionTypeIdPos > 0) || !(transactionTypeIdNeg > 0)) + { + // transaction import and stock journal definitions are not setup -- function requires both to be setup + int temp; + temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchStringPos); + temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchStringNeg); + MiscFunction.EventLogInsert("TransposeFbaInventoryReceiptReport() function requires that both +ve and -ve types are setup. Cancelling operation", 2); + return; + } + + try + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaInventoryReceiptReport WHERE IsProcessed=0 " + + "ORDER BY [received-date];" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaInventoryReceiptReportID"); + int index02 = reader.GetOrdinal("received-date"); + int index03 = reader.GetOrdinal("sku"); + int index04 = reader.GetOrdinal("quantity"); + int index05 = reader.GetOrdinal("fba-shipment-id"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + int importTableId = reader.GetInt32(index01); + string sku = reader.GetString(index03); + int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + if (skuId < 1) + { + transposeSkip = transposeSkip + 1; + continue; + } + int quantity = reader.GetInt32(index04); + string reference = reader.GetString(index05); + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + int transactionId; + if (quantity > 0) + { + transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeIdPos, skuId, quantity, 0, reference, "", false, 0); + } + else if (quantity < 0) + { + // attempt to update/correct earlier incorrect +ve StockTransaction entry + using (SqlCommand cmd2 = new SqlCommand(@" + SELECT StockTransactionID, Quantity FROM tblStockTransaction + WHERE StockTransactionTypeID=@stockTransactionTypeId AND Reference=@reference AND SkuID=@skuId AND Quantity>=@quantity AND IsProcessed=0 + ", transConn)) + { + cmd2.Parameters.AddWithValue("stockTransactionTypeId", transactionTypeIdPos); + cmd2.Parameters.AddWithValue("reference", reference); + cmd2.Parameters.AddWithValue("skuId", skuId); + cmd2.Parameters.AddWithValue("quantity", (quantity * -1)); + + using (SqlDataReader reader2 = cmd2.ExecuteReader()) + { + if (reader2.Read()) + { + transactionId = reader2.GetInt32(0); + quantity = reader2.GetInt32(1) + quantity; + + // delete stock transation entry if quantities cancel each other out + if (quantity == 0) + { + using (SqlCommand cmd3 = new SqlCommand(@" + UPDATE tblImportFbaInventoryReceiptReport + SET StockTransactionID=NULL + WHERE StockTransactionID=@transactionId + ", transConn)) + { + cmd3.Parameters.AddWithValue("transactionId", transactionId); + cmd3.ExecuteNonQuery(); + } + using (SqlCommand cmd3 = new SqlCommand(@" + DELETE FROM tblStockTransaction + WHERE StockTransactionID=@transactionId + ", transConn)) + { + cmd3.Parameters.AddWithValue("transactionId", transactionId); + cmd3.ExecuteNonQuery(); + } + transactionId = 0; + } + // else update transaction quantity + else + { + using (SqlCommand cmd3 = new SqlCommand(@" + UPDATE tblStockTransaction + SET Quantity=@quantity + WHERE StockTransactionID=@transactionId + ", transConn)) + { + cmd3.Parameters.AddWithValue("transactionId", transactionId); + cmd3.Parameters.AddWithValue("quantity", quantity); + cmd3.ExecuteNonQuery(); + } + } + } + // reader returned no matching rows, add new transaction + else + { + transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeIdNeg, skuId, (quantity * -1) + , 0, reference, "", false, 0); + } + } + } + } + else if (quantity == 0) + { + transactionId = 0; + } + else + { + transposeSkip = transposeSkip + 1; + continue; + } + + // update isprocessed and transactionId on import table + using (SqlCommand updateCmd = new SqlCommand( + "UPDATE tblImportFbaInventoryReceiptReport " + + "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "WHERE ImportFbaInventoryReceiptReportID=@importTableId;", + transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + scope.Complete(); + transposeCount = transposeCount + 1; + } + } + } + Console.Write("\r"); + } + } + } + } + MiscFunction.EventLogInsert("TransposeFbaInventoryReceiptReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaInventoryReceiptReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting TransposeFbaInventoryReceiptReport(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + } + public void ProcessFbaSaleShipmentData(string sqlConnectionString) + { + // hack time, method requires uptodate fba order information in db order tables + // this next 'hack' method runs to get minimum required data fbaSalesShipment report table + // should not be used where persistant data is required (data is retrived from report import tables, + // which at some point may have older records deleted), but will do for this purpose + + var hack = new Stock.StockReconciliation(); + hack.WIP_GetSetFbaOrderRefs(sqlConnectionString); + + MiscFunction.EventLogInsert("Starting TransposeFbaSaleShipmentReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int stockJouranlTypeId = 7; + string matchString = "<_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_>"; + int transactionTypeId; + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, yype is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + + try + { + transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("TransposeFbaSaleShipmentReport() failed to retrive 'TransactionTypeID from method, cancelling operation. More details available.", 1, ex.ToString()); + return; + } + + if (transactionTypeId == 0) + { + // transaction import and stock journal definitions are not setup, cancel + int temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJouranlTypeId, matchString); + return; + } + + try + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaSaleShipment WHERE IsProcessed=0 " + + "ORDER BY [payments-date];" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaSaleShipmentID"); + int index02 = reader.GetOrdinal("payments-date"); + int index03 = reader.GetOrdinal("sku"); + int index04 = reader.GetOrdinal("quantity-shipped"); + int index05 = reader.GetOrdinal("sales-channel"); + int index06 = reader.GetOrdinal("amazon-order-id"); + int index07 = reader.GetOrdinal("amazon-order-item-id"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + int importTableId = reader.GetInt32(index01); + string sku = reader.GetString(index03); + int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + if (skuId < 1) + { transposeSkip = transposeSkip + 1; continue; } + int quantity = reader.GetInt32(index04); + int orderChannelId = Order.OrderQuery.GetSaleChannelIdByName(sqlConnectionString, reader.GetString(index05), true); + string amazonOrderId = reader.GetString(index06); + int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, amazonOrderId, true); + string amazonOrderItemId = reader.GetString(index07); + int orderItemId = Order.OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); + + if (quantity > 0 && transactionTypeId == 0) + { transposeSkip = transposeSkip + 1; continue; } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + int transactionId; + if (quantity > 0 & transactionTypeId > 0) + { transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeId, skuId, quantity, orderItemId, amazonOrderId, "", false, 0); } + else if (quantity == 0) + { transactionId = 0; } + else + { transposeSkip = transposeSkip + 1; continue; } + + using (SqlCommand updateCmd = new SqlCommand( + "UPDATE tblImportFbaSaleShipment " + + "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "WHERE ImportFbaSaleShipmentID=@importTableId;", + transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + } + transposeCount = transposeCount + 1; + scope.Complete(); + } + } + Console.Write("\r"); + } + } + } + } + MiscFunction.EventLogInsert("TransposeFbaSaleShipmentReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaSaleShipmentReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting TransposeFbaSaleShipmentReport(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + } + public void WIP_GetSetFbaOrderRefs(string sqlConnectionString) + { + // currently a hack, gets info from FBA sale shipment import table and has to run before the inforation is transposed to transaction table + // reqires work so app uses MWS api for order/sales data + + // should not be used where persistant data is required (data is retrived from report import tables, + // which at some point may have older records deleted), but will do for this purpose + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + using (SqlCommand cmd = new SqlCommand(@" + SELECT [amazon-order-id], [amazon-order-item-id], [sales-channel], sku + FROM tblImportFbaSaleShipment WHERE IsProcessed=0 + ", sqlConn)) + { + sqlConn.Open(); + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int index01 = reader.GetOrdinal("amazon-order-id"); + int index02 = reader.GetOrdinal("amazon-order-item-id"); + int index03 = reader.GetOrdinal("sales-channel"); + int index04 = reader.GetOrdinal("sku"); + + int record = 0; + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + string amazonOrderId = reader.GetString(index01); + string amazonOrderItemId = reader.GetString(index02); + string salesChannel = reader.GetString(index03); + string sku = reader.GetString(index04); + + // get orderchannelId + int salesChannelId = Order.OrderQuery.GetSaleChannelIdByName(sqlConnectionString, salesChannel); + + // get/set order ref + int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, salesChannelId, amazonOrderId, true); + + // get/set order item ref + int orderItemId = Order.OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); + // + } + Console.Write("\r"); + Console.WriteLine("Processed {0} total records.", record); + } + } + } + } + public void ProcessFbaReturnsData(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Starting TransposeFbaReturnsReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int stockJournalTypeId = 9; + + try + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaCustomerReturn WHERE IsProcessed=0 " + + "ORDER BY [return-date];" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaCustomerReturnID"); + int index02 = reader.GetOrdinal("return-date"); + int index03 = reader.GetOrdinal("sku"); + int index04 = reader.GetOrdinal("quantity"); + int index05 = reader.GetOrdinal("order-id"); + int index06 = reader.GetOrdinal("detailed-disposition"); + int index07 = reader.GetOrdinal("status"); + int index08 = reader.GetOrdinal("reason"); + int index09 = reader.GetOrdinal("customer-comments"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + + // create the match string + string matchString = "<_GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA_>"; + string status = reader.GetString(index07); + string disposition = reader.GetString(index06); + + if (string.Equals(status, "Reimbursed", StringComparison.OrdinalIgnoreCase)) + { + matchString = matchString + ""; + } + else + { + if (string.Equals(disposition, "SELLABLE", StringComparison.OrdinalIgnoreCase)) + { + matchString = matchString + ""; + } + else + { + matchString = matchString + ""; + } + } + + int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, yype is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + if (transactionTypeId == 0) + { + int temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchString); + continue; + } + + // import data + int importTableId = reader.GetInt32(index01); + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + string sku = reader.GetString(index03); + int quantity = reader.GetInt32(index04); + string reference = reader.GetString(index05); + int orderChannelId = Order.OrderQuery.GetSaleChannelIdByAmazonOrderId(sqlConnectionString, reference); + int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, reference, true); + string detail = + "Amazon Assessment: " + disposition + Environment.NewLine + + "Status: " + reader.GetString(index07) + Environment.NewLine + + "Customer Return Reason: " + reader.GetString(index08); + if (!reader.IsDBNull(index09)) + { detail = detail + Environment.NewLine + "Customer Comments: " + reader.GetString(index09); } + + int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + if (skuId < 1) + { transposeSkip = transposeSkip + 1; continue; } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + + int transactionId = 0; + if (transactionTypeId > 0) + { transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeId, skuId, quantity, orderId, "", detail, false, 0); } + else if (quantity == 0) + { transactionId = 0; } + + using (SqlCommand updateCmd = new SqlCommand( + "UPDATE tblImportFbaCustomerReturn " + + "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "WHERE ImportFbaCustomerReturnID=@importTableId;", + transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + scope.Complete(); + transposeCount = transposeCount + 1; + } + } + } + Console.Write("\r"); + } + } + } + } + MiscFunction.EventLogInsert("TransposeFbaReturnsReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaReturnsReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting TransposeFbaReturnsReport(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + } + public void ProcessFbaAdustmentData(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Starting TransposeFbaAdustmentReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int stockJournalTypeId = 8; + + // create dictionary of known adjustment codes and searchString + Dictionary adjCodes = new Dictionary(); + adjCodes.Add("1", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><1><+ve>"); + adjCodes.Add("2", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><2><-ve>"); + adjCodes.Add("3", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><3><+ve>"); + adjCodes.Add("4", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><4><-ve>"); + adjCodes.Add("5", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><5><-ve>"); + adjCodes.Add("6", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><6><-ve>"); + adjCodes.Add("D", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("E", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("F", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><+ve>"); + adjCodes.Add("H", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("J", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><+ve>"); + adjCodes.Add("K", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("M", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("N", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><+ve>"); + adjCodes.Add("O", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("P", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_>

<+ve>"); + adjCodes.Add("Q", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("U", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + adjCodes.Add("X", "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"); + + try + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaInventoryAdjustmentReport WHERE IsProcessed=0 " + + "ORDER BY [adjusted-date], ImportFbaInventoryAdjustmentReportID DESC;" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaInventoryAdjustmentReportID"); + int index02 = reader.GetOrdinal("adjusted-date"); + int index03 = reader.GetOrdinal("sku"); + int index04 = reader.GetOrdinal("quantity"); + int index05 = reader.GetOrdinal("transaction-item-id"); + int index06 = reader.GetOrdinal("reason"); + int index07 = reader.GetOrdinal("disposition"); + int index08 = reader.GetOrdinal("fnsku"); + int index09 = reader.GetOrdinal("fulfillment-center-id"); + + while (reader.Read()) + { + int importTableId = reader.GetInt32(index01); + record = record + 1; + bool addTransaction = true; + Console.Write("\rProcessing record: " + record); + + string matchString = ""; + string reasonCode = reader.GetString(index06); + string disposition = reader.GetString(index07); + if (adjCodes.ContainsKey(reasonCode)) + { + matchString = adjCodes[reasonCode] + "<" + disposition + ">"; + } + else if (reasonCode.Length > 0) + { + matchString = "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><" + reasonCode + "><" + disposition + ">"; + } + else + { + MiscFunction.EventLogInsert( + "Aborted TransposeFbaAdustmentReport(), no reason code was found in import table/file. Check imput data.", + 1); + return; + } + + int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 By default, new unreviewed type will return 0 to skip transpose. + * if enabled, new unreviewed type will return id, data will be transposed to table, reconciliation will pickup new items + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + if (transactionTypeId == 0) + { + transactionTypeId = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchString); + } + + // not used any more, stock reconciliation will pickup new types + //if (transactionTypeId == 0) + //{ + // string errorMessage = + // "New transaction-type created/detected while running TransposeFbaAdustmentReport. Stock transaction table incomplete, update transaction-type table and run import/transpose again before stock reconciliation. WHERE ImportFbaInventoryAdjustmentReportID=" + importTableId; + // //MiscFunction.EventLogInsert(errorMessage, 1); + // throw new Exception(errorMessage); + //} + + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + string sku = reader.GetString(index03); + string fnsku = reader.GetString(index08); + string fulfillmentCenterId = reader.GetString(index09); + int quantity = reader.GetInt32(index04); + if (quantity < 0) { quantity = quantity * -1; } + string reference = reader.GetString(index05); + + int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + int transactionId = 0; + + if (quantity == 0) + { + // this will set record IsProcessed=True and StockTransactionID=Null + transactionId = 0; + } + + /* Special Case - Found Inventory + * + * No transaction table reconciliation issues if sku is lost before it is found. However, transactions + * will be un-reconcilable if sku is found before it is lost. In this case, hold 'found' transaction(s) + * in import table. When a corresponding sku lost is posted, transfer 'found' transaction over + * to transaction table and manually reconcile. + * + * Additional issues with points above (and how code is set up), misplaced and found do not always balance + * (i.e. F - M <> 0). An sku lost in a inbound shipment can be found, but will not get registered as misplaced. + */ + + // always add 'misplaced' inventory to transaction table + else if (false) //(reasonCode == "F") + { + int misplacedTotal = 0; + int foundProcessedTotal = 0; + + // retrive total misplaced (all) + using (SqlCommand cmd2 = new SqlCommand(@" + SELECT Sum(quantity) As SumOfQuantity + FROM tblImportFbaInventoryAdjustmentReport + WHERE reason='M' AND sku=@sku; + ", transConn)) + { + cmd2.Parameters.AddWithValue("sku", sku); + //cmd2.Parameters.AddWithValue("disposition", disposition); + + object result = cmd2.ExecuteScalar(); + if (!(result == DBNull.Value)) + { + misplacedTotal = (int)result * -1; + } + } + + // retrive total found (processed) + using (SqlCommand cmd2 = new SqlCommand(@" + SELECT Sum(quantity) As SumOfQuantity + FROM tblImportFbaInventoryAdjustmentReport + WHERE reason='F' AND sku=@sku AND IsProcessed=1; + ", transConn)) + { + cmd2.Parameters.AddWithValue("sku", sku); + //cmd2.Parameters.AddWithValue("disposition", disposition); + + object result = cmd2.ExecuteScalar(); + if (!(result == DBNull.Value)) + { + foundProcessedTotal = (int)result; + } + } + + int misplacedAvaliable = misplacedTotal - foundProcessedTotal; + + // leave in import table, unprocessed + if (misplacedAvaliable < 1) + { + continue; + } + + // item can be copied striaght into trans table and marked as processed + else if (misplacedAvaliable == quantity) + { + // nothing to do + } + + // split record and add correct quantity to transaction table + else if (misplacedAvaliable < quantity) + { + // add new cloned record with unmatched quantity + using (SqlCommand cmd2 = new SqlCommand(@" + INSERT INTO tblImportFbaInventoryAdjustmentReport ( + [adjusted-date], [transaction-item-id], fnsku, sku, [fulfillment-center-id], quantity, reason, disposition, IsProcessed ) + VALUES ( + @adjustedDate, @transactionItemId, @fnsku, @sku, @fulfillmentCenterId, @quantity, @reason, @disposition, 0 ) + ", transConn)) + { + cmd2.Parameters.AddWithValue("adjustedDate", transactionDate.ToUniversalTime()); + cmd2.Parameters.AddWithValue("transactionItemId", transactionTypeId); + cmd2.Parameters.AddWithValue("fnsku", fnsku); + cmd2.Parameters.AddWithValue("sku", sku); + cmd2.Parameters.AddWithValue("fulfillmentCenterId", fulfillmentCenterId); + cmd2.Parameters.AddWithValue("quantity", (quantity - misplacedAvaliable)); + cmd2.Parameters.AddWithValue("reason", reasonCode); + cmd2.Parameters.AddWithValue("disposition", disposition); + + cmd2.ExecuteNonQuery(); + } + + quantity = misplacedAvaliable; + + // update quantity of soon to be processed record (added to trans table) + using (SqlCommand cmd2 = new SqlCommand(@" + UPDATE tblImportFbaInventoryAdjustmentReport + SET quantity=@quantity + WHERE ImportFbaInventoryAdjustmentReportID=@importTableId + ", transConn)) + { + cmd2.Parameters.AddWithValue("quantity", quantity); + cmd2.Parameters.AddWithValue("importTableId", importTableId); + + cmd2.ExecuteNonQuery(); + } + } + + else if (misplacedAvaliable > quantity) + { + // nothing to do + } + + // should never get here + else + { + throw new Exception("Shit the bed, 'unreachable' code has been reached..."); + } + + + + //// very old code + //using (SqlCommand cmd2 = new SqlCommand(@" + //SELECT StockTransactionID, Quantity FROM tblStockTransaction + //WHERE StockTransactionTypeID=@stockTransactionTypeId AND SkuID=@skuId AND Quantity>0 AND IsProcessed=0 + //ORDER BY TransactionDate + //", transConn)) + //{ + // // retrive transaction type ids + // int oppTransactionTypeId = 0; + // if (reasonCode == "F") + // { + // oppTransactionTypeId = GeneralQueries.GetStockTransactionTypeId(sqlConnectionString, adjCodes["M"] + "<" + disposition + ">"); + // } + // else + // { + // oppTransactionTypeId = GeneralQueries.GetStockTransactionTypeId(sqlConnectionString, adjCodes["F"] + "<" + disposition + ">"); + // } + + // if (oppTransactionTypeId < 1) + // { + // continue; + // } + + // cmd2.Parameters.AddWithValue("stockTransactionTypeId", oppTransactionTypeId); + // cmd2.Parameters.AddWithValue("skuId", skuId); + // //cmd2.Parameters.AddWithValue("quantity", quantity); + + // using (SqlDataReader reader2 = cmd2.ExecuteReader()) + // { + // if (reader2.HasRows) + // { + // while (reader2.Read() && quantity > 0) + // { + // transactionId = reader2.GetInt32(0); + // int quantityAvaliable = reader2.GetInt32(1); + + // // case: only transaction quantity requires update i.e. there is qty remaining + // if (quantityAvaliable > quantity) + // { + // quantityAvaliable = quantityAvaliable - quantity; + + // using (SqlCommand cmd3 = new SqlCommand(@" + // UPDATE tblStockTransaction + // SET Quantity=@quantity + // WHERE StockTransactionID=@transactionId + // ", transConn)) + // { + // cmd3.Parameters.AddWithValue("transactionId", transactionId); + // cmd3.Parameters.AddWithValue("quantity", quantityAvaliable); + // cmd3.ExecuteNonQuery(); + + // quantity = 0; + // } + // } + // // case: delete transaction as quantity availiable is <= quantity + // else + // { + // using (SqlCommand cmd3 = new SqlCommand(@" + // UPDATE tblImportFbaInventoryAdjustmentReport + // SET StockTransactionID=NULL + // WHERE StockTransactionID=@transactionId + // ", transConn)) + // { + // cmd3.Parameters.AddWithValue("transactionId", transactionId); + // cmd3.ExecuteNonQuery(); + // } + // using (SqlCommand cmd3 = new SqlCommand(@" + // DELETE FROM tblStockTransaction + // WHERE StockTransactionID=@transactionId + // ", transConn)) + // { + // cmd3.Parameters.AddWithValue("transactionId", transactionId); + // cmd3.ExecuteNonQuery(); + // } + // transactionId = 0; + // quantity = quantity - quantityAvaliable; + // } + // } + // if (quantity == 0) + // { + // addTransaction = false; + // } + // } + // else + // { + // //do nothing, leave entry uneffected + // addTransaction = true; + // } + // } + //} + } + + // usual case + if (transactionTypeId > 0 && addTransaction == true) + { + transactionId = Stock.StockReconciliation.StockTransactionInsert( + sqlConnectionString, transactionDate, transactionTypeId, skuId, quantity, 0, reference, "", false, 0 + ); + } + + using (SqlCommand updateCmd = new SqlCommand( + "UPDATE tblImportFbaInventoryAdjustmentReport " + + "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "WHERE ImportFbaInventoryAdjustmentReportID=@importTableId;", + transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + scope.Complete(); + transposeCount = transposeCount + 1; + } + } + } + Console.Write("\r"); + } + } + + } + } + MiscFunction.EventLogInsert("TransposeFbaAdustmentReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaAdustmentReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting TransposeFbaAdustmentReport(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + + return; + } + public void WIP_ProcessFbaReimbursementData(string sqlConnectionString) + { + /* + * Not to be used for stock reconciliation! A single stock item can have multiple reimburesements aginst it. + * Only use to move lost inventory to Amazon ownership (even then, with some caveats!) + * + * generally any lost or damaged stock goes to lost and found (and is hence written off) + * once amazon have reimbursed (confitmation via this report) the stock is then move to amazon owvership + * and also the 'Cost of goods' amounts moved to the appropreate account id + */ + + MiscFunction.EventLogInsert("Starting TransposeFbaRemovalOrderReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int stockJournalTypeId = 11; + + try + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaReimbursementReport WHERE IsProcessed=0 " + + "ORDER BY [approval-date];" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaReimbursementReportID"); + int index02 = reader.GetOrdinal("approval-date"); + int index03 = reader.GetOrdinal("reimbursement-id"); + int index04 = reader.GetOrdinal("reason"); + int index05 = reader.GetOrdinal("sku"); + int index06 = reader.GetOrdinal("quantity-reimbursed-total"); + int index07 = reader.GetOrdinal("quantity-reimbursed-Inventory"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + + int invRecived = reader.GetInt32(index07); + string matchStringPos = ""; + int transactionTypeIdPos = 0; + + // get transtypeIds for qty transaferred to amazon ownership + string matchStringNeg = "<_GET_FBA_REIMBURSEMENTS_DATA_><-ve><" + reader.GetString(index04) + ">"; + int transactionTypeIdNeg = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + if (invRecived > 0) + { + matchStringPos = "<_GET_FBA_REIMBURSEMENTS_DATA_><+ve><" + reader.GetString(index04) + ">"; + transactionTypeIdPos = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + } + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + if (transactionTypeIdNeg == 0 || (transactionTypeIdPos == 0 && invRecived > 0)) + { + transposeSkip = transposeSkip + 1; + int temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchStringNeg); + if (transactionTypeIdPos == 0 && invRecived > 0) + { + temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchStringPos); + } + continue; + } + + int importTableId = reader.GetInt32(index01); + DateTime transactionDate = DateTime.SpecifyKind(reader.GetDateTime(index02), DateTimeKind.Utc); + string sku = reader.GetString(index05); + string reference = reader.GetString(index03); + + int quantityTotal = reader.GetInt32(index06); + int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, reader.GetString(index05), true); + if (skuId < 1) + { + transposeSkip = transposeSkip + 1; + continue; + } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + + int transactionId = 0; + if (transactionTypeIdNeg > 0) + { + transactionId = Stock.StockReconciliation.StockTransactionInsert( + sqlConnectionString, transactionDate, transactionTypeIdNeg, skuId, quantityTotal, 0, reference); + } + if (transactionTypeIdPos > 0) + { + int temp = Stock.StockReconciliation.StockTransactionInsert( + sqlConnectionString, transactionDate, transactionTypeIdPos, skuId, invRecived, 0, reference); + } + + using (SqlCommand updateCmd = new SqlCommand(@" + UPDATE + tblImportFbaReimbursementReport + SET + StockTransactionID=@transactionId, + IsProcessed=1 + WHERE + ImportFbaReimbursementReportID=@importTableId; + ", transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + scope.Complete(); + transposeCount = transposeCount + 1; + } + } + } + Console.Write("\r"); + } + } + } + } + MiscFunction.EventLogInsert("ProcessFbaReimbursementData() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaRemovalOrderReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting ProcessFbaReimbursementData(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + } + public void ProcessReportFbaRemovalOrder(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Starting TransposeFbaRemovalOrderReport()"); + int transposeCount = 0; + int transposeSkip = 0; + int stockJournalTypeId = 10; + + try + { + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT * FROM tblImportFbaRemovalOrderReport WHERE IsProcessed=0 " + + "ORDER BY [request-date];" + , conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int record = 0; + int index01 = reader.GetOrdinal("ImportFbaRemovalOrderReportID"); + int index02 = reader.GetOrdinal("request-date"); + int index03 = reader.GetOrdinal("sku"); + //int index04 = reader.GetOrdinal("requested-quantity"); + int index05 = reader.GetOrdinal("order-id"); + int index06 = reader.GetOrdinal("order-type"); + int index07 = reader.GetOrdinal("order-status"); + int index08 = reader.GetOrdinal("disposition"); + int index09 = reader.GetOrdinal("disposed-quantity"); + int index10 = reader.GetOrdinal("shipped-quantity"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: " + record); + + // skip if order is not "Completed" status + if (!(reader.GetString(index07) == "Completed")) { continue; } + + string matchString = "<_GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA_><" + + reader.GetString(index06) + "><" + reader.GetString(index08) + ">"; + int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type is new or has not been reviewed yet + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + if (transactionTypeId == 0) + { + int temp = Stock.StockJournal.StockTransactionTypeIdInsert(sqlConnectionString, stockJournalTypeId, matchString); + transposeSkip = transposeSkip + 1; + continue; + } + + int importTableId = reader.GetInt32(index01); + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + string sku = reader.GetString(index03); + string reference = reader.GetString(index05); + + int quantity = 0; + int skuId = 0; + if (!reader.IsDBNull(index09)) + { quantity = reader.GetInt32(index09); } + if (!reader.IsDBNull(index10)) + { quantity = reader.GetInt32(index10); } + if (quantity == 0) + { transactionTypeId = -1; } + else + { skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); } + if (skuId < 1) + { transposeSkip = transposeSkip + 1; continue; } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + + int transactionId = 0; + if (transactionTypeId > 0) + { transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeId, skuId, quantity, 0, reference, "", false, 0); } + + using (SqlCommand updateCmd = new SqlCommand( + "UPDATE tblImportFbaRemovalOrderReport " + + "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "WHERE ImportFbaRemovalOrderReportID=@importTableId;", + transConn)) + { + if (transactionId == 0) { updateCmd.Parameters.AddWithValue("@transactionId", DBNull.Value); } + else { updateCmd.Parameters.AddWithValue("@transactionId", transactionId); } + updateCmd.Parameters.AddWithValue("@importTableId", importTableId); + + updateCmd.ExecuteNonQuery(); + } + scope.Complete(); + transposeCount = transposeCount + 1; + } + } + } + Console.Write("\r"); + } + } + } + } + MiscFunction.EventLogInsert("TransposeFbaRemovalOrderReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); + if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaRemovalOrderReport() operation.", 2); } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Exception catch, aborting TransposeFbaRemovalOrderReport(), see detailed info. " + + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); + } + } + + public static int StockTransactionInsert(string sqlConnectionString, DateTime transactionUtcDate, int transactionTypeId, int skuId, int quantity, + int foreignKey = 0, string reference = "", string detail = "", bool isProcessed = false, int stockJournalId = 0) + { + transactionUtcDate = DateTime.SpecifyKind(transactionUtcDate, DateTimeKind.Utc); + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblStockTransaction ( TransactionDate, StockTransactionTypeID, ForeignKey, SkuID, Quantity, Reference, Detail, IsProcessed, StockJournalID ) " + + "OUTPUT INSERTED.StockTransactionID " + + "VALUES (@transactionDate, @transactionTypeId, @foreignKey, @skuId, @Quantity, @reference, @detail, @isProcessed, @StockJournalId );", + sqlConn)) + { + cmd.Parameters.AddWithValue("@transactionDate", transactionUtcDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); + cmd.Parameters.AddWithValue("@skuId", skuId); + cmd.Parameters.AddWithValue("@Quantity", quantity); + if (foreignKey == 0) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@foreignKey", foreignKey); } + if (reference == "") { cmd.Parameters.AddWithValue("@reference", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reference", reference); } + if (detail == "") { cmd.Parameters.AddWithValue("@detail", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@detail", detail); } + if (isProcessed == false) { cmd.Parameters.AddWithValue("@isProcessed", 0); } + else { cmd.Parameters.AddWithValue("@isProcessed", 1); } + if (stockJournalId == 0) { cmd.Parameters.AddWithValue("@StockJournalId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId); } + + + int transactionId = Convert.ToInt32(cmd.ExecuteScalar()); + return transactionId; + } + } + } + + // iterates through the stock transaction table and inserts stock journal entries, where applicable + // N.B. This function does not make allowances for status' that can create stock (i.e. if a status does not have stock available, this function will halt processing rows) + public ReconcileStockTransactionsResult ReconcileStockTransactions(string sqlConnectionString, bool updateTransactions) + { + // create the return object + ReconcileStockTransactionsResult returnResult = new ReconcileStockTransactionsResult(); + + string currentMethodName = nameof(ReconcileStockTransactions); + //bool returnComplete = false; + //string returnMessage = ""; + //string returnDetails = ""; + + // ensure import table have been processed into transaction table without exception + if (updateTransactions == true) + { + try + { + var preCheck = new StockReconciliation(); + preCheck.ProcessFbaStockImportData(sqlConnectionString); + } + catch (Exception ex) + { + returnResult.ProgressMessage = "Precheck failed: " + ex.Message; + return returnResult; + } + } + + MiscFunction.EventLogInsert("Starting ReconcileStockTransactions()"); + int record = 0; + int recordSkip = 0; + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + string sqlPartString = @" + FROM tblStockTransaction INNER JOIN + tblStockTransactionType ON tblStockTransaction.StockTransactionTypeID = tblStockTransactionType.StockTransactionTypeID + WHERE tblStockTransaction.IsProcessed = 0 AND tblStockTransaction.SkuID IS NOT NULL AND tblStockTransaction.Quantity IS NOT NULL + AND ( tblStockTransactionType.StockJournalEntryEnabled = 1 OR tblStockTransactionType.IsNewReviewRequired = 1 ) "; + + + // get row count of record set + using (SqlCommand cmd = new SqlCommand("SELECT COUNT (tblStockTransaction.StockTransactionID) " + sqlPartString, conn)) + { + returnResult.ItemsRemaining = (int)cmd.ExecuteScalar(); + returnResult.ItemsCompleted = 0; + } + + // order by stocktransId desc = Amazon reports are listed in datetime ASC order, some reports have date only, however I have reason to believe these are in time order + // also. adding this means they at least get processed in the correct order (maybe)! + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblStockTransaction.StockTransactionID, tblStockTransaction.TransactionDate, tblStockTransaction.StockTransactionTypeID, tblStockTransaction.ForeignKey, + tblStockTransaction.Reference, tblStockTransaction.Detail, tblStockTransaction.SkuID, tblStockTransaction.Quantity, + tblStockTransactionType.StockJournalEntryEnabled, tblStockTransactionType.DebitStockStatusID, tblStockTransactionType.CreditStockStatusID, + tblStockTransactionType.StatusBalanceCheckRequired, tblStockTransactionType.CreditStatusFirstInFirstOut, tblStockTransactionType.IsNewReviewRequired, + tblStockTransactionType.FilterStockOnDateTime, tblStockTransactionType.MatchString, StockJournalTypeID " + + sqlPartString + @" + ORDER BY tblStockTransaction.TransactionDate ASC, tblStockTransaction.StockTransactionID DESC; + ", conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + int index01 = reader.GetOrdinal("StockTransactionID"); + int index02 = reader.GetOrdinal("TransactionDate"); + int index03 = reader.GetOrdinal("StockTransactionTypeID"); + int index04 = reader.GetOrdinal("SkuID"); + int index05 = reader.GetOrdinal("Quantity"); + int index06 = reader.GetOrdinal("StockJournalEntryEnabled"); + int index07 = reader.GetOrdinal("ForeignKey"); + int index08 = reader.GetOrdinal("Reference"); + int index09 = reader.GetOrdinal("Detail"); + int index10 = reader.GetOrdinal("CreditStatusFirstInFirstOut"); + int index11 = reader.GetOrdinal("DebitStockStatusID"); + int index12 = reader.GetOrdinal("CreditStockStatusID"); + int index13 = reader.GetOrdinal("IsNewReviewRequired"); + int index14 = reader.GetOrdinal("FilterStockOnDateTime"); + int index15 = reader.GetOrdinal("MatchString"); + int index16 = reader.GetOrdinal("StockJournalTypeID"); + + while (reader.Read()) + { + record = record + 1; + Console.Write("\rProcessing record: {0} ({1} skipped)", (record + recordSkip), recordSkip); + + // read values into variables + int stockTransactionId = reader.GetInt32(index01); + DateTime transactionDate = reader.GetDateTime(index02); + transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); + int transactionTypeID = reader.GetInt32(index03); + int skuId = reader.GetInt32(index04); + int quantity = reader.GetInt32(index05); + bool entryEnabled = reader.GetBoolean(index06); + int foreignKey = 0; + if (reader[index07] != DBNull.Value) + { foreignKey = reader.GetInt32(index07); } + string reference = ""; + if (reader[index08] != DBNull.Value) + { reference = reader.GetString(index08); } + string detail = ""; + if (reader[index09] != DBNull.Value) + { detail = reader.GetString(index09); } + bool orderAsc = reader.GetBoolean(index10); + // check/set debit/credit staus to 0 for special cases + int debitStatus = 0; + if (!reader.IsDBNull(index11)) + { debitStatus = reader.GetInt32(index11); } + int creditStatus = 0; + if (!reader.IsDBNull(index12)) + { creditStatus = reader.GetInt32(index12); } + bool filterStockOnDateTime = reader.GetBoolean(index14); + string matchString = ""; + if (!reader.IsDBNull(index15)) + { + matchString = reader.GetString(index15); + } + int journalTypeId = reader.GetInt32(index16); + + // setup return values + returnResult.StockTransactionId = stockTransactionId; + returnResult.StockTransactionTypeId = transactionTypeID; + returnResult.LastItemDateTime = transactionDate; + + + // stop if a new transactiontype is encountered + if (reader.GetBoolean(index13) == true) + { + returnResult.ProgressMessage = "New 'Transaction-Type' encountered"; + //Console.Write("\r"); + //MiscFunction.EventLogInsert(errMessage, 1); + goto Finish; + } + + // set debit/credit status' for special cases (i.e. NULL or 0 debit/credit ids in stockTransactionType table) + if (entryEnabled == true && (debitStatus == 0 || creditStatus == 0)) + { + // FBA Shipment Receipt +ve + if (matchString == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>" + || matchString == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><-ve>") + { + using (SqlCommand cmd2 = new SqlCommand("" + + "SELECT ShipmentStockStatusID FROM tblAmazonShipment WHERE ShipmentId=@reference", conn)) + { + cmd2.Parameters.Add(new SqlParameter("reference", reference)); + + object temp = cmd2.ExecuteScalar(); + if (temp != DBNull.Value) + { + // +ve shipment receipt + if (creditStatus == 0 && debitStatus > 0) + { creditStatus = Convert.ToInt32(temp); } + + // -ve shipment receipt + else if (debitStatus == 0 && creditStatus > 0) + { debitStatus = Convert.ToInt32(temp); } + + // something went wrong, raise error + else + { + returnResult.ProgressMessage = "Unable to retrive FBA shipment location/status from tblAmazonShipment for Amazon shipment '" + reference + "'."; + recordSkip = recordSkip + 1; + //Console.Write("\r"); + //MiscFunction.EventLogInsert("Debit or credit id value missing for shipment receipt WHERE StockTransactionTypeId=" + // + transactionTypeID, 1, "", default(DateTime), true, conn); + goto Finish; + } + } + } + } + // something went wrong, raise error + else + { + returnResult.ProgressMessage = "Coding required. Unhandled special case Transaction-Type encountered (Transaction-Type debit or credit is set to 0)."; + recordSkip = recordSkip + 1; + goto Finish; + } + } + + // make the changes + if (entryEnabled == false) + { + using (SqlCommand cmdIsProcessed = new SqlCommand(@" + UPDATE tblStockTransaction + SET IsProcessed=1 + WHERE StockTransactionID=@stockTransactionId + ", conn)) + { + cmdIsProcessed.Parameters.AddWithValue("@stockTransactionId", stockTransactionId); + + cmdIsProcessed.ExecuteNonQuery(); + } + } + else + { + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) + { + transConn.Open(); + List> list = new List>(); + if (filterStockOnDateTime == true) + { + list = Stock.StockJournal.StockReallocateBySkuId(sqlConnectionString, journalTypeId, skuId, quantity, debitStatus, creditStatus, orderAsc, + transactionDate.ToUniversalTime(), false); + } + else + { + list = Stock.StockJournal.StockReallocateBySkuId(sqlConnectionString, journalTypeId, skuId, quantity, debitStatus, creditStatus, orderAsc, + DateTime.UtcNow, false); + } + + // insufficient balance available + if (list == null) + { + // in special case (found inventory), continue + if (matchString.Contains("<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_>")) + { + continue; + } + else + { + returnResult.ProgressMessage = "Insurficent status/location balance to relocate stock"; + recordSkip = recordSkip + 1; + //Console.Write("\r"); + //MiscFunction.EventLogInsert("StockReallocateBySkuId() returned null (i.e. no avaiable stock to relocate), WHERE StockTransactionId=" + // + stockTransactionId, 2, "", default(DateTime), true, conn); + goto Finish; + } + } + + // fail safe + if ((list.Sum(c => c.Item2) > quantity)) + { + throw new Exception( + currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function" + + stockTransactionId); + //recordSkip = recordSkip + 1; + //Console.Write("\r"); + //MiscFunction.EventLogInsert("StockReallocateBySkuId() returned retuned a greater quantity than passed to function, WHERE StockTransactionId=" + // + stockTransactionId, 1, "", default(DateTime), true, conn); + //goto Finish; + } + + + using (SqlCommand cmdUpdate = new SqlCommand(@" + UPDATE tblStockTransaction + SET Quantity=@quantity, StockJournalID=@StockJournalId, IsProcessed=1 + WHERE StockTransactionID=@stockTransactionId + ", transConn)) + { + cmdUpdate.Parameters.AddWithValue("@StockJournalId", list[0].Item1); + cmdUpdate.Parameters.AddWithValue("@quantity", list[0].Item2); + cmdUpdate.Parameters.AddWithValue("@stockTransactionId", stockTransactionId); + + cmdUpdate.ExecuteNonQuery(); + } + quantity = quantity - list[0].Item2; + + // only nessecary when there is more than one StockJournal entry - stockTransction row will be copied and quantities split accordingly + if (list.Count > 1) + { + for (int i = 1; i < list.Count; i++) + { + int tempInt = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, + transactionDate.ToUniversalTime(), transactionTypeID, skuId, list[i].Item2, foreignKey, reference, detail, true, list[i].Item1); + quantity = quantity - list[i].Item2; + + //fail safe + if (quantity < 0) + { + throw new Exception( + currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function" + + stockTransactionId); + //MiscFunction.EventLogInsert("StockReallocateBySkuId() function assigned/returned more quantity than was passed to function", + // 1, "", default(DateTime), true, conn); + //goto Finish; + } + } + } + + // any remaining quantity not reallocated is added back to transaction table with no corresponding stock journal entry + if (quantity > 0) + { + int tempInt = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, + transactionDate.ToUniversalTime(), transactionTypeID, skuId, quantity, foreignKey, reference, detail, false, 0); + } + + scope.Complete(); + //} + } + } + } + returnResult.ItemsCompleted = returnResult.ItemsCompleted + 1; + returnResult.ItemsRemaining = returnResult.ItemsRemaining - 1; + } + } + // no records returned + else + { + returnResult.ReconciliationComplete = true; + returnResult.ProgressMessage = "No new transactions to process"; + goto Finish; + } + } + } + Console.Write("\r"); + } + + returnResult.ReconciliationComplete = true; + returnResult.ProgressMessage = "Stock transactions fully reconciled!"; + + Finish: + + MiscFunction.EventLogInsert("ProcessStockTransactions() compete. " + (record - recordSkip) + " total records processed, " + recordSkip + " rows uncompllete due to insurficent stock."); + MiscFunction.EventLogInsert("ProcessStockTransactions(), " + recordSkip + " rows skipped due to insurficent stock.", 2); + return returnResult; + } + + } + } + namespace Sku + { + public class SkuQuery + { + public static int SkuLookupId(string sqlConnectionString, string sku, bool enableLegacy = false) + { + // if enableLegacy = true, function will attempt to lookup value by sku count + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT skuSkuID FROM tblSku WHERE skuSkuNumber=@sku; + ", conn)) + { + cmd.Parameters.AddWithValue("@sku", sku); + + object obj = cmd.ExecuteScalar(); + if (!(obj == null)) + { + return Convert.ToInt32(obj); + } + } + // if that didn't work, lookup buy sku count + if (sku.Length == 6 & enableLegacy == true) + { + int skucount; + bool okay = int.TryParse(sku, out skucount); + if (okay) + { + using (SqlCommand cmd = new SqlCommand( + "SELECT skuSkuID FROM tblSku WHERE skuSkuCount=@skuCount;" + , conn)) + { + cmd.Parameters.AddWithValue("@skuCount", skucount); + + object obj = cmd.ExecuteScalar(); + if (!(obj == null)) + { + return Convert.ToInt32(obj); + } + else + { + return -1; + } + } + } + } + } + return -1; + } + + // used for retriving SKU that matched parameters, creates new if required, returns 0 if not found + public static int WIP_SkuGetSet(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, bool noMatchInsertNew) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // look for existing entry + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblSku.skuSkuID + FROM + tblSku + WHERE + (((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + object obj = cmd.ExecuteScalar(); + if (obj != null) + { + return (int)obj; + } + } + + // value check insert bool + if (noMatchInsertNew == false) + { + return 0; + } + else + { + // get this far, check tax code id is a valid for SKU + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblAccountTaxCode.InvoiceSales + FROM tblAccountTaxCode + WHERE (((tblAccountTaxCode.AccountTaxCodeID)=@accountTaxCodeId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!"); + } + else + { + bool result = (bool)obj; + if (result == false) + { + throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU."); + } + } + } + + // get info to create sku number + int skuCount; + int skuSuffix; + using (SqlCommand cmd = new SqlCommand("SELECT NEXT VALUE FOR SkuCountSequence;", conn)) + { + skuCount = (int)cmd.ExecuteScalar(); + } + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblSkuCondition.scnSkuNumberSuffix + FROM tblSkuCondition + WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@conditionId", conditionId); + + try + { + skuSuffix = (int)cmd.ExecuteScalar(); + } + catch (Exception ex) + { + throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." + + System.Environment.NewLine + "Error Message: " + ex.Message); + } + } + string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2"); + + // insert new sku + int skuId; + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblSku + (skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID) + OUTPUT INSERTED.skuSkuID + VALUES + (@skuNumber, @productId, @conditionId, @accountTaxCodeId) + ", conn)) + { + cmd.Parameters.AddWithValue("@skuNumber", skuNumber); + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + skuId = (int)cmd.ExecuteScalar(); + } + + scope.Complete(); + return skuId; + } + } + } + } + } + namespace Inventory + { + public class InventoryPricing + { + + public static void AmazonMinMaxTemp(string sqlConnectionString) + { + MiscFunction.ConsoleUpdate("Operation started."); + + // first command line git commit and push + + DateTime crTimeStamp = DateTime.SpecifyKind( DateTime.UtcNow, DateTimeKind.Utc); + int count = 0; + int exceptionSku = 0; + + string stringSql = @" + SELECT + b.SkuID + ,b.SkuTotalQuantity + ,b.SkuTotalCost + ,b.SkuAvgUnitCost + ,tblSku.skuProductID + ,tblSku.skuSkuConditionID + ,tblSku.AccountTaxCodeID + ,tblProductCategory.ProfitMinPercent + ,tblProductCategory.ProfitMinAmount + ,(tblAmazonFeeEstimate.ReferralFee / tblAmazonFeeEstimate.PriceToEstimateFeeListingPrice) As AmazonMargin + ,(tblAmazonFeeEstimate.VariableClosingFee + tblAmazonFeeEstimate.PerItemFee + tblAmazonFeeEstimate.FBAFee + tblAmazonFeeEstimate.OtherFee_Exception) AS AmazonFees + ,tblAccountTaxCode.TaxRateMultiplierNet + ,tblAccountTaxCode.TaxRateNameShort + ,tblSkuCondition.IsFixedPrice + ,tblSkuCondition.CompetitivePriceMultiplierNew + ,tblSkuCondition.CompetitivePriceMultiplierMatch + ,tblSkuCondition.scnSkuNumberSuffix + FROM + ((((( + SELECT + a.SkuID, + Sum(a.SumOfQuantity) AS SkuTotalQuantity, + Sum(a.QuanityTimesUnitCost) AS SkuTotalCost, + Sum(a.QuanityTimesUnitCost)/Sum(a.SumOfQuantity) AS SkuAvgUnitCost + FROM + ( + SELECT + tblStock.SkuID, + Sum(tblStockJournalPost.Quantity) AS SumOfQuantity, + tblStockJournal.StockID, tblAccountStockCost.AmountUnit, + Sum([tblStockJournalPost].[Quantity])*[tblAccountStockCost].[AmountUnit] AS QuanityTimesUnitCost + FROM + (((tblStockJournalPost + INNER JOIN tblStockStatus + ON tblStockJournalPost.StockStatusID = tblStockStatus.StockStatusID) + INNER JOIN tblStockJournal ON tblStockJournalPost.StockJournalID = tblStockJournal.StockJournalID) + INNER JOIN tblAccountStockCost ON tblStockJournal.StockID = tblAccountStockCost.StockID) + INNER JOIN tblStock ON tblAccountStockCost.StockID = tblStock.StockID + WHERE + tblStockStatus.StockStatusTypeID=3 + OR tblStockStatus.StockStatusTypeID=4 + GROUP BY + tblStockJournal.StockID, + tblAccountStockCost.AmountUnit, + tblStock.SkuID + HAVING + Sum(tblStockJournalPost.Quantity)>0 + ) a + GROUP BY + a.SkuID + ) b + INNER JOIN tblSku ON b.SkuID = tblSku.skuSkuID) + INNER JOIN tblProduct ON tblSku.skuProductID = tblProduct.prdProductID) + LEFT JOIN tblAmazonFeeEstimate ON tblProduct.prdProductID = tblAmazonFeeEstimate.ProductIdentifier ) + INNER JOIN tblProductCategory ON tblProduct.ProductCategoryID = tblProductCategory.ProductCategoryID) + INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID + INNER JOIN tblSkuCondition ON tblSku.skuSkuConditionID = tblSkuCondition.scnSkuConditionID + "; + try + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // loop through table + using (var cmd01 = new SqlCommand(stringSql, conn)) + { + using (var reader01 = cmd01.ExecuteReader()) + { + if (reader01.HasRows) + { + + } + else + { + throw new Exception("Querying the database returned no records."); + } + + // get ordinlals + int ordinalSkuID = reader01.GetOrdinal("SkuID"); + int ordinalSkuTotalQuantity = reader01.GetOrdinal("SkuTotalQuantity"); + int ordinalSkuTotalCost = reader01.GetOrdinal("SkuTotalCost"); + int ordinalSkuAvgUnitCost = reader01.GetOrdinal("SkuAvgUnitCost"); + int ordinalProductId = reader01.GetOrdinal("skuProductID"); + int ordinalSkuConditionId = reader01.GetOrdinal("skuSkuConditionID"); + int ordinalAccountTaxCodeID = reader01.GetOrdinal("AccountTaxCodeID"); + int ordinalProfitMinPercent = reader01.GetOrdinal("ProfitMinPercent"); + int ordinalProfitMinAmount = reader01.GetOrdinal("ProfitMinAmount"); + int ordinalAmazonMargin = reader01.GetOrdinal("AmazonMargin"); + int ordinalAmazonFees = reader01.GetOrdinal("AmazonFees"); + int ordinalTaxRateMultiplierNet = reader01.GetOrdinal("TaxRateMultiplierNet"); + int ordinalTaxRateNameShort = reader01.GetOrdinal("TaxRateNameShort"); + int ordinalIsFixedPrice = reader01.GetOrdinal("IsFixedPrice"); + int ordinalCompetitivePriceMultiplierNew = reader01.GetOrdinal("CompetitivePriceMultiplierNew"); + int ordinalCompetitivePriceMultiplierMatch = reader01.GetOrdinal("CompetitivePriceMultiplierMatch"); + int ordinalSkuNumberSuffix = reader01.GetOrdinal("scnSkuNumberSuffix"); + + + while (reader01.Read()) + { + // other required variables + int skuId = reader01.GetInt32(ordinalSkuID); + exceptionSku = skuId; + int skuProductId = reader01.GetInt32(ordinalProductId); + int skuConditionId = reader01.GetInt32(ordinalSkuConditionId); + int skuTaxCodeId = reader01.GetInt32(ordinalAccountTaxCodeID); + decimal skuProfitMargin = reader01.GetDecimal(ordinalProfitMinPercent) / 100; + decimal skuAmazonMargin = decimal.Round(reader01.GetDecimal(ordinalAmazonMargin), 3); + decimal skuVatMargin = reader01.GetDecimal(ordinalTaxRateMultiplierNet); + string skuTaxRateName = reader01.GetString(ordinalTaxRateNameShort); + bool skuIsFixedPrice = reader01.GetBoolean(ordinalIsFixedPrice); + decimal skuCompetitivePriceMultiplierNew = reader01.GetDecimal(ordinalCompetitivePriceMultiplierNew); + decimal skuCompetitivePriceMultiplierMatch = reader01.GetDecimal(ordinalCompetitivePriceMultiplierMatch); + decimal skuTotalCost = reader01.GetDecimal(ordinalSkuTotalCost); + decimal skuPriceMinProfit = reader01.GetDecimal(ordinalProfitMinAmount); + decimal skuOrderChannelFee = reader01.GetDecimal(ordinalAmazonFees); + decimal crUnitAvgCost = reader01.GetDecimal(ordinalSkuAvgUnitCost); + int skuNumberSuffix = reader01.GetInt32(ordinalSkuNumberSuffix); + + + // STAGE 2 + // SKU current stock details (i.e. quantity, cost per unit, inventory age, etc.) + + + + // Stage 4 + // Set MIN Price + decimal crUnitAvgCostActual = crUnitAvgCost; + decimal crPriceMinAmountAuto; + decimal crPriceMinAmountFinal; + decimal crProfitMinAmount; + + // used loss, sells just to cover fees + if (skuNumberSuffix >= 11 && skuNumberSuffix <= 14) + { + if (crUnitAvgCost == 0) + { + skuVatMargin = 0m; + } + crUnitAvgCost = 0m; + skuProfitMargin = 0m; + crProfitMinAmount = 0m; + skuPriceMinProfit = 0m; + } + + if (skuTaxRateName == "MS" || skuTaxRateName == "GA") + { + crPriceMinAmountAuto = (5m * crUnitAvgCost + 6m * skuOrderChannelFee) / (-6m * skuProfitMargin - 6m * skuAmazonMargin + 5m); + //crPriceMinCalculatedTax = (crPriceMinAmountAuto - crUnitAvgCost) * (1 / 6); + crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; + } + else + { + crPriceMinAmountAuto = (crUnitAvgCost + skuOrderChannelFee) / (1 - (skuProfitMargin + skuAmazonMargin + skuVatMargin)); + //crPriceMinCalculatedTax = crPriceMinAmountAuto * skuVatMargin; + crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; + } + + // if profit margin is less than min required, redo + if (crProfitMinAmount < skuPriceMinProfit) + { + if (skuTaxRateName == "MS" || skuTaxRateName == "GA") + { + crPriceMinAmountAuto = (6m * skuPriceMinProfit + 5m * crUnitAvgCost + 6m * skuOrderChannelFee) / (-6m * skuAmazonMargin + 5m); + //crPriceMinCalculatedTax = (crPriceMinAmountAuto - crUnitAvgCost) * (1 / 6); + crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; + } + else + { + crPriceMinAmountAuto = (crUnitAvgCost + skuOrderChannelFee + skuPriceMinProfit) / (1 - (skuAmazonMargin + skuVatMargin)); + //crPriceMinCalculatedTax = crPriceMinAmountAuto * skuVatMargin; + crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; + } + } + + crPriceMinAmountFinal = crPriceMinAmountAuto; + + + // STAGE 6 + // Set MAX Price + decimal crPriceMaxAmountFinal; + + // CASE: Reset MAX-Price base & multiplier values (new record or switching back to auto) + // get competative price and apply multiplier + var request = new bnhtradeDatabaseClient.Product.ProductQuery(); + var compPrice = request.ProductCompetitivePriceGet(sqlConnectionString, skuProductId, 10); + if (compPrice.price == null || compPrice.priceDate == null) + { + using (var cmd02 = new SqlCommand(@" + SELECT tblProduct.prdMaxPrice + FROM tblSku INNER JOIN tblProduct ON tblSku.skuProductID = tblProduct.prdProductID + WHERE (((tblSku.skuSkuID)=@skuId)); + ", conn)) + { + cmd02.Parameters.AddWithValue("@skuId", skuId); + + crPriceMaxAmountFinal = (decimal)cmd02.ExecuteNonQuery(); + } + } + else + { + crPriceMaxAmountFinal = (int)(compPrice.price * skuCompetitivePriceMultiplierNew); + } + + + // for fixed price items + if (skuIsFixedPrice == true) + { + using (var cmd02 = new SqlCommand(@" + SELECT tblSku.skuPriceMin, tblSku.skuPriceMax + FROM tblSku + WHERE (((tblSku.skuSkuID)=@skuId)); + ", conn)) + { + cmd02.Parameters.AddWithValue("@skuId", skuId); + + using (var reader02 = cmd02.ExecuteReader()) + { + decimal? max = null; + decimal? min = null; + reader02.Read(); + + if (!reader02.IsDBNull(0)) { min = reader02.GetDecimal(0); } + if (!reader02.IsDBNull(1)) { max = reader02.GetDecimal(1); } + + if (max == min && max != null) + { + crPriceMinAmountFinal = (decimal)min; + crPriceMaxAmountFinal = (decimal)max; + } + } + } + } + + // STAGE 7 + // Checks before update + + // max < min + if (crPriceMaxAmountFinal < crPriceMinAmountFinal) + { + crPriceMaxAmountFinal = crPriceMinAmountFinal; + } + + // this should be last check + // check for zero values (where there should not be any) -- this could be a life saver i.e. selling item for £0.00 + if (crPriceMinAmountFinal * crPriceMaxAmountFinal == 0) + { + throw new Exception("Min and/or Max value has comouted to 0 for SkuId=" + skuId); + } + + + // STAGE 8 + // Update sku table min/max values + + // round decimals for db comarison + crUnitAvgCost = decimal.Round(crUnitAvgCost, 2); + crUnitAvgCostActual = decimal.Round(crUnitAvgCostActual, 2); + crPriceMinAmountAuto = decimal.Round(crPriceMinAmountAuto, 2); + crPriceMinAmountFinal = decimal.Round(crPriceMinAmountFinal, 2); + crPriceMaxAmountFinal = decimal.Round(crPriceMaxAmountFinal, 2); + + // update sku table + using (var cmd03 = new SqlCommand(@" + UPDATE + tblSku + SET + tblSku.skuPriceMin = @priceMinAmountFinal + , tblSku.skuPriceMax = @priceMaxAmountFinal + ,tblSku.skuMinMaxExpire = Null + ,tblSku.skuSkuAvgCost = @unitAvgCost + ,tblSku.skuSkuAvgCostDate = @unitAvgCostDate + ,tblSku.skuPriceCompetitive = @compPrice + , tblSku.skuPriceCompetitiveDate = @compPriceDate + WHERE (((tblSku.skuSkuID)=@skuId)); + ", conn)) + { + cmd03.Parameters.AddWithValue("@priceMinAmountFinal", crPriceMinAmountFinal); + cmd03.Parameters.AddWithValue("@priceMaxAmountFinal", crPriceMaxAmountFinal); + cmd03.Parameters.AddWithValue("@unitAvgCost", crUnitAvgCostActual); + cmd03.Parameters.AddWithValue("@unitAvgCostDate", crTimeStamp.ToUniversalTime()); + if (compPrice.price == null) + { + cmd03.Parameters.AddWithValue("@compPrice", DBNull.Value); + cmd03.Parameters.AddWithValue("@compPriceDate", DBNull.Value); + } + else + { + cmd03.Parameters.AddWithValue("@compPrice", compPrice.price); + cmd03.Parameters.AddWithValue("@compPriceDate", DateTime.SpecifyKind((DateTime)compPrice.priceDate, DateTimeKind.Utc).ToUniversalTime()); + } + cmd03.Parameters.AddWithValue("@skuId", skuId); + + int updated = cmd03.ExecuteNonQuery(); + + if (!(updated > 0)) + { + throw new Exception("record not updated, for some reasonq"); + } + } + + count = count + 1; + } // drop out of query while loop here + } + } + } + MiscFunction.ConsoleUpdate("Complete. " + count + "SKUs updated."); + } + catch (Exception ex) + { + MiscFunction.ConsoleUpdate("Operation incomplete, stopped at SkuId=" + exceptionSku +". " + count + "SKUs updated."); + MiscFunction.ConsoleUpdate("Exception: " + ex.Message); + throw ex; + } + } + } + } + namespace Order + { + public class OrderQuery + { + public static int GetSaleChannelIdByName(string sqlConnectionString, string orderChannel, bool addChannel = false) + { + if (orderChannel == "Amazon.co.uk") { return 2; } + else if (orderChannel == "Amazon.de") { return 3; } + else if (orderChannel == "Amazon.fr") { return 4; } + else if (orderChannel == "Amazon.it") { return 5; } + else if (orderChannel == "Amazon.es") { return 6; } + else if (orderChannel.Length > 0) + { + int orderChannelId; + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand selectCmd = new SqlCommand(@" + SELECT OrderChannelID FROM tblOrderChannel WHERE OrderChannel=@orderChannel + ", sqlConn)) + { + selectCmd.Parameters.AddWithValue("@orderChannel", orderChannel); + object obj = selectCmd.ExecuteScalar(); + if ((addChannel = true) & (obj == null)) + { + using (SqlCommand insertCmd = new SqlCommand(@" + INSERT INTO tblOrderChannel ( OrderChannel ) + OUTPUT INSERTED.OrderChannelID + VALUES ( @orderChannel ) + ", sqlConn)) + { + insertCmd.Parameters.AddWithValue("@orderChannel", orderChannel); + object orderIdObject = selectCmd.ExecuteScalar(); + orderChannelId = Convert.ToInt32(orderIdObject); + return orderChannelId; + } + } + else + { + orderChannelId = Convert.ToInt32(obj); + return orderChannelId; + } + } + } + } + else { return -1; } + } + public static int GetOrderIdBySaleChannelRef(string sqlConnectionString, int saleChannelId, string saleChannelOrderRef, Boolean autoAdd = false) + { + + if (saleChannelId < 1) + { + throw new Exception("Order Channel Id must be greater than zero"); + } + if (saleChannelOrderRef.Length == 0) + { + throw new Exception("Incorrect Order Reference passed to method"); + } + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT OrderID FROM tblOrder WHERE OrderChannelID=@orderChannelId AND OrderChannelRef=@orderChannelRef + ", sqlConn)) + { + sqlConn.Open(); + sqlCommand.Parameters.AddWithValue("@orderChannelId", saleChannelId); + sqlCommand.Parameters.AddWithValue("@orderChannelRef", saleChannelOrderRef); + int orderId = new int(); + object obj = sqlCommand.ExecuteScalar(); + if (!(obj == null)) + { + orderId = Convert.ToInt32(obj); + return orderId; + } + else if (autoAdd == true) + { + using (SqlCommand sqlInsert = new SqlCommand(@" + INSERT INTO tblOrder ( OrderChannelID, OrderChannelRef ) + OUTPUT INSERTED.OrderID + VALUES ( @orderChannelId, @orderChannelRef ) + ", sqlConn)) + { + sqlInsert.Parameters.AddWithValue("@orderChannelId", saleChannelId); + sqlInsert.Parameters.AddWithValue("@orderChannelRef", saleChannelOrderRef); + orderId = (int)sqlInsert.ExecuteScalar(); + return orderId; + } + } + else + { + return -1; + } + } + } + } + catch (Exception) + { + throw; + } + } + public static int GetOrderItemIdBySaleChannelRef(string sqlConnectionString, int orderId, string saleChannelOrderItemRef, Boolean autoAdd = false) + { + + if (orderId < 1) + { + throw new Exception("Order Channel Id must be greater than zero"); + } + if (saleChannelOrderItemRef.Length == 0) + { + throw new Exception("Incorrect Order Reference passed to method"); + } + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT OrderItemID FROM tblOrderItem WHERE OrderID=@orderId AND OrderChannelItemRef=@orderChannelItemRef + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@orderId", orderId); + sqlCommand.Parameters.AddWithValue("@orderChannelItemRef", saleChannelOrderItemRef); + int orderItemId = new int(); + object obj = sqlCommand.ExecuteScalar(); + if (!(obj == null)) + { + orderItemId = Convert.ToInt32(obj); + return orderItemId; + } + else if (autoAdd == true) + { + using (SqlCommand sqlInsert = new SqlCommand(@" + INSERT INTO tblOrderItem ( OrderID, OrderChannelItemRef ) + OUTPUT INSERTED.OrderID + VALUES ( @orderId, @orderChannelItemRef ) + ", sqlConn)) + { + sqlInsert.Parameters.AddWithValue("@orderId", orderId); + sqlInsert.Parameters.AddWithValue("@orderChannelItemRef", saleChannelOrderItemRef); + orderItemId = (int)sqlInsert.ExecuteScalar(); + return orderItemId; + } + } + else + { + return -1; + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + public static int GetSaleChannelIdByAmazonOrderId(string sqlConnectionString, string amazonOrderId) + { + // private, as it gets sale channel from Fba order shipment table, which may only hold data for limited period of time + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + // retrive sale channel id + string saleChannelName; + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT [sales-channel] FROM tblImportFbaSaleShipment WHERE [amazon-order-id]=@amazonOrderId + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@amazonOrderId", amazonOrderId); + + object obj = sqlCommand.ExecuteScalar(); + if (!(obj == null)) + { + saleChannelName = Convert.ToString(obj); + } + else + { + throw new Exception("Could not retrive Amazon Order channel from imported order table, is the import table up to date?"); + } + } + return Order.OrderQuery.GetSaleChannelIdByName(sqlConnectionString, saleChannelName, true); + } + } + catch (Exception) + { + throw; + } + } + public static List GetFbaOrderStockIdBySku(string sqlConnectionString, int orderId, int skuId) + { + // return list of stockIds that are attached to an order sku + int stockStatusId; + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + // retrive info for FbaOrders - transactionTypeId and it's debit statusId + int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, "<_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_>"); + if (transactionTypeId < 1) + { + throw new Exception("Could not retirve stockTransactionId for amazon shipped orders"); + } + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT DebitStockStatusID FROM tblStockTransactionType WHERE StockTransactionTypeID=@transactionTypeId + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); + + object obj = sqlCommand.ExecuteScalar(); + if (obj == null || obj == DBNull.Value) + { + throw new Exception("Could not retrive debit status for amazon shipped orders"); + } + else + { + stockStatusId = Convert.ToInt32(obj); + } + } + + // retrive orderItemId(s) + List stockIdList = new List(); + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT StockJournalID FROM tblStockTransaction + WHERE StockTransactionTypeID=@transactionTypeId AND ForeignKey=@orderId AND SkuID=@skuId + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); + sqlCommand.Parameters.AddWithValue("@orderId", orderId); + sqlCommand.Parameters.AddWithValue("@skuId", skuId); + + using (SqlDataReader reader = sqlCommand.ExecuteReader()) + { + if (reader.HasRows) + { + int index01 = reader.GetOrdinal("StockJournalID"); + + while (reader.Read()) + { + stockIdList.Add(Stock.StockJournal.GetStockIdByStockJournalId(sqlConnectionString, reader.GetInt32(index01))); + } + } + else + { + return null; + } + } + } + // any further checking of available qquantities should be done by the calling function (to reduce to amount of stautus balance sql calls/checks) + return stockIdList; + } + } + catch (Exception) + { + throw; + } + } + + } + } + namespace AmazonMWS + { + public class AmazonMwsCredential + { + public string merchantId { get { return "A3RUYNKLWWM5KW"; } } + public string marketPlaceId { get { return "A1F83G8C2ARO7P"; } } // Amazon.co.uk + public string accessKeyId { get { return "AKIAJU45WSYVINEN45UA"; } } + public string secretAccessKey { get { return "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"; } } + public string applicationName { get { return "bnhtrade Database Client"; } } + public string applicationVersion { get { return "0.1"; } } + public string serviceURL { get { return "https://mws.amazonservices.co.uk"; } } + } + + public class AmazonMwsService + { + public MarketplaceWebService.MarketplaceWebService GetAmazonMwsService() + { + AmazonMwsCredential cred = new AmazonMwsCredential(); + MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); + + MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient( + cred.accessKeyId, + cred.secretAccessKey, + cred.applicationName, + cred.applicationVersion, + config); + + config.ServiceURL = cred.serviceURL; + return service; + } + } + + public class AmazonMwsProduct + { + public MarketplaceWebServiceProducts.MarketplaceWebServiceProducts GetAmazonMwsServiceProduct() + { + AmazonMwsCredential cred = new AmazonMwsCredential(); + MarketplaceWebServiceProductsConfig config = new MarketplaceWebServiceProductsConfig(); + + config.ServiceURL = cred.serviceURL; + + MarketplaceWebServiceProducts.MarketplaceWebServiceProducts service = new MarketplaceWebServiceProductsClient( + cred.applicationName, + cred.applicationVersion, + cred.accessKeyId, + cred.secretAccessKey, + config); + + return service; + } + + ///

+ /// + /// + /// + public List WIP_GetProductEstimateFee( FeesEstimateRequestList requestList) + { + AmazonMwsCredential cred = new AmazonMwsCredential(); + AmazonMwsProduct mwsProduct = new AmazonMwsProduct(); + MarketplaceWebServiceProducts.MarketplaceWebServiceProducts service = mwsProduct.GetAmazonMwsServiceProduct(); + + // Create a request. + GetMyFeesEstimateRequest request = new GetMyFeesEstimateRequest(); + request.SellerId = cred.merchantId; + request.MWSAuthToken = "example"; + //FeesEstimateRequestList requestList = new FeesEstimateRequestList(); + + //foreach (var item in itemList) + //{ + // string idType; + // if (item.IdValueIsAsin) { idType = "ASIN"; } + // else { idType = "SellerSku"; } + + // requestList.FeesEstimateRequest.Add(new FeesEstimateRequest + // { + // MarketplaceId = item.marketPlaceId, + // IdType = idType, + // IdValue = item.IdValue, + // PriceToEstimateFees = new PriceToEstimateFees + // { + // ListingPrice = new MoneyType { Amount = item.listingPrice, CurrencyCode = item.currencyCode }, + // //Shipping = new MoneyType { Amount = 3.5M, CurrencyCode = "GBP" }, + // //Points = new Points { PointsNumber = 0 } + // }, + // Identifier = "request_" + Guid.NewGuid().ToString(), + // IsAmazonFulfilled = true + // }); + //} + request.FeesEstimateRequestList = requestList; + + // define the list + GetMyFeesEstimateResult result = new GetMyFeesEstimateResult(); + //List resultList = new List(); + + try + { + int count = 0; + do + { + GetMyFeesEstimateResponse response = service.GetMyFeesEstimate(request); + if (response.IsSetGetMyFeesEstimateResult()) + { + result = response.GetMyFeesEstimateResult; + FeesEstimateResultList resultList = result.FeesEstimateResultList; + + List fees = resultList.FeesEstimateResult; + + return fees; + } + else + { + Thread.Sleep(500); + count++; + } + } while (count < 60); + throw new Exception("Response timeout"); + } + catch + { + throw; + } + } + + } + + } + public class AmazonReport + { + string merchantId = "A3RUYNKLWWM5KW"; + string marketplaceId = "A1F83G8C2ARO7P"; // Amazon.co.uk + string accessKeyId = "AKIAJU45WSYVINEN45UA"; + string secretAccessKey = "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"; + string applicationName = "AmazonApiApp"; + string applicationVersion = "0.1"; + string serviceURL = "https://mws.amazonservices.co.uk"; + public MarketplaceWebService.MarketplaceWebService GetMwsService() + { + MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); + + MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient( + accessKeyId, + secretAccessKey, + applicationName, + applicationVersion, + config); + + config.ServiceURL = serviceURL; + return service; + } + public List GetMwsReportList(GetReportListRequest requestList) + { + MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + + //define the list + GetReportListResult getReportListResult = new GetReportListResult(); + List reportInfoList = new List(); + + do + { + try + { + GetReportListResponse responseList = service.GetReportList(requestList); + if (responseList.IsSetGetReportListResult()) + { + getReportListResult = responseList.GetReportListResult; + reportInfoList = getReportListResult.ReportInfo; + } + MiscFunction.EventLogInsert("MWS 'GetReportListRequest' Successful, retrived list of " + reportInfoList.Count + " reports."); + return reportInfoList; + } + catch (MarketplaceWebServiceException ex) when (ex.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(73); + } + catch (MarketplaceWebServiceException ex) + { + MiscFunction.EventLogInsert( + "MWS 'GetReportListRequest' failed with exception: " + ex.Message, + 1, + "Caught Exception: " + ex.Message + + "\r\nResponse Status Code: " + ex.StatusCode + + "\r\nError Code: " + ex.ErrorCode + + "\r\nError Type: " + ex.ErrorType + + "\r\nRequest ID: " + ex.RequestId + + "\r\nResponseHeaderMetadata: " + ex.ResponseHeaderMetadata + + "\r\nXML:\r\n" + ex.XML + ); + return null; + } + } while (true); + + } + public string GetMwsReportById(string reportId) + { + // retrives report by reportId, saves to disk, and returns filepath + + MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + + string filePath = MiscFunction.GetTempFilePath(reportId + ".txt"); + + GetReportRequest reportRequest = new GetReportRequest(); + reportRequest.Merchant = merchantId; + //reportRequest.WithReportId(getReportListResult.ReportInfo[0].ReportId); + reportRequest.ReportId = reportId; + //reportRequest.WithReportId(reportID); + GetReportResponse reportResponse = new GetReportResponse(); + do + { + try + { + using (reportRequest.Report = File.Open(filePath, FileMode.Create, FileAccess.ReadWrite)) + { + reportResponse = service.GetReport(reportRequest); + MiscFunction.EventLogInsert("Succesfully downloaded Report '" + reportId + "'"); + } + return filePath; + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(80); + } + catch (MarketplaceWebServiceException e) + { + MiscFunction.EventLogInsert( + "MWS request for ReportId '" + reportId + "' failed. See extended details for MWS exception.", + 1, + "Request failed with MWS exception: " + e.Message + + "\r\nCaught Exception: " + e.Message + + "\r\nResponse Status Code: " + e.StatusCode + + "\r\nError Code: " + e.ErrorCode + + "\r\nError Type: " + e.ErrorType + + "\r\nRequest ID: " + e.RequestId + + "\r\nResponseHeaderMetadata: " + e.ResponseHeaderMetadata + + "\r\nXML:\r\n" + e.XML + ); + break; + } + catch (Exception e) + { + MiscFunction.EventLogInsert( + "MWS request for ReportId '" + reportId + "' failed. See extended details for exception thrown.", + 1, + e.ToString() + ); + } + } while (true); + return ""; + } + public string GetMwsReportByRequest(RequestReportRequest requestReport) + { + try + { + string targetRptType = requestReport.ReportType.ToString(); + MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + + string status; + RequestReportResponse requestResponse = new RequestReportResponse(); + while (true) + { + try + { + requestResponse = service.RequestReport(requestReport); + MiscFunction.ConsoleCountDown("Requested, status check in {0} seconds...", 30); + break; + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(60); + } + } + + while (true) + { + try + { + status = requestResponse.RequestReportResult.ReportRequestInfo.ReportProcessingStatus; + break; + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(60); + } + } + + GetReportRequestListRequest requestList = new GetReportRequestListRequest(); + requestList.Merchant = merchantId; + List myListzz = new List(); + + GetReportRequestListResponse requestListResponse = new GetReportRequestListResponse(); + while (true) + { + try + { + requestListResponse = service.GetReportRequestList(requestList); + break; + + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(60); + } + } + + GetReportRequestListResult requestListResult = new GetReportRequestListResult(); + while (true) + { + try + { + requestListResult = requestListResponse.GetReportRequestListResult; + break; + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(60); + } + } + + //wait until status = done + myListzz = requestListResult.ReportRequestInfo; + status = myListzz[0].ReportProcessingStatus.ToString(); + // Misc.EventLogInsert("Report status: " + status); + while ( + status != "_CANCELLED_" && + status != "_DONE_" && + status != "_DONE_NO_DATA_" + ) + { + try + { + MiscFunction.ConsoleCountDown("Request status '" + status + "' next check {0} seconds...", 30); + requestListResponse = service.GetReportRequestList(requestList); + requestListResult = requestListResponse.GetReportRequestListResult; + myListzz = requestListResult.ReportRequestInfo; + string newStatus = myListzz[0].ReportProcessingStatus.ToString(); + if (newStatus != status) + { + status = newStatus; + //Misc.EventLogInsert("Request status: " + status); + } + } + catch (MarketplaceWebServiceException e) when (e.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(60); + } + } + + if (status == "_CANCELLED_") + { + MiscFunction.EventLogInsert("Request result: " + status); + return "_CANCELLED_"; + } + else if (status == "_DONE_NO_DATA_") + { + MiscFunction.EventLogInsert("Request result: " + status); + return "_DONE_NO_DATA_"; + } + else + { + MiscFunction.EventLogInsert("Request result: " + status); + } + + GetReportListRequest listRequest = new GetReportListRequest(); + listRequest.Merchant = merchantId; + listRequest.ReportRequestIdList = new IdList(); + listRequest.ReportRequestIdList.Id.Add(requestResponse.RequestReportResult.ReportRequestInfo.ReportRequestId); + + GetReportListResponse listResponse = service.GetReportList(listRequest); + + GetReportListResult getReportListResult = listResponse.GetReportListResult; + + string reportId = getReportListResult.ReportInfo[0].ReportId.ToString(); + + return GetMwsReportById(reportId); + } + catch (MarketplaceWebServiceException e) + { + MiscFunction.EventLogInsert( + "Request failed with MWS exception: " + e.Message, + 1, + "Caught Exception: " + e.Message + + "\r\nResponse Status Code: " + e.StatusCode + + "\r\nError Code: " + e.ErrorCode + + "\r\nError Type: " + e.ErrorType + + "\r\nRequest ID: " + e.RequestId + + "\r\nResponseHeaderMetadata: " + e.ResponseHeaderMetadata + + "\r\nXML:\r\n" + e.XML + ); + return ""; + } + } + public List GetMwsReportByPeriod(string mwsReportEnum, DateTime startTime, DateTime endTime, int maxReportCount = 12, int reportMaxPeriod = 30) + { + // method downloads reports and returns a list of filePaths + + // startTime => + // endTime =< + + List reportIdList = new List(); + DateTime now = DateTime.UtcNow; + // time checks + if (startTime.ToUniversalTime() > now.ToUniversalTime()) + { + MiscFunction.EventLogInsert( + "The most current date supplied from the database is a head of the current time. stoping...", + 1, + MiscFunction.TraceMessage() + ); + reportIdList.Clear(); + return reportIdList; + } + else if (endTime.ToUniversalTime() > now.ToUniversalTime()) + { + MiscFunction.EventLogInsert( + "Get report end time is ahead of current time, re-setting to current time", + 2 + ); + } + + int reportCount = 0; + bool stopFlag = false; + endTime = startTime.AddDays(reportMaxPeriod); + do + { + reportCount = reportCount + 1; + now = DateTime.UtcNow.AddMinutes(0); + if (endTime.ToUniversalTime() > now.ToUniversalTime()) + { + endTime = now; + stopFlag = true; + } + // build the request + RequestReportRequest requestReport = new RequestReportRequest(); + requestReport.Merchant = merchantId; + requestReport.ReportType = mwsReportEnum; + requestReport.StartDate = startTime.ToUniversalTime(); + requestReport.EndDate = endTime.ToUniversalTime(); + + MiscFunction.EventLogInsert("Requesting '" + mwsReportEnum + "' '" + startTime.ToUniversalTime() + "' to '" + endTime.ToUniversalTime() + "'"); + string filePath = GetMwsReportByRequest(requestReport); + + if (filePath == "_DONE_NO_DATA_") + { + // do nothing, carry on with next iteration + } + else if (filePath == "_CANCELLED_") + { + /* + / this is probably MWS higher level throttling when requesting duplicate report + / for near real time reports waiting 30 minutes + / for daily reports wait 4 hours + */ + return reportIdList; + } + else if (filePath.Length > 0) + { + reportIdList.Add(filePath); + } + else + { + MiscFunction.EventLogInsert( + "Something went wrong downloading a full list of reports over the defined period. Report downloaded up until this point (if any) will be processed.", + 2 + ); + return reportIdList; + } + + // add 30 days onto start date and loop + startTime = endTime.AddSeconds(1); + endTime = endTime.AddDays(reportMaxPeriod); + if (startTime.ToUniversalTime() > now.ToUniversalTime()) + { + stopFlag = true; + } + if (reportCount == maxReportCount) + { + stopFlag = true; + } + } while (stopFlag == false); + + return reportIdList; + } + public bool SetMwsReportAcknowledgement(string reportId, bool acknowledged = true) + { + MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + + do + { + try + { + UpdateReportAcknowledgementsRequest request = new UpdateReportAcknowledgementsRequest(); + request.Merchant = merchantId; + request.Acknowledged = acknowledged; + var reportIdList = new IdList(); + reportIdList.Id.Add(reportId); + request.ReportIdList = reportIdList; + + UpdateReportAcknowledgementsResponse response = service.UpdateReportAcknowledgements(request); + if (response.IsSetUpdateReportAcknowledgementsResult()) + { + UpdateReportAcknowledgementsResult updateReportAcknowledgementsResult = response.UpdateReportAcknowledgementsResult; + List reportAckList = updateReportAcknowledgementsResult.ReportInfo; + MiscFunction.EventLogInsert("Report '" + reportAckList[0].ReportId + "' Acknowledgement set to '" + reportAckList[0].Acknowledged + "'"); + } + return true; + } + catch (MarketplaceWebServiceException ex) when (ex.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(80); + } + catch (MarketplaceWebServiceException ex) + { + MiscFunction.EventLogInsert( + "MWS 'UpdateReportAcknowledgementsRequest' failed with exception: " + ex.Message, + 1, + "Caught Exception: " + ex.Message + + "\r\nResponse Status Code: " + ex.StatusCode + + "\r\nError Code: " + ex.ErrorCode + + "\r\nError Type: " + ex.ErrorType + + "\r\nRequest ID: " + ex.RequestId + + "\r\nResponseHeaderMetadata: " + ex.ResponseHeaderMetadata + + "\r\nXML:\r\n" + ex.XML + ); + + Console.WriteLine("Caught Exception: " + ex.Message); + Console.WriteLine("Response Status Code: " + ex.StatusCode); + Console.WriteLine("Error Code: " + ex.ErrorCode); + Console.WriteLine("Error Type: " + ex.ErrorType); + Console.WriteLine("Request ID: " + ex.RequestId); + Console.WriteLine("XML: " + ex.XML); + Console.WriteLine("ResponseHeaderMetadata: " + ex.ResponseHeaderMetadata); + Console.ReadKey(); + break; + } + } while (true); + return false; + } + public bool ImportReportSettlementData(string sqlConnectionString, string filePath) + { + try + { + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + int settlementReportId = 0; + string settlementRef = ""; + bool marketPlaceUpdated = false; + decimal settlementAmount = 0m; + int lineNumber = 2; + int lineSkip = 0; + + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int indexSettlementId = Array.IndexOf(headers, "settlement-id"); + int indexSettlementStartDate = Array.IndexOf(headers, "settlement-start-date"); + int indexSettlementEndDate = Array.IndexOf(headers, "settlement-end-date"); + int indexDepositDate = Array.IndexOf(headers, "deposit-date"); + int indexTotalAmount = Array.IndexOf(headers, "total-amount"); + int indexCurrency = Array.IndexOf(headers, "currency"); + int indexTransactionType = Array.IndexOf(headers, "transaction-type"); + int indexOrderId = Array.IndexOf(headers, "order-id"); + int indexMerchantOrderId = Array.IndexOf(headers, "merchant-order-id"); + int indexAdjustmentId = Array.IndexOf(headers, "adjustment-id"); + int indexShipmentId = Array.IndexOf(headers, "shipment-id"); + int indexMarketplaceName = Array.IndexOf(headers, "marketplace-name"); + int indexAmountType = Array.IndexOf(headers, "amount-type"); + int indexAmountDescription = Array.IndexOf(headers, "amount-description"); + int indexAmount = Array.IndexOf(headers, "amount"); + int indexFulfillmentId = Array.IndexOf(headers, "fulfillment-id"); + // int indexPostedDate = Array.IndexOf(headers, "posted-date"); + int indexPostedDateTime = Array.IndexOf(headers, "posted-date-time"); + int indexOrderItemCode = Array.IndexOf(headers, "order-item-code"); + int indexMerchantOrderItemId = Array.IndexOf(headers, "merchant-order-item-id"); + int indexMerchantAdjustmentItemId = Array.IndexOf(headers, "merchant-adjustment-item-id"); + int indexSku = Array.IndexOf(headers, "sku"); + int indexQuantityPurchased = Array.IndexOf(headers, "quantity-purchased"); + int indexPromotionId = Array.IndexOf(headers, "promotion-id"); + + string currency = ""; + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineSkip = lineSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else if (lineNumber == 2) + { + // check if settlement has already been imported + using (SqlCommand sqlCommand = new SqlCommand( + "SELECT COUNT(*) FROM tblImportAmazonSettlementReport WHERE [settlement-id]=@settlementId;" + , sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@settlementId", long.Parse(items[indexSettlementId])); + int recordCount = (int)sqlCommand.ExecuteScalar(); + if (recordCount > 0) + { + MiscFunction.ConsoleUpdate("Settlement report already imported, skipping..."); + return true; + } + } + //set currencyId + //currencyId = GeneralQueries.GetCurrencyId(items[5]); + + //set currency + currency = items[indexCurrency]; + settlementAmount = decimal.Parse(items[indexTotalAmount].Replace(",", ".")); + + // insert + using (SqlCommand sqlCommand = new SqlCommand( + "INSERT INTO tblImportAmazonSettlementReport ( " + + "[settlement-id], [settlement-start-date], [settlement-end-date], [deposit-date], [total-amount], [currency] ) " + + "OUTPUT INSERTED.ImportAmazonSettlementReportID " + + "VALUES ( @settlementId, @settlementStartDate, @settlementEndDate, @depositDate, @settlementotalAmounttId, @currency );" + , sqlConn)) + { + // add parameters + if (indexSettlementId == -1 || items[indexSettlementId].Length == 0) { sqlCommand.Parameters.AddWithValue("@settlementId", DBNull.Value); } + else + { + settlementRef = items[indexSettlementId]; + sqlCommand.Parameters.AddWithValue("@settlementId", settlementRef); + } + + if (indexSettlementStartDate == -1 || items[indexSettlementStartDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@settlementStartDate", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@settlementStartDate", MiscFunction.ParseMwsReportDateTime(items[indexSettlementStartDate])); } + + if (indexSettlementEndDate == -1 || items[indexSettlementEndDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@settlementEndDate", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@settlementEndDate", MiscFunction.ParseMwsReportDateTime(items[indexSettlementEndDate])); } + + if (indexDepositDate == -1 || items[indexDepositDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@depositDate", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@depositDate", MiscFunction.ParseMwsReportDateTime(items[indexDepositDate])); } + + if (indexTotalAmount == -1 || items[indexTotalAmount].Length == 0) { sqlCommand.Parameters.AddWithValue("@totalAmount", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@settlementotalAmounttId", settlementAmount); } + + sqlCommand.Parameters.AddWithValue("@currency", currency); + + //if (currencyId == -1) { sqlCommand.Parameters.AddWithValue("@currencyId", DBNull.Value); } + //else { sqlCommand.Parameters.AddWithValue("@currencyId", currencyId); } + + //execute and retrive id + settlementReportId = (int)sqlCommand.ExecuteScalar(); + + } + } + else + { + //update market place name in main table, if required + if (marketPlaceUpdated == false && settlementReportId > 0 && items[indexMarketplaceName].Length > 1) + { + using (SqlCommand sqlCommand = new SqlCommand(@" + UPDATE tblImportAmazonSettlementReport + SET [marketplace-name]=@MarketplaceName + WHERE ImportAmazonSettlementReportID=@ImportAmazonSettlementReportID + ", sqlConn)) + { + sqlCommand.Parameters.AddWithValue("@MarketplaceName", items[indexMarketplaceName]); + sqlCommand.Parameters.AddWithValue("@ImportAmazonSettlementReportID", settlementReportId); + + sqlCommand.ExecuteNonQuery(); + marketPlaceUpdated = true; + } + } + + //insert report items + using (SqlCommand sqlCommand = new SqlCommand( + "INSERT INTO tblImportAmazonSettlementReportLine ( " + + "ImportAmazonSettlementReportID, [transaction-type], [order-id], [merchant-order-id], [adjustment-id], [shipment-id], [marketplace-name], " + + "[amount-type], [amount-description], [currency], [amount], [fulfillment-id], [posted-date-time], [order-item-code], " + + "[merchant-order-item-id], [merchant-adjustment-item-id], [sku], [quantity-purchased], [promotion-id] ) " + + "VALUES ( " + + "@ImportAmazonSettlementReportID, @TransactionType, @orderRef, @merchantOrderRef, @AdjustmentRef, @ShipmentRef, @MarketplaceName, " + + "@AmountType, @AmountDescription, @currency, @Amount, @FulfillmentRef, @PostedDateTimeUTC, @OrderItemCode, " + + "@MerchantOrderItemRef, @MerchantAdjustmentItemRef, @SkuNumber, @QuantityPurchased, @PromotionRef );" + , sqlConn)) + { + // add parameters + sqlCommand.Parameters.AddWithValue("@ImportAmazonSettlementReportID", settlementReportId); + + sqlCommand.Parameters.AddWithValue("@currency", currency); + + if (indexTransactionType == -1 || items[indexTransactionType].Length == 0) { sqlCommand.Parameters.AddWithValue("@TransactionType", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@TransactionType", items[indexTransactionType]); } + + if (indexOrderId == -1 || items[indexOrderId].Length == 0) { sqlCommand.Parameters.AddWithValue("@orderRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@orderRef", items[indexOrderId]); } + + if (indexMerchantOrderId == -1 || items[indexMerchantOrderId].Length == 0) { sqlCommand.Parameters.AddWithValue("@merchantOrderRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@merchantOrderRef", items[indexMerchantOrderId]); } + + if (indexAdjustmentId == -1 || items[indexAdjustmentId].Length == 0) { sqlCommand.Parameters.AddWithValue("@AdjustmentRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@AdjustmentRef", items[indexAdjustmentId]); } + + if (indexShipmentId == -1 || items[indexShipmentId].Length == 0) { sqlCommand.Parameters.AddWithValue("@ShipmentRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@ShipmentRef", items[indexShipmentId]); } + + if (indexMarketplaceName == -1 || items[indexMarketplaceName].Length == 0) { sqlCommand.Parameters.AddWithValue("@MarketplaceName", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@MarketplaceName", items[indexMarketplaceName]); } + + if (indexAmountType == -1 || items[indexAmountType].Length == 0) { sqlCommand.Parameters.AddWithValue("@AmountType", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@AmountType", items[indexAmountType]); } + + if (indexAmountDescription == -1 || items[indexAmountDescription].Length == 0) { sqlCommand.Parameters.AddWithValue("@AmountDescription", DBNull.Value); } + else + { + string amountDescription = items[indexAmountDescription]; + if (amountDescription.Length > 100) { amountDescription = amountDescription.Substring(0, 100); } + sqlCommand.Parameters.AddWithValue("@AmountDescription", amountDescription); + } + + if (indexAmount == -1 || items[indexAmount].Length == 0) { sqlCommand.Parameters.AddWithValue("@Amount", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@Amount", decimal.Parse(items[indexAmount].Replace(",", "."))); } + + if (indexFulfillmentId == -1 || items[indexFulfillmentId].Length == 0) { sqlCommand.Parameters.AddWithValue("@FulfillmentRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@FulfillmentRef", items[indexFulfillmentId]); } + + if (indexPostedDateTime == -1 || items[indexPostedDateTime].Length == 0) { sqlCommand.Parameters.AddWithValue("@PostedDateTimeUTC", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@PostedDateTimeUTC", MiscFunction.ParseMwsReportDateTime(items[indexPostedDateTime])); } + + if (indexOrderItemCode == -1 || items[indexOrderItemCode].Length == 0) { sqlCommand.Parameters.AddWithValue("@OrderItemCode", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@OrderItemCode", long.Parse(items[indexOrderItemCode])); } + + if (indexMerchantOrderItemId == -1 || items[indexMerchantOrderItemId].Length == 0) { sqlCommand.Parameters.AddWithValue("@MerchantOrderItemRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@MerchantOrderItemRef", long.Parse(items[indexMerchantOrderItemId])); } + + if (indexMerchantAdjustmentItemId == -1 || items[indexMerchantAdjustmentItemId].Length == 0) { sqlCommand.Parameters.AddWithValue("@MerchantAdjustmentItemRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@MerchantAdjustmentItemRef", items[indexMerchantAdjustmentItemId]); } + + if (indexSku == -1 || items[indexSku].Length == 0) { sqlCommand.Parameters.AddWithValue("@SkuNumber", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@SkuNumber", items[indexSku]); } + + if (indexQuantityPurchased == -1 || items[indexQuantityPurchased].Length == 0) { sqlCommand.Parameters.AddWithValue("@QuantityPurchased", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@QuantityPurchased", int.Parse(items[indexQuantityPurchased])); } + + if (indexPromotionId == -1 || items[indexPromotionId].Length == 0) { sqlCommand.Parameters.AddWithValue("@PromotionRef", DBNull.Value); } + else { sqlCommand.Parameters.AddWithValue("@PromotionRef", items[indexPromotionId]); } + + sqlCommand.ExecuteNonQuery(); + } + } + lineNumber = lineNumber + 1; + } + } + + //final check - settlement amount matches sum of inserted settlement lines + using (SqlCommand sqlCommand = new SqlCommand(@" + SELECT Sum(tblImportAmazonSettlementReportLine.amount) AS SumOfAmount + FROM tblImportAmazonSettlementReportLine + WHERE ImportAmazonSettlementReportID=@ImportAmazonSettlementReportID; + ", sqlConn)) + { + decimal sumOfAmount = -1.12345m; + + sqlCommand.Parameters.AddWithValue("@ImportAmazonSettlementReportID", settlementReportId); + sumOfAmount = (decimal)sqlCommand.ExecuteScalar(); + + if (sumOfAmount != settlementAmount) + { + MiscFunction.EventLogInsert("Error importing settlement id'" + settlementRef + "'. Sum of inserted settlement lines (" + sumOfAmount + + ") does not match settlement amount (" + settlementAmount + ").", 1); + return false; + } + } + scope.Complete(); + + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (2 + lineSkip)) + " total settlement items inserted"); + if (lineSkip > 0) + { + MiscFunction.EventLogInsert(lineSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + Console.ReadKey(); + return false; + } + return true; + } + public bool ImportReportFbaInventoryReceipt(string sqlConnectionString, string filePath, DateTime startDate) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineOutsideScope = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + // create notification if amazon add extra headers + if (columnCount > 7) + { + MiscFunction.EventLogInsert( + "Amazon have added a new column to their 'Fba Inventory Receipt' report, you may want to check this out.", + 2); + } + + int indexOfReceivedDate = Array.IndexOf(headers, "received-date"); + int indexOfFnsku = Array.IndexOf(headers, "fnsku"); + int indexOfSku = Array.IndexOf(headers, "sku"); + int indexOfProductName = Array.IndexOf(headers, "product-name"); + int indexOfQuantity = Array.IndexOf(headers, "quantity"); + int indexOfFbaShipmentId = Array.IndexOf(headers, "fba-shipment-id"); + int indexOfFulfillmentCenterId = Array.IndexOf(headers, "fulfillment-center-id"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + DateTime receivedDate = DateTime.Parse( + items[indexOfReceivedDate], + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal); + + //ensure line has recieved date <= startdate + // due to mws bug, downloaded report can contain records outside of the requested scope + if(receivedDate < startDate) + { + lineOutsideScope = lineOutsideScope + 1; + continue; + } + + string fnsku = items[indexOfFnsku]; + string sku = items[indexOfSku]; + int quantity = int.Parse(items[indexOfQuantity]); + string fbaShipemntId = items[indexOfFbaShipmentId]; + string fulfillmentCenterId = items[indexOfFulfillmentCenterId]; + + //insert report items + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblImportFbaInventoryReceiptReport ( " + + "[received-date], [fnsku], [sku], [quantity], [fba-shipment-id], [fulfillment-center-id] ) " + + "VALUES ( " + + "@receivedDate, @fnsku, @sku, @quantity, @FbaShipmentId, @FulfillmentCenterId );" + , sqlConn, trans)) + { + // add parameters + insertCmd.Parameters.AddWithValue("@receivedDate", receivedDate.ToUniversalTime()); + insertCmd.Parameters.AddWithValue("@fnsku", fnsku); + insertCmd.Parameters.AddWithValue("@sku", sku); + insertCmd.Parameters.AddWithValue("@quantity", quantity); + insertCmd.Parameters.AddWithValue("@fbaShipmentId", fbaShipemntId); + insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); + + insertCmd.ExecuteNonQuery(); + } + + + ////check for duplicate line in db + //using (SqlCommand cmd = new SqlCommand( + // "SELECT ImportFbaInventoryReceiptReportID FROM tblImportFbaInventoryReceiptReport " + + // "WHERE [received-date]=@receivedDate AND [fnsku]=@fnsku AND [fba-shipment-id]=@fbaShipmentId AND [fulfillment-center-id]=@fulfillmentCenterId;" + // , sqlConn, trans)) + //{ + // cmd.Parameters.AddWithValue("@receivedDate", receivedDate); + // cmd.Parameters.AddWithValue("@fnsku", fnsku); + // cmd.Parameters.AddWithValue("@fbaShipmentId", fbaShipemntId); + // cmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); + + // using (SqlDataReader sqlReader = cmd.ExecuteReader()) + // { + // if (sqlReader.HasRows == true) + // { + // lineDuplicateSkip = lineDuplicateSkip + 1; + // } + // else + // { + // } + // } + + //} + } + } + // only commit if records all complete with no errors -- ommiting duplcates relies on all records from one day being committed together + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (1 + lineErrorSkip + lineOutsideScope)) + " total report items inserted into db, " + lineOutsideScope + " item(s) outside of requested time scope where skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public bool ImportReportFbaSaleShipment(string sqlConnectionString, string filePath) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineDuplicateSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "amazon-order-id"); + int index02 = Array.IndexOf(headers, "merchant-order-id"); + int index03 = Array.IndexOf(headers, "shipment-id"); + int index04 = Array.IndexOf(headers, "shipment-item-id"); + int index05 = Array.IndexOf(headers, "amazon-order-item-id"); + int index06 = Array.IndexOf(headers, "merchant-order-item-id"); + int index07 = Array.IndexOf(headers, "purchase-date"); + int index08 = Array.IndexOf(headers, "payments-date"); + int index09 = Array.IndexOf(headers, "shipment-date"); + int index10 = Array.IndexOf(headers, "reporting-date"); + int index11 = Array.IndexOf(headers, "buyer-email"); + int index12 = Array.IndexOf(headers, "buyer-name"); + int index13 = Array.IndexOf(headers, "sku"); + int index14 = Array.IndexOf(headers, "quantity-shipped"); + int index15 = Array.IndexOf(headers, "currency"); + int index16 = Array.IndexOf(headers, "item-price"); + int index17 = Array.IndexOf(headers, "item-tax"); + int index18 = Array.IndexOf(headers, "shipping-price"); + int index19 = Array.IndexOf(headers, "shipping-tax"); + int index20 = Array.IndexOf(headers, "gift-wrap-price"); + int index21 = Array.IndexOf(headers, "gift-wrap-tax"); + int index22 = Array.IndexOf(headers, "recipient-name"); + int index23 = Array.IndexOf(headers, "ship-address-1"); + int index24 = Array.IndexOf(headers, "ship-address-2"); + int index25 = Array.IndexOf(headers, "ship-address-3"); + int index26 = Array.IndexOf(headers, "ship-city"); + int index27 = Array.IndexOf(headers, "ship-state"); + int index28 = Array.IndexOf(headers, "ship-postal-code"); + int index29 = Array.IndexOf(headers, "ship-country"); + int index30 = Array.IndexOf(headers, "ship-phone-number"); + int index31 = Array.IndexOf(headers, "bill-address-1"); + int index32 = Array.IndexOf(headers, "bill-address-2"); + int index33 = Array.IndexOf(headers, "bill-address-3"); + int index34 = Array.IndexOf(headers, "bill-city"); + int index35 = Array.IndexOf(headers, "bill-state"); + int index36 = Array.IndexOf(headers, "bill-postal-code"); + int index37 = Array.IndexOf(headers, "bill-country"); + int index38 = Array.IndexOf(headers, "item-promotion-discount"); + int index39 = Array.IndexOf(headers, "ship-promotion-discount"); + int index40 = Array.IndexOf(headers, "fulfillment-center-id"); + int index41 = Array.IndexOf(headers, "fulfillment-channel"); + int index42 = Array.IndexOf(headers, "sales-channel"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string amazonOrderId = items[index01]; + string merchantOrderid = items[index02]; + string shipmentId = items[index03]; + string shipmentItemId = items[index04]; + string amazonOrderItemId = items[index05]; + string merchantOrderItemId = items[index06]; + DateTime purchaseDate = DateTime.Parse(items[index07]); + DateTime paymentsDate = DateTime.Parse(items[index08]); + DateTime shipmentDate = DateTime.Parse(items[index09]); + DateTime reportingDate = DateTime.Parse(items[index10]); + string buyerEmail = items[index11]; + string buyerName = items[index12]; + string sku = items[index13]; + int quantityShipped = Int32.Parse(items[index14]); + string currency = items[index15]; + decimal itemPrice = decimal.Parse(items[index16]); + decimal itemTax = decimal.Parse(items[index17]); + decimal shippingPrice = decimal.Parse(items[index18]); + decimal shippingTax = decimal.Parse(items[index19]); + decimal giftWrapPrice = decimal.Parse(items[index20]); + decimal giftWrapTax = decimal.Parse(items[index21]); + string recipientName = items[index22]; + string shipAddress1 = items[index23]; + string shipAddress2 = items[index24]; + string shipAddress3 = items[index25]; + string shipCity = items[index26]; + string shipState = items[index27]; + string shipPostalCode = items[index28]; + string shipCountry = items[index29]; + string shipPhoneNumber = items[index30]; + string billAddress1 = items[index31]; + string billAddress2 = items[index32]; + string billAddress3 = items[index33]; + string billCity = items[index34]; + string billState = items[index35]; + string billPostalCode = items[index36]; + string billCountry = items[index37]; + string itemPromotionDiscount = items[index38]; + string shipPromotionDiscount = items[index39]; + string fulfillmentCenterId = items[index40]; + string fulfillmentChannel = items[index41]; + string salesChannel = items[index42]; + + //check for duplicate line in db + using (SqlCommand cmd = new SqlCommand( + "SELECT ImportFbaSaleShipmentID FROM tblImportFbaSaleShipment " + + "WHERE [shipment-item-id]=@shipmentItemId;" + , sqlConn, trans)) + { + cmd.Parameters.AddWithValue("@shipmentItemId", shipmentItemId); + + using (SqlDataReader sqlReader = cmd.ExecuteReader()) + { + if (sqlReader.Read()) + { + lineDuplicateSkip = lineDuplicateSkip + 1; + } + else + { + //insert report items + + //start transaction + + + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblImportFbaSaleShipment ( " + + "[amazon-order-id], [merchant-order-id], [shipment-id], [shipment-item-id], [amazon-order-item-id], " + + "[merchant-order-item-id], [purchase-date], [payments-date], [shipment-date], [reporting-date], " + + "[buyer-email], [buyer-name], sku, [quantity-shipped], currency, " + + "[item-price], [item-tax], [shipping-price], [shipping-tax], [gift-wrap-price], " + + "[gift-wrap-tax], [recipient-name], [ship-address-1], [ship-address-2], [ship-address-3], " + + "[ship-city], [ship-state], [ship-postal-code], [ship-country], [ship-phone-number], " + + "[bill-address-1], [bill-address-2], [bill-address-3], [bill-city], [bill-state], " + + "[bill-postal-code], [bill-country], [item-promotion-discount], [ship-promotion-discount], [fulfillment-center-id], " + + "[fulfillment-channel], [sales-channel] ) " + + "VALUES ( " + + "@amazonOrderId, @merchantOrderid, @shipmentId, @shipmentItemId, @amazonOrderItemId, " + + "@merchantOrderItemId, @purchaseDate, @paymentsDate, @shipmentDate, @reportingDate, " + + "@buyerEmail, @buyerName, @sku, @quantityShipped, @currency, " + + "@itemPrice, @itemTax, @shippingPrice, @shippingTax, @giftWrapPrice, " + + "@giftWrapTax, @recipientName, @shipAddress1, @shipAddress2, @shipAddress3, " + + "@shipCity, @shipState, @shipPostalCode, @shipCountry, @shipPhoneNumber, " + + "@billAddress1, @billAddress2, @billAddress3, @billCity, @billState, " + + "@billPostalCode, @billCountry, @itemPromotionDiscount, @shipPromotionDiscount, @fulfillmentCenterId, " + + "@fulfillmentChannel, @salesChannel );" + , sqlConn, trans)) + { + // add parameters + if (amazonOrderId == "") { insertCmd.Parameters.AddWithValue("@amazonOrderId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@amazonOrderId", amazonOrderId); } + if (merchantOrderid == "") { insertCmd.Parameters.AddWithValue("@merchantOrderid", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@merchantOrderid", merchantOrderid); } + if (shipmentId == "") { insertCmd.Parameters.AddWithValue("@shipmentId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipmentId", shipmentId); } + if (shipmentItemId == "") { insertCmd.Parameters.AddWithValue("@shipmentItemId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipmentItemId", shipmentItemId); } + if (amazonOrderItemId == "") { insertCmd.Parameters.AddWithValue("@amazonOrderItemId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@amazonOrderItemId", amazonOrderItemId); } + if (merchantOrderItemId == "") { insertCmd.Parameters.AddWithValue("@merchantOrderItemId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@merchantOrderItemId", merchantOrderItemId); } + if (purchaseDate == DateTime.MinValue) { insertCmd.Parameters.AddWithValue("@purchaseDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@purchaseDate", purchaseDate.ToUniversalTime()); } + if (paymentsDate == DateTime.MinValue) { insertCmd.Parameters.AddWithValue("@paymentsDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@paymentsDate", paymentsDate.ToUniversalTime()); } + if (shipmentDate == DateTime.MinValue) { insertCmd.Parameters.AddWithValue("@shipmentDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipmentDate", shipmentDate.ToUniversalTime()); } + if (reportingDate == DateTime.MinValue) { insertCmd.Parameters.AddWithValue("@reportingDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@reportingDate", reportingDate.ToUniversalTime()); } + if (buyerEmail == "") { insertCmd.Parameters.AddWithValue("@buyerEmail", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@buyerEmail", buyerEmail); } + if (buyerName == "") { insertCmd.Parameters.AddWithValue("@buyerName", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@buyerName", buyerName); } + if (sku == "") { insertCmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@sku", sku); } + insertCmd.Parameters.AddWithValue("@quantityShipped", quantityShipped); + if (currency == "") { insertCmd.Parameters.AddWithValue("@currency", DBNull.Value); } + insertCmd.Parameters.AddWithValue("@currency", currency); + insertCmd.Parameters.AddWithValue("@itemPrice", itemPrice); + insertCmd.Parameters.AddWithValue("@itemTax", itemTax); + insertCmd.Parameters.AddWithValue("@shippingPrice", shippingPrice); + insertCmd.Parameters.AddWithValue("@shippingTax", shippingTax); + insertCmd.Parameters.AddWithValue("@giftWrapPrice", giftWrapPrice); + insertCmd.Parameters.AddWithValue("@giftWrapTax", giftWrapTax); + if (recipientName == "") { insertCmd.Parameters.AddWithValue("@recipientName", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@recipientName", recipientName); } + if (shipAddress1 == "") { insertCmd.Parameters.AddWithValue("@shipAddress1", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipAddress1", shipAddress1); } + if (shipAddress2 == "") { insertCmd.Parameters.AddWithValue("@shipAddress2", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipAddress2", shipAddress2); } + if (shipAddress3 == "") { insertCmd.Parameters.AddWithValue("@shipAddress3", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipAddress3", shipAddress3); } + if (shipCity == "") { insertCmd.Parameters.AddWithValue("@shipCity", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipCity", shipCity); } + if (shipState == "") { insertCmd.Parameters.AddWithValue("@shipState", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipState", shipState); } + if (shipPostalCode == "") { insertCmd.Parameters.AddWithValue("@shipPostalCode", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipPostalCode", shipPostalCode); } + if (shipCountry == "") { insertCmd.Parameters.AddWithValue("@shipCountry", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipCountry", shipCountry); } + if (shipPhoneNumber == "") { insertCmd.Parameters.AddWithValue("@shipPhoneNumber", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipPhoneNumber", shipPhoneNumber); } + if (billAddress1 == "") { insertCmd.Parameters.AddWithValue("@billAddress1", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billAddress1", billAddress1); } + if (billAddress2 == "") { insertCmd.Parameters.AddWithValue("@billAddress2", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billAddress2", billAddress2); } + if (billAddress3 == "") { insertCmd.Parameters.AddWithValue("@billAddress3", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billAddress3", billAddress3); } + if (billCity == "") { insertCmd.Parameters.AddWithValue("@billCity", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billCity", billCity); } + if (billState == "") { insertCmd.Parameters.AddWithValue("@billState", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billState", billState); } + if (billPostalCode == "") { insertCmd.Parameters.AddWithValue("@billPostalCode", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billPostalCode", billPostalCode); } + if (billCountry == "") { insertCmd.Parameters.AddWithValue("@billCountry", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@billCountry", billCountry); } + if (itemPromotionDiscount == "") { insertCmd.Parameters.AddWithValue("@itemPromotionDiscount", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@itemPromotionDiscount", itemPromotionDiscount); } + if (shipPromotionDiscount == "") { insertCmd.Parameters.AddWithValue("@shipPromotionDiscount", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@shipPromotionDiscount", shipPromotionDiscount); } + if (fulfillmentCenterId == "") { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); } + if (fulfillmentChannel == "") { insertCmd.Parameters.AddWithValue("@fulfillmentChannel", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fulfillmentChannel", fulfillmentChannel); } + if (salesChannel == "") { insertCmd.Parameters.AddWithValue("@salesChannel", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@salesChannel", salesChannel); } + + insertCmd.ExecuteNonQuery(); + } + } + } + } + } + } + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public bool ImportReportFbaReturns(string sqlConnectionString, string filePath) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineDuplicateSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "return-date"); + int index02 = Array.IndexOf(headers, "order-id"); + int index03 = Array.IndexOf(headers, "sku"); + int index04 = Array.IndexOf(headers, "asin"); + int index05 = Array.IndexOf(headers, "fnsku"); + int index06 = Array.IndexOf(headers, "quantity"); + int index07 = Array.IndexOf(headers, "fulfillment-center-id"); + int index08 = Array.IndexOf(headers, "detailed-disposition"); + int index09 = Array.IndexOf(headers, "reason"); + int index10 = Array.IndexOf(headers, "status"); + int index11 = Array.IndexOf(headers, "license-plate-number"); + int index12 = Array.IndexOf(headers, "customer-comments"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string returnDate = items[index01]; + string orderId = items[index02]; + string sku = items[index03]; + string asin = items[index04]; + string fnsku = items[index05]; + string quantity = items[index06]; + string fulfillmentCenterId = items[index07]; + string detailedDisposition = items[index08]; + string reason = items[index09]; + string status = items[index10]; + string licensePlateNumber = items[index11]; + string customerComments = items[index12]; + + // check number of times line conbination appears in file + int fileCount = 0; + int dbCount = 0; + using (var dupReader = new StreamReader(filePath)) + { + dupReader.ReadLine(); // read header row + string dupFileRow; + while ((dupFileRow = dupReader.ReadLine()) != null) + { + string[] dupItems = dupFileRow.Split('\t'); + if (dupItems.Length != columnCount) + { + // skip + } + else + { + if (items[index01] == dupItems[index01] && + items[index02] == dupItems[index02] && + items[index05] == dupItems[index05] && + items[index11] == dupItems[index11]) + { + // count will always find at least one (itself) + fileCount = fileCount + 1; + } + } + } + } + + //check for duplicate line in db + using (SqlCommand cmd = new SqlCommand( + "SELECT COUNT(ImportFbaCustomerReturnID) FROM tblImportFbaCustomerReturn " + + "WHERE [return-date]=@returnDate AND [order-id]=@orderId AND [fnsku]=@fnsku " + + "AND ([license-plate-number]=@licensePlateNumber OR [license-plate-number] IS NULL) ;" + , sqlConn, trans)) + { + if (returnDate == "") { cmd.Parameters.AddWithValue("@returnDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@returnDate", DateTime.Parse(returnDate).ToUniversalTime()); } + if (orderId == "") { cmd.Parameters.AddWithValue("@orderId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@orderId", orderId); } + if (fnsku == "") { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (licensePlateNumber == "") { cmd.Parameters.AddWithValue("@licensePlateNumber", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@licensePlateNumber", licensePlateNumber); } + + dbCount = (int)cmd.ExecuteScalar(); + } + + if (fileCount <= dbCount) + { + //skip + lineDuplicateSkip = lineDuplicateSkip + 1; + } + else + { + //insert report items + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblImportFbaCustomerReturn ( " + + "[return-date], [order-id], sku, asin, fnsku, " + + "quantity, [fulfillment-center-id], [detailed-disposition], reason, status, " + + "[license-plate-number], [customer-comments] ) " + + "VALUES ( " + + "@returnDate, @orderId, @sku, @asin, @fnsku, " + + "@quantity, @fulfillmentCenterId, @detailedDisposition, @reason, @status, " + + "@licensePlateNumber, @customerComments );" + , sqlConn, trans)) + { + // add parameters + if (returnDate == "") { insertCmd.Parameters.AddWithValue("@returnDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@returnDate", DateTime.Parse(returnDate).ToUniversalTime()); } + if (orderId == "") { insertCmd.Parameters.AddWithValue("@orderId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@orderId", orderId); } + if (sku == "") { insertCmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@sku", sku); } + if (asin == "") { insertCmd.Parameters.AddWithValue("@asin", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@asin", asin); } + if (fnsku == "") { insertCmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (quantity == "") { insertCmd.Parameters.AddWithValue("@quantity", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@quantity", int.Parse(quantity)); } + if (fulfillmentCenterId == "") { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); } + if (detailedDisposition == "") { insertCmd.Parameters.AddWithValue("@detailedDisposition", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@detailedDisposition", detailedDisposition); } + if (reason == "") { insertCmd.Parameters.AddWithValue("@reason", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@reason", reason); } + if (status == "") { insertCmd.Parameters.AddWithValue("@status", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@status", status); } + if (licensePlateNumber == "") { insertCmd.Parameters.AddWithValue("@licensePlateNumber", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@licensePlateNumber", licensePlateNumber); } + if (customerComments == "") { insertCmd.Parameters.AddWithValue("@customerComments", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@customerComments", customerComments); } + + insertCmd.ExecuteNonQuery(); + } + } + } + } + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public bool ImportReportFbaAdjustment(string sqlConnectionString, string filePath) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineDuplicateSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "adjusted-date"); + int index02 = Array.IndexOf(headers, "transaction-item-id"); + int index03 = Array.IndexOf(headers, "fnsku"); + int index04 = Array.IndexOf(headers, "sku"); + int index05 = Array.IndexOf(headers, "product-name"); + int index06 = Array.IndexOf(headers, "fulfillment-center-id"); + int index07 = Array.IndexOf(headers, "quantity"); + int index08 = Array.IndexOf(headers, "reason"); + int index09 = Array.IndexOf(headers, "disposition"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string adjustmentDate = items[index01]; + string transactionItemId = items[index02]; + string fnsku = items[index03]; + string sku = items[index04]; + string fulfillmentCenterId = items[index06]; + string quantity = items[index07]; + string reason = items[index08]; + string disposition = items[index09]; + + // check number of times line combination appears in file + // don't think is a nesseary step, the transactionItemId is a unique identifier, I'm 99% sure + int fileCount = 0; + int dbCount = 0; + using (var dupReader = new StreamReader(filePath)) + { + dupReader.ReadLine(); // read header row + string dupFileRow; + while ((dupFileRow = dupReader.ReadLine()) != null) + { + string[] dupItems = dupFileRow.Split('\t'); + if (dupItems.Length != columnCount) + { + // skip + } + else + { + if (items[index01] == dupItems[index01] && + items[index02] == dupItems[index02] && + items[index03] == dupItems[index03] && + items[index06] == dupItems[index06] && + items[index08] == dupItems[index08] && + items[index09] == dupItems[index09] + ) + { + // count will always find at least one (itself) + fileCount = fileCount + 1; + } + } + } + } + + //check for duplicate line in db + + //using (SqlCommand cmd = new SqlCommand( + // "SELECT COUNT(ImportFbaInventoryAdjustmentReportID) FROM tblImportFbaInventoryAdjustmentReport " + + // "WHERE [adjusted-date]=@adjustmentDate AND [transaction-item-id]=@transactionItemId AND [fnsku]=@fnsku " + + // " AND [fulfillment-center-id]=@fulfillmentCenterId AND [reason]=@reason AND [disposition]=@disposition;" + // , sqlConn, trans)) + //{ + // if (adjustmentDate == "") { cmd.Parameters.AddWithValue("@adjustmentDate", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@adjustmentDate", DateTime.Parse(adjustmentDate).ToUniversalTime()); } + // if (transactionItemId == "") { cmd.Parameters.AddWithValue("@transactionItemId", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@transactionItemId", transactionItemId); } + // if (fnsku == "") { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + // if (fulfillmentCenterId == "") { cmd.Parameters.AddWithValue("@fulfillmentCenterId", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); } + // if (reason == "") { cmd.Parameters.AddWithValue("@reason", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@reason", reason); } + // if (disposition == "") { cmd.Parameters.AddWithValue("@disposition", DBNull.Value); } + // else { cmd.Parameters.AddWithValue("@disposition", disposition); } + + // dbCount = (int)cmd.ExecuteScalar(); + //} + using (SqlCommand cmd = new SqlCommand( + "SELECT COUNT(ImportFbaInventoryAdjustmentReportID) FROM tblImportFbaInventoryAdjustmentReport " + + "WHERE [transaction-item-id]=@transactionItemId;" + , sqlConn, trans)) + { + cmd.Parameters.AddWithValue("@transactionItemId", transactionItemId); + + dbCount = (int)cmd.ExecuteScalar(); + } + + + if (fileCount <= dbCount) + { + //skip + lineDuplicateSkip = lineDuplicateSkip + 1; + } + else + { + //insert report items + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblImportFbaInventoryAdjustmentReport ( " + + "[adjusted-date], [transaction-item-id], fnsku, sku, " + + "[fulfillment-center-id], quantity, reason, disposition ) " + + "VALUES ( " + + "@adjustmentDate, @transactionItemId, @fnsku, @sku, " + + "@fulfillmentCenterId, @quantity, @reason, @disposition );" + , sqlConn, trans)) + { + // add parameters + if (adjustmentDate == "") { insertCmd.Parameters.AddWithValue("@adjustmentDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@adjustmentDate", DateTime.Parse(adjustmentDate).ToUniversalTime()); } + if (transactionItemId == "") { insertCmd.Parameters.AddWithValue("@transactionItemId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@transactionItemId", transactionItemId); } + if (fnsku == "") { insertCmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (sku == "") { insertCmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@sku", sku); } + if (fulfillmentCenterId == "") { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fulfillmentCenterId", fulfillmentCenterId); } + if (quantity == "") { insertCmd.Parameters.AddWithValue("@quantity", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@quantity", int.Parse(quantity)); } + if (reason == "") { insertCmd.Parameters.AddWithValue("@reason", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@reason", reason); } + if (disposition == "") { insertCmd.Parameters.AddWithValue("@disposition", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@disposition", disposition); } + + insertCmd.ExecuteNonQuery(); + } + } + } + } + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running ImportFbaAdustmentReport method, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public bool ImportReportFbaReimbursement(string sqlConnectionString, string filePath) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineDuplicateSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "approval-date"); + int index02 = Array.IndexOf(headers, "reimbursement-id"); + int index03 = Array.IndexOf(headers, "case-id"); + int index04 = Array.IndexOf(headers, "amazon-order-id"); + int index05 = Array.IndexOf(headers, "reason"); + int index06 = Array.IndexOf(headers, "sku"); + int index07 = Array.IndexOf(headers, "fnsku"); + int index08 = Array.IndexOf(headers, "asin"); + int index09 = Array.IndexOf(headers, "product-name"); + int index10 = Array.IndexOf(headers, "condition"); + int index11 = Array.IndexOf(headers, "currency-unit"); + int index12 = Array.IndexOf(headers, "amount-per-unit"); + int index13 = Array.IndexOf(headers, "amount-total"); + int index14 = Array.IndexOf(headers, "quantity-reimbursed-cash"); + int index15 = Array.IndexOf(headers, "quantity-reimbursed-inventory"); + int index16 = Array.IndexOf(headers, "quantity-reimbursed-total"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string approvalDate = items[index01]; + string reimbursementid = items[index02]; + string caseid = items[index03]; + string amazonOrderId = items[index04]; + string reason = items[index05]; + string sku = items[index06]; + string fnsku = items[index07]; + string asin = items[index08]; + string productName = items[index09]; + string condition = items[index10]; + string currencyUnit = items[index11]; + string amountPerUnit = items[index12]; + string amountTotal = items[index13]; + + int quantityReimbursedCash = 0; + if (items[index14] != "") + { quantityReimbursedCash = int.Parse(items[index14]); } + + int quantityReimbursedInventory = 0; + if (items[index15] != "") + { quantityReimbursedInventory = int.Parse(items[index15]); } + + int quantityReimbursedTotal = 0; + if (items[index16] != "") + { quantityReimbursedTotal = int.Parse(items[index16]); } + + // totals checks + if (quantityReimbursedTotal == 0) + { + throw new Exception("Total Reimbursed total cannot be zero."); + } + if (quantityReimbursedCash + quantityReimbursedInventory != quantityReimbursedTotal) + { + throw new Exception("Reimbursed totals do not tally."); + } + + // check number of times line conbination appears in file + int fileCount = 0; + int dbCount = 0; + using (var dupReader = new StreamReader(filePath)) + { + dupReader.ReadLine(); // read header row + string dupFileRow; + while ((dupFileRow = dupReader.ReadLine()) != null) + { + string[] dupItems = dupFileRow.Split('\t'); + if (dupItems.Length != columnCount) + { + // skip + } + else + { + if (items[index01] == dupItems[index01] && + items[index02] == dupItems[index02] && + items[index03] == dupItems[index03] && + items[index04] == dupItems[index04] && + items[index05] == dupItems[index05] && + items[index07] == dupItems[index07] && + items[index13] == dupItems[index13] + ) + { + // count will always find at least one (itself) + fileCount = fileCount + 1; + } + } + } + } + + //check for duplicate line in db + using (SqlCommand cmd = new SqlCommand(@" + SELECT + COUNT(ImportFbaReimbursementReportID) AS number + FROM + tblImportFbaReimbursementReport + WHERE + [reimbursement-id]=@reimbursementid + AND ([case-id]=@caseid OR [case-id] IS NULL) + AND ([amazon-order-id]=@amazonOrderId OR [amazon-order-id] IS NULL) + AND reason=@reason AND fnsku=@fnsku + AND [amount-total]=@amountTotal; + ", sqlConn, trans)) + { + if (reimbursementid == "") { cmd.Parameters.AddWithValue("@reimbursementid", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reimbursementid", reimbursementid); } + if (caseid == "") { cmd.Parameters.AddWithValue("@caseid", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@caseid", caseid); } + if (amazonOrderId == "") { cmd.Parameters.AddWithValue("@amazonOrderId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@amazonOrderId", amazonOrderId); } + if (reason == "") { cmd.Parameters.AddWithValue("@reason", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reason", reason); } + if (fnsku == "") { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (amountTotal == "") { cmd.Parameters.AddWithValue("@amountTotal", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@amountTotal", decimal.Parse(amountTotal)); } + + dbCount = (int)cmd.ExecuteScalar(); + } + + if (fileCount <= dbCount) + { + //skip + lineDuplicateSkip = lineDuplicateSkip + 1; + } + else + { + //insert report items + using (SqlCommand insertCmd = new SqlCommand( + "INSERT INTO tblImportFbaReimbursementReport ( " + + "[approval-date], [reimbursement-id], [case-id], [amazon-order-id], reason, " + + "sku, fnsku, asin, condition, [currency-unit], " + + "[amount-per-unit], [amount-total], [quantity-reimbursed-cash], [quantity-reimbursed-inventory], [quantity-reimbursed-total] )" + + "VALUES ( " + + "@approvalDate, @reimbursementid, @caseid, @amazonOrderId, @reason, " + + "@sku, @fnsku, @asin, @condition, @currencyUnit, " + + "@amountPerUnit, @amountTotal, @quantityReimbursedCash, @quantityReimbursedInventory, @quantityReimbursedTotal );" + , sqlConn, trans)) + { + // add parameters + if (approvalDate == "") { insertCmd.Parameters.AddWithValue("@approvalDate", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@approvalDate", DateTime.Parse(approvalDate).ToUniversalTime()); } + if (reimbursementid == "") { insertCmd.Parameters.AddWithValue("@reimbursementid", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@reimbursementid", reimbursementid); } + if (caseid == "") { insertCmd.Parameters.AddWithValue("@caseid", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@caseid", caseid); } + if (amazonOrderId == "") { insertCmd.Parameters.AddWithValue("@amazonOrderId", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@amazonOrderId", amazonOrderId); } + if (reason == "") { insertCmd.Parameters.AddWithValue("@reason", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@reason", reason); } + if (sku == "") { insertCmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@sku", sku); } + if (fnsku == "") { insertCmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (asin == "") { insertCmd.Parameters.AddWithValue("@asin", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@asin", asin); } + if (condition == "") { insertCmd.Parameters.AddWithValue("@condition", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@condition", condition); } + if (currencyUnit == "") { insertCmd.Parameters.AddWithValue("@currencyUnit", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@currencyUnit", currencyUnit); } + if (amountPerUnit == "") { insertCmd.Parameters.AddWithValue("@amountPerUnit", DBNull.Value); } + else { insertCmd.Parameters.AddWithValue("@amountPerUnit", decimal.Parse(amountPerUnit)); } + if (amountTotal == "") { insertCmd.Parameters.AddWithValue("@amountTotal", DBNull.Value); } + else {insertCmd.Parameters.AddWithValue("@amountTotal", decimal.Parse(amountTotal)); } + insertCmd.Parameters.AddWithValue("@quantityReimbursedCash", quantityReimbursedCash); + insertCmd.Parameters.AddWithValue("@quantityReimbursedInventory", quantityReimbursedInventory); + insertCmd.Parameters.AddWithValue("@quantityReimbursedTotal", quantityReimbursedTotal); + + insertCmd.ExecuteNonQuery(); + } + } + } + } + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running ImportFbaReimbursementReport method, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public bool ImportReportFbaRemovalOrder(string sqlConnectionString, string filePath) + { + SqlConnection sqlConn; + SqlTransaction trans; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (trans = sqlConn.BeginTransaction()) + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineUpdate = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "request-date"); + int index02 = Array.IndexOf(headers, "order-id"); + int index03 = Array.IndexOf(headers, "order-type"); + int index04 = Array.IndexOf(headers, "service-speed"); + int index05 = Array.IndexOf(headers, "order-status"); + int index06 = Array.IndexOf(headers, "last-updated-date"); + int index07 = Array.IndexOf(headers, "sku"); + int index08 = Array.IndexOf(headers, "fnsku"); + int index09 = Array.IndexOf(headers, "disposition"); + int index10 = Array.IndexOf(headers, "requested-quantity"); + int index11 = Array.IndexOf(headers, "cancelled-quantity"); + int index12 = Array.IndexOf(headers, "disposed-quantity"); + int index13 = Array.IndexOf(headers, "shipped-quantity"); + int index14 = Array.IndexOf(headers, "in-process-quantity"); + int index15 = Array.IndexOf(headers, "removal-fee"); + int index16 = Array.IndexOf(headers, "currency"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string requestDate = items[index01]; + string orderId = items[index02]; + string orderType = items[index03]; + string serviceSpeed = items[index04]; + string orderStatus = items[index05]; + string lastUpdatedDate = items[index06]; + string sku = items[index07]; + string fnsku = items[index08]; + string disposition = items[index09]; + string requestedQuantity = items[index10]; + string cancelledQuantity = items[index11]; + string disposedQuantity = items[index12]; + string shippedQuantity = items[index13]; + string inProcessQuantity = items[index14]; + string removalFee = items[index15]; + string currency = items[index16]; + + if (orderId == "") { continue; } + int importTableId = 0; + + //check for existing orderId + using (SqlCommand cmd = new SqlCommand( + "SELECT ImportFbaRemovalOrderReportID FROM tblImportFbaRemovalOrderReport WHERE [order-id]=@orderId AND fnsku=@fnsku AND disposition=@disposition;" + , sqlConn, trans)) + { + cmd.Parameters.AddWithValue("@orderId", orderId); + cmd.Parameters.AddWithValue("@fnsku", fnsku); + cmd.Parameters.AddWithValue("@disposition", disposition); + importTableId = Convert.ToInt32(cmd.ExecuteScalar()); + } + + string sqlQuery; + if (importTableId > 0) + { + // update + lineUpdate = lineUpdate + 1; + sqlQuery = + "UPDATE tblImportFbaRemovalOrderReport SET " + + "[request-date]=@requestDate, [order-id]=@orderId, [order-type]=@orderType, [service-speed]=@serviceSpeed, " + + "[order-status]=@orderStatus, [last-updated-date]=@lastUpdatedDate, sku=@sku, fnsku=@fnsku, " + + "disposition=@disposition, [requested-quantity]=@requestedQuantity, [cancelled-quantity]=@cancelledQuantity, [disposed-quantity]=@disposedQuantity, " + + "[shipped-quantity]=@shippedQuantity, [in-process-quantity]=@inProcessQuantity, [removal-fee]=@removalFee, currency=@currency " + + "WHERE ImportFbaRemovalOrderReportID=@importTableId;"; + } + else + { + // insert + sqlQuery = + "INSERT INTO tblImportFbaRemovalOrderReport ( " + + "[request-date], [order-id], [order-type], [service-speed], [order-status], [last-updated-date], sku, fnsku, " + + "disposition, [requested-quantity], [cancelled-quantity], [disposed-quantity], [shipped-quantity], [in-process-quantity], [removal-fee], currency ) " + + "VALUES ( " + + "@requestDate, @orderId, @orderType, @serviceSpeed, @orderStatus, @lastUpdatedDate, @sku, @fnsku, " + + "@disposition, @requestedQuantity, @cancelledQuantity, @disposedQuantity, @shippedQuantity, @inProcessQuantity, @removalFee, @currency );"; + } + + // make the update/insert + using (SqlCommand cmd = new SqlCommand(sqlQuery, sqlConn, trans)) + { + // add parameters + cmd.Parameters.AddWithValue("@importTableId", importTableId); + if (requestDate == "") { cmd.Parameters.AddWithValue("@requestDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@requestDate", DateTime.Parse(requestDate).ToUniversalTime()); } + if (orderId == "") { cmd.Parameters.AddWithValue("@orderId", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@orderId", orderId); } + if (orderType == "") { cmd.Parameters.AddWithValue("@orderType", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@orderType", orderType); } + if (serviceSpeed == "") { cmd.Parameters.AddWithValue("@serviceSpeed", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@serviceSpeed", serviceSpeed); } + if (orderStatus == "") { cmd.Parameters.AddWithValue("@orderStatus", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@orderStatus", orderStatus); } + if (lastUpdatedDate == "") { cmd.Parameters.AddWithValue("@lastUpdatedDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@lastUpdatedDate", DateTime.Parse(lastUpdatedDate).ToUniversalTime()); } + if (sku == "") { cmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@sku", sku); } + if (fnsku == "") { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (disposition == "") { cmd.Parameters.AddWithValue("@disposition", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@disposition", disposition); } + if (requestedQuantity == "") { cmd.Parameters.AddWithValue("@requestedQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@requestedQuantity", int.Parse(requestedQuantity)); } + if (cancelledQuantity == "") { cmd.Parameters.AddWithValue("@cancelledQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@cancelledQuantity", int.Parse(cancelledQuantity)); } + if (disposedQuantity == "") { cmd.Parameters.AddWithValue("@disposedQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@disposedQuantity", int.Parse(disposedQuantity)); } + if (shippedQuantity == "") { cmd.Parameters.AddWithValue("@shippedQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@shippedQuantity", int.Parse(shippedQuantity)); } + if (inProcessQuantity == "") { cmd.Parameters.AddWithValue("@inProcessQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@inProcessQuantity", int.Parse(inProcessQuantity)); } + if (removalFee == "") { cmd.Parameters.AddWithValue("@removalFee", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@removalFee", decimal.Parse(removalFee)); } + if (currency == "") { cmd.Parameters.AddWithValue("@currency", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@currency", currency); } + + cmd.ExecuteNonQuery(); + } + } + } + trans.Commit(); + Console.Write("\r"); + MiscFunction.EventLogInsert("ImportFbaRemovalOrderReport() " + (lineNumber - (1 + lineErrorSkip + lineUpdate)) + " records created, " + lineUpdate + " records updated."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running ImportFbaRemovalOrderReport method, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return false; + } + return true; + } + public void UpdateFbaInventoryData(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Staring ImportFbaInventoryData()..."); + string mwsReportEnum = "_GET_FBA_MYI_ALL_INVENTORY_DATA_"; + + string filePath = ""; + // Uncomment to override getreport and load directly from file + //filePath = @"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\8539341218017503.txt"; + + // build the request + if (filePath == "") + { + RequestReportRequest requestReport = new RequestReportRequest(); + requestReport.Merchant = merchantId; + requestReport.ReportType = mwsReportEnum; + + MiscFunction.EventLogInsert("Requesting '" + mwsReportEnum + "''"); + filePath = GetMwsReportByRequest(requestReport); + + if (filePath == "_DONE_NO_DATA_") + { + // do nothing, carry on with next iteration + } + else if (filePath == "_CANCELLED_") + { + /* + / this is probably MWS higher level throttling when requesting duplicate report + / for near real time reports waiting 30 minutes + / for daily reports wait 4 hours + */ + } + else if (filePath.Length == 0) + { + MiscFunction.EventLogInsert( + "Something went wrong retriving report from MWS. Operation cancelled.", + 2 + ); + return; + } + } + + // import into database + SqlConnection sqlConn; + try + { + using (TransactionScope scope = new TransactionScope()) + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + //clear table data + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblImportFbaManageInventory; + ", sqlConn)) + { + cmd.ExecuteNonQuery(); + } + + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineNoStockSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "sku"); + int index02 = Array.IndexOf(headers, "fnsku"); + int index03 = Array.IndexOf(headers, "asin"); + int index04 = Array.IndexOf(headers, "product-name"); + int index05 = Array.IndexOf(headers, "condition"); + int index06 = Array.IndexOf(headers, "your-price"); + int index07 = Array.IndexOf(headers, "mfn-listing-exists"); + int index08 = Array.IndexOf(headers, "mfn-fulfillable-quantity"); + int index09 = Array.IndexOf(headers, "afn-listing-exists"); + int index10 = Array.IndexOf(headers, "afn-warehouse-quantity"); + int index11 = Array.IndexOf(headers, "afn-fulfillable-quantity"); + int index12 = Array.IndexOf(headers, "afn-unsellable-quantity"); + int index13 = Array.IndexOf(headers, "afn-reserved-quantity"); + int index14 = Array.IndexOf(headers, "afn-total-quantity"); + int index15 = Array.IndexOf(headers, "per-unit-volume"); + int index16 = Array.IndexOf(headers, "afn-inbound-working-quantity"); + int index17 = Array.IndexOf(headers, "afn-inbound-shipped-quantity"); + int index18 = Array.IndexOf(headers, "afn-inbound-receiving-quantity"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + // only import sku with stock + // afnTotalQuantity includes fba stock and inbound shipments + string afnTotalQuantity = items[index14]; + //if (int.Parse(afnTotalQuantity) == 0) + //{ + // lineNoStockSkip = lineNoStockSkip + 1; + // continue; + //} + + //read values + string sku = items[index01]; + string fnsku = items[index02]; + string asin = items[index03]; + string productName = items[index04]; + string condition = items[index05]; + string yourPrice = items[index06]; + string mfnListingExists = items[index07]; + string mfnFulfillableQuantity = items[index08]; + string afnListingExists = items[index09]; + string afnWarehouseQuantity = items[index10]; + string afnFulfillableQuantity = items[index11]; + string afnUnsellableQuantity = items[index12]; + string afnReservedQuantity = items[index13]; + string perUnitVolume = items[index15]; + string afnInboundWorkingQuantity = items[index16]; + string afnInboundShippedQuantity = items[index17]; + string afnInboundReceivingQuantity = items[index18]; + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblImportFbaManageInventory( + sku, fnsku, asin, [product-name], condition, [your-price], [mfn-listing-exists], [mfn-fulfillable-quantity], + [afn-listing-exists], [afn-warehouse-quantity], [afn-fulfillable-quantity], [afn-unsellable-quantity], + [afn-reserved-quantity], [afn-total-quantity], [per-unit-volume], [afn-inbound-working-quantity], + [afn-inbound-shipped-quantity], [afn-inbound-receiving-quantity] ) + VALUES ( + @sku, @fnsku, @asin, @productName, @condition, @yourPrice, @mfnListingExists, @mfnFulfillableQuantity, + @afnListingExists, @afnWarehouseQuantity, @afnFulfillableQuantity, @afnUnsellableQuantity, + @afnReservedQuantity, @afnTotalQuantity, @perUnitVolume, @afnInboundWorkingQuantity, + @afnInboundShippedQuantity, @afnInboundReceivingQuantity ); + ", sqlConn)) + { + // add parameters + cmd.Parameters.AddWithValue("@sku", sku); + + if (fnsku.Length == 0) { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + if (asin.Length == 0) { cmd.Parameters.AddWithValue("@asin", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@asin", asin); } + if (productName.Length == 0) { cmd.Parameters.AddWithValue("@productName", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@productName", productName); } + if (condition.Length == 0) { cmd.Parameters.AddWithValue("@condition", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@condition", condition); } + if (yourPrice.Length == 0) { cmd.Parameters.AddWithValue("@yourPrice", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@yourPrice", decimal.Parse(yourPrice)); } + if (mfnListingExists.Length == 0) { cmd.Parameters.AddWithValue("@mfnListingExists", DBNull.Value); } + else if (mfnListingExists == "Yes") { cmd.Parameters.AddWithValue("@mfnListingExists", true); } + else { cmd.Parameters.AddWithValue("@mfnListingExists", false); } + if (mfnFulfillableQuantity.Length == 0) { cmd.Parameters.AddWithValue("@mfnFulfillableQuantity", 0); } + else { cmd.Parameters.AddWithValue("@mfnFulfillableQuantity", int.Parse(mfnFulfillableQuantity)); } + if (afnListingExists.Length == 0) { cmd.Parameters.AddWithValue("@afnListingExists", DBNull.Value); } + else if (afnListingExists == "Yes") { cmd.Parameters.AddWithValue("@afnListingExists", true); } + else { cmd.Parameters.AddWithValue("@afnListingExists", false); } + if (afnWarehouseQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnWarehouseQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnWarehouseQuantity", int.Parse(afnWarehouseQuantity)); } + if (afnFulfillableQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnFulfillableQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnFulfillableQuantity", int.Parse(afnFulfillableQuantity)); } + if (afnUnsellableQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnUnsellableQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnUnsellableQuantity", int.Parse(afnUnsellableQuantity)); } + if (afnReservedQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnReservedQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnReservedQuantity", int.Parse(afnReservedQuantity)); } + if (afnTotalQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnTotalQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnTotalQuantity", int.Parse(afnTotalQuantity)); } + if (perUnitVolume.Length == 0) { cmd.Parameters.AddWithValue("@perUnitVolume", 0); } + else { cmd.Parameters.AddWithValue("@perUnitVolume", decimal.Parse(perUnitVolume)); } + if (afnInboundWorkingQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnInboundWorkingQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnInboundWorkingQuantity", int.Parse(afnInboundWorkingQuantity)); } + if (afnInboundShippedQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnInboundShippedQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnInboundShippedQuantity", int.Parse(afnInboundShippedQuantity)); } + if (afnInboundReceivingQuantity.Length == 0) { cmd.Parameters.AddWithValue("@afnInboundReceivingQuantity", 0); } + else { cmd.Parameters.AddWithValue("@afnInboundReceivingQuantity", int.Parse(afnInboundReceivingQuantity)); } + + + // execute the query + cmd.ExecuteNonQuery(); + } + } + } + Console.Write("\r"); + MiscFunction.EventLogInsert( + "Operation complete. " + lineNumber + " items processes. " + (lineNumber - lineErrorSkip - lineNoStockSkip) + " total new items inserted, " + + lineNoStockSkip + " 'No Stock' records were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + scope.Complete(); + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Something went wrong during import, check details for more.", 1, ex.ToString()); + Console.WriteLine(ex.ToString()); + } + } + public void UpdateFbaInventoryAgeData(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Staring ImportFbaInventoryAgeReport()..."); + string mwsReportEnum = "_GET_FBA_INVENTORY_AGED_DATA_"; + + string filePath = ""; + // Uncomment to override getreport and load directly from file + //filePath = @"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\8539341218017503.txt"; + + // build the request + if (filePath == "") + { + RequestReportRequest requestReport = new RequestReportRequest(); + requestReport.Merchant = merchantId; + requestReport.ReportType = mwsReportEnum; + + MiscFunction.EventLogInsert("Requesting '" + mwsReportEnum + "''"); + filePath = GetMwsReportByRequest(requestReport); + + if (filePath == "_DONE_NO_DATA_") + { + // do nothing, carry on with next iteration + } + else if (filePath == "_CANCELLED_") + { + /* + / this is probably MWS higher level throttling when requesting duplicate report + / for near real time reports waiting 30 minutes + / for daily reports wait 4 hours + */ + } + else if (filePath.Length == 0) + { + MiscFunction.EventLogInsert( + "Something went wrong retriving report from MWS. Operation cancelled.", + 2 + ); + return; + } + } + + // import into database + SqlConnection sqlConn; + try + { + using (TransactionScope scope = new TransactionScope()) + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + //clear table data + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblImportFbaInventoryAgeReport; + ", sqlConn)) + { + cmd.ExecuteNonQuery(); + } + + using (var reader = new StreamReader(filePath)) + { + //read file one line at a time and insert data into table if required + int lineNumber = 1; + int lineErrorSkip = 0; + int lineNoStockSkip = 0; + + // read header and retrive information + string headerRow = reader.ReadLine(); + string[] headers = headerRow.Split('\t'); + + int columnCount = headers.Length; + + int index01 = Array.IndexOf(headers, "snapshot-date"); + int index02 = Array.IndexOf(headers, "marketplace"); + int index03 = Array.IndexOf(headers, "sku"); + int index04 = Array.IndexOf(headers, "fnsku"); + int index05 = Array.IndexOf(headers, "asin"); + int index06 = Array.IndexOf(headers, "product-name"); + int index07 = Array.IndexOf(headers, "condition"); + int index08 = Array.IndexOf(headers, "avaliable-quantity(sellable)"); + int index09 = Array.IndexOf(headers, "qty-with-removals-in-progress"); + int index10 = Array.IndexOf(headers, "inv-age-0-to-90-days"); + int index11 = Array.IndexOf(headers, "inv-age-91-to-180-days"); + int index12 = Array.IndexOf(headers, "inv-age-181-to-270-days"); + int index13 = Array.IndexOf(headers, "inv-age-271-to-365-days"); + int index14 = Array.IndexOf(headers, "inv-age-365-plus-days"); + int index15 = Array.IndexOf(headers, "currency"); + int index16 = Array.IndexOf(headers, "qty-to-be-charged-ltsf-6-mo"); + int index17 = Array.IndexOf(headers, "projected-ltsf-6-mo"); + int index18 = Array.IndexOf(headers, "qty-to-be-charged-ltsf-12-mo"); + int index19 = Array.IndexOf(headers, "projected-ltsf-12-mo"); + int index20 = Array.IndexOf(headers, "units-shipped-last-7-days"); + int index21 = Array.IndexOf(headers, "units-shipped-last-30-days"); + int index22 = Array.IndexOf(headers, "units-shipped-last-60-days"); + int index23 = Array.IndexOf(headers, "units-shipped-last-90-days"); + int index24 = Array.IndexOf(headers, "alert"); + int index25 = Array.IndexOf(headers, "your-price"); + int index26 = Array.IndexOf(headers, "sales_price"); + int index27 = Array.IndexOf(headers, "lowest_price_new"); + int index28 = Array.IndexOf(headers, "lowest_price_used"); + int index29 = Array.IndexOf(headers, "Recommended action"); + int index30 = Array.IndexOf(headers, "Healthy Inventory Level"); + int index31 = Array.IndexOf(headers, "Recommended sales price"); + int index32 = Array.IndexOf(headers, "Recommended sale duration (days)"); + int index33 = Array.IndexOf(headers, "Recommended Removal Quantity"); + int index34 = Array.IndexOf(headers, "Estimated cost savings of removal"); + + string fileRow; + while ((fileRow = reader.ReadLine()) != null) + { + lineNumber = lineNumber + 1; + Console.Write("\rParsing record: " + lineNumber); + //split line into array + string[] items = fileRow.Split('\t'); + if (items.Length != columnCount) + { + // skip line + lineErrorSkip = lineErrorSkip + 1; + MiscFunction.EventLogInsert( + "Line #" + lineNumber + " skipped due to no enough element in row.", + 2, + filePath + ); + } + else + { + //read values + string snapshotDate = items[index01]; + string marketplace = items[index02]; + string sku = items[index03]; + string fnsku = items[index04]; + string asin = items[index05]; + string productName = items[index06]; + string condition = items[index07]; + string avaliableQuantity = items[index08]; + string qtyWithRemovalsInProgress = items[index09]; + string invAge0To90Days = items[index10]; + string invAge91To180Days = items[index11]; + string invAge181To270Days = items[index12]; + string invAge271To365Days = items[index13]; + string invAge365PlusDays = items[index14]; + string currency = items[index15]; + string qtyToBeChargedLtsf6Mo = items[index16]; + string projectedLtsf6Mo = Regex.Replace(items[index17], "[^.0-9]", ""); // strip currency code prefix + string qtyToBeChargedLtsf12Mo = items[index18]; + string projectedLtsf12Mo = Regex.Replace(items[index19], "[^.0-9]", ""); // strip currency code prefix + string unitsShippedLast7Days = items[index20]; + string unitsShippedLast30Days = items[index21]; + string unitsShippedLast60Days = items[index22]; + string unitsShippedLast90Days = items[index23]; + string alert = items[index24]; + string yourPrice = Regex.Replace(items[index25], "[^.0-9]", ""); // strip currency code prefix + string salesPrice = Regex.Replace(items[index26], "[^.0-9]", ""); // strip currency code prefix + string lowestPriceNew = Regex.Replace(items[index27], "[^.0-9]", ""); // strip currency code prefix + string lowestPriceUsed = Regex.Replace(items[index28], "[^.0-9]", ""); // strip currency code prefix + string recommendedAction = items[index29]; + string healthyInventoryLevel = items[index30]; + string recommendedSalesPrice = Regex.Replace(items[index31], "[^.0-9]", ""); // strip currency code prefix + string recommendedSaleDuration = items[index32]; + string recommendedRemovalQuantity = items[index33]; + string estimatedCostSavingsOfRemoval = items[index34]; + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblImportFbaInventoryAgeReport( + [snapshot-date], marketplace, sku, fnsku, asin, [product-name], condition, [avaliable-quantity(sellable)], + [qty-with-removals-in-progress], [inv-age-0-to-90-days], [inv-age-91-to-180-days], [inv-age-181-to-270-days], + [inv-age-271-to-365-days], [inv-age-365-plus-days], currency, [qty-to-be-charged-ltsf-6-mo], [projected-ltsf-6-mo], + [qty-to-be-charged-ltsf-12-mo], [projected-ltsf-12-mo], [units-shipped-last-7-days], [units-shipped-last-30-days], + [units-shipped-last-60-days], [units-shipped-last-90-days], alert, [your-price], sales_price, lowest_price_new, + lowest_price_used, [Recommended action], [Healthy Inventory Level], [Recommended sales price], + [Recommended sale duration (days)], [Recommended Removal Quantity], [Estimated cost savings of removal] ) + VALUES ( + @snapshotDate, @marketplace, @sku, @fnsku, @asin, @productName, @condition, @avaliableQuantity, + @qtyWithRemovalsInProgress, @invAge0To90Days, @invAge91To180Days, @invAge181To270Days, @invAge271To365Days, @invAge365PlusDays, @currency, @qtyToBeChargedLtsf6Mo, + @projectedLtsf6Mo, @qtyToBeChargedLtsf12Mo, @projectedLtsf12Mo, @unitsShippedLast7Days, @unitsShippedLast30Days, @unitsShippedLast60Days, @unitsShippedLast90Days, @alert, + @yourPrice, @salesPrice, @lowestPriceNew, @lowestPriceUsed, @recommendedAction, @healthyInventoryLevel, @recommendedSalesPrice, @recommendedSaleDuration, + @recommendedRemovalQuantity, @estimatedCostSavingsOfRemoval ); + ", sqlConn)) + { + // add parameters + if (snapshotDate.Length == 0) { cmd.Parameters.AddWithValue("@snapshotDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@snapshotDate", DateTime.Parse(snapshotDate).ToUniversalTime()); } + + if (marketplace.Length == 0) { cmd.Parameters.AddWithValue("@marketplace", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@marketplace", marketplace); } + + if (sku.Length == 0) { cmd.Parameters.AddWithValue("@sku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@sku", sku); } + + if (fnsku.Length == 0) { cmd.Parameters.AddWithValue("@fnsku", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@fnsku", fnsku); } + + if (asin.Length == 0) { cmd.Parameters.AddWithValue("@asin", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@asin", asin); } + + if (productName.Length == 0) { cmd.Parameters.AddWithValue("@productName", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@productName", productName); } + + if (condition.Length == 0) { cmd.Parameters.AddWithValue("@condition", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@condition", condition); } + + if (avaliableQuantity.Length == 0) { cmd.Parameters.AddWithValue("@avaliableQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@avaliableQuantity", int.Parse(avaliableQuantity)); } + + if (qtyWithRemovalsInProgress.Length == 0) { cmd.Parameters.AddWithValue("@qtyWithRemovalsInProgress", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@qtyWithRemovalsInProgress", int.Parse(qtyWithRemovalsInProgress)); } + + if (invAge0To90Days.Length == 0) { cmd.Parameters.AddWithValue("@invAge0To90Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@invAge0To90Days", int.Parse(invAge0To90Days)); } + + if (invAge91To180Days.Length == 0) { cmd.Parameters.AddWithValue("@invAge91To180Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@invAge91To180Days", int.Parse(invAge91To180Days)); } + + if (invAge181To270Days.Length == 0) { cmd.Parameters.AddWithValue("@invAge181To270Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@invAge181To270Days", int.Parse(invAge181To270Days)); } + + if (invAge271To365Days.Length == 0) { cmd.Parameters.AddWithValue("@invAge271To365Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@invAge271To365Days", int.Parse(invAge271To365Days)); } + + if (invAge365PlusDays.Length == 0) { cmd.Parameters.AddWithValue("@invAge365PlusDays", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@invAge365PlusDays", int.Parse(invAge365PlusDays)); } + + if (currency.Length == 0) { cmd.Parameters.AddWithValue("@currency", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@currency", currency); } + + if (qtyToBeChargedLtsf6Mo.Length == 0) { cmd.Parameters.AddWithValue("@qtyToBeChargedLtsf6Mo", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@qtyToBeChargedLtsf6Mo", int.Parse(qtyToBeChargedLtsf6Mo)); } + + if (projectedLtsf6Mo.Length == 0) { cmd.Parameters.AddWithValue("@projectedLtsf6Mo", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@projectedLtsf6Mo", decimal.Parse(projectedLtsf6Mo)); } + + if (qtyToBeChargedLtsf12Mo.Length == 0) { cmd.Parameters.AddWithValue("@qtyToBeChargedLtsf12Mo", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@qtyToBeChargedLtsf12Mo", int.Parse(qtyToBeChargedLtsf12Mo)); } + + if (projectedLtsf12Mo.Length == 0) { cmd.Parameters.AddWithValue("@projectedLtsf12Mo", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@projectedLtsf12Mo", decimal.Parse(projectedLtsf12Mo)); } + + if (unitsShippedLast7Days.Length == 0) { cmd.Parameters.AddWithValue("@unitsShippedLast7Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@unitsShippedLast7Days", int.Parse(unitsShippedLast7Days)); } + + if (unitsShippedLast30Days.Length == 0) { cmd.Parameters.AddWithValue("@unitsShippedLast30Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@unitsShippedLast30Days", int.Parse(unitsShippedLast30Days)); } + + if (unitsShippedLast60Days.Length == 0) { cmd.Parameters.AddWithValue("@unitsShippedLast60Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@unitsShippedLast60Days", int.Parse(unitsShippedLast60Days)); } + + if (unitsShippedLast90Days.Length == 0) { cmd.Parameters.AddWithValue("@unitsShippedLast90Days", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@unitsShippedLast90Days", int.Parse(unitsShippedLast90Days)); } + + if (alert.Length == 0) { cmd.Parameters.AddWithValue("@alert", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@alert", alert); } + + if (yourPrice.Length == 0) { cmd.Parameters.AddWithValue("@yourPrice", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@yourPrice", decimal.Parse(yourPrice)); } + + if (salesPrice.Length == 0) { cmd.Parameters.AddWithValue("@salesPrice", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@salesPrice", decimal.Parse(salesPrice)); } + + if (lowestPriceNew.Length == 0) { cmd.Parameters.AddWithValue("@lowestPriceNew", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@lowestPriceNew", decimal.Parse(lowestPriceNew)); } + + if (lowestPriceUsed.Length == 0) { cmd.Parameters.AddWithValue("@lowestPriceUsed", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@lowestPriceUsed", decimal.Parse(lowestPriceUsed)); } + + if (recommendedAction.Length == 0) { cmd.Parameters.AddWithValue("@recommendedAction", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@recommendedAction", recommendedAction); } + + if (healthyInventoryLevel.Length == 0) { cmd.Parameters.AddWithValue("@healthyInventoryLevel", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@healthyInventoryLevel", int.Parse(healthyInventoryLevel)); } + + if (recommendedSalesPrice.Length == 0) { cmd.Parameters.AddWithValue("@recommendedSalesPrice", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@recommendedSalesPrice", decimal.Parse(recommendedSalesPrice)); } + + if (recommendedSaleDuration.Length == 0) { cmd.Parameters.AddWithValue("@recommendedSaleDuration", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@recommendedSaleDuration", int.Parse(recommendedSaleDuration)); } + + if (recommendedRemovalQuantity.Length == 0) { cmd.Parameters.AddWithValue("@recommendedRemovalQuantity", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@recommendedRemovalQuantity", int.Parse(recommendedRemovalQuantity)); } + + if (estimatedCostSavingsOfRemoval.Length == 0) { cmd.Parameters.AddWithValue("@estimatedCostSavingsOfRemoval", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@estimatedCostSavingsOfRemoval", decimal.Parse(estimatedCostSavingsOfRemoval)); } + + // execute the query + cmd.ExecuteNonQuery(); + } + } + } + Console.Write("\r"); + MiscFunction.EventLogInsert( + "Operation complete. " + lineNumber + " items processes. " + (lineNumber - lineErrorSkip - lineNoStockSkip) + " total new items inserted, " + + lineNoStockSkip + " 'No Stock' records were skipped."); + if (lineErrorSkip > 0) + { + MiscFunction.EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1); + } + } + } + scope.Complete(); + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Something went wrong during import, check details for more.", 1, ex.ToString()); + Console.WriteLine(ex.ToString()); + } + } + public void UpdateAmazonSettlementData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE_V2_"; + + MiscFunction.EventLogInsert("Requesting 'unacknowledged' '" + mwsReportEnum + "' MWS reports"); + + /* + / get the list of avaiable reports + */ + + TypeList reportList = new TypeList(); + reportList.Type.Add(mwsReportEnum); + GetReportListRequest requestList = new GetReportListRequest(); + requestList.Merchant = merchantId; + requestList.MaxCount = 100; + requestList.ReportTypeList = reportList; + bool? returnAcknowledged = false; + if (returnAcknowledged == true) { requestList.Acknowledged = true; } + else if (returnAcknowledged == false) { requestList.Acknowledged = false; } + + /* + / request, recive request, and then iterate through the list + */ + + List reportInfoList = GetMwsReportList(requestList); + + int reportsImported = 0; + foreach (ReportInfo reportInfo in reportInfoList) + { + //don't know what this next line does, might need it + //if (reportInfo.IsSetReportId() & reportInfo.IsSetAcknowledged()) + + string reportId = reportInfo.ReportId; + bool acknowledged = reportInfo.Acknowledged; + string filePath = GetMwsReportById(reportInfo.ReportId); + + /* + * Pass file path to function to parse into database + */ + + bool import = ImportReportSettlementData(sqlConnectionString, filePath); + + // if opertion succeded, set the acknowledged property + if (import & (returnAcknowledged == false | returnAcknowledged == null)) + { + SetMwsReportAcknowledgement(reportId, true); + } + if (import == true) + { + reportsImported = reportsImported + 1; + } + } + if (reportsImported > 0) + { + MiscFunction.EventLogInsert("No new '" + mwsReportEnum + "' reports available for download."); + //return true; + } + else + { + MiscFunction.EventLogInsert("Total of " + reportsImported + " new settlement reports imported"); + //return false; + } + } + public void UpdateFbaInventoryReceiptData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_"; + + /* + * Not able to uniquley define each row in flat file and check for duplicate in DB + * therefore, do not download report date range that has already been imported, as records will be duplicated + * + * Due to a MWS bug, MWS can/will include some records that are before the specified date range. As mws report is updated once daily, + * it is safe to omitt lines < startDate when parsing/inserting lines into db (as these will have been previously imported) + */ + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + DateTime currentTime = DateTime.UtcNow.AddMinutes(-5); + + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([received-date]) AS MaxDate FROM tblImportFbaInventoryReceiptReport;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2014-09-01T00:00:00Z"); + // no need to specific timezone, etc, as "Z" already specifis UTC + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + startTime = startTime.AddSeconds(1); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping UpdateFbaInventoryReceiptData method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaInventoryReceipt(sqlConnectionString, reportPath, startTime); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + public void UpdateFbaSaleShipmentData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_"; + + //// Uncomment to override getreport and load directly from file + //bool ackImportTemp = FbaSaleShipmentReportImport(@"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\7019109828017378.txt"); + //return; + + /* + * flat file lines/rows are unique + * FROM MWS GUIDANCE + * https://docs.developer.amazonservices.com/en_UK/fba_guide/FBAGuide_TipsShipmentsReport.html + * Overlap report by 3 days. To disambiguate duplicate shipment reports, use the ShipmentItemId (not the OrderId or the OrderItemId) + */ + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + DateTime latestTime = DateTime.UtcNow.AddMinutes(-5); + + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([shipment-date]) AS MaxDate FROM tblImportFbaSaleShipment;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2014-09-01T00:00:00Z"); + // no need to specific timezone, etc, as "Z" already specifis UTC + startTime = DateTime.Parse("2016-02-01T00:00:00Z"); + // fba sale shipments for previous 18 months only + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + // Amazon states in MWS guidance that shipments are added in near real time, however, in most cases, + // there will be a delay of approximately one to three hours. In some rare cases there could be a delay of up to 24 hours. + startTime = startTime.AddDays(-3); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping GetFbaReturnsReport method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaSaleShipment(sqlConnectionString, reportPath); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + public void UpdateFbaReturnData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA_"; + + //_GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA_ + + //// Uncomment to override getreport and load directly from file + //bool ackImportTemp = ImportFbaReturnsReport(@"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\7027223463017379.txt"); + //return; + + /* + * flat file lines/rows maybe unique + * Overlap reports by 3 days. + * To disambiguate duplicate row, I will use combination of date, orderid, fnsku, quantity, LPN#, disposition, and reason. + */ + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([return-date]) AS MaxDate FROM tblImportFbaCustomerReturn;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2015-08-25T00:00:00Z"); //this before first return + // no need to specific timezone, etc, as "Z" already specifis UTC + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + // Amazon states in MWS guidance that content updated daily. + startTime = startTime.AddDays(-14); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running GetFbaReturnsReport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping GetFbaReturnsReport method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaReturns(sqlConnectionString, reportPath); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + public void UpdateFbaAdustmentData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_"; + + //// Uncomment to override getreport and load directly from file + //bool ackImportTemp = ImportFbaAdustmentReport(@"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\7034366409017380.txt"); + //return; + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([adjusted-date]) AS MaxDate FROM tblImportFbaInventoryAdjustmentReport;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2014-09-01T00:00:00Z"); + // no need to specific timezone, etc, as "Z" already specifis UTC + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + // Amazon states in MWS guidance that content updated daily. + startTime = startTime.AddDays(-3); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running GetFbaAdustmentData, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping GetFbaAdustmentData method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaAdjustment(sqlConnectionString, reportPath); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + public void UpdateFbaReimbursementData(string sqlConnectionString) + { + string mwsReportEnum = "_GET_FBA_REIMBURSEMENTS_DATA_"; + + // Uncomment to override getreport and load directly from file + //bool ackImportTemp = ImportFbaReimbursementReport(@"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\7037074827017380.txt"); + //return; + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([approval-date]) AS MaxDate FROM tblImportFbaReimbursementReport;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2014-09-01T00:00:00Z"); + // no need to specific timezone, etc, as "Z" already specifis UTC + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + // Amazon states in MWS guidance that content updated daily. + startTime = startTime.AddDays(-3); + //startTime = DateTime.Parse("2015-05-01T00:00:00Z"); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running GetFbaReimbursementData, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping GetFbaReimbursementData method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaReimbursement(sqlConnectionString, reportPath); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + public void UpdateFbaRemovalOrderReport(string sqlConnectionString) + { + string mwsReportEnum = "_GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA_"; + + // Uncomment to override getreport and load directly from file + //bool ackImportTemp = ImportFbaReimbursementReport(@"C:\Users\Bobbie\AppData\Local\Temp\_e2A Client\File\7037074827017380.txt"); + //return; + + // get the most recent date from db table + DateTime startTime; + DateTime endTime = DateTime.UtcNow; + SqlConnection sqlConn; + try + { + using (sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand( + "SELECT Max([request-date]) AS MaxDate FROM tblImportFbaRemovalOrderReport;" + , sqlConn)) + { + if (cmd.ExecuteScalar() == DBNull.Value) + { + // use first month started selling on Amazon + startTime = DateTime.Parse("2015-09-15T00:00:00Z"); + // no need to specific timezone, etc, as "Z" already specifis UTC + } + else + { + startTime = ((DateTime)cmd.ExecuteScalar()); + startTime = DateTime.SpecifyKind(startTime, DateTimeKind.Utc); + startTime = startTime.AddDays(-30); // yes, that's right -30 days + //startTime = DateTime.Parse("2015-05-01T00:00:00Z"); + } + } + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("Error running GetFbaRemovalOrderReport, no records were commited", + 1, + ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage() + ); + return; + } + + // get list of reports + List reportPathList = GetMwsReportByPeriod(mwsReportEnum, startTime, endTime, 24); + if (reportPathList.Count == 0) + { + // no report downloadeded + MiscFunction.EventLogInsert("No reports downloaded, stopping GetFbaReimbursementData method..."); + return; + } + + // loop throught list of filepaths + foreach (string reportPath in reportPathList) + { + bool ackImport = ImportReportFbaRemovalOrder(sqlConnectionString, reportPath); + if (ackImport == false) + { + MiscFunction.EventLogInsert("Problem importing report '" + mwsReportEnum + "'. stopping further report imports...", + 1, + MiscFunction.TraceMessage() + ); + return; + } + } + } + + } + public class MiscFunction + { + public static void EventLogInsert + (string detailShort = "", int eventType = 3, string detailLong = "", DateTime eventDateTime = default(DateTime), bool consolePrint = true) + { + // login credentials only allow insert on log table + string userId = "Log_bnhtrade"; + string password = "52ya9dky55cniyynwro5e48mV9"; + string sqlConnectionString = + "Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=TRUE;User ID=" + userId + + ";Password=" + password + ";MultipleActiveResultSets=TRUE"; + + using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress)) + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + if (detailShort.Length == 0) + { + throw new ArgumentException("The string parameter detailShort is empty, this is a required paramenter."); + } + if (eventDateTime == default(DateTime)) + { + eventDateTime = DateTime.UtcNow; + } + try + { + using (SqlCommand cmd = new SqlCommand( + "INSERT INTO tblLogEvent ( EventDateTime, LogEventTypeID, LogEventSourceID, Detail, DetailLong )" + + "VALUES ( @eventDateTime, @eventType, 1, @detailShort, @detailLong );" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@eventDateTime", eventDateTime); + cmd.Parameters.AddWithValue("@eventType", eventType); + cmd.Parameters.AddWithValue("@detailShort", detailShort); + cmd.Parameters.AddWithValue("@detailLong", detailLong); + + cmd.ExecuteNonQuery(); + } + ConsoleUpdate(detailShort); + } + catch (Exception ex) + { + ConsoleUpdate("WTF!!!! Error with error logging, jobs foooked!"); + throw ex; + } + scope.Complete(); + } + } + } + public static string TraceMessage( + [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", + [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", + [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) + { + string traceMessage = + "Trace:" + + "\r\n\tmember name: " + memberName + + "\r\n\tsource file path: " + sourceFilePath + + "\r\n\tsource line number: " + sourceLineNumber; + return traceMessage; + } + public static void MwsThrottleWait(int waitSeconds) + { + MiscFunction.EventLogInsert("MWS request throttled, retrying in " + waitSeconds + " seconds..."); + string consoleMessage = "{0} seconds remaining..."; + ConsoleCountDown(consoleMessage, waitSeconds); + } + public static void ConsoleCountDown(string consoleMessage, int waitSeconds) + { + do + { + Console.Write("\r[--------] " + consoleMessage, String.Format("{0:00}", waitSeconds)); + System.Threading.Thread.Sleep(1000); + waitSeconds = waitSeconds - 1; + } while (waitSeconds > 0); + Console.Write("\r"); + Console.Write(new String(' ', Console.BufferWidth -1)); + Console.Write("\r"); + } + public static void ConsoleUpdate(string consoleText, Boolean newLine = true) + { + if (newLine) + { + Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + consoleText); + } + else + { + Console.WriteLine("\r[" + DateTime.Now.ToString("HH:mm:ss") + "] " + consoleText); + } + } + public static string GetTempFilePath(string fileName) + { + string directoryPath = Path.GetTempPath() + + "_" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + + "\\File\\"; + System.IO.Directory.CreateDirectory(directoryPath); + string fullPath = directoryPath + fileName; + return fullPath; + } + public static 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); + } + + } + public class TempFunction + { + public void UpdateSkuCost(string sqlConnectionString) + { + MiscFunction.EventLogInsert("Starting temp function UpdateSkuCost()"); + int count = 0; + + try + { + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd01 = sqlConn.CreateCommand()) + { + //query for list of all sku's with stock + + cmd01.CommandText = @" + SELECT sku, [mfn-fulfillable-quantity], [afn-total-quantity] + FROM tblImportFbaManageInventory + WHERE ( [mfn-fulfillable-quantity] > 0 ) OR ( [afn-total-quantity] > 0 ) + "; + + using (SqlDataReader reader01 = cmd01.ExecuteReader()) + { + // retrive index of columns for faster operation + int indexOfColumn1 = reader01.GetOrdinal("sku"); + int indexOfColumn2 = reader01.GetOrdinal("mfn-fulfillable-quantity"); + int indexOfColumn3 = reader01.GetOrdinal("afn-total-quantity"); + + while (reader01.Read()) + { + count = count + 1; + Console.Write("\rProcessing record #" + count); + + //assign values + string skuNumber = reader01.GetString(indexOfColumn1); + + int mfnTotal; + if (reader01.IsDBNull(indexOfColumn2)) { mfnTotal = 0; } + else { mfnTotal = reader01.GetInt32(indexOfColumn2); } + + int afnTotal; + if (reader01.IsDBNull(indexOfColumn3)) { afnTotal = 0; } + else { afnTotal = reader01.GetInt32(indexOfColumn3); } + + int total = mfnTotal + afnTotal; + + //query for average unit cost + using (SqlCommand cmd02 = new SqlCommand(@" + SELECT AVG(Q.UnitCost) AS AvgCost + FROM( + SELECT TOP (@total) UnitQuantity, n, UnitCost + FROM(tblNumbers INNER JOIN tblStock ON n <= UnitQuantity) INNER JOIN tblSku ON SkuID = skuSkuID + WHERE(skuSkuNumber = @skuNumber) + ORDER BY StockID DESC + ) Q + ", sqlConn)) + { + cmd02.Parameters.AddWithValue("@total", total); + cmd02.Parameters.AddWithValue("@skuNumber", skuNumber); + + decimal AvgCost = 0; + object obj = cmd02.ExecuteScalar(); + if (obj == null || obj == DBNull.Value) + { + AvgCost = 0; + } + else + { + AvgCost = Convert.ToDecimal(obj); + } + AvgCost = Math.Round(AvgCost, 2); + + //Console.WriteLine(skuNumber + " " + AvgCost); + + //update sku table + using (SqlCommand cmd03 = sqlConn.CreateCommand()) + { + cmd03.Parameters.AddWithValue("@skuNumber", skuNumber); + cmd03.Parameters.AddWithValue("@AvgCost", AvgCost); + cmd03.Parameters.AddWithValue("@timeStamp", DateTime.UtcNow); + + Console.Write(" £" + AvgCost ); + + cmd03.CommandText = + "UPDATE tblSku " + + "SET skuSkuAvgCost = @AvgCost, skuSkuAvgCostUpdate = @timeStamp " + + "WHERE skuSkuNumber = @skuNumber;"; + cmd03.ExecuteNonQuery(); + } + } + } + + } + } + Console.Write("\r"); + MiscFunction.EventLogInsert("UpdateSkuCost() operation complete. " + count + " total SKU average cost(s) updated"); + } + } + catch (Exception ex) + { + MiscFunction.EventLogInsert("UpdateSkuCost() operation exceltion. See 'details' for further information.", 1, ex.ToString()); + Console.WriteLine(ex.ToString()); + } + } + } +} \ No newline at end of file diff --git a/bnhtrade Database Client/Properties/AssemblyInfo.cs b/bnhtrade Database Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0ee464f --- /dev/null +++ b/bnhtrade Database Client/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("bnhtrade Database Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("bnhtrade Database Client")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("339d7413-3da7-46ea-a55c-255a9a6b95eb")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/bnhtrade Database Client/Properties/Settings.Designer.cs b/bnhtrade Database Client/Properties/Settings.Designer.cs new file mode 100644 index 0000000..da84bd8 --- /dev/null +++ b/bnhtrade Database Client/Properties/Settings.Designer.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace bnhtradeDatabaseClient.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] + [global::System.Configuration.DefaultSettingValueAttribute("Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=True;User ID=e2A" + + " Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=true")] + public string ConnectionString { + get { + return ((string)(this["ConnectionString"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("%USERPROFILE%\\Desktop\\e2A_Client\\Archive\\")] + public string DocArchivePath { + get { + return ((string)(this["DocArchivePath"])); + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("%USERPROFILE%\\Desktop\\e2A_Client\\Processing\\")] + public string DocProcessingPath { + get { + return ((string)(this["DocProcessingPath"])); + } + } + } +} diff --git a/bnhtrade Database Client/Properties/Settings.settings b/bnhtrade Database Client/Properties/Settings.settings new file mode 100644 index 0000000..3f9552e --- /dev/null +++ b/bnhtrade Database Client/Properties/Settings.settings @@ -0,0 +1,20 @@ + + + + + + <?xml version="1.0" encoding="utf-16"?> +<SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <ConnectionString>Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=True;User ID=e2A Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=true</ConnectionString> + <ProviderName>System.Data.SqlClient</ProviderName> +</SerializableConnectionString> + Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=True;User ID=e2A Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=true + + + %USERPROFILE%\Desktop\e2A_Client\Archive\ + + + %USERPROFILE%\Desktop\e2A_Client\Processing\ + + + \ No newline at end of file diff --git a/bnhtrade Database Client/SQL Connection.cs b/bnhtrade Database Client/SQL Connection.cs new file mode 100644 index 0000000..a819dbb --- /dev/null +++ b/bnhtrade Database Client/SQL Connection.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Data.SqlClient; +using System.Runtime.InteropServices; + +namespace DatabaseConnection +{ + //[ComVisible(true)] + //[Guid("8bebe939-7a73-4ba3-877b-50cd2a7e4586")] + //[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface bnhtradeDbInterface + { + SqlConnection Connection(string DataSource, string InitialCatalog, string UserId, string Password, bool PersistSecurityInfo = true, bool MultipleActiveResultSets = true); + } + + //[ComVisible(true)] + //[Guid("b0e29c9e-d353-4d3a-83dd-5278b520af54")] + //[ClassInterface(ClassInterfaceType.None)] + ////[ProgId("MyNameSpace.Criteria")] + public class bnhtradeDb : bnhtradeDbInterface + { + public SqlConnection Connection(string DataSource, string InitialCatalog, string UserId, string Password, bool PersistSecurityInfo = true, bool MultipleActiveResultSets = true) + { + if (InitialCatalog == "" || DataSource == "" || UserId == "" || Password == "") + { + throw new Exception("Insuficent info supplied for sql connection string"); + } + string connString = + "Data Source=" + DataSource + ";Initial Catalog=" + InitialCatalog + ";Persist Security Info=" + PersistSecurityInfo.ToString() + ";" + + "User ID=" + UserId + ";Password=" + Password + ";MultipleActiveResultSets=" + MultipleActiveResultSets.ToString() + ""; + + SqlConnection sqlConn = new SqlConnection(connString); + + return sqlConn; + } + } +} \ No newline at end of file diff --git a/bnhtrade Database Client/VBA Wrapper.cs b/bnhtrade Database Client/VBA Wrapper.cs new file mode 100644 index 0000000..5e7f583 --- /dev/null +++ b/bnhtrade Database Client/VBA Wrapper.cs @@ -0,0 +1,539 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using bnhtradeDatabaseClient.Product; +using bnhtradeDatabaseClient.EbayQuery; +using bnhtradeDatabaseClient.Database; +using bnhtradeDatabaseClient; +using bnhtradeDatabaseClient; +using System.Data.SqlClient; +using System.IO; +using System.Reflection; +using static Vba6.StockQuery; + +namespace Vba6 +{ + [ComVisible(true)] + [Guid("033326dd-6edb-4343-8334-4c31acf3565e")] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IConnectionCredential + { + string UserId { get; set; } + string Password { get; set; } + string ConnectionString { get; } + } + + [ComVisible(true)] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + [Guid("b670a3fc-feeb-487b-ad25-89a1115e9aa5")] + public interface IVbaSqlConnection + { + SqlConnection GetSqlConnection(ConnectionCredential vbaConnCred); + } + + [ComVisible(true)] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + [Guid("05860bc9-6a6d-4b8f-a611-3921c4b4755c")] + public interface IEbayQuery + { + int EbayListingItemGet(string itemNumber, DateTime listingEnd, ConnectionCredential sqlConnCred); + + object[] EbayListingItemInsert(string itemNumber, DateTime listingEnd, string listingTitle, string listingDescription, string ebayUser, + bool isAuction, [MarshalAs(UnmanagedType.Currency)] decimal price, DateTime priceTime, [MarshalAs(UnmanagedType.Currency)] decimal shipping, + string itemLocation, string category, string imageFilePath, ConnectionCredential sqlConnCred); + } + + [ComVisible(true)] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + [Guid("0fd536ce-b913-438d-9343-9a1a7a40af71")] + public interface IAmazonMws + { + + } + + [ComVisible(true)] + [Guid("90eefc75-11d7-449d-a99f-3e4d1a795ebc")] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IPurchaseQuery + { + void PurchaseLineTransactionNetInsert(ConnectionCredential sqlConnCred, int purchaseLineId, int debitAccountId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, + DateTime entryDate); + + void PurchaseLineTransactionNetUpdate(ConnectionCredential sqlConnCred, int accountJouranlId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, int debitAccountId); + + void PurchaseLineTransactionDelete(ConnectionCredential sqlConnCred, int purchaseLineId, int accountJournalId); + + int PurchaseLineTransactionStockInsert(ConnectionCredential sqlConnCred, int accountJournalId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, + int accountTaxCodeId, int stockDebitStatusId); + + void PurchaseLineTransactionStockDelete(ConnectionCredential sqlConnCred, int stockId); + } + + + [ComVisible(true)] + [Guid("b6215466-7b84-4d1f-807f-6b305a4c05f0")] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IAccountQuery + { + int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false); + + bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId); + + [return: MarshalAs(UnmanagedType.Currency)] + decimal CurrencyConvertToGbp(ConnectionCredential sqlConnCred, string currencyCode, + [MarshalAs(UnmanagedType.Currency)] decimal amount, DateTime conversionDate); + + int CurrencyExchangeRateInsert(ConnectionCredential sqlConnCred, int exchangeRateSource, string currencyCode, + [MarshalAs(UnmanagedType.Currency)] decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false); + } + + [ComVisible(true)] + [Guid("ca9ef5b4-f0e6-4b77-9602-0d5f123a1d8d")] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IProductQuery + { + string ReturnStringValue(string stringValue); + + double ReturnDateValueAsDouble(string stringValue); + + int ProductGetProductIdByCatId(int catId, ConnectionCredential sqlConnCred); + + string ProductCompetitivePriceGet(int productId, int conditionId, ConnectionCredential sqlConnCred); + + int ProductCompetitivePriceSet(int productId, int conditionId, [MarshalAs(UnmanagedType.Currency)] decimal price, bool isBuyBoxPrice, DateTime priceDate, ConnectionCredential sqlConnCred); + + void ProductUpdateAmazonEstimateFee(ConnectionCredential sqlConnCred, object inputList); + } + + [ComVisible(true)] + [Guid("d595d682-8b1e-4aa4-86b7-700e44950e1b")] + [InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IStockQuery + { + int StockInsertPurchase(ConnectionCredential sqlConnCred, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId); + + int StockInsertOwnerIntroduced(ConnectionCredential sqlConnCred, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId); + + void StockDeletePurchase(ConnectionCredential sqlConnCred, int stockId); + + void StockDeleteOwnerIntroduced(ConnectionCredential sqlConnCred, int stockId); + + int StockReallocate(ConnectionCredential sqlConnCred, int stockId, int quantity, int debitStatusId, int creditStatusId, DateTime entryDate); + + void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId); + + object ReconcileStockTransactions(ConnectionCredential sqlConnCred); + + bool StockJournalConsistencyCheck(ConnectionCredential sqlConnCred, int stockId); + } + + //[ComVisible(true)] + //[Guid("0558e6dc-f5d4-41b6-a51c-856426e77e21")] + //[InterfaceType(ComInterfaceType.InterfaceIsDual)] + //public interface IReconcileStockTransactionsResult + //{ + // bool ReconciliationComplete { get; set; } + // int StockTransactionId { get; set; } + // int StockTransactionTypeId { get; set; } + // string ProgressMessage { get; set; } + // int ItemsCompleted { get; set; } + // int ItemsRemaining { get; set; } + // DateTime LastItemDateTime { get; set; } + //} + + + + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.None)] + [Guid("7aa43409-317a-43ad-85f9-2019b5883ab8")] + [ProgId("bnhtradeDb.ConnectionCredential")] + public class ConnectionCredential : IConnectionCredential + { + public string UserId { get; set; } + public string Password { get; set; } + public string ConnectionString + { + get + { + return "Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=True;User ID=" + UserId + + ";Password=" + Password + ";MultipleActiveResultSets=true"; + } + } + } + + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.None)] + [Guid("ab7f6468-42db-4f33-8c94-62dc7e1759ea")] + [ProgId("bnhtradeDb.Connection")] + public class VbaSqlConnection : IVbaSqlConnection + { + [ComVisible(false)] + public SqlConnection GetSqlConnection(ConnectionCredential vbaConnCred) + { + Connection.DatabaseConnectionDetail connDetail = new Connection.DatabaseConnectionDetail(); + connDetail.UserId = vbaConnCred.UserId; + connDetail.Password = vbaConnCred.Password; + + SqlConnection sqlConn = new SqlConnection(connDetail.ConnectionString); + + return sqlConn; + } + } + + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.None)] + [Guid("e6743dfa-47d3-4aeb-8f2b-d4e0d5312146")] + [ProgId("bnhtradeDb.EbayQuery")] + public class EbayQuery : IEbayQuery + { + public int EbayListingItemGet(string itemNumber, DateTime listingEnd, ConnectionCredential sqlConnCred) + { + Ebay request = new Ebay(); + return request.EbayListingItemGet(sqlConnCred.ConnectionString, itemNumber, listingEnd); + + } + + public object[] EbayListingItemInsert(string itemNumber, DateTime listingEnd, string listingTitle, string listingDescription, string ebayUser, + bool isAuction, [MarshalAs(UnmanagedType.Currency)] decimal price, DateTime priceTime, [MarshalAs(UnmanagedType.Currency)] decimal shipping, + string itemLocation, string category, string imageFilePath, ConnectionCredential sqlConnCred) + { + // load imagefile + FileStream imageFile = null; + string imageFileExtension = ""; + if (imageFilePath.Length > 0) + { + imageFileExtension = Path.GetExtension(imageFilePath); + if (imageFileExtension == string.Empty) + { + throw new Exception("Error parsing file extension from file path."); + } + imageFileExtension = imageFileExtension.Substring(1); + imageFile = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read); + } + + // create the return array object + Ebay request = new Ebay(); + (int ListingItemId, bool IsNewListingItem, bool IsNewListing) result = + request.EbayListingItemInsert(sqlConnCred.ConnectionString, itemNumber, listingEnd, listingTitle, listingDescription, ebayUser, + isAuction, price, priceTime, shipping, itemLocation, category, imageFile, imageFileExtension); + if (imageFile != null) + { imageFile.Dispose(); } + + // create return array + object[] returnArray = new object[3]; + returnArray[0] = result.ListingItemId; + returnArray[1] = result.IsNewListingItem; + returnArray[2] = result.IsNewListing; + return returnArray; + + } + } + + [ComVisible(true)] + [Guid("23527370-5f3f-47d8-b6a0-35b73890876c")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("bnhtradeDb.AmazonMws")] + // [ClassInterface(ClassInterfaceType.AutoDual)] + public class AmazonMws : IAmazonMws + { + static void ProductUpdateAmazonEstimateFee() + { + + } + } + + [ComVisible(true)] + [Guid("59afd52d-86f4-4863-98e9-7b63a8b3ba51")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("bnhtradeDb.ProductQuery")] + public class PurchaseQuery : IPurchaseQuery + { + public void PurchaseLineTransactionNetInsert(ConnectionCredential sqlConnCred, int purchaseLineId, int debitAccountId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, + DateTime entryDate) + { + bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetInsert(sqlConnCred.ConnectionString, + purchaseLineId, currencyCode, amountNet, entryDate); + } + + public void PurchaseLineTransactionNetUpdate(ConnectionCredential sqlConnCred, int accountJouranlId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, int debitAccountId) + { + bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetUpdate(sqlConnCred.ConnectionString, + accountJouranlId, currencyCode, amountNet, debitAccountId); + } + + public void PurchaseLineTransactionDelete(ConnectionCredential sqlConnCred, int purchaseLineId, int accountJournalId) + { + bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionDelete(sqlConnCred.ConnectionString, purchaseLineId, accountJournalId); + } + + public int PurchaseLineTransactionStockInsert(ConnectionCredential sqlConnCred, int accountJournalId, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, + int accountTaxCodeId, int stockDebitStatusId) + { + return bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockInsertPurchase(sqlConnCred.ConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, quantity, stockDebitStatusId); + } + + public void PurchaseLineTransactionStockDelete(ConnectionCredential sqlConnCred, int stockId) + { + bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockDeletePurchase(sqlConnCred.ConnectionString, stockId); + } + } + +[ComVisible(true)] + [Guid("debaee08-a3d5-4f9b-b8cf-ad146c3e0ee9")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("bnhtradeDb.AccountQuery")] + public class AccountQuery : IAccountQuery + { + public int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate, + string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false) + { + return bnhtradeDatabaseClient.Account.AccountQuery.AccountJournalInsert(sqlConnCred.ConnectionString, journalTypeId, entryDate, + currencyCode, amount, debitAccountId, creditAccountId, lockEntry); + } + + public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId) + { + return bnhtradeDatabaseClient.Account.AccountQuery.AccountJournalDelete(sqlConnCred.ConnectionString, accountJournalId); + } + + [return: MarshalAs(UnmanagedType.Currency)] + public decimal CurrencyConvertToGbp(ConnectionCredential sqlConnCred, string currencyCode, + [MarshalAs(UnmanagedType.Currency)] decimal amount, DateTime conversionDate) + { + return bnhtradeDatabaseClient.Account.AccountQuery.CurrencyConvertToGbp(sqlConnCred.ConnectionString, currencyCode, amount, conversionDate); + } + + public int CurrencyExchangeRateInsert(ConnectionCredential sqlConnCred, int exchangeRateSource, string currencyCode, + [MarshalAs(UnmanagedType.Currency)] decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false) + { + return bnhtradeDatabaseClient.Account.AccountQuery.CurrencyExchangeRateInsert(sqlConnCred.ConnectionString, exchangeRateSource, currencyCode, + currencyUnitsPerGbp, periodStart, periodEnd, checkOverride); + } + } + + [ComVisible(true)] + [Guid("237ac4be-87f0-4500-bd74-0423d1f72c75")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("bnhtradeDb.ProductQuery")] + public class ProductQuery : IProductQuery + { + [ComVisible(false)] + [return: MarshalAs(UnmanagedType.BStr)] + public string ReturnStringValue(string stringValue) + { + return "kj;lk1"; + } + + [ComVisible(false)] + public double ReturnDateValueAsDouble(string stringValue) + { + DateTime theTimeNow = DateTime.UtcNow; + return theTimeNow.ToOADate(); + // back in vba use the CDate(return) function to convert the double + // vba Date --> c# DateTime works without marshalling + } + + public int ProductGetProductIdByCatId(int catId, ConnectionCredential sqlConnCred) + { + var request = new bnhtradeDatabaseClient.Product.ProductQuery(); + int? result = request.ProductGetProductIdByCatId(sqlConnCred.ConnectionString, catId); + if (result == null) + { + return 0; + } + else + { + return result.Value; + } + } + + public string ProductCompetitivePriceGet(int productId, int conditionId, ConnectionCredential sqlConnCred) + { + var request = new bnhtradeDatabaseClient.Product.ProductQuery(); + (decimal? price, DateTime? priceDate) result = request.ProductCompetitivePriceGet(sqlConnCred.ConnectionString, productId, conditionId); + if (result.price == null || result.priceDate == null) + { + return ""; + } + else + { + DateTime priceDate2 = result.priceDate.Value; + return result.price.ToString() + ";" + priceDate2.ToOADate(); + } + } + public int ProductCompetitivePriceSet(int productId, int conditionId, [MarshalAs(UnmanagedType.Currency)] decimal price, bool isBuyBoxPrice, DateTime priceDate, ConnectionCredential sqlConnCred) + { + var request = new bnhtradeDatabaseClient.Product.ProductQuery(); + return request.ProductCompetitivePriceSet(sqlConnCred.ConnectionString, productId, conditionId, price, isBuyBoxPrice, priceDate); + } + + public void ProductUpdateAmazonEstimateFee(ConnectionCredential sqlConnCred, object inputList) + { + // get com object in string array + var inputTuple = new List<(string asin, decimal priceToEstimate)>(); + string[] stringArray = Vba6.Functions.LoadComObjectIntoStringArray(inputList); + + foreach (var item in stringArray) + { + string[] split = item.Split(';'); + if (split.Length != 2) + { + throw new Exception("Split function failed on line: " + item); + } + var tempTuple = (split[0], decimal.Parse(split[1])); + inputTuple.Add(tempTuple); + } + + bnhtradeDatabaseClient.Product.ProductQuery.ProductUpdateAmazonEstimateFee(sqlConnCred.ConnectionString, inputTuple); + } + + } + + [ComVisible(true)] + [Guid("10ff112d-a94f-4818-add4-8dddabf1fa9e")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("bnhtradeDb.StockQuery")] + // [ClassInterface(ClassInterfaceType.AutoDual)] + public class StockQuery : IStockQuery + { + public int StockInsertPurchase(ConnectionCredential sqlConnCred, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId) + { + return bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockInsertPurchase(sqlConnCred.ConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, quantity, statusDebitId); + } + + public int StockInsertOwnerIntroduced(ConnectionCredential sqlConnCred, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) + { + return bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockInsertOwnerIntroduced(sqlConnCred.ConnectionString, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId); + } + + public void StockDeletePurchase(ConnectionCredential sqlConnCred, int stockId) + { + bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockDeletePurchase(sqlConnCred.ConnectionString, stockId); + } + + public void StockDeleteOwnerIntroduced(ConnectionCredential sqlConnCred, int stockId) + { + bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockDeleteOwnerIntroduced(sqlConnCred.ConnectionString, stockId); + } + + public int StockReallocate(ConnectionCredential sqlConnCred, int stockId, int quantity, int debitStatusId, int creditStatusId, DateTime entryDate) + { + entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + return bnhtradeDatabaseClient.Stock.StockJournal.StockReallocateByStockId(sqlConnCred.ConnectionString, 4, stockId, quantity, debitStatusId, creditStatusId, entryDate); + } + + public void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId) + { + bnhtradeDatabaseClient.Stock.StockJournal.StockJournalDelete(sqlConnCred.ConnectionString, stockJournalId); + } + + public object ReconcileStockTransactions(ConnectionCredential sqlConnCred) + { + var request = new bnhtradeDatabaseClient.Stock.StockReconciliation(); + var result = new bnhtradeDatabaseClient.Stock.StockReconciliation.ReconcileStockTransactionsResult(); + + result = request.ReconcileStockTransactions(sqlConnCred.ConnectionString, false); + + //ReconcileStockTransactionsResult returnObject = new ReconcileStockTransactionsResult(); + + // copy values between classes + + //PropertyInfo[] infos = typeof(ReconcileStockTransactionsResult).GetProperties(); + //foreach (PropertyInfo info in infos) + //{ + // info.SetValue(returnObject, info.GetValue(result, null), null); + //} + + //foreach (PropertyInfo property in typeof(ReconcileStockTransactionsResult).GetProperties()) + //{ + // if (property.CanWrite) + // { + // property.SetValue(returnObject, property.GetValue(result, null), null); + // } + //} + + //returnObject.ItemsCompleted = result.ItemsCompleted; + //returnObject.ItemsRemaining = result.ItemsRemaining; + //returnObject.LastItemDateTime = result.LastItemDateTime; + //returnObject.ProgressMessage = result.ProgressMessage; + //returnObject.ReconciliationComplete = returnObject.ReconciliationComplete; + //returnObject.StockTransactionId = result.StockTransactionId; + //returnObject.StockTransactionTypeId = result.StockTransactionTypeId; + + //create the return array + object[] returnArray = new object[7]; + returnArray[0] = result.ReconciliationComplete; + returnArray[1] = result.ProgressMessage; + returnArray[2] = result.StockTransactionId; + returnArray[3] = result.StockTransactionTypeId; + returnArray[4] = result.LastItemDateTime; + returnArray[5] = result.ItemsCompleted; + returnArray[6] = result.ItemsRemaining; + return returnArray; + + //return returnObject; + + } + + public bool StockJournalConsistencyCheck(ConnectionCredential sqlConnCred, int stockId) + { + return bnhtradeDatabaseClient.Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnCred.ConnectionString, stockId, null); + } + } + + //[ComVisible(true)] + //[Guid("75a40c36-0b36-4954-8f60-3093f040e54f")] + //[ClassInterface(ClassInterfaceType.None)] + //[ProgId("bnhtradeDb.StockReconciliationResult")] + //// [ClassInterface(ClassInterfaceType.AutoDual)] + //public class ReconcileStockTransactionsResult : IReconcileStockTransactionsResult + //{ + // public bool ReconciliationComplete { get; set; } = false; + // public int StockTransactionId { get; set; } + // public int StockTransactionTypeId { get; set; } + // public string ProgressMessage { get; set; } + // public int ItemsCompleted { get; set; } + // public int ItemsRemaining { get; set; } + // public DateTime LastItemDateTime { get; set; } + //} + + public class Functions + { + public static string[] LoadComObjectIntoStringArray(object comObject) + { + Type thisType = comObject.GetType(); + Type strType = Type.GetType("System.Object[]"); + //Type strType = Type.GetType("System.String[*]"); + string[] stringArray = new string[1]; + // temporary allocation to keep compiler happy. + if (thisType == strType) + { + object[] args = new object[1]; + + int numEntries = (int)thisType.InvokeMember("Length", BindingFlags.GetProperty, null, comObject, null); + stringArray = new string[numEntries]; + for (int i = 0; i < numEntries; i++) + { + args[0] = i; // since VB arrays index from 1, mine doesn't + stringArray[i] = (string)thisType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObject, args); + } + } // End if(thisType == dblType) + else + { + throw new Exception("something went wrong loading object into c# array. Type is '" + thisType.ToString() + "'"); + } + return stringArray; + } // End LoadComObjectIntoDoubleArray() + } +} \ No newline at end of file diff --git a/bnhtrade Database Client/bnhtradeDatabaseClient.csproj b/bnhtrade Database Client/bnhtradeDatabaseClient.csproj new file mode 100644 index 0000000..e982ba9 --- /dev/null +++ b/bnhtrade Database Client/bnhtradeDatabaseClient.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {339D7413-3DA7-46EA-A55C-255A9A6B95EB} + Library + Properties + bnhtradeDatabaseClient + bnhtradeDatabaseClient + v4.7.1 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + ..\packages\ABrain.AmazonMWS.1.0.1.6\lib\ABrain.AmazonMWS.dll + True + + + + + + + + + + + + + + + + + True + True + Settings.settings + + + + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + \ No newline at end of file diff --git a/bnhtrade Database Client/packages.config b/bnhtrade Database Client/packages.config new file mode 100644 index 0000000..7f80eca --- /dev/null +++ b/bnhtrade Database Client/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/bnhtrade Scheduled Tasks/App.config b/bnhtrade Scheduled Tasks/App.config new file mode 100644 index 0000000..710e132 --- /dev/null +++ b/bnhtrade Scheduled Tasks/App.config @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/bnhtrade Scheduled Tasks/Program.cs b/bnhtrade Scheduled Tasks/Program.cs new file mode 100644 index 0000000..0810158 --- /dev/null +++ b/bnhtrade Scheduled Tasks/Program.cs @@ -0,0 +1,552 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using bnhtradeDatabaseClient; +using bnhtradeDatabaseClient.Stock; +using System.Configuration; +using System.Transactions; + +namespace bnhtradeScheduledTasks +{ + class Program + { + static string sqlConnectionString = ConfigurationManager.ConnectionStrings["bnhtradeDbConnString"].ConnectionString; + //public static string BNHtradeDbConnectionString() + //{ + // return ConfigurationManager.ConnectionStrings["bnhtradeDbConnString"].ConnectionString; + //} + static void Main(string[] args) + { + //string sqlConnectionString = BNHtradeDbConnectionString(); + + if (args.Length == 0) + { + // get db connection string + //string sqlConnectionString = BNHtradeDbConnectionString(); + + string consoleHeader = "Welcome to THE application!\n"; + + do + { + Console.Clear(); + Console.WriteLine(consoleHeader); + Console.WriteLine("Main Menu"); + Console.WriteLine(); + Console.WriteLine("<1> Amazon reports"); + Console.WriteLine("<2> Stock functions"); + Console.WriteLine(""); + Console.WriteLine("<9> Dev functions"); + Console.WriteLine(""); + Console.WriteLine("<0> Exit"); + Console.WriteLine(""); + Console.Write("Enter an option >"); + string input = Console.ReadLine(); + + + if (input == "0") + { + break; + } + else if (input == "1") + { + do + { + Console.Clear(); + Console.WriteLine(consoleHeader); + Console.WriteLine("Main Menu > Amazon Reports"); + Console.WriteLine(); + Console.WriteLine("<1> Update all Amazon inventory and settlement data"); + Console.WriteLine("<2> Update FBA Inventory Data"); + Console.WriteLine("<3> Update FBA Inventory Age Data"); + Console.WriteLine("<4> Update Amazon Settlement Data"); + Console.WriteLine("<5> Update Fba Inventory Receipt Data"); + Console.WriteLine("<6> Update Fba Sale Shipment Data"); + Console.WriteLine("<7> Update Fba Return Data"); + Console.WriteLine("<8> Update Fba Adustment Data"); + Console.WriteLine(); + Console.WriteLine("<0> Back"); + Console.WriteLine(""); + Console.Write("Enter an option >"); + input = Console.ReadLine(); + + if (input == "0") + { + break; + } + else if (input == "1") + { + Console.Clear(); + DownloadAll(); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "2") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaInventoryData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "3") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaInventoryAgeData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "4") + { + Console.Clear(); + var task = new AmazonReport(); + var task2 = new StockReconciliation(); + task.UpdateAmazonSettlementData(sqlConnectionString); + task2.WIP_ProcessAmazonSettlementData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "5") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaInventoryReceiptData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "6") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaSaleShipmentData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "7") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaReturnData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "8") + { + Console.Clear(); + var task = new AmazonReport(); + task.UpdateFbaAdustmentData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + } while (true); + } + else if (input == "2") + { + do + { + Console.Clear(); + Console.WriteLine(consoleHeader); + Console.WriteLine("Main Menu > Stock Funcions"); + Console.WriteLine(); + Console.WriteLine("Stock Reconciliation"); + Console.WriteLine(); + Console.WriteLine("<1> Update Fba Stock Import Data"); + Console.WriteLine("<2> Process Fba Stock Import Data"); + Console.WriteLine("<3> Reconcile stock transactions"); + Console.WriteLine("<4> Run all above"); + Console.WriteLine(); + Console.WriteLine("<5> (temp) Update Amazon/Sku Min Max values"); + Console.WriteLine(); + Console.WriteLine("<0> Back"); + Console.WriteLine(""); + Console.Write("Enter an option >"); + input = Console.ReadLine(); + + if (input == "0") + { + break; + } + else if (input == "1") + { + Console.Clear(); + var task = new StockReconciliation(); + try + { + task.UpdateFbaStockImportData(sqlConnectionString); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message.ToString()); + } + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "2") + { + Console.Clear(); + var task = new StockReconciliation(); + try + { + task.ProcessFbaStockImportData(sqlConnectionString); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message.ToString()); + } + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "3") + { + Console.Clear(); + var task = new StockReconciliation(); + var result = new StockReconciliation.ReconcileStockTransactionsResult(); + try + { + result = task.ReconcileStockTransactions(sqlConnectionString, false); + Console.WriteLine(result.ItemsCompleted + " of " + (result.ItemsCompleted + result.ItemsRemaining) + " items completed."); + Console.WriteLine("Current transaction ID=" + result.StockTransactionId); + Console.WriteLine(result.ProgressMessage); + Console.WriteLine(""); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message.ToString()); + } + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "4") + { + Console.Clear(); + var task = new StockReconciliation(); + try + { + task.UpdateFbaStockImportData(sqlConnectionString); + task.ProcessFbaStockImportData(sqlConnectionString); + task.ReconcileStockTransactions(sqlConnectionString, false); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message.ToString()); + } + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "5") + { + Console.Clear(); + //try + //{ + bnhtradeDatabaseClient.Inventory.InventoryPricing.AmazonMinMaxTemp(sqlConnectionString); + //} + //catch (Exception ex) + //{ + //Console.WriteLine(ex.Message.ToString()); + //} + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + + + + } while (true); + } + else if (input == "9") + { + do + { + Console.Clear(); + Console.WriteLine(consoleHeader); + Console.WriteLine("Main Menu > Dev Funcions"); + Console.WriteLine(); + Console.WriteLine("<1> Test Import of Amazon Settlement Data into Account Transaction Table"); + Console.WriteLine("<2> Test Stock Journal Reallocate"); + Console.WriteLine("<3> test Product Update Amazon Estimate Fee"); + Console.WriteLine("<4> Process Amazon Reimbursement Report (into transactiontable)"); + Console.WriteLine("<5> Test Stock Table Delete"); + Console.WriteLine("<6> Test Owner intro insert"); + Console.WriteLine("<7> Currency exchange rate insert"); + Console.WriteLine("<8> Update Amazon Inventory Table"); + Console.WriteLine(); + Console.WriteLine("<0> Back"); + Console.WriteLine(""); + Console.Write("Enter an option >"); + input = Console.ReadLine(); + + if (input == "0") + { + break; + } + else if (input == "1") + { + Console.Clear(); + var task = new StockReconciliation(); + task.WIP_ProcessAmazonSettlementData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "2") + { + Console.Clear(); + int result = new int(); + try + { + result = TempStuff.TempTasks.testStockReallocate(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + Console.WriteLine(result); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "3") + { + Console.Clear(); + TempStuff.TempTasks.test_ProductUpdateAmazonEstimateFee(); + Console.WriteLine("Done"); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "4") + { + Console.Clear(); + var task = new StockReconciliation(); + task.WIP_ProcessFbaReimbursementData(sqlConnectionString); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "5") + { + Console.Clear(); + int result = new int(); + try + { + TempStuff.TempTasks.testStockJournalDelete(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + Console.WriteLine(result); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "6") + { + Console.Clear(); + int result = 0; + try + { + result = TempStuff.TempTasks.input6(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + Console.WriteLine(result.ToString()); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "7") + { + Console.Clear(); + //bool result = false; + int result = 0; + try + { + result = TempStuff.TempTasks.CurrencyExchangeInsert(); + Console.WriteLine("Result: " + result.ToString()); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + else if (input == "8") + { + Console.Clear(); + try + { + TempStuff.TempTasks.test_AmazonInventoryTableUpdate(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + //Console.WriteLine(result.ToString()); + Console.WriteLine("Complete, press any key to continue..."); + Console.ReadKey(); + } + + + + + } while (true); + } + } while (true); + } + else + { + if (args.Length > 1) + { + Console.WriteLine("Currently only one command line argument is accepted. Exiting application..."); + Thread.Sleep(3000); + } + else + { + if (args[0] == "RunAll") + { + Console.WriteLine("Starting all reports download..."); + Thread.Sleep(3000); + Console.Clear(); + DownloadAll(); + Console.WriteLine("Finished!! Exiting application..."); + Thread.Sleep(3000); + } + else if (args[0] == "StockReconcileUnsafe") + { + Console.WriteLine("Starting (unsafe) stock reconciliation..."); + Console.Clear(); + StockReconciliation task = new StockReconciliation(); + StockReconciliation.ReconcileStockTransactionsResult result = new StockReconciliation.ReconcileStockTransactionsResult(); + result = task.ReconcileStockTransactions(sqlConnectionString, false); + Console.WriteLine("Progress: " + result.ProgressMessage); + Console.WriteLine("Reconciled date: " + result.LastItemDateTime.ToString()); + Console.WriteLine("Transactions completed: " + result.ItemsCompleted); + Console.WriteLine("Transactions remaining: " + result.ItemsRemaining); + if (!result.ReconciliationComplete) + { + Console.WriteLine("Halted at Stock Transaction ID: " + result.StockTransactionId); + } + Console.WriteLine("Exiting application..."); + } + else + { + Console.WriteLine("Command line parameter not recognised. Exiting application..."); + Thread.Sleep(3000); + } + } + Environment.Exit(0); + } + } + private static void DownloadAll() + { + MiscFunction.EventLogInsert("Nightly scheduled tasks started."); + + var account = new AmazonReport(); + var stock = new StockReconciliation(); + + bool accountUpdate = false; + bool stockUpdate = false; + + bool accountProcess = false; + bool stockProcess = false; + + while (true) + { + try + { + if (accountUpdate == false) { accountUpdate = true; account.UpdateAmazonSettlementData(sqlConnectionString); } + if (stockUpdate == false) { stockUpdate = true; stock.UpdateFbaStockImportData(sqlConnectionString); } + + if (accountProcess == false) { accountProcess = true; stock.WIP_ProcessAmazonSettlementData(sqlConnectionString); } + // if (stockProcess == false) { stockProcess = true; stock.ProcessFbaStockImportData(); } + // ^^^^^^ best to process manually, case, fba inventory recepts, if a correction is made days later (ie -1) the already incorrect value + // will have been entered in the stocktransaction table and maked as processed in the inventoryreceipt table + + break; + } + catch (Exception ex) + { + MiscFunction.EventLogInsert( + "Exception caught running all report get method, see for further details", + 1, + ex.ToString() + ); + } + } + MiscFunction.EventLogInsert("Nightly scheduled tasks finished."); + } + } +} +namespace TempStuff +{ + public class TempTasks + { + static string sqlConnectionString = ConfigurationManager.ConnectionStrings["bnhtradeDbConnString"].ConnectionString; + + public static void testStockTableDelete() + { + //bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockTableDelete(sqlConnectionString, 15776); + } + + public static bool testStockConsistCheck() + { + //return bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockJournalConsistencyCheck(sqlConnectionString, 22677); + return false; + } + + public static void testStockDelete() + { + //bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockDelete(sqlConnectionString, 15798); + } + + public static void testStockJournalDelete() + { + //bnhtradeDatabaseClient.Stock.StockQuery.StockJournalDelete(sqlConnectionString, 33763); + } + + + public static int testStockReallocate() + { + int creditStatusId = 4; + int debitStatusId = 21; + DateTime entryDate = new DateTime(2099, 06, 15); + + //return bnhtradeDatabaseClient.Stock.StockQuery.StockReallocateByStockId(sqlConnectionString, 4, 15776, 1, debitStatusId, creditStatusId, entryDate); + + return 0; + } + public static void testPurchaseLineInsert() + { + DateTime entrdate = DateTime.Parse("07/09/2016 08:13:54"); + + //return bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineNetTransactionInsert(sqlConnectionString, 10164, "GBP", 138, 9.98m, entrdate); + bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetUpdate(sqlConnectionString, 10164, "GBP", 138, 100000); + } + public static void test_ProductUpdateAmazonEstimateFee() + { + var list = new List<(string asin, decimal price)>(); + + list.Add(("B000MGVBG4", 1.99m)); + + bnhtradeDatabaseClient.Product.ProductQuery.ProductUpdateAmazonEstimateFee(sqlConnectionString, list); + } + public static void test_AmazonInventoryTableUpdate() + { + //bnhtradeDatabaseClient.Inventory.InventoryPricing.AmazonInventoryTableUpdate(sqlConnectionString); + } + public static int input6() + { + DateTime entrdate = DateTime.Parse("28/11/2018 08:13:54"); + + return bnhtradeDatabaseClient.Stock.StockCreate.WIP_StockInsertOwnerIntroduced(sqlConnectionString, 0.01m, 7, 15374, 51, 16, entrdate, 51); + } + public static int CurrencyExchangeInsert() + { + DateTime start = new DateTime(2019, 03, 01); + DateTime finish = new DateTime(2019, 04, 01); + + return bnhtradeDatabaseClient.Account.AccountQuery.CurrencyExchangeRateInsert(sqlConnectionString, 1, "USD", 222m, start, finish, true ); + } + } +} diff --git a/bnhtrade Scheduled Tasks/Properties/AssemblyInfo.cs b/bnhtrade Scheduled Tasks/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..791fba4 --- /dev/null +++ b/bnhtrade Scheduled Tasks/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("bnhtrade Scheduled Tasks")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("bnhtrade Scheduled Tasks")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5d6e1d66-3901-4340-95c6-ee65051ab623")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/bnhtrade Scheduled Tasks/Properties/Settings.Designer.cs b/bnhtrade Scheduled Tasks/Properties/Settings.Designer.cs new file mode 100644 index 0000000..c797b60 --- /dev/null +++ b/bnhtrade Scheduled Tasks/Properties/Settings.Designer.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace bnhtrade_Scheduled_Tasks.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] + [global::System.Configuration.DefaultSettingValueAttribute("Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=TRUE;User ID=e2A" + + " Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=TRUE")] + public string bnhtradeDbConnString { + get { + return ((string)(this["bnhtradeDbConnString"])); + } + } + } +} diff --git a/bnhtrade Scheduled Tasks/Properties/Settings.settings b/bnhtrade Scheduled Tasks/Properties/Settings.settings new file mode 100644 index 0000000..415ae6a --- /dev/null +++ b/bnhtrade Scheduled Tasks/Properties/Settings.settings @@ -0,0 +1,13 @@ + + + + + + <?xml version="1.0" encoding="utf-16"?> +<SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <ConnectionString>Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=TRUE;User ID=e2A Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=TRUE</ConnectionString> +</SerializableConnectionString> + Data Source=SQL-Server;Initial Catalog=e2A;Persist Security Info=TRUE;User ID=e2A Client;Password=eSYH4EYoK6Guc5KIclhgFDlGc4;MultipleActiveResultSets=TRUE + + + \ No newline at end of file diff --git a/bnhtrade Scheduled Tasks/bnhtradeScheduledTasks.csproj b/bnhtrade Scheduled Tasks/bnhtradeScheduledTasks.csproj new file mode 100644 index 0000000..0139bf5 --- /dev/null +++ b/bnhtrade Scheduled Tasks/bnhtradeScheduledTasks.csproj @@ -0,0 +1,99 @@ + + + + + Debug + AnyCPU + {5D6E1D66-3901-4340-95C6-EE65051AB623} + Exe + bnhtrade_Scheduled_Tasks + bnhtradeScheduledTasks + v4.7.1 + 512 + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + bnhtradeScheduledTasks.Program + + + + + + + + + + + + + + + + + + True + True + Settings.settings + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {339d7413-3da7-46ea-a55c-255a9a6b95eb} + bnhtradeDatabaseClient + + + + + False + Microsoft .NET Framework 4.7.1 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + \ No newline at end of file diff --git a/bnhtradeRegasmInstall.bat b/bnhtradeRegasmInstall.bat new file mode 100644 index 0000000..0d4398f --- /dev/null +++ b/bnhtradeRegasmInstall.bat @@ -0,0 +1,23 @@ +@set batchpath=%~dp0 +@set dllpath=%batchpath%bnhtrade Database Client\bin\Release\ + +@copy "%dllpath%bnhtradeDatabaseClient.dll" "%SYSTEMROOT%\SysWOW64\bnhtradeDatabaseClient.dll" +@copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" + +@copy "%dllpath%bnhtradeDatabaseClient.dll" "%SYSTEMROOT%\System32\bnhtradeDatabaseClient.dll" +@copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" + +@c: +@cd\Windows\Microsoft.NET\Framework\v4.* +regasm.exe /codebase /tlb "bnhtradeDatabaseClient.dll" +regasm.exe /codebase /tlb "ABrain.AmazonMWS.dll" + +@cd\Windows\Microsoft.NET\Framework64\v4.* +regasm.exe /codebase /tlb "bnhtradeDatabaseClient.dll" +regasm.exe /codebase /tlb "ABrain.AmazonMWS.dll" + +@echo. +@echo Finished running regasm install script. +@echo. +@rem if no arguments passed, pause +@IF "%~1"=="" @pause \ No newline at end of file diff --git a/bnhtradeRegasmRefresh.bat b/bnhtradeRegasmRefresh.bat new file mode 100644 index 0000000..e4fa7b5 --- /dev/null +++ b/bnhtradeRegasmRefresh.bat @@ -0,0 +1,7 @@ +@set mypath=%~dp0 + +call "%mypath%bnhtradeRegasmUninstall.bat" nopause +call "%mypath%bnhtradeRegasmInstall.bat" nopause +@echo Completed regasm refresh +@echo. +@pause diff --git a/bnhtradeRegasmUninstall.bat b/bnhtradeRegasmUninstall.bat new file mode 100644 index 0000000..00ae47b --- /dev/null +++ b/bnhtradeRegasmUninstall.bat @@ -0,0 +1,21 @@ +@c: +@cd\Windows\Microsoft.NET\Framework\v4.* +regasm.exe /u "bnhtradeDatabaseClient.dll" +@cd\Windows\Microsoft.NET\Framework64\v4.* +regasm.exe /u "bnhtradeDatabaseClient.dll" + +@del /q "%SYSTEMROOT%\SysWOW64\bnhtradeDatabaseClient.dll" +@del /q "%SYSTEMROOT%\SysWOW64\bnhtradeDatabaseClient.tlb" +@del /q "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" +@del /q "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.tlb" + +@del /q "%SYSTEMROOT%\System32\bnhtradeDatabaseClient.dll" +@del /q "%SYSTEMROOT%\System32\bnhtradeDatabaseClient.tlb" +@del /q "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" +@del /q "%SYSTEMROOT%\System32\ABrain.AmazonMWS.tlb" + +@echo. +@echo Finished running regasm uninstall script. +@rem if no arguments passed, pause +@echo. +@IF "%~1"=="" @pause \ No newline at end of file