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:
Bobbie Hodgetts
2024-05-07 08:24:00 +01:00
committed by GitHub
parent 2f919d7b5a
commit 91ef9acc78
1272 changed files with 4944 additions and 2773311 deletions

View File

@@ -0,0 +1,129 @@
using CsvHelper.Configuration.Attributes;
using NUnit.Framework.Interfaces;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace bnhtrade.Core.Model.Import
{
public class AmazonFbaInventoryLedgerDetail : IValidatableObject
{
private int? quantity = null;
private DateTime dateAndTime;
[Required()]
[Name("Date and Time")]
public DateTime DateAndTime
{
get { return dateAndTime; }
set { dateAndTime = value.ToUniversalTime(); }
}
[Required()]
[Name("FNSKU")]
public string Fnsku { get; set; }
[Required()]
[Name("ASIN")]
public string Asin { get; set; }
[Required()]
[Name("MSKU")]
public string Msku { get; set; }
[Required()]
[Name("Title")]
public string Title { get; set; }
[Required()]
[Name("Event Type")]
public string EventType { get; set; }
[Name("Reference ID")]
public string ReferenceId { get; set; }
[Required()]
[Name("Quantity")]
public int Quantity
{
get
{
return quantity ?? default(int);
}
set
{
quantity = value;
}
}
[Required()]
[Name("Fulfillment Center")]
public string FulfillmentCenter { get; set; }
[Required()]
[Name("Disposition")]
public string Disposition { get; set; }
[Name("Reason")]
public string Reason { get; set; }
[Required()]
[Name("Country")]
public string Country { get; set; }
[Name("Reconciled Quantity")]
public int? ReconciledQuantity { get; set; }
[Name("Unreconciled Quantity")]
public int? UnreconciledQuantity { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var resultList = new List<ValidationResult>();
// data validation matches sql table -- if changes are made, make sure they match each other
if (DateAndTime == default(DateTime))
resultList.Add(new ValidationResult(nameof(DateAndTime) + " is not set"));
if (string.IsNullOrEmpty(Fnsku) || Fnsku.Length != 10)
resultList.Add(new ValidationResult(nameof(Fnsku) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(Asin) || Asin.Length != 10)
resultList.Add(new ValidationResult(nameof(Asin) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(Msku) || Msku.Length != 9)
resultList.Add(new ValidationResult(nameof(Msku) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(Title) || Title.Length > 200)
resultList.Add(new ValidationResult(nameof(Title) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(EventType) || EventType.Length > 50)
resultList.Add(new ValidationResult(nameof(EventType) + " is incorrect format or not set"));
if (ReferenceId == null || ReferenceId.Length > 50)
resultList.Add(new ValidationResult(nameof(ReferenceId) + " is incorrect format or not set"));
if (quantity == null)
resultList.Add(new ValidationResult(nameof(Quantity) + " is not set"));
if (string.IsNullOrEmpty(FulfillmentCenter) || FulfillmentCenter.Length != 4)
resultList.Add(new ValidationResult(nameof(FulfillmentCenter) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(Disposition) || Disposition.Length > 50)
resultList.Add(new ValidationResult(nameof(Disposition) + " is incorrect format or not set"));
if ( Reason != null && Reason.Length > 200)
resultList.Add(new ValidationResult(nameof(Reason) + " is incorrect format or not set"));
if (string.IsNullOrEmpty(Country) || Country.Length != 2)
resultList.Add(new ValidationResult(nameof(Country) + " is incorrect format or not set"));
return resultList;
}
}
}

View File

@@ -0,0 +1,65 @@
using bnhtrade.Core.Logic.Validate;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
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.Model.Import
{
public class FbaReimbursementReport : IValidatableObject
{
public int FbaReimbursementReportID { get; set; }
[Required]
public DateTime ApprovalDate { get; set; }
[Required]
public string ReimbursementId { get; set; }
public string CaseId { get; set; }
public string AmazonOrderId { get; set; }
[Required]
public string Reason { get; set; }
[Required]
public string Sku { get; set; }
[Required]
public string Fnsku { get; set; }
[Required]
public string Asin { get; set; }
[Required]
public string Condition { get; set; }
[Required]
public string CurrencyUnit { get; set; }
public decimal AmountPerUnit { get; set; }
public decimal AmountTotal { get; set; }
public int QuantityReimbursedCash { get; set; }
public int QuantityReimbursedInventory { get; set; }
public int QuantityReimbursedTotal { get; set; }
public bool IsProcessed { get; set; }
public int? StockSkuTransactionID { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
throw new NotImplementedException();
}
}
}

View File

@@ -7,206 +7,88 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class SkuTransaction : IValidatableObject
public class SkuTransaction : SkuTransactionCreate
{
private DateTime? transactionDate = null;
private bool? isProcessed = null;
private short? quantity = null;
private int? stockjournalId = null;
private int? skuTransactionId = null;
private int? foreignKey = null;
private string skuTransactionTypeCode;
private Model.Stock.SkuTransactionType skuTransactionType;
public int SkuTransactionId { get; private set; }
public int SkuTransactionId
public bool IsProcessed { get; private set; }
public int? StockJournalId { get; private set; }
public DateTime RecordCreated { get;private set; }
public SkuTransaction(int transactionId, DateTime transactionDate, string transactionTypeCode, int? foreignKey, string reference, string detail
, string skuNumber, int quantity, bool isProcessed, int? journalId, DateTime created)
: base(transactionDate, transactionTypeCode, foreignKey, reference, detail, skuNumber, quantity)
{
get { return skuTransactionId.GetValueOrDefault(); }
set { skuTransactionId = value; }
SkuTransactionId = transactionId;
IsProcessed = isProcessed;
StockJournalId = journalId;
RecordCreated = created;
}
public bool IsSetSkuTransactionId
public SkuTransaction(SkuTransactionCreate newTransactionObj, int transactionId, bool isProcessed, int? journalId, DateTime created)
: base(newTransactionObj.TransactionDate, newTransactionObj.SkuTransactionTypeCode, newTransactionObj.ForeignKey
, newTransactionObj.Reference, newTransactionObj.Detail, newTransactionObj.SkuNumber, newTransactionObj.Quantity)
{
get { return skuTransactionId != null; }
}
[Required()]
public DateTime TransactionDate
{
get { return transactionDate.GetValueOrDefault(); }
set { transactionDate = value; }
}
public bool IsSetTransactionDate
{
get { return transactionDate != null; }
}
[Required()]
public string SkuTransactionTypeCode
{
get
{
if (IsSetSkuTransactionType)
{
return SkuTransactionType.TypeCode;
}
else
{
return skuTransactionTypeCode;
}
}
set
{
if (IsSetSkuTransactionType)
{
if (SkuTransactionType.TypeCode != value)
{
SkuTransactionType = null;
skuTransactionTypeCode = value;
}
}
else
{
skuTransactionTypeCode = value;
}
}
}
public bool IsSetSkuTransactionTypeCode
{
get { return SkuTransactionTypeCode != null; }
}
public Model.Stock.SkuTransactionType SkuTransactionType
{
get
{
return skuTransactionType;
}
set
{
if (IsSetSkuTransactionTypeCode)
{
skuTransactionTypeCode = null;
}
skuTransactionType = value;
}
}
public bool IsSetSkuTransactionType
{
get { return SkuTransactionType != null; }
}
public int ForeignKey
{
get { return foreignKey.GetValueOrDefault(); }
set { foreignKey = value; }
}
public bool IsSetForeignKey
{
get { return foreignKey != null; }
}
public string Reference { get; set; }
public bool IsSetReference
{
get { return Reference != null; }
}
public string Detail { get; set; }
public bool IsSetDetail
{
get { return Detail != null; }
}
[Required()]
public string SkuNumber { get; set; }
public bool IsSetSkuNumber
{
get { return SkuNumber != null; }
}
[Required(), Range(0, short.MaxValue)]
public short Quantity
{
get { return quantity.GetValueOrDefault(); }
set { quantity = value; }
}
public bool IsSetQuantity
{
get { return quantity != null; }
}
public bool IsProcessed
{
get { return isProcessed.GetValueOrDefault(); }
set { isProcessed = value; }
}
public bool IsSetIsProcessed
{
get { return isProcessed != null; }
}
public int StockJournalId
{
get { return stockjournalId.GetValueOrDefault(); }
set { stockjournalId = value; }
}
public bool IsSetStockJournalId
{
get { return stockjournalId != null; }
SkuTransactionId = transactionId;
IsProcessed = isProcessed;
StockJournalId = journalId;
RecordCreated = created;
}
public SkuTransaction Clone()
{
var clone = new SkuTransaction();
int transactionId = SkuTransactionId;
if (IsSetDetail) { clone.Detail = string.Copy(this.Detail); }
if (IsSetForeignKey) { clone.ForeignKey = this.ForeignKey; }
if (IsSetIsProcessed) { clone.IsProcessed = this.IsProcessed; }
if (IsSetQuantity) { clone.Quantity = this.Quantity; }
if (IsSetReference) { clone.Reference = string.Copy(this.Reference); }
if (IsSetSkuNumber) { clone.SkuNumber = string.Copy(this.SkuNumber); }
if (IsSetStockJournalId) { clone.StockJournalId = this.StockJournalId; }
if (IsSetSkuTransactionId) { clone.SkuTransactionId = this.SkuTransactionId; }
if (IsSetTransactionDate) { clone.TransactionDate = this.TransactionDate; }
if (IsSetSkuTransactionType) { clone.SkuTransactionType = this.SkuTransactionType; }
else if (IsSetSkuTransactionTypeCode) { clone.SkuTransactionTypeCode = string.Copy(this.SkuTransactionTypeCode); }
DateTime transactionDate = TransactionDate;
return clone;
string transactionCode = string.Copy(SkuTransactionTypeCode);
int? foreignKey = null;
if (ForeignKey != null) { foreignKey = ForeignKey; }
string reference = null;
if (Reference != null) { reference = string.Copy(Reference); }
string detail = null;
if (Detail != null) { detail = string.Copy(Detail); }
string skuNumber = string.Copy(SkuNumber);
int quantity = Quantity;
bool isProcessed = IsProcessed;
int? journalId = null;
if(StockJournalId != null) { journalId = StockJournalId; }
DateTime created = RecordCreated;
return new SkuTransaction(
transactionId
, transactionDate
, transactionCode
, foreignKey
, reference
, detail
, skuNumber
, quantity
, isProcessed
, journalId
, created
);
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
public new IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var result = new List<ValidationResult>();
result.AddRange(base.Validate(validationContext));
if (!IsSetTransactionDate)
if (StockJournalId != null && IsProcessed == false)
{
result.Add(new ValidationResult("Transaction date is not set"));
}
if (!IsSetIsProcessed)
{
result.Add(new ValidationResult("IsProcessed is not set"));
}
if (!IsSetQuantity)
{
result.Add(new ValidationResult("Quantity is not set"));
}
//if (!IsSetSkuTransactionId)
//{
// result.Add(new ValidationResult("Stock Transaction Id is not set"));
//}
if (IsSetStockJournalId && (!IsSetIsProcessed || IsProcessed == false))
{
result.Add(new ValidationResult("Stock Journal Id is set, IsProcessed must be set to true"));
result.Add(new ValidationResult("Stock Journal Id is set, IsProcessed cannot be false"));
}
return result;

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
/// <summary>
/// Model/Data used to create an intial entry in the stock SKU transaction table
/// </summary>
public class SkuTransactionCreate : IValidatableObject
{
[Required()]
public DateTime TransactionDate { get; private set; }
[Required()]
public string SkuTransactionTypeCode { get; private set; }
public int? ForeignKey { get; private set; }
public string Reference { get; private set; }
public string Detail { get; private set; }
[Required()]
public string SkuNumber { get; private set; }
[Required(), Range(0, short.MaxValue)]
public int Quantity { get; private set; } // cannot be negative
public SkuTransactionCreate(DateTime transactionDate, string transactionTypeCode, int? foreignKey, string reference, string detail
, string skuNumber, int quantity)
{
this.TransactionDate = transactionDate;
this.SkuTransactionTypeCode = transactionTypeCode;
this.ForeignKey = foreignKey;
this.Reference = reference;
this.Detail = detail;
this.SkuNumber = skuNumber;
this.Quantity = quantity;
//var context = new ValidationContext(null);
var vaild = Validate(null);
if (new Logic.Validate.SkuTransaction().IsValidResult)
if (vaild.Any())
{
throw new Exception("Invalid parameters set");
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var result = new List<ValidationResult>();
if (Logic.Validate.Format.DateTime(TransactionDate))
{
result.Add(new ValidationResult("Invalid transaction date"));
}
if (string.IsNullOrEmpty(SkuTransactionTypeCode))
{
result.Add(new ValidationResult("Invalid transaction type code"));
}
if (Logic.Validate.Format.SkuNumber(SkuNumber))
{
result.Add(new ValidationResult("Invalid SKU number"));
}
return result;
}
}
}

View File

@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class SkuTransactionDepreciated : IValidatableObject
{
private DateTime? transactionDate = null;
private bool? isProcessed = null;
private short? quantity = null;
private int? stockjournalId = null;
private int? skuTransactionId = null;
private int? foreignKey = null;
private string skuTransactionTypeCode;
private Model.Stock.SkuTransactionType skuTransactionType;
public int SkuTransactionId
{
get { return skuTransactionId.GetValueOrDefault(); }
set { skuTransactionId = value; }
}
public bool IsSetSkuTransactionId
{
get { return skuTransactionId != null; }
}
[Required()]
public DateTime TransactionDate
{
get { return transactionDate.GetValueOrDefault(); }
set { transactionDate = value; }
}
public bool IsSetTransactionDate
{
get { return transactionDate != null; }
}
[Required()]
public string SkuTransactionTypeCode
{
get
{
if (IsSetSkuTransactionType)
{
return SkuTransactionType.TypeCode;
}
else
{
return skuTransactionTypeCode;
}
}
set
{
if (IsSetSkuTransactionType)
{
if (SkuTransactionType.TypeCode != value)
{
SkuTransactionType = null;
skuTransactionTypeCode = value;
}
}
else
{
skuTransactionTypeCode = value;
}
}
}
public bool IsSetSkuTransactionTypeCode
{
get { return SkuTransactionTypeCode != null; }
}
public Model.Stock.SkuTransactionType SkuTransactionType
{
get
{
return skuTransactionType;
}
set
{
if (IsSetSkuTransactionTypeCode)
{
skuTransactionTypeCode = null;
}
skuTransactionType = value;
}
}
public bool IsSetSkuTransactionType
{
get { return SkuTransactionType != null; }
}
public int ForeignKey
{
get { return foreignKey.GetValueOrDefault(); }
set { foreignKey = value; }
}
public bool IsSetForeignKey
{
get { return foreignKey != null; }
}
public string Reference { get; set; }
public bool IsSetReference
{
get { return Reference != null; }
}
public string Detail { get; set; }
public bool IsSetDetail
{
get { return Detail != null; }
}
[Required()]
public string SkuNumber { get; set; }
public bool IsSetSkuNumber
{
get { return SkuNumber != null; }
}
[Required(), Range(0, short.MaxValue)]
public short Quantity
{
get { return quantity.GetValueOrDefault(); }
set { quantity = value; }
}
public bool IsSetQuantity
{
get { return quantity != null; }
}
public bool IsProcessed
{
get { return isProcessed.GetValueOrDefault(); }
set { isProcessed = value; }
}
public bool IsSetIsProcessed
{
get { return isProcessed != null; }
}
public int StockJournalId
{
get { return stockjournalId.GetValueOrDefault(); }
set { stockjournalId = value; }
}
public bool IsSetStockJournalId
{
get { return stockjournalId != null; }
}
public SkuTransactionDepreciated Clone()
{
var clone = new SkuTransactionDepreciated();
if (IsSetDetail) { clone.Detail = string.Copy(this.Detail); }
if (IsSetForeignKey) { clone.ForeignKey = this.ForeignKey; }
if (IsSetIsProcessed) { clone.IsProcessed = this.IsProcessed; }
if (IsSetQuantity) { clone.Quantity = this.Quantity; }
if (IsSetReference) { clone.Reference = string.Copy(this.Reference); }
if (IsSetSkuNumber) { clone.SkuNumber = string.Copy(this.SkuNumber); }
if (IsSetStockJournalId) { clone.StockJournalId = this.StockJournalId; }
if (IsSetSkuTransactionId) { clone.SkuTransactionId = this.SkuTransactionId; }
if (IsSetTransactionDate) { clone.TransactionDate = this.TransactionDate; }
if (IsSetSkuTransactionType) { clone.SkuTransactionType = this.SkuTransactionType; }
else if (IsSetSkuTransactionTypeCode) { clone.SkuTransactionTypeCode = string.Copy(this.SkuTransactionTypeCode); }
return clone;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var result = new List<ValidationResult>();
if (!IsSetTransactionDate)
{
result.Add(new ValidationResult("Transaction date is not set"));
}
if (!IsSetIsProcessed)
{
result.Add(new ValidationResult("IsProcessed is not set"));
}
if (IsSetSkuNumber && SkuNumber.Length != 9)
{
result.Add(new ValidationResult("SKU number is an incorrect format"));
}
if (!IsSetQuantity)
{
result.Add(new ValidationResult("Quantity is not set"));
}
//if (!IsSetSkuTransactionId)
//{
// result.Add(new ValidationResult("Stock Transaction Id is not set"));
//}
if (IsSetStockJournalId && (!IsSetIsProcessed || IsProcessed == false))
{
result.Add(new ValidationResult("Stock Journal Id is set, IsProcessed must be set to true"));
}
return result;
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
@@ -59,5 +60,30 @@ namespace bnhtrade.Core.Model.Stock
public bool FilterStockOnDateTime { get; set; }
public bool FirstInFirstOut { get; set; } // TODO: move FIFO rule to 'Stock Status'
public SkuTransactionType Clone()
{
var clone = new SkuTransactionType();
if (IsSetTypeId) { clone.TypeId = this.TypeId; }
if (TypeName != null) { clone.TypeName = string.Copy(TypeName); }
if (TypeCode != null) { clone.TypeCode = string.Copy(TypeCode); }
if (TypeDescription != null) { clone.TypeDescription = string.Copy(TypeDescription); }
clone.StockJournalTypeId = StockJournalTypeId;
if (TransactionForeignKeyName != null) { clone.TransactionForeignKeyName = string.Copy(TransactionForeignKeyName); }
if (TransactionReferenceType != null) { clone.TransactionReferenceType = string.Copy(TransactionReferenceType); }
clone.IsNewReviewRequired = IsNewReviewRequired;
clone.TransactionImportEnabled = TransactionImportEnabled;
clone.StockJournalEntryEnabled = StockJournalEntryEnabled;
if (DebitStockStatusId != null) { clone.DebitStockStatusId = DebitStockStatusId; }
if (DebitStockStatus != null) { clone.DebitStockStatus = string.Copy(DebitStockStatus); }
if (CreditStockStatusId != null) { clone.CreditStockStatusId = CreditStockStatusId; }
if (CreditStockStatus != null) { clone.CreditStockStatus = string.Copy(CreditStockStatus); }
clone.StatusBalanceCheckRequired = StatusBalanceCheckRequired;
clone.FilterStockOnDateTime = FilterStockOnDateTime;
clone.FirstInFirstOut = FirstInFirstOut;
return clone;
}
}
}
}