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) and sku's where tax is included string matchString = "<" + match01 + "><" + match02 + ">"; if ((match01 == "Order" || match01 == "Refund") && match02 == "ItemPrice" && (match03 == "Principal" || match03 == "Goodwill" || match03 == "Tax")) { if (lineSku == "") { throw new Exception("Could not retrive Sku from SettleLineId=" + settlementLineId); } if (match03 == "Goodwill") { matchString = matchString + ""; } else { matchString = matchString + "<" + match03 + ">"; } 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()); } } } }