mirror of
https://github.com/stokebob/bnhtrade.git
synced 2026-03-21 15:27:15 +00:00
SP-API stock reconciliation
Amazon had depreciated a number of reports that were used for stock reconciliation. Application now uses the new fba ledger report to reconcile. It is currently untested, as this requires data from Amazon. Methods that require testing will return a 'NotImplementedException'. Also, removed the depreciated ILMerge and replaced with ILRepack. Plus much more tidying up, and improvements.
This commit is contained in:
@@ -9,11 +9,10 @@ namespace bnhtrade.Core.Data.Database.Account
|
||||
{
|
||||
public class ReadTaxCode : Connection
|
||||
{
|
||||
private Data.Database.SqlWhereBuilder whereBuilder;
|
||||
private Data.Database.SqlWhereBuilder whereBuilder = new SqlWhereBuilder();
|
||||
|
||||
public ReadTaxCode()
|
||||
{
|
||||
whereBuilder = new SqlWhereBuilder();
|
||||
}
|
||||
|
||||
private List<Model.Account.TaxCodeInfo> Execute(string sqlWhere, Dictionary<string, object> parameters)
|
||||
@@ -101,6 +100,23 @@ namespace bnhtrade.Core.Data.Database.Account
|
||||
return Execute(whereBuilder.SqlWhereString, whereBuilder.ParameterList);
|
||||
}
|
||||
|
||||
public List<Model.Account.TaxCodeInfo> GetByTaxCodeId(List<int> taxcodeIdList)
|
||||
{
|
||||
var resultList = new List<Model.Account.TaxCodeInfo>();
|
||||
|
||||
if (taxcodeIdList == null || !taxcodeIdList.Any())
|
||||
{
|
||||
return resultList;
|
||||
}
|
||||
|
||||
taxcodeIdList = taxcodeIdList.Distinct().ToList();
|
||||
|
||||
whereBuilder.Innit();
|
||||
whereBuilder.In("AccountTaxCodeID", taxcodeIdList, "WHERE");
|
||||
|
||||
return Execute(whereBuilder.SqlWhereString, whereBuilder.ParameterList);
|
||||
}
|
||||
|
||||
public List<Model.Account.TaxCodeInfo> GetAllActive()
|
||||
{
|
||||
string sqlWhere = @"
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace bnhtrade.Core.Data.Database.AmazonShipment
|
||||
{
|
||||
if (skuIdLoopkup == null)
|
||||
{
|
||||
skuIdLoopkup = new Sku.GetSkuId(SqlConnectionString);
|
||||
skuIdLoopkup = new Sku.GetSkuId();
|
||||
}
|
||||
return skuIdLoopkup;
|
||||
}
|
||||
|
||||
@@ -20,14 +20,62 @@ namespace bnhtrade.Core.Data.Database
|
||||
|
||||
public Connection()
|
||||
{
|
||||
var config = new Config().GetConfiguration();
|
||||
|
||||
// attempt to retrive credentials from app.local.config
|
||||
try
|
||||
{
|
||||
var dbCredentials = new bnhtrade.Core.Model.Credentials.bnhtradeDB(
|
||||
ConfigurationManager.AppSettings["DbDataSource"]
|
||||
, ConfigurationManager.AppSettings["DbUserId"]
|
||||
, ConfigurationManager.AppSettings["DbUserPassword"]
|
||||
);
|
||||
string dataSource = config.AppSettings.Settings["DbDataSource"].Value;
|
||||
string userId = config.AppSettings.Settings["DbUserId"].Value;
|
||||
string pass = config.AppSettings.Settings["DbUserPassword"].Value;
|
||||
|
||||
// check
|
||||
if (string.IsNullOrEmpty(dataSource))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbDataSource' from config file");
|
||||
}
|
||||
else if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbUserId' from config file");
|
||||
}
|
||||
else if (string.IsNullOrEmpty(pass))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbUserPassword' from config file");
|
||||
}
|
||||
|
||||
var dbCredentials = new bnhtrade.Core.Model.Credentials.bnhtradeDB(dataSource, userId, pass);
|
||||
this.dbCredentials = dbCredentials;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("Unable to retirve DB credentials: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectionOld()
|
||||
{
|
||||
// attempt to retrive credentials from app.local.config
|
||||
try
|
||||
{
|
||||
string dataSource = ConfigurationManager.AppSettings["DbDataSource"];
|
||||
string userId = ConfigurationManager.AppSettings["DbUserId"];
|
||||
string pass = ConfigurationManager.AppSettings["DbUserPassword"];
|
||||
|
||||
// check
|
||||
if (string.IsNullOrEmpty(dataSource))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbDataSource' from config file");
|
||||
}
|
||||
else if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbUserId' from config file");
|
||||
}
|
||||
else if (string.IsNullOrEmpty(pass))
|
||||
{
|
||||
throw new ArgumentException("Could not retrive 'DbUserPassword' from config file");
|
||||
}
|
||||
|
||||
var dbCredentials = new bnhtrade.Core.Model.Credentials.bnhtradeDB(dataSource, userId, pass);
|
||||
this.dbCredentials = dbCredentials;
|
||||
}
|
||||
catch(Exception ex)
|
||||
@@ -43,6 +91,7 @@ namespace bnhtrade.Core.Data.Database
|
||||
{
|
||||
throw new Exception("DB credentials object is null");
|
||||
}
|
||||
this.dbCredentials = dbCredentials;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,19 @@ namespace bnhtrade.Core.Data.Database
|
||||
// add the rest as needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sql table ID for a Stock Journal Type
|
||||
/// </summary>
|
||||
public enum StockJournalType
|
||||
{
|
||||
SkuReconciliationFbaReceipt = 6,
|
||||
SkuReconciliationFbaShipment = 7,
|
||||
SkuReconciliationFbaAdjustment = 8,
|
||||
SkuReconciliationFbaCustomerReturn = 9,
|
||||
SkuReconciliationFbaVendorReturn = 10,
|
||||
SkuReconciliationFbaReimbursement = 11,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sql table ID for a stock status type
|
||||
/// </summary>
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaCustomerReturn : Connection
|
||||
{
|
||||
Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaCustomerReturn()
|
||||
{
|
||||
|
||||
@@ -62,9 +64,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -183,18 +184,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
trans.Commit();
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
log.LogInformation((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogWarning(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -219,8 +219,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
if (cmd.ExecuteScalar() == DBNull.Value)
|
||||
{
|
||||
// use first month started selling on Amazon
|
||||
lastRecordDate = DateTime.Parse("2015-08-25T00:00:00Z"); //this before first return
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
lastRecordDate = lastRecordDate = Constants.GetBusinessStartUtc();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -234,8 +233,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running GetFbaReturnsReport, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running GetFbaReturnsReport, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaInventoryAdjustment : Connection
|
||||
{
|
||||
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaInventoryAdjustment()
|
||||
{
|
||||
|
||||
@@ -59,9 +57,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -185,18 +182,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
trans.Commit();
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
log.LogInformation((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running ImportFbaAdustmentReport method, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running ImportFbaAdustmentReport method, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -221,8 +217,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
if (cmd.ExecuteScalar() == DBNull.Value)
|
||||
{
|
||||
// use first month started selling on Amazon
|
||||
lastRecordDate = DateTime.Parse("2014-09-01T00:00:00Z");
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
lastRecordDate = lastRecordDate = Constants.GetBusinessStartUtc();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -236,8 +231,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running GetFbaAdustmentData, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running GetFbaAdustmentData, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaInventoryAgeData : Connection
|
||||
{
|
||||
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaInventoryAgeData()
|
||||
{
|
||||
|
||||
@@ -100,9 +102,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -276,12 +277,12 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
}
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogInformation(
|
||||
"Operation complete. " + lineNumber + " items processes. " + (lineNumber - lineErrorSkip - lineNoStockSkip) + " total new items inserted, "
|
||||
+ lineNoStockSkip + " 'No Stock' records were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +291,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Something went wrong during import, check details for more.", 1, ex.ToString());
|
||||
log.LogError("Something went wrong during import, check details for more.", ex.ToString());
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaInventoryData : Connection
|
||||
{
|
||||
Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaInventoryData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void InsertByFlatFile(string filePath)
|
||||
@@ -78,9 +78,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -174,12 +173,12 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
}
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogInformation(
|
||||
"Operation complete. " + lineNumber + " items processes. " + (lineNumber - lineErrorSkip - lineNoStockSkip) + " total new items inserted, "
|
||||
+ lineNoStockSkip + " 'No Stock' records were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +187,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Something went wrong during import, check details for more.", 1, ex.ToString());
|
||||
log.LogError("Something went wrong during import, check details for more.", ex.ToString());
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
using Amazon.Runtime.Internal.Transform;
|
||||
using bnhtrade.Core.Logic.Amazon.Fba;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaInventoryLedgerDetail : Connection
|
||||
{
|
||||
public AmazonFbaInventoryLedgerDetail()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Import.AmazonFbaInventoryLedgerDetail> Insert(List<Model.Import.AmazonFbaInventoryLedgerDetail> insertList)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Import.AmazonFbaInventoryLedgerDetail>();
|
||||
|
||||
if (insertList == null || insertList.Any() == false)
|
||||
return returnDict;
|
||||
|
||||
SqlConnection conn;
|
||||
SqlTransaction trans;
|
||||
|
||||
using (conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
using (trans = conn.BeginTransaction())
|
||||
{
|
||||
foreach (var item in insertList)
|
||||
{
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
INSERT INTO tblImportFbaInventoryLedgerDetail (
|
||||
FNSKU
|
||||
,ASIN
|
||||
,MSKU
|
||||
,Title
|
||||
,[Event Type]
|
||||
,[Reference ID]
|
||||
,Quantity
|
||||
,[Fulfillment Center]
|
||||
,Disposition
|
||||
,Reason
|
||||
,Country
|
||||
,[Reconciled Quantity]
|
||||
,[Unreconciled Quantity]
|
||||
,[Date and Time]
|
||||
)
|
||||
OUTPUT INSERTED.ImportFbaInventoryLedgerDetailID
|
||||
VALUES (
|
||||
@fnsku
|
||||
,@asin
|
||||
,@msku
|
||||
,@title
|
||||
,@eventType
|
||||
,@referenceid
|
||||
,@quantity
|
||||
,@fulfillmentCenter
|
||||
,@disposition
|
||||
,@reason
|
||||
,@country
|
||||
,@reconciledQuantity
|
||||
,@unreconciledQuantity
|
||||
,@dateAndTime
|
||||
)
|
||||
", conn, trans))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@fnsku", item.Fnsku);
|
||||
cmd.Parameters.AddWithValue("@asin", item.Asin);
|
||||
cmd.Parameters.AddWithValue("@msku", item.Msku);
|
||||
cmd.Parameters.AddWithValue("@title", item.Title);
|
||||
cmd.Parameters.AddWithValue("@eventType", item.EventType);
|
||||
cmd.Parameters.AddWithValue("@referenceid", item.ReferenceId);
|
||||
cmd.Parameters.AddWithValue("@quantity", item.Quantity);
|
||||
cmd.Parameters.AddWithValue("@fulfillmentCenter", item.FulfillmentCenter);
|
||||
cmd.Parameters.AddWithValue("@disposition", item.Disposition);
|
||||
cmd.Parameters.AddWithValue("@reason", item.Reason);
|
||||
cmd.Parameters.AddWithValue("@country", item.Country);
|
||||
if (item.ReconciledQuantity == null) { cmd.Parameters.AddWithValue("@reconciledQuantity", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@reconciledQuantity", item.ReconciledQuantity); }
|
||||
if (item.UnreconciledQuantity == null) { cmd.Parameters.AddWithValue("@unreconciledQuantity", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@unreconciledQuantity", item.UnreconciledQuantity); }
|
||||
cmd.Parameters.AddWithValue("@dateAndTime", item.DateAndTime);
|
||||
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
throw new Exception("Error inserting new defalt invoice line item into database");
|
||||
}
|
||||
|
||||
returnDict.Add((int)obj, item);
|
||||
}
|
||||
}
|
||||
if (insertList.Count != returnDict.Count)
|
||||
throw new Exception("AmazonFbaInventoryLedgerDetail db insert failed, not all records could be commmitted. Transaction rolled back");
|
||||
trans.Commit();
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrives the AmazonFbaInventoryLedgerDetail object from the database
|
||||
/// </summary>
|
||||
/// <param name="utcFrom">date time filter</param>
|
||||
/// <param name="utcTo">date time filter</param>
|
||||
/// <param name="isProcessed">isprocessed filter</param>
|
||||
/// <returns>dictionary key=AmazonFbaInventoryLedgerDetailIs, value=AmazonFbaInventoryLedgerDetail object</returns>
|
||||
public Dictionary<int, Model.Import.AmazonFbaInventoryLedgerDetail> Read(DateTime? utcFrom = null, DateTime? utcTo = null, bool? isProcessed = null)
|
||||
{
|
||||
var resultList = new Dictionary<int, Model.Import.AmazonFbaInventoryLedgerDetail>();
|
||||
|
||||
string sql = @"
|
||||
SELECT TOP (1000) [ImportFbaInventoryLedgerDetailId]
|
||||
,[FNSKU]
|
||||
,[ASIN]
|
||||
,[MSKU]
|
||||
,[Title]
|
||||
,[Event Type]
|
||||
,[Reference ID]
|
||||
,[Quantity]
|
||||
,[Fulfillment Center]
|
||||
,[Disposition]
|
||||
,[Reason]
|
||||
,[Country]
|
||||
,[Reconciled Quantity]
|
||||
,[Unreconciled Quantity]
|
||||
,[Date and Time]
|
||||
,[IsProcessed]
|
||||
,[StockSkuTransactionID]
|
||||
FROM [e2A].[dbo].[tblImportFbaInventoryLedgerDetail]
|
||||
WHERE 1=1";
|
||||
|
||||
if (utcFrom != null)
|
||||
sql = sql + " AND [Date and Time] >= @utcFrom";
|
||||
if (utcTo != null)
|
||||
sql = sql + " AND [Date and Time] <= @utcFrom";
|
||||
if (isProcessed != null)
|
||||
sql = sql + " AND [IsProcessed] = @isProcessed";
|
||||
|
||||
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
if (utcFrom != null)
|
||||
cmd.Parameters.AddWithValue("@utcFrom", utcFrom);
|
||||
if (utcTo != null)
|
||||
cmd.Parameters.AddWithValue("@utcFrom", utcTo);
|
||||
if (isProcessed != null)
|
||||
cmd.Parameters.AddWithValue("@isProcessed", isProcessed);
|
||||
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.HasRows)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var result = new Model.Import.AmazonFbaInventoryLedgerDetail();
|
||||
|
||||
result.Fnsku = reader.GetString(1);
|
||||
result.Asin = reader.GetString(2);
|
||||
result.Msku = reader.GetString(3);
|
||||
result.Title = reader.GetString(4);
|
||||
result.EventType = reader.GetString(5);
|
||||
if (!reader.IsDBNull(6))
|
||||
result.ReferenceId = reader.GetString(6);
|
||||
result.Quantity = reader.GetInt32(7);
|
||||
result.FulfillmentCenter = reader.GetString(8);
|
||||
result.Disposition = reader.GetString(9);
|
||||
if (!reader.IsDBNull(10))
|
||||
result.Reason = reader.GetString(10);
|
||||
result.Country = reader.GetString(11);
|
||||
if (!reader.IsDBNull(12))
|
||||
result.ReconciledQuantity = reader.GetInt32(12);
|
||||
if (!reader.IsDBNull(13))
|
||||
result.UnreconciledQuantity = reader.GetInt32(13);
|
||||
result.DateAndTime = DateTime.SpecifyKind(reader.GetDateTime(14), DateTimeKind.Utc);
|
||||
|
||||
resultList.Add(reader.GetInt32(0), result);
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the record as processed, where no entry has been made into the stock sku transaction table
|
||||
/// </summary>
|
||||
public void UpdateIsProcessed(int fbaInventoryLedgerDetailId, bool isProcessed)
|
||||
{
|
||||
UpdateIsProcessed(fbaInventoryLedgerDetailId, isProcessed, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the record as processed, and an entry has been made into the stock sku transaction table
|
||||
/// </summary>
|
||||
public void UpdateIsProcessed(int fbaInventoryLedgerDetailId, int stockSkuTransactionId)
|
||||
{
|
||||
UpdateIsProcessed(fbaInventoryLedgerDetailId, true, stockSkuTransactionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use of the two methods above ensures that the transactionId can not be set when the isProcessed is false
|
||||
/// </summary>
|
||||
private void UpdateIsProcessed(int fbaInventoryLedgerDetailId, bool? isProcessed, int? stockSkuTransactionId)
|
||||
{
|
||||
string sql = @"
|
||||
UPDATE
|
||||
tblImportFbaInventoryLedgerDetail
|
||||
SET
|
||||
IsProcessed = @isProcessed
|
||||
, StockSkuTransactionID = @stockSkuTransactionId
|
||||
WHERE
|
||||
(ImportFbaInventoryLedgerDetailID = @fbaInventoryLedgerDetailId)";
|
||||
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
if (isProcessed == null) { cmd.Parameters.AddWithValue("@isProcessed", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@isProcessed", isProcessed); }
|
||||
|
||||
if (stockSkuTransactionId == null) { cmd.Parameters.AddWithValue("@stockSkuTransactionId", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@stockSkuTransactionId", stockSkuTransactionId); }
|
||||
|
||||
cmd.Parameters.AddWithValue("@fbaInventoryLedgerDetailId", fbaInventoryLedgerDetailId);
|
||||
|
||||
int i = cmd.ExecuteNonQuery();
|
||||
|
||||
if (i < 1)
|
||||
throw new Exception("No row were effected by the update operation");
|
||||
|
||||
if (i > 1)
|
||||
throw new Exception("Multiple rows were effected by the update operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaInventoryReceipt : Connection
|
||||
{
|
||||
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaInventoryReceipt()
|
||||
{
|
||||
|
||||
@@ -42,9 +44,9 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
// create notification if amazon add extra headers
|
||||
if (columnCount > 7)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
"Amazon have added a new column to their 'Fba Inventory Receipt' report, you may want to check this out.",
|
||||
2);
|
||||
log.LogWarning(
|
||||
"Amazon have added a new column to their 'Fba Inventory Receipt' report, you may want to check this out."
|
||||
);
|
||||
}
|
||||
|
||||
int indexOfReceivedDate = Array.IndexOf(headers, "received-date");
|
||||
@@ -66,9 +68,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -142,18 +143,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
// 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");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (1 + lineErrorSkip + lineOutsideScope)) + " total report items inserted into db, " + lineOutsideScope + " item(s) outside of requested time scope where skipped.");
|
||||
log.LogInformation((lineNumber - (1 + lineErrorSkip + lineOutsideScope)) + " total report items inserted into db, " + lineOutsideScope + " item(s) outside of requested time scope where skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -178,8 +178,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
if (cmd.ExecuteScalar() == DBNull.Value)
|
||||
{
|
||||
// use first month started selling on Amazon
|
||||
lastRecordDate = DateTime.Parse("2014-09-01T00:00:00Z");
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
lastRecordDate = lastRecordDate = Constants.GetBusinessStartUtc();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -193,8 +192,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
using System;
|
||||
using FikaAmazonAPI.AmazonSpApiSDK.Models.Finances;
|
||||
using FikaAmazonAPI.ConstructFeed.Messages;
|
||||
using NUnit.Framework.Constraints;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaReimbursement : Connection
|
||||
{
|
||||
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaReimbursement()
|
||||
{
|
||||
|
||||
@@ -66,9 +75,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -228,18 +236,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
trans.Commit();
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
log.LogInformation((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running ImportFbaReimbursementReport method, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running ImportFbaReimbursementReport method, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -264,8 +271,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
if (cmd.ExecuteScalar() == DBNull.Value)
|
||||
{
|
||||
// use first month started selling on Amazon
|
||||
lastRecordDate = DateTime.Parse("2014-09-01T00:00:00Z");
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
lastRecordDate = lastRecordDate = Constants.GetBusinessStartUtc();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -279,13 +285,124 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running GetFbaReimbursementData, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running GetFbaReimbursementData, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Model.Import.FbaReimbursementReport> Read(bool? isProcessed = null)
|
||||
{
|
||||
var returnList = new List<Model.Import.FbaReimbursementReport>();
|
||||
|
||||
string sql = @"
|
||||
SELECT
|
||||
[ImportFbaReimbursementReportID]
|
||||
,[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]
|
||||
,[IsProcessed]
|
||||
,[StockSkuTransactionID]
|
||||
FROM [tblImportFbaReimbursementReport]
|
||||
where (1=1) ";
|
||||
|
||||
if (isProcessed.HasValue)
|
||||
{
|
||||
if (isProcessed == true)
|
||||
{
|
||||
sql = sql + " AND (IsProcessed = 1) ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = sql + " AND (IsProcessed = 0) ";
|
||||
}
|
||||
}
|
||||
|
||||
SqlConnection sqlConn;
|
||||
using (sqlConn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
sqlConn.Open();
|
||||
using (SqlCommand cmd = new SqlCommand(sql, sqlConn))
|
||||
{
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var item = new Model.Import.FbaReimbursementReport();
|
||||
|
||||
item.FbaReimbursementReportID = reader.GetInt32(0);
|
||||
item.ApprovalDate = DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc);
|
||||
item.ReimbursementId = reader.GetString(2);
|
||||
if (!reader.IsDBNull(3)) { item.CaseId = reader.GetString(3); }
|
||||
if (!reader.IsDBNull(4)) { item.AmazonOrderId = reader.GetString(4); }
|
||||
item.Reason = reader.GetString(5);
|
||||
item.Sku = reader.GetString(6);
|
||||
item.Fnsku = reader.GetString(7);
|
||||
item.Asin = reader.GetString(8);
|
||||
item.Condition = reader.GetString(9);
|
||||
item.CurrencyUnit = reader.GetString(10);
|
||||
item.AmountPerUnit = reader.GetInt32(11);
|
||||
item.AmountTotal = reader.GetInt32(12);
|
||||
item.QuantityReimbursedCash = reader.GetInt32(13);
|
||||
item.QuantityReimbursedInventory = reader.GetInt32(14);
|
||||
item.QuantityReimbursedTotal = reader.GetInt32(15);
|
||||
item.IsProcessed = reader.GetBoolean(16);
|
||||
if (!reader.IsDBNull(17)) { item.StockSkuTransactionID = reader.GetInt32(17); }
|
||||
|
||||
returnList.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public void UpdateIsProcessed(int fbaReimbursementReportID, bool isProcessed, int? stockSkuTransactionId)
|
||||
{
|
||||
// consistancy checks
|
||||
if (isProcessed == false && stockSkuTransactionId.HasValue)
|
||||
{
|
||||
throw new ArgumentException("Consistancy check error, incorrect argument combination passed to function");
|
||||
}
|
||||
|
||||
string sql = @"
|
||||
UPDATE
|
||||
tblImportFbaReimbursementReport
|
||||
SET
|
||||
IsProcessed=@isProcessed
|
||||
, StockSkuTransactionID=@transactionId
|
||||
WHERE
|
||||
ImportFbaReimbursementReportID=@importTableId;
|
||||
";
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@importTableId", fbaReimbursementReportID);
|
||||
cmd.Parameters.AddWithValue("@isProcessed", isProcessed);
|
||||
if (stockSkuTransactionId.HasValue) { cmd.Parameters.AddWithValue("@transactionId", stockSkuTransactionId); }
|
||||
else { cmd.Parameters.AddWithValue("@transactionId", DBNull.Value); }
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaRemovalOrder : Connection
|
||||
{
|
||||
Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaRemovalOrder()
|
||||
{
|
||||
|
||||
@@ -66,9 +68,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -175,18 +176,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
trans.Commit();
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert("ImportFbaRemovalOrderReport() " + (lineNumber - (1 + lineErrorSkip + lineUpdate)) + " records created, " + lineUpdate + " records updated.");
|
||||
log.LogInformation("ImportFbaRemovalOrderReport() " + (lineNumber - (1 + lineErrorSkip + lineUpdate)) + " records created, " + lineUpdate + " records updated.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogInformation(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running ImportFbaRemovalOrderReport method, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running ImportFbaRemovalOrderReport method, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -194,47 +194,5 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public DateTime ReadRecentDate()
|
||||
{
|
||||
DateTime lastRecordDate;
|
||||
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
|
||||
lastRecordDate = DateTime.Parse("2015-09-15T00:00:00Z");
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
}
|
||||
else
|
||||
{
|
||||
lastRecordDate = ((DateTime)cmd.ExecuteScalar());
|
||||
lastRecordDate = DateTime.SpecifyKind(lastRecordDate, DateTimeKind.Utc);
|
||||
lastRecordDate = lastRecordDate.AddDays(-30); // yes, that's right -30 days
|
||||
//startTime = DateTime.Parse("2015-05-01T00:00:00Z");
|
||||
}
|
||||
|
||||
return lastRecordDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running GetFbaRemovalOrderReport, no records were commited",
|
||||
1,
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonFbaSaleShipment : Connection
|
||||
{
|
||||
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonFbaSaleShipment()
|
||||
{
|
||||
|
||||
@@ -96,9 +98,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineErrorSkip = lineErrorSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -280,18 +281,17 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
}
|
||||
trans.Commit();
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
log.LogInformation((lineNumber - (1 + lineErrorSkip + lineDuplicateSkip)) + " total new items inserted, " + lineDuplicateSkip + " duplicates were skipped.");
|
||||
if (lineErrorSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineErrorSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
1,
|
||||
log.LogError("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
@@ -585,48 +585,6 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public DateTime ReadRecentDate()
|
||||
{
|
||||
DateTime lastRecordDate;
|
||||
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
|
||||
lastRecordDate = DateTime.Parse("2014-09-01T00:00:00Z");
|
||||
// no need to specific timezone, etc, as "Z" already specifis UTC
|
||||
lastRecordDate = DateTime.Parse("2016-02-01T00:00:00Z");
|
||||
// fba sale shipments for previous 18 months only
|
||||
}
|
||||
else
|
||||
{
|
||||
lastRecordDate = ((DateTime)cmd.ExecuteScalar());
|
||||
lastRecordDate = DateTime.SpecifyKind(lastRecordDate, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
return lastRecordDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error running FbaInventoryReceiptReportImport, no records were commited",
|
||||
1,
|
||||
ex.ToString() + "\r\nTraceMessage:\r\n" + MiscFunction.TraceMessage()
|
||||
);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, int> ReadSaleCount(List<string> skuNumber, DateTime periodStart, DateTime periodEnd)
|
||||
{
|
||||
var returnList = new Dictionary<string, int>();
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
public class AmazonSettlementInsert : Connection
|
||||
{
|
||||
Logic.Log.LogEvent log = new Logic.Log.LogEvent();
|
||||
|
||||
public AmazonSettlementInsert ()
|
||||
{
|
||||
|
||||
@@ -84,9 +86,8 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
{
|
||||
// skip line
|
||||
lineSkip = lineSkip + 1;
|
||||
new Logic.Log.LogEvent().EventLogInsert(
|
||||
log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
2,
|
||||
filePath
|
||||
);
|
||||
}
|
||||
@@ -102,7 +103,7 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
if (recordCount > 0)
|
||||
{
|
||||
UpdateSpapiReportId(items[indexSettlementId], reportId);
|
||||
new Logic.Log.LogEvent().EventLogInsert("Settlement report already imported, skipping...");
|
||||
log.LogInformation("Settlement report already imported, skipping...");
|
||||
scope.Complete();
|
||||
return true;
|
||||
}
|
||||
@@ -285,18 +286,18 @@ namespace bnhtrade.Core.Data.Database.Import
|
||||
|
||||
if (sumOfAmount != settlementAmount)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert("Error importing settlement id'" + settlementRef + "'. Sum of inserted settlement lines (" + sumOfAmount +
|
||||
") does not match settlement amount (" + settlementAmount + ").", 1);
|
||||
log.LogError("Error importing settlement id'" + settlementRef + "'. Sum of inserted settlement lines (" + sumOfAmount +
|
||||
") does not match settlement amount (" + settlementAmount + ").");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
scope.Complete();
|
||||
|
||||
Console.Write("\r");
|
||||
new Logic.Log.LogEvent().EventLogInsert((lineNumber - (2 + lineSkip)) + " total settlement items inserted");
|
||||
log.LogInformation((lineNumber - (2 + lineSkip)) + " total settlement items inserted");
|
||||
if (lineSkip > 0)
|
||||
{
|
||||
new Logic.Log.LogEvent().EventLogInsert(lineSkip + " total line(s) where skipped due to insufficent number of cells on row", 1);
|
||||
log.LogError(lineSkip + " total line(s) where skipped due to insufficent number of cells on row");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace bnhtrade.Core.Data.Database.Log
|
||||
/// Gets the Date and Time by a unique string.
|
||||
/// </summary>
|
||||
/// <param name="logDateTimeId">Unique string</param>
|
||||
/// <returns>UTC DateTime or null</returns>
|
||||
/// <returns>UTC DateTime</returns>
|
||||
public DateTime GetDateTimeUtc(string logDateTimeId)
|
||||
{
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
@@ -52,7 +52,10 @@ namespace bnhtrade.Core.Data.Database.Log
|
||||
|
||||
public void SetDateTimeUtc(string logDateTimeID, DateTime utcDateTime)
|
||||
{
|
||||
utcDateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Utc);
|
||||
if (utcDateTime.Kind != DateTimeKind.Utc)
|
||||
{
|
||||
throw new Exception("Datetime kind is not set to UTC");
|
||||
}
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
@@ -86,7 +89,10 @@ namespace bnhtrade.Core.Data.Database.Log
|
||||
if (string.IsNullOrWhiteSpace(LogDateTimeId))
|
||||
{ throw new Exception("Invalid LogDateTimeID"); }
|
||||
|
||||
utcDateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Utc);
|
||||
if (utcDateTime.Kind != DateTimeKind.Utc)
|
||||
{
|
||||
throw new Exception("Datetime kind is not set to UTC");
|
||||
}
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
@@ -111,7 +117,7 @@ namespace bnhtrade.Core.Data.Database.Log
|
||||
{
|
||||
var nowTime = DateTime.UtcNow;
|
||||
cmd.Parameters.AddWithValue("@logDateTimeId", LogDateTimeId);
|
||||
cmd.Parameters.AddWithValue("@utcDateTime", utcDateTime);
|
||||
cmd.Parameters.AddWithValue("@utcDateTime", utcDateTime.ToUniversalTime());
|
||||
if (string.IsNullOrWhiteSpace(comments)) { cmd.Parameters.AddWithValue("@comments", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@comments", comments); }
|
||||
cmd.Parameters.AddWithValue("@recordModified", nowTime.ToUniversalTime());
|
||||
|
||||
@@ -4,24 +4,18 @@ using System.Data.SqlClient;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Sku
|
||||
{
|
||||
public class GetSkuId
|
||||
public class GetSkuId : Connection
|
||||
{
|
||||
private Dictionary<string, int> SKUIdBySKUNumber { get; set; }
|
||||
private Dictionary<int, string> SKUNumberBySKUId { get; set; }
|
||||
private string SqlConnectionString { get; set; }
|
||||
public GetSkuId(string sqlConnectionString)
|
||||
{
|
||||
// setup sql parameters
|
||||
if (sqlConnectionString.Length == 0)
|
||||
{
|
||||
throw new Exception("Zero length sql connectionstring passed");
|
||||
}
|
||||
SqlConnectionString = sqlConnectionString;
|
||||
private Dictionary<string, int> SkuIdBySkuNumber { get; set; }
|
||||
|
||||
private Dictionary<int, string> SkuNumberBySkuId { get; set; }
|
||||
|
||||
public GetSkuId()
|
||||
{
|
||||
// set paramters
|
||||
SKUIdBySKUNumber = new Dictionary<string, int>();
|
||||
SKUNumberBySKUId = new Dictionary<int, string>();
|
||||
}
|
||||
SkuIdBySkuNumber = new Dictionary<string, int>();
|
||||
SkuNumberBySkuId = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get SKUId by SKU number.
|
||||
@@ -32,9 +26,9 @@ namespace bnhtrade.Core.Data.Database.Sku
|
||||
/// <returns>Database SKUId or Exception if not found.</returns>
|
||||
public int BySKUNumber(string skuNumber, bool enableLegacy = false, bool forceRequery = false)
|
||||
{
|
||||
if (forceRequery == false && SKUIdBySKUNumber.ContainsKey(skuNumber))
|
||||
if (forceRequery == false && SkuIdBySkuNumber.ContainsKey(skuNumber))
|
||||
{
|
||||
return SKUIdBySKUNumber[skuNumber];
|
||||
return SkuIdBySkuNumber[skuNumber];
|
||||
}
|
||||
|
||||
int skuId = 0;
|
||||
@@ -81,13 +75,13 @@ namespace bnhtrade.Core.Data.Database.Sku
|
||||
// update cache
|
||||
if (skuId > 0)
|
||||
{
|
||||
if (SKUIdBySKUNumber.ContainsKey(skuNumber))
|
||||
{ SKUIdBySKUNumber.Remove(skuNumber); }
|
||||
SKUIdBySKUNumber.Add(skuNumber, skuId);
|
||||
if (SkuIdBySkuNumber.ContainsKey(skuNumber))
|
||||
{ SkuIdBySkuNumber.Remove(skuNumber); }
|
||||
SkuIdBySkuNumber.Add(skuNumber, skuId);
|
||||
|
||||
if (SKUNumberBySKUId.ContainsKey(skuId))
|
||||
{ SKUNumberBySKUId.Remove(skuId); }
|
||||
SKUNumberBySKUId.Add(skuId, skuNumber);
|
||||
if (SkuNumberBySkuId.ContainsKey(skuId))
|
||||
{ SkuNumberBySkuId.Remove(skuId); }
|
||||
SkuNumberBySkuId.Add(skuId, skuNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -96,5 +90,45 @@ namespace bnhtrade.Core.Data.Database.Sku
|
||||
|
||||
return skuId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does what it says on the tin.
|
||||
/// </summary>
|
||||
/// <param name="productId"></param>
|
||||
/// <param name="conditionId"></param>
|
||||
/// <param name="accountTaxCodeId"></param>
|
||||
/// <param name="noMatchInsertNew"></param>
|
||||
/// <returns>SkuId or null</returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public int? ByParameters(int productId, int conditionId, int accountTaxCodeId)
|
||||
{
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
int? returnId = null;
|
||||
|
||||
conn.Open();
|
||||
|
||||
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 || obj == DBNull.Value)
|
||||
{
|
||||
returnId = (int)obj;
|
||||
}
|
||||
}
|
||||
return returnId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
85
src/bnhtrade.Core/Data/Database/SKU/InsertSku.cs
Normal file
85
src/bnhtrade.Core/Data/Database/SKU/InsertSku.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using FikaAmazonAPI.AmazonSpApiSDK.Models.ProductPricing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Sku
|
||||
{
|
||||
public class InsertSku : Connection
|
||||
{
|
||||
public int InsertNew(int productId, int conditionId, int accountTaxCodeId)
|
||||
{
|
||||
using (TransactionScope scope = new TransactionScope())
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// check tax code id is a valid for SKU
|
||||
var dbTax = new Data.Database.Account.ReadTaxCode();
|
||||
var taxCodeList = dbTax.GetByTaxCodeId(new List<int> { accountTaxCodeId });
|
||||
|
||||
if (!taxCodeList.Any())
|
||||
{
|
||||
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!");
|
||||
}
|
||||
else if (taxCodeList[0].IsValidOnIncome == 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Sku
|
||||
{
|
||||
|
||||
@@ -7,13 +7,16 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
public class CreateSkuTransaction : Connection
|
||||
public class InsertSkuTransaction : Connection
|
||||
{
|
||||
public CreateSkuTransaction()
|
||||
/// <summary>
|
||||
/// Not to be used directly, all CRUD operation should be accessed via the logic layer implementation
|
||||
/// </summary>
|
||||
public InsertSkuTransaction()
|
||||
{
|
||||
}
|
||||
|
||||
public void Create(Model.Stock.SkuTransaction skuTransaction)
|
||||
public int Insert(Model.Stock.SkuTransactionCreate skuTransaction)
|
||||
{
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
@@ -55,17 +58,16 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@transactionDate", skuTransaction.TransactionDate.ToUniversalTime());
|
||||
cmd.Parameters.AddWithValue("@skuTransactionTypeCode", skuTransaction.SkuTransactionTypeCode);
|
||||
if (!skuTransaction.IsSetForeignKey) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); }
|
||||
if (skuTransaction.ForeignKey == null) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@foreignKey", skuTransaction.ForeignKey); }
|
||||
if (!skuTransaction.IsSetReference) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); }
|
||||
if (skuTransaction.Reference == null) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@reference", skuTransaction.Reference); }
|
||||
if (!skuTransaction.IsSetDetail) { cmd.Parameters.AddWithValue("@detail", DBNull.Value); }
|
||||
if (skuTransaction.Detail == null) { cmd.Parameters.AddWithValue("@detail", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@detail", skuTransaction.Detail); }
|
||||
cmd.Parameters.AddWithValue("@skuNumber", skuTransaction.SkuNumber);
|
||||
cmd.Parameters.AddWithValue("@quantity", skuTransaction.Quantity);
|
||||
cmd.Parameters.AddWithValue("@isProcessed", skuTransaction.IsProcessed);
|
||||
if (!skuTransaction.IsSetStockJournalId) { cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@stockJournalID", skuTransaction.StockJournalId); }
|
||||
cmd.Parameters.AddWithValue("@isProcessed", false);
|
||||
cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
@@ -74,7 +76,8 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
throw new Exception("Sku Reconcile Transaction insert failed");
|
||||
}
|
||||
|
||||
skuTransaction.SkuTransactionId = (int)obj;
|
||||
int transactionId = (int)obj;
|
||||
return transactionId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
public class InsertSkuTransactionType : Connection
|
||||
{
|
||||
/// <summary>
|
||||
/// The insert command will not participate in any amibent transaction scope. Default is true.
|
||||
/// </summary>
|
||||
public bool SuppressTransactionScope { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new SKU Transaction Type
|
||||
/// </summary>
|
||||
/// <param name="stockJournalTypeId"></param>
|
||||
/// <param name="skuTransactionCode"></param>
|
||||
/// <returns>ID of the created record</returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public int Create(string skuTransactionCode, int stockJournalTypeId)
|
||||
{
|
||||
int id;
|
||||
var scopeOption = new TransactionScopeOption();
|
||||
if (SuppressTransactionScope)
|
||||
{
|
||||
scopeOption = TransactionScopeOption.Suppress;
|
||||
}
|
||||
else
|
||||
{
|
||||
scopeOption = TransactionScopeOption.Required;
|
||||
}
|
||||
|
||||
using (TransactionScope scope = new TransactionScope(scopeOption))
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// insert new and retrive new value
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
INSERT INTO tblStockSkuTransactionType
|
||||
( TypeName, StockJournalTypeID, TypeCode )
|
||||
OUTPUT
|
||||
INSERTED.StockSkuTransactionTypeID
|
||||
VALUES
|
||||
( @typeName, @stockJournalTypeId, @typeCode );
|
||||
", conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@typeName", skuTransactionCode);
|
||||
cmd.Parameters.AddWithValue("@typeCode", skuTransactionCode);
|
||||
cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
throw new Exception("tblStockSkuTransactionType insert operation returned null");
|
||||
|
||||
id = (int)obj;
|
||||
}
|
||||
scope.Complete();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
602
src/bnhtrade.Core/Data/Database/Stock/JournalCrud.cs
Normal file
602
src/bnhtrade.Core/Data/Database/Stock/JournalCrud.cs
Normal file
@@ -0,0 +1,602 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
public class JournalCrud : Connection
|
||||
{
|
||||
// only to be assessable via code, use stock relocate to move stock bewtween status'
|
||||
public int StockJournalInsert(int journalTypeId, int stockId, List<(int statusId, int quantity)> journalPosts,
|
||||
DateTime entryDate, bool isNewStock = false)
|
||||
{
|
||||
/*
|
||||
* TODO: currently the consistancy check checks the journal after the entry has been inserted to the db, if the check fails
|
||||
* the transaction scope is disposed, and the ne journal entries roll back. However, if this is done within a higher
|
||||
* level transaction scope, this nested dispose() also rolls back the all transacopes scopes it is a child of.
|
||||
*
|
||||
* Therefore, a consistancy check needs to be simulated in code to negate the need to rollback/dispose of a db transaction.
|
||||
* This would also have some slight performance benefits.
|
||||
*
|
||||
* Once you've done this, fix the SkuTransactionReconcile class: Currently it's transactionscope only covers updates.
|
||||
* Need to set the scope to cover the intial table read (to lock the records). The issue above restricts this.
|
||||
*/
|
||||
|
||||
|
||||
// balance and status IsCredit checks made by post insert function
|
||||
|
||||
// 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
|
||||
StockJournalPostInsert(conn, stockId, stockJournalId, journalPosts, isNewStock);
|
||||
|
||||
// consistency check
|
||||
bool consistencyResult = true;
|
||||
if (consistencyRequired)
|
||||
{
|
||||
consistencyResult = false;
|
||||
// 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 = StockJournalConsistencyCheck(stockId, statusIdEffected);
|
||||
}
|
||||
|
||||
if (consistencyResult)
|
||||
{
|
||||
// commit
|
||||
scope.Complete();
|
||||
return stockJournalId;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to insert stock journal entry, consistancy check failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StockJournalDelete(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 = StockJournalConsistencyCheck(stockId, debitList);
|
||||
}
|
||||
|
||||
if (consistencyResult)
|
||||
{
|
||||
// commit
|
||||
scope.Complete();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to delete stock journal entry, consistancy check failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private 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 = new Data.Database.Stock.ReadStatusBalance().ByStockId(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 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 bool StockJournalConsistencyCheck(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using NUnit.Framework.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
//using Dapper;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
@@ -76,6 +77,37 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrevies the IsProcessed for a given stock sku transaction
|
||||
/// </summary>
|
||||
/// <param name="skuTransactionId">the stock transaction id</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException">Invalid stock transaction id</exception>
|
||||
public bool GetIsProcessed(int skuTransactionId)
|
||||
{
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (var cmd = new SqlCommand(@"
|
||||
SELECT IsProcessed FROM tblStockSkuTransaction WHERE StockSkuTransactionID=@skuTransactionId
|
||||
", conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@skuTransactionId", skuTransactionId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
throw new ArgumentException("invalid stock transaction id");
|
||||
}
|
||||
else
|
||||
{
|
||||
return (bool)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates model class from filtered database results
|
||||
@@ -88,7 +120,8 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
// Adding this means they at least get processed in the correct order (maybe)!
|
||||
|
||||
var resultList = new List<Model.Stock.SkuTransaction>();
|
||||
var parameters = new DynamicParameters();
|
||||
//var parameters = new DynamicParameters();
|
||||
var parameterNew = new Dictionary<string, object>();
|
||||
|
||||
string sql = @"
|
||||
SELECT tblStockSkuTransaction.StockSkuTransactionID AS SkuTransactionId
|
||||
@@ -102,7 +135,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
,tblStockSkuTransactionType.TypeCode AS SkuTransactionTypeCode
|
||||
,tblStockSkuTransactionType.TypeName AS SkuTransactionTypeName
|
||||
,tblSku.skuSkuNumber AS SkuNumber
|
||||
,tblStockSkuTransaction.SkuID
|
||||
,tblStockSkuTransaction.RecordCreated
|
||||
FROM tblStockSkuTransaction
|
||||
INNER JOIN tblStockSkuTransactionType ON tblStockSkuTransaction.StockSkuTransactionTypeID = tblStockSkuTransactionType.StockSkuTransactionTypeID
|
||||
INNER JOIN tblSku ON tblStockSkuTransaction.SkuID = tblSku.skuSkuID
|
||||
@@ -110,7 +143,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
|
||||
if (transactionIdList.Any())
|
||||
{
|
||||
parameters.Add("@transactionIdList", this.transactionIdList);
|
||||
parameterNew.Add("@transactionIdList", this.transactionIdList);
|
||||
|
||||
sql += @"
|
||||
AND tblStockSkuTransaction.StockSkuTransactionID IN @transactionIdList ";
|
||||
@@ -133,7 +166,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
|
||||
if (StockTransactionTypeName != null && StockTransactionTypeName.Any())
|
||||
{
|
||||
parameters.Add("@stockTransactionTypeName", StockTransactionTypeName);
|
||||
parameterNew.Add("@stockTransactionTypeName", StockTransactionTypeName);
|
||||
|
||||
sql += @"
|
||||
AND tblStockSkuTransactionType.TypeName IN @stockTransactionTypeName ";
|
||||
@@ -141,7 +174,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
|
||||
if (StockTransactionTypeCode != null && StockTransactionTypeCode.Any())
|
||||
{
|
||||
parameters.Add("@stockTransactionTypeCode", StockTransactionTypeCode);
|
||||
parameterNew.Add("@stockTransactionTypeCode", StockTransactionTypeCode);
|
||||
|
||||
sql += @"
|
||||
AND tblStockSkuTransactionType.TypeCode IN @stockTransactionTypeCode ";
|
||||
@@ -155,23 +188,64 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
resultList = conn.Query<Model.Stock.SkuTransaction>(sql, parameters).ToList();
|
||||
}
|
||||
|
||||
// set datetime kind
|
||||
for (int i = 0; i < resultList.Count; i++)
|
||||
{
|
||||
if (resultList[i].IsSetTransactionDate)
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
resultList[i].TransactionDate = DateTime.SpecifyKind(resultList[i].TransactionDate, DateTimeKind.Utc);
|
||||
foreach (var param in parameterNew)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (!reader.HasRows)
|
||||
{
|
||||
return resultList;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
int skuTransactionId = reader.GetInt32(0);
|
||||
|
||||
DateTime transactionDate = DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc);
|
||||
|
||||
int? foreignKey = null;
|
||||
if (!reader.IsDBNull(2)) { reader.GetInt32(2); }
|
||||
|
||||
string reference = null;
|
||||
if (!reader.IsDBNull(3)) { reader.GetString(3); }
|
||||
|
||||
string detail = null;
|
||||
if (!reader.IsDBNull(4)) { reader.GetString(4); }
|
||||
|
||||
int quantity = reader.GetInt32(5);
|
||||
|
||||
bool isProcessed = reader.GetBoolean(6);
|
||||
|
||||
int? stockJournalId = null;
|
||||
if (!reader.IsDBNull(7)) { reader.GetInt32(7); }
|
||||
|
||||
string skuTransactionTypeCode = reader.GetString(8);
|
||||
|
||||
string skuTransactionTypeName = reader.GetString(9);
|
||||
|
||||
string skuNumber = reader.GetString(10);
|
||||
|
||||
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(11), DateTimeKind.Utc);
|
||||
|
||||
var item = new Model.Stock.SkuTransaction(skuTransactionId, transactionDate, skuTransactionTypeCode, foreignKey, reference
|
||||
, detail, skuNumber, quantity, isProcessed, stockJournalId, recordCreated);
|
||||
resultList.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Stock SKU Transaction by ID
|
||||
/// Get Stock SKU Transaction by ID. Overrides any filters already set.
|
||||
/// </summary>
|
||||
/// <param name="transactionIdList"></param>
|
||||
/// <returns>List of SkuTransaction</returns>
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
public int GetTypeId(string typeCode)
|
||||
{
|
||||
/* GetStockTransactionTypeId return meanings
|
||||
* >0 use the as the TypeId when inserting transaction
|
||||
* >0 use 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 */
|
||||
|
||||
@@ -123,15 +123,17 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
}
|
||||
}
|
||||
|
||||
public List<Model.Stock.SkuTransactionType> ByTypeCode(List<string> typeCode)
|
||||
public List<Model.Stock.SkuTransactionType> ByTypeCode(List<string> typeCodeList)
|
||||
{
|
||||
typeCode.RemoveAll(string.IsNullOrWhiteSpace);
|
||||
typeCodeList.RemoveAll(string.IsNullOrWhiteSpace);
|
||||
|
||||
typeCodeList = typeCodeList.Distinct().ToList();
|
||||
|
||||
string sqlWhere = @"
|
||||
WHERE TypeCode IN @typeCode ";
|
||||
|
||||
var param = new DynamicParameters();
|
||||
param.Add("@typeCode", typeCode);
|
||||
param.Add("@typeCode", typeCodeList);
|
||||
|
||||
return Execute(sqlWhere, param);
|
||||
}
|
||||
|
||||
@@ -4,150 +4,28 @@ using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
public class UpdateSkuTransaction : Connection
|
||||
{
|
||||
// Any update method below to the quanity, isprocessed or journalId, implements a consistancy check.
|
||||
|
||||
private string err = "Database UpdateSkuTransaction: ";
|
||||
private ReadSkuTransaction dbRead = new ReadSkuTransaction();
|
||||
|
||||
public UpdateSkuTransaction()
|
||||
{
|
||||
}
|
||||
|
||||
public void Update(int skuTransactionId, bool isProcessed)
|
||||
{
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET IsProcessed=@isProcessed
|
||||
WHERE StockSkuTransactionID=@transactionId
|
||||
", conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@isProcessed", isProcessed);
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransactionId);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected < 1)
|
||||
{
|
||||
throw new Exception(err += "Sku Transaction IsProcessed update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the StockJournalID field. Will also set the IsProcessed value base on input.
|
||||
/// </summary>
|
||||
/// <param name="skuTransactionId">Sku Transaction Id</param>
|
||||
/// <param name="stockJournalId">Stock Journal Id or null to unset</param>
|
||||
public void Update(int skuTransactionId, int? stockJournalId)
|
||||
{
|
||||
string sql = @"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET IsProcessed = @isProcessed
|
||||
,StockJournalID = @stockJournalID
|
||||
WHERE StockSkuTransactionID = @transactionId;";
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
if (stockJournalId == null) { cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@stockJournalID", (int)stockJournalId); }
|
||||
if (stockJournalId == null) { cmd.Parameters.AddWithValue("@isProcessed", false); }
|
||||
else { cmd.Parameters.AddWithValue("@isProcessed", true); }
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransactionId);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected < 1)
|
||||
{
|
||||
throw new Exception(err += "Sku Transaction StockJournalID update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(int skuTransactionId, int quantity, bool isProcessed)
|
||||
{
|
||||
string sql = @"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET IsProcessed = @isProcessed
|
||||
,Quantity = @quantity
|
||||
WHERE StockSkuTransactionID = @transactionId;";
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@isProcessed", isProcessed);
|
||||
cmd.Parameters.AddWithValue("@quantity", quantity);
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransactionId);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected < 1)
|
||||
{
|
||||
throw new Exception(err += "Sku Transaction quantity and isprocessed update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the StockJournalID field. Will also set the IsProcessed value base on input.
|
||||
/// </summary>
|
||||
/// <param name="skuTransactionId">Sku Transaction Id</param>
|
||||
/// <param name="quantity">Sku Transaction quantity. Set to null to leave database value unchanged.</param>
|
||||
/// <param name="stockJournalId">Stock Journal Id</param>
|
||||
public void Update(int skuTransactionId, int? quantity, int stockJournalId)
|
||||
{
|
||||
string sql = @"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET IsProcessed = @isProcessed
|
||||
,StockJournalID = @stockJournalID ";
|
||||
|
||||
if (quantity != null)
|
||||
{
|
||||
sql += @"
|
||||
,Quantity = @quantity ";
|
||||
}
|
||||
|
||||
sql += @"
|
||||
WHERE StockSkuTransactionID = @transactionId;";
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
if (quantity != null) { cmd.Parameters.AddWithValue("@quantity", (int)quantity); }
|
||||
cmd.Parameters.AddWithValue("@isProcessed", true);
|
||||
cmd.Parameters.AddWithValue("@stockJournalID", stockJournalId);
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransactionId);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected < 1)
|
||||
{
|
||||
throw new Exception(err += "Sku Transaction IsProcessed update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(Model.Stock.SkuTransaction skuTransaction)
|
||||
{
|
||||
// Consistancy check: is the target marked as is processed?
|
||||
dbRead.Init();
|
||||
if (dbRead.GetIsProcessed(skuTransaction.SkuTransactionId))
|
||||
throw new InvalidOperationException("Update restricted, sku transaction isProcessed=true");
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
@@ -176,16 +54,16 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@transactionDate", skuTransaction.TransactionDate.ToUniversalTime());
|
||||
cmd.Parameters.AddWithValue("@skuTransactionTypeCode", skuTransaction.SkuTransactionTypeCode);
|
||||
if (!skuTransaction.IsSetForeignKey) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); }
|
||||
if (skuTransaction.ForeignKey == null) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@foreignKey", skuTransaction.ForeignKey); }
|
||||
if (!skuTransaction.IsSetReference) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); }
|
||||
if (skuTransaction.Reference == null) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@reference", skuTransaction.Reference); }
|
||||
if (!skuTransaction.IsSetDetail) { cmd.Parameters.AddWithValue("@detail", DBNull.Value); }
|
||||
if (skuTransaction.Detail == null) { cmd.Parameters.AddWithValue("@detail", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@detail", skuTransaction.Detail); }
|
||||
cmd.Parameters.AddWithValue("@skuNumber", skuTransaction.SkuNumber);
|
||||
cmd.Parameters.AddWithValue("@quantity", skuTransaction.Quantity);
|
||||
cmd.Parameters.AddWithValue("@isProcessed", skuTransaction.IsProcessed);
|
||||
if (!skuTransaction.IsSetStockJournalId) { cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value); }
|
||||
if (skuTransaction.StockJournalId == null) { cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@stockJournalID", skuTransaction.StockJournalId); }
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransaction.SkuTransactionId);
|
||||
|
||||
@@ -198,5 +76,123 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the isProcessed and StockJournalId field, with journal consistancy check.
|
||||
/// </summary>
|
||||
/// <param name="skuTransactionId">Sku Transaction Id</param>
|
||||
/// <param name="isProcessed"></param>
|
||||
/// <param name="stockJournalId"></param>
|
||||
/// <exception cref="InvalidOperationException">Invalid journalId, isProcessed combination</exception>
|
||||
/// <exception cref="Exception">DB update sql fail</exception>
|
||||
public void UpdateIsProcessed(int skuTransactionId, bool isProcessed, int? stockJournalId, bool enableJournalDelete = false)
|
||||
{
|
||||
// IMPORTANT!!!!
|
||||
// For consistancy reasons: need to make sure that if a journal entry exists, it is deteled before it is
|
||||
// edited, or removed from the transaction table
|
||||
// Best to implement this here, at only point where the isprocessed/journalId can be updated
|
||||
|
||||
|
||||
// intial checks
|
||||
if (isProcessed == false && stockJournalId != null)
|
||||
throw new InvalidOperationException("If stock journal id is set, isProcessed must be true");
|
||||
|
||||
|
||||
using (var scope = new TransactionScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
// check for existing journal Id in transactin table
|
||||
var existingJournalId = new Data.Database.Stock.ReadSkuTransaction().GetJournalId(skuTransactionId);
|
||||
bool journalDeleteRequired = false;
|
||||
if (existingJournalId != null)
|
||||
{
|
||||
if (stockJournalId == null || stockJournalId != existingJournalId)
|
||||
{
|
||||
journalDeleteRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
// make the journal delete, if required and enabled
|
||||
if (journalDeleteRequired && enableJournalDelete)
|
||||
{
|
||||
new Data.Database.Stock.JournalCrud().StockJournalDelete((int)existingJournalId);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Removal of stock journal to update sku transaction table not allowed");
|
||||
}
|
||||
|
||||
// update the transaction table
|
||||
string sql = @"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET IsProcessed = @isProcessed
|
||||
,StockJournalID = @stockJournalID
|
||||
WHERE StockSkuTransactionID = @transactionId;";
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@isProcessed", isProcessed);
|
||||
if (stockJournalId == null) { cmd.Parameters.AddWithValue("@stockJournalID", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@stockJournalID", (int)stockJournalId); }
|
||||
cmd.Parameters.AddWithValue("@transactionId", skuTransactionId);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected != 1)
|
||||
{
|
||||
throw new Exception(err += "Sku Transaction StockJournalID update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.Complete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
scope.Dispose();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the quantity field, with journal consistancy check.
|
||||
/// </summary>
|
||||
/// <param name="skuTransactionId">stock sku transaction id</param>
|
||||
/// <param name="quantity">quantity</param>
|
||||
/// <exception cref="InvalidOperationException">Update restricted, sku transaction isProcessed=true</exception>
|
||||
/// <exception cref="Exception">Database write failed</exception>
|
||||
public void UpdateQuanitity(int skuTransactionId, int quantity)
|
||||
{
|
||||
// Consistancy check: is the target marked as is processed?
|
||||
dbRead.Init();
|
||||
if (dbRead.GetIsProcessed(skuTransactionId))
|
||||
throw new InvalidOperationException("Update restricted, sku transaction isProcessed=true");
|
||||
|
||||
using (var conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
UPDATE tblStockSkuTransaction
|
||||
SET Quantity = @quantity
|
||||
WHERE StockSkuTransactionID = @transactionId
|
||||
", conn))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@quantity", quantity);
|
||||
|
||||
int effected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (effected != 1)
|
||||
{
|
||||
throw new Exception(err += "stockSkuTransaction Quantity update failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user