Files
bnhtrade/bnhtrade Database Client/Program.cs
Bobbie Hodgetts 24eee320e8 Feature to handle different SKU tax types when creating sales invoices
Added feature to handle different tax types when creating Xero sales invoice from Amazon settlement reports. (#1)
2019-03-25 16:32:22 +00:00

9678 lines
544 KiB
C#

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
{
/// <summary>
/// Function returns records ID if a matching listing is found, 0 if not
/// </summary>
/// <param name="itemNumber"></param> 12 digit number string
/// <param name="listingEnd"></param> Allows for an error of +/- 2 days in supplied end datetime -- function will accept date with no time
/// <param name="sqlConn"></param>
/// <returns></returns>
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<FeesEstimateResult> 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> 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<int>();
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<int>();
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<int, int>();
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<int, bool>();
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<int> statusIdEffected = null)
{
if (statusIdEffected == null)
{
statusIdEffected = new List<int>();
}
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<int, bool>();
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<Tuple<int, DateTime, int>> 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<Tuple<int, DateTime, int>> list = new List<Tuple<int, DateTime, int>>();
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<int, DateTime, int>(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<Tuple<int, int>> 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<Tuple<int, DateTime, int>> list = GetStockStatusBalanceBySkuId(sqlConnectionString, skuId, creditStatusId, entryDate, moveOldestFirst);
if (list == null)
{
return null;
}
List<Tuple<int, int>> returnList = new List<Tuple<int, int>>();
// quantity check
int avaiableQuantity = 0;
foreach (Tuple<int, DateTime, int> 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<int, DateTime, int> 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<int, int>(tempInt, item.Item3));
}
else
{
int tempInt = StockReallocateByStockId(sqlConnectionString, journalTypeId, item.Item1, quantity, debitStatusId, creditStatusId, entryDate);
returnList.Add(new Tuple<int, int>(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<string, int>();
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<int> insertedInvoiceIds = new List<int>();
// 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<DateTime> dateList = new List<DateTime>();
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<string, int>();
var dicSettlementLineToLineType = new Dictionary<int, int>();
var dicLineTypeTotal = new Dictionary<int, decimal>();
//var dicTransTypeToJournal = new Dictionary<int, int>();
var dicLineTypeToLineId = new Dictionary<int, int>();
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 = "<AmazonReport><SettlementReportLine><" + 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 + "<Principal>";
}
else
{
matchString = matchString + "<" + match03 + ">";
}
if (dicSkuToTaxCodeId.ContainsKey(lineSku))
{
matchString = matchString + "<AccountTaxCodeID=" + dicSkuToTaxCodeId[lineSku] + ">";
}
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<int, decimal> 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<int, decimal> 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<int, int> 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<int, decimal> 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<int, string>();
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 = "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>";
string matchStringNeg = "<AmazonReport><_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 = "<AmazonReport><_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 = "<AmazonReport><_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 + "<Reimbursed>";
}
else
{
if (string.Equals(disposition, "SELLABLE", StringComparison.OrdinalIgnoreCase))
{
matchString = matchString + "<Sellable>";
}
else
{
matchString = matchString + "<Unsellable>";
}
}
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<string, string> adjCodes = new Dictionary<string, string>();
adjCodes.Add("1", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><1><+ve><SoftwareCorrections>");
adjCodes.Add("2", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><2><-ve><SoftwareCorrections>");
adjCodes.Add("3", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><3><+ve><CatalogueManagement>");
adjCodes.Add("4", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><4><-ve><CatalogueManagement>");
adjCodes.Add("5", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><5><-ve><Unrecoverableinventory>");
adjCodes.Add("6", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><6><-ve><DamagedInventoryInboundCarrier>");
adjCodes.Add("D", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><D><-ve><DestroyedInventory>");
adjCodes.Add("E", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><E><-ve><DamagedInventoryFulfilmentCentre>");
adjCodes.Add("F", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><F><+ve><InventoryFound>");
adjCodes.Add("H", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><H><-ve><DamagedInventoryCustomerReturn>");
adjCodes.Add("J", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><J><+ve><SoftwareCorrections>");
adjCodes.Add("K", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><K><-ve><DamagedInventoryItemDefect>");
adjCodes.Add("M", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><M><-ve><InventoryMisplaced>");
adjCodes.Add("N", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><N><+ve><TransferringOwnership>");
adjCodes.Add("O", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><O><-ve><TransferringOwnership>");
adjCodes.Add("P", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><P><+ve><UnsellableInventory>");
adjCodes.Add("Q", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><Q><-ve><DamagedInventoryMiscellaneous>");
adjCodes.Add("U", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><U><-ve><DamagedInventoryMerchant>");
adjCodes.Add("X", "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><X><-ve><InboundShipmentReceiveAdjustments>");
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 = "<AmazonReport><_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 = "<AmazonReport><_GET_FBA_REIMBURSEMENTS_DATA_><-ve><" + reader.GetString(index04) + ">";
int transactionTypeIdNeg = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg);
if (invRecived > 0)
{
matchStringPos = "<AmazonReport><_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 = "<AmazonReport><_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 == "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>"
|| matchString == "<AmazonReport><_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<Tuple<int, int>> list = new List<Tuple<int, int>>();
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("<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><F>"))
{
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<int> 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, "<AmazonReport><_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<int> stockIdList = new List<int>();
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;
}
/// <summary>
///
/// </summary>
/// <param name="itemList"></param>
public List<FeesEstimateResult> 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<GetMyFeesEstimateResult> resultList = new List<GetMyFeesEstimateResult>();
try
{
int count = 0;
do
{
GetMyFeesEstimateResponse response = service.GetMyFeesEstimate(request);
if (response.IsSetGetMyFeesEstimateResult())
{
result = response.GetMyFeesEstimateResult;
FeesEstimateResultList resultList = result.FeesEstimateResultList;
List<FeesEstimateResult> 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<ReportInfo> GetMwsReportList(GetReportListRequest requestList)
{
MarketplaceWebService.MarketplaceWebService service = GetMwsService();
//define the list
GetReportListResult getReportListResult = new GetReportListResult();
List<ReportInfo> reportInfoList = new List<ReportInfo>();
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<ReportRequestInfo> myListzz = new List<ReportRequestInfo>();
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<string> 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<string> reportIdList = new List<string>();
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<ReportInfo> 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<ReportInfo> 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<string> 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<string> 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<string> 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<string> 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<string> 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<string> 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());
}
}
}
}