mirror of
https://github.com/stokebob/bnhtrade.git
synced 2026-05-18 19:48:23 +00:00
399 lines
17 KiB
C#
399 lines
17 KiB
C#
using Amazon.Runtime.Internal.Transform;
|
|
using bnhtrade.Core.Model.Stock;
|
|
using FikaAmazonAPI.AmazonSpApiSDK.Models.Restrictions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Microsoft.Data.SqlClient;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Transactions;
|
|
|
|
namespace bnhtrade.Core.Logic.Stock
|
|
{
|
|
public class SkuTransactionImport
|
|
{
|
|
private Log.LogEvent log = new Log.LogEvent();
|
|
|
|
private string ConstructTransactionTypeCode(Model.Import.FbaReimbursementReport record, bool isPositive)
|
|
{
|
|
if (string.IsNullOrEmpty(record.Reason))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string transactionCode = "<AmazonReport><_GET_FBA_REIMBURSEMENTS_DATA_>";
|
|
|
|
if (isPositive)
|
|
{
|
|
transactionCode = transactionCode + "<+ve>";
|
|
}
|
|
else
|
|
{
|
|
transactionCode = transactionCode + "<-ve>";
|
|
}
|
|
|
|
transactionCode = transactionCode + "<" + record.Reason + ">";
|
|
return transactionCode;
|
|
}
|
|
|
|
private string ConstructTransactionTypeCode(Model.Import.AmazonFbaInventoryLedgerDetail record)
|
|
{
|
|
//if (string.IsNullOrEmpty(record.Reason))
|
|
//{
|
|
// return null;
|
|
//}
|
|
|
|
string transactionCode = "<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><" + record.EventType + ">";
|
|
|
|
if (!string.IsNullOrEmpty(record.Reason))
|
|
{
|
|
transactionCode = transactionCode + "<" + record.Reason + ">";
|
|
}
|
|
|
|
if (record.Quantity < 0)
|
|
{
|
|
transactionCode = transactionCode + "<-ve>";
|
|
}
|
|
else
|
|
{
|
|
transactionCode = transactionCode + "<+ve>";
|
|
}
|
|
|
|
transactionCode = transactionCode + "<" + record.Disposition + ">";
|
|
|
|
return transactionCode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imports/Transaposes all required data into sku transaction table for reconcilation.
|
|
/// </summary>
|
|
public void ImportAll()
|
|
{
|
|
string methodName = "'Import all' data to 'Stock SKU Transactions'";
|
|
|
|
log.LogInformation(methodName + " started...");
|
|
|
|
try
|
|
{
|
|
ImportAmazonFbaLedgerDetail();
|
|
ImportAmazonFbaReimbursement();
|
|
}
|
|
catch
|
|
{
|
|
log.LogError(methodName + " did not complete.");
|
|
throw;
|
|
}
|
|
|
|
log.LogInformation(methodName + " complete.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imports/Transaposes data from the Amazon FBA Reimbursement report table, into the SKU transaction table, ready for reconcilation.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
public void ImportAmazonFbaReimbursement()
|
|
{
|
|
string methodName = "Import 'Amazon FBA Reimbursement' into 'Stock SKU Transactions'";
|
|
|
|
//throw new NotImplementedException("Needs testing");
|
|
|
|
/*
|
|
* Not to be used for stock reconciliation! A single stock item can have multiple reimburesements aginst it.
|
|
* Only use to move lost inventory to Amazon ownership (even then, with some caveats!)
|
|
*
|
|
* generally any lost or damaged stock goes to lost and found (and is hence written off)
|
|
* once amazon have reimbursed (confitmation via this report) the stock is then moved to amazon owvership
|
|
* and also the 'Cost of goods' amounts moved to the appropreate account id
|
|
*/
|
|
|
|
log.LogInformation(methodName + " started...");
|
|
int importedCount = 0;
|
|
int processedCount = 0;
|
|
var dbAmznReport = new Data.Database.Import.AmazonFbaReimbursement();
|
|
var dbTransType = new Logic.Stock.SkuTransactionTypeCrud();
|
|
|
|
try
|
|
{
|
|
var importList = dbAmznReport.Read(false);
|
|
|
|
// we need to retrive the transaction-types from the database
|
|
|
|
// run through the returned records and build list of transaction-type codes
|
|
var transTypeCodeList = new List<string>();
|
|
foreach (var item in importList)
|
|
{
|
|
processedCount++;
|
|
|
|
transTypeCodeList.Add(ConstructTransactionTypeCode(item, false));
|
|
// any that reimburse inventory, will have two entries
|
|
if(item.QuantityReimbursedInventory > 0)
|
|
{
|
|
transTypeCodeList.Add(ConstructTransactionTypeCode(item, true));
|
|
}
|
|
}
|
|
transTypeCodeList = transTypeCodeList.Distinct().ToList();
|
|
|
|
// get transaction-type objects from db
|
|
var transTypeDict = dbTransType.GetByTypeCode(transTypeCodeList);
|
|
|
|
// new transaction-type check
|
|
var foundNewType = false;
|
|
foreach (var transTypeCode in transTypeCodeList)
|
|
{
|
|
// if a transaction-type code did not exist in the db, we need to create it
|
|
if (transTypeDict.ContainsKey(transTypeCode) == false)
|
|
{
|
|
dbTransType.Create(
|
|
transTypeCode,
|
|
(int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaReimbursement
|
|
);
|
|
var newItem = dbTransType.GetByTypeCode(transTypeCode);
|
|
if (newItem == null)
|
|
{
|
|
throw new Exception("Createing new transaction-type returned null");
|
|
}
|
|
transTypeDict.Add(newItem.TypeCode, newItem);
|
|
foundNewType = true;
|
|
}
|
|
|
|
// also check existing transaction-type for 'is new'
|
|
if (transTypeDict[transTypeCode].IsNewReviewRequired)
|
|
{
|
|
foundNewType = true;
|
|
}
|
|
}
|
|
|
|
// don't go any further until the transaction-type has been reviewed/setup
|
|
if (foundNewType)
|
|
{
|
|
log.LogWarning(methodName + " unable to complete. New 'Stock Trnasaction Type' found. Review required/");
|
|
return;
|
|
}
|
|
|
|
// we're all setup, time to transpose the report into the transaction table
|
|
using (TransactionScope scope = new TransactionScope())
|
|
{
|
|
var dbTrans = new Logic.Stock.SkuTransactionCrud();
|
|
foreach (var item in importList)
|
|
{
|
|
int? transId = null;
|
|
// always added
|
|
if (true)
|
|
{
|
|
string typeCode = ConstructTransactionTypeCode(item, false);
|
|
var transType = transTypeDict[typeCode];
|
|
|
|
if (transType.IsNewReviewRequired)
|
|
{
|
|
throw new Exception(methodName + " fail safe: Buggy code, should not get here!");
|
|
}
|
|
else if (transType.TransactionImportEnabled)
|
|
{
|
|
var newTransaction = new Model.Stock.SkuTransactionCreate(
|
|
item.ApprovalDate,
|
|
typeCode,
|
|
item.FbaReimbursementReportID,
|
|
item.ReimbursementId,
|
|
item.Reason,
|
|
item.Sku,
|
|
item.QuantityReimbursedInventory
|
|
);
|
|
|
|
transId = dbTrans.Create(newTransaction);
|
|
}
|
|
}
|
|
// double transaction added if true
|
|
if (item.QuantityReimbursedInventory > 0)
|
|
{
|
|
string typeCode = ConstructTransactionTypeCode(item, true);
|
|
var transType = transTypeDict[typeCode];
|
|
|
|
if (transType.IsNewReviewRequired)
|
|
{
|
|
throw new Exception(methodName + " fail safe: Buggy code, should not get here!");
|
|
}
|
|
else if (transType.TransactionImportEnabled)
|
|
{
|
|
var newTransaction = new Model.Stock.SkuTransactionCreate(
|
|
item.ApprovalDate,
|
|
typeCode,
|
|
item.FbaReimbursementReportID,
|
|
item.ReimbursementId,
|
|
item.Reason,
|
|
item.Sku,
|
|
item.QuantityReimbursedInventory
|
|
);
|
|
|
|
transId = dbTrans.Create(newTransaction);
|
|
}
|
|
}
|
|
// update the amazon report table
|
|
dbAmznReport.UpdateIsProcessed(item.FbaReimbursementReportID, true, transId);
|
|
importedCount++;
|
|
}
|
|
// drop out of loop
|
|
scope.Complete();
|
|
}
|
|
Console.Write("\r");
|
|
|
|
log.LogInformation(
|
|
methodName + " complete. Records transferred/processed " + importedCount + "/" + processedCount
|
|
);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.LogError(
|
|
methodName + " aborted due an exception, no records where modified."
|
|
, ex.ToString()
|
|
);
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imports/Transaposes data from the Amazon FBA Ledger Detail report table, into the SKU transaction table, ready for reconcilation.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException"></exception>
|
|
public void ImportAmazonFbaLedgerDetail()
|
|
{
|
|
string methodName = "Import 'Amazon FBA Ledger Detail' into 'Stock SKU Transactions'";
|
|
|
|
log.LogInformation(methodName + " started");
|
|
int transferredCount = 0;
|
|
int processedCount = 0;
|
|
|
|
using (var scope = new TransactionScope())
|
|
{
|
|
try
|
|
{
|
|
// get unprocessed amazon ledger report items
|
|
var dbImport = new Data.Database.Import.AmazonFbaInventoryLedgerDetail();
|
|
var reportDict = dbImport.Read(null, null, false);
|
|
|
|
// create transaction list to insert into transaction table
|
|
var transactionList = new List<SkuTransactionCreate>();
|
|
var transCodeToJournalTypeId = new Dictionary<string, int>();
|
|
foreach (var item in reportDict)
|
|
{
|
|
processedCount++;
|
|
|
|
// test for internal Amazon stuff that we don't care about and mark as processed
|
|
if (item.Value.EventType == "WhseTransfers")
|
|
{
|
|
dbImport.UpdateIsProcessed(item.Key, true);
|
|
}
|
|
// add the the transaction list
|
|
else
|
|
{
|
|
// build the transaction code
|
|
string transactionCode = ConstructTransactionTypeCode(item.Value);
|
|
|
|
// load the report item into parameter
|
|
DateTime transactionDate = item.Value.DateAndTime;
|
|
|
|
int foreignKey = item.Key;
|
|
|
|
string reference = null;
|
|
if (!string.IsNullOrEmpty(item.Value.ReferenceId))
|
|
{ reference = item.Value.ReferenceId; }
|
|
|
|
string detail = "Fulfillment Center: " + item.Value.FulfillmentCenter;
|
|
|
|
string skuNumber = item.Value.Msku;
|
|
|
|
// quanity in the transaction table is always be +ve
|
|
int quantity = item.Value.Quantity;
|
|
if (quantity < 0)
|
|
quantity = quantity * -1;
|
|
|
|
// create the objet class and add to the list
|
|
var transaction = new Model.Stock.SkuTransactionCreate(
|
|
transactionDate
|
|
, transactionCode
|
|
, foreignKey
|
|
, reference
|
|
, detail
|
|
, skuNumber
|
|
, quantity
|
|
);
|
|
transactionList.Add(transaction);
|
|
|
|
// add transtypecode to dictionary to 'stock journal type' dictionary. Needed if there's a new transaction type
|
|
if (transCodeToJournalTypeId.ContainsKey(transactionCode) == false)
|
|
{
|
|
int journalTypeId = 0;
|
|
if (item.Value.EventType == "Receipts")
|
|
{ journalTypeId = (int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaReceipt; }
|
|
else if (item.Value.EventType == "Shipments")
|
|
{ journalTypeId = (int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaShipment; }
|
|
else if (item.Value.EventType == "Adjustments")
|
|
{ journalTypeId = (int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaAdjustment; }
|
|
else if (item.Value.EventType == "CustomerReturns")
|
|
{ journalTypeId = (int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaCustomerReturn; }
|
|
else if (item.Value.EventType == "VendorReturns")
|
|
{ journalTypeId = (int)Data.Database.Constants.StockJournalType.SkuReconciliationFbaVendorReturn; }
|
|
else if (item.Value.EventType == "WhseTransfers")
|
|
{ journalTypeId = -1; }
|
|
else
|
|
{ throw new Exception("New event-type " + item.Value.EventType + " in the GET_LEDGER_DETAIL_VIEW_DATA report"); }
|
|
|
|
transCodeToJournalTypeId.Add(transactionCode, journalTypeId);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for any new types codes, remove existing from list and add remaing to db
|
|
using (TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Suppress))
|
|
{
|
|
var dbTransType = new Logic.Stock.SkuTransactionTypeCrud();
|
|
|
|
var transTypeList = dbTransType.GetByTypeCode(transCodeToJournalTypeId.Keys.ToList());
|
|
|
|
foreach (var transType in transTypeList)
|
|
{
|
|
if (transCodeToJournalTypeId.ContainsKey(transType.Key))
|
|
{
|
|
transCodeToJournalTypeId.Remove(transType.Key);
|
|
}
|
|
}
|
|
|
|
foreach (var newItem in transCodeToJournalTypeId)
|
|
{
|
|
dbTransType.Create(newItem.Key, newItem.Value);
|
|
}
|
|
}
|
|
|
|
// finally, add the transction list to the table
|
|
var dbTransaction = new Logic.Stock.SkuTransactionCrud();
|
|
foreach (var item in transactionList)
|
|
{
|
|
int id = dbTransaction.Create(item);
|
|
dbImport.UpdateIsProcessed((int)item.ForeignKey, id);
|
|
transferredCount++;
|
|
}
|
|
|
|
scope.Complete();
|
|
|
|
log.LogInformation(
|
|
methodName + " complete. Records transferred/processed " + transferredCount + "/" + processedCount
|
|
);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
scope.Dispose();
|
|
|
|
log.LogError(
|
|
methodName + " aborted, no records modified. See additional info exception details."
|
|
, ex.ToString()
|
|
);
|
|
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|