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

@@ -2,31 +2,12 @@
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="bnhtrade.Core.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="e2A_Client.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<applicationSettings>
<bnhtrade.Core.Properties.Settings>
<setting name="DocArchivePath" serializeAs="String">
<value>%USERPROFILE%\Desktop\e2A_Client\Archive\</value>
</setting>
<setting name="DocProcessingPath" serializeAs="String">
<value>%USERPROFILE%\Desktop\e2A_Client\Processing\</value>
</setting>
</bnhtrade.Core.Properties.Settings>
<e2A_Client.Properties.Settings>
<setting name="DocArchivePath" serializeAs="String">
<value>%USERPROFILE%\Desktop\e2A_Client\Archive\</value>
</setting>
<setting name="DocProcessingPath" serializeAs="String">
<value>%USERPROFILE%\Desktop\e2A_Client\Processing\</value>
</setting>
</e2A_Client.Properties.Settings>
</applicationSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
@@ -39,7 +20,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
@@ -59,7 +40,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.2" newVersion="7.0.0.2" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.3" newVersion="8.0.0.3" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core
{
public class Config
{
public string GetAppDataPath()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\bnhtrade\";
return path;
}
/// <summary>
/// return the directory path for temp files, just add file name onto end
/// </summary>
/// <returns></returns>
public static string GetTempFileDirectoryPath()
{
string directoryPath = Path.GetTempPath()
+ "_" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
System.IO.Directory.CreateDirectory(directoryPath);
return directoryPath;
}
/// <summary>
/// Returns configuration file from local users directory
/// </summary>
/// <returns></returns>
internal Configuration GetConfiguration()
{
string path = new bnhtrade.Core.Config().GetAppDataPath();
string configFileName = "app.local.config";
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = path + configFileName;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
return config;
}
}
}

View File

@@ -12,6 +12,7 @@ namespace bnhtrade.Core.Data.Amazon.ProductFee
{
public class GetFeeEstimate
{
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
private AmazonConnection amznConn = new SpApiConnection().Connection;
public string CurrencyCode { get; set; } = "GBP";
@@ -56,7 +57,7 @@ namespace bnhtrade.Core.Data.Amazon.ProductFee
if (result.Error.Type != null)
{ sb.AppendLine("Type: " + result.Error.Type); }
new Logic.Log.LogEvent().EventLogInsert("Error running GetProductEstimateFee for ASIN:" + asin + ", further details attached.", 1, sb.ToString());
log.LogError("Error running GetProductEstimateFee for ASIN:" + asin + ", further details attached.", sb.ToString());
throw new Exception("ProductFeeEstimate error, check logs for further details");
}

View File

@@ -17,7 +17,7 @@ namespace bnhtrade.Core.Data.Amazon.Report
{
// Amazon will throttle (return 'FATAL' error) when requesting this report twice within 15 minutes
DownloadSnapshotReport(reportMaxAge);
DownloadReport(reportMaxAge);
}
}
}

View File

@@ -0,0 +1,91 @@
using CsvHelper;
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentOutbound;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using static FikaAmazonAPI.Utils.Constants;
using System.Linq;
using CsvHelper.Configuration;
using NUnit.Framework.Interfaces;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaInventoryLedgerDetailed : ReportLogic
{
List<Model.Import.AmazonFbaInventoryLedgerDetail> resultList = null;
/// <summary>
/// Get report will download the file to local storage. Use this to transpose the data to a model class.
/// </summary>
public List<Model.Import.AmazonFbaInventoryLedgerDetail> ResultList
{
get
{
if (resultList == null)
{
TransposeFileToClass();
}
return resultList;
}
}
public bool IsSetResultList
{
get { return IsSetReportFilePath; }
}
public FbaInventoryLedgerDetailed() : base(ReportTypes.GET_LEDGER_DETAIL_VIEW_DATA)
{
}
public new void Init()
{
base.Init();
resultList = null;
}
public void GetReport(DateTime utcDataStartTime, DateTime utcDataEndTime)
{
// 18 months max historical transactions for report
DownloadTimePeriodReport(utcDataStartTime, utcDataEndTime, 0, 547);
}
private void TransposeFileToClass()
{
var transposeResult = new List<Model.Import.AmazonFbaInventoryLedgerDetail>();
if (IsSetReportFilePath == false)
{
resultList = transposeResult;
}
else
{
using (var reader = new StreamReader(ReportFilePath))
{
// setup csvhelper
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = "\t",
};
using (var csvreader = new CsvReader(reader, config))
{
// check header count
csvreader.Read();
csvreader.ReadHeader();
int columns = csvreader.HeaderRecord.Count();
if (columns < 15)
throw new Exception("Malformed report 'GET_LEDGER_DETAIL_VIEW_DATA' does not have enough headers");
if (columns > 15)
log.LogError("New column in 'GET_LEDGER_DETAIL_VIEW_DATA'");
// transpose the data
transposeResult = csvreader.GetRecords<Model.Import.AmazonFbaInventoryLedgerDetail>().ToList();
resultList = transposeResult;
}
}
}
}
}
}

View File

@@ -1,11 +1,13 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Reports;
using FikaAmazonAPI.Parameter.Report;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
@@ -13,11 +15,35 @@ namespace bnhtrade.Core.Data.Amazon.Report
{
public class ReportLogic
{
public enum ProcessingStatus
{
NULL,
INQUEUE,
INPROGRESS,
CANCELLED,
DONE,
FATAL
}
private bool _isSetReportProcessingStatus = false;
private AmazonConnection amznConn = new SpApiConnection().Connection;
private FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report;
private FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report = new FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report();
private ReportTypes reportType;
protected Logic.Log.LogEvent log = new Logic.Log.LogEvent();
public ProcessingStatus ReportProcessingStatus { get; private set; }
public bool IsSetReportProcessingStatus
{
get
{
if (ReportProcessingStatus == ProcessingStatus.NULL)
return false;
else
return true;
}
}
public DateTime? ReportCreatedTime
{
get
@@ -27,13 +53,19 @@ namespace bnhtrade.Core.Data.Amazon.Report
}
}
/// <summary>
/// The report has completed, but there is no data (and hence no file) to download.
/// </summary>
public bool ReportDoneNoData { get; private set; }
/// <summary>
/// File path the the local location of the file
/// </summary>
public string ReportFilePath { get; private set; }
private FikaAmazonAPI.Utils.MarketplaceIds MarketPlaceIds { get; set; }
public bool ReportFilePathIsSet
public bool IsSetReportFilePath
{
get { return !string.IsNullOrWhiteSpace(ReportFilePath); }
}
@@ -43,35 +75,45 @@ namespace bnhtrade.Core.Data.Amazon.Report
this.reportType = reportType;
this.MarketPlaceIds = new MarketplaceIds();
this.MarketPlaceIds.Add(amznConn.GetCurrentMarketplace.ID);
Innit();
Init();
}
private void Innit()
protected void Init()
{
ReportDoneNoData = false;
ReportFilePath = null;
report = null;
ReportProcessingStatus = ProcessingStatus.NULL;
}
/// <summary>
/// Always use this function to report and it's filepath, this ensures the two correlate
/// For reports that require a start and end period to report over.
/// </summary>
/// <param name="report"></param>
/// <param name="reportFilePath"></param>
private void SetFilePath(FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, string reportFilePath)
{
this.report = report;
this.ReportFilePath = reportFilePath;
}
protected void DownloadTimePeriodReport(DateTime utcDataStartTime, DateTime utcDataEndTime, int maxDateRangeDays)
/// <param name="utcDataStartTime"></param>
/// <param name="utcDataEndTime"></param>
/// <param name="maxDateRangeDays">The max time in days between the start and end date time</param>
/// <param name="maxDataAgeDays">The max time that Amazon retains the data for, in days</param>
/// <exception cref="Exception"></exception>
protected void DownloadTimePeriodReport(DateTime utcDataStartTime, DateTime utcDataEndTime, int maxDateRangeDays, int maxDataAgeDays = 0)
{
if (utcDataStartTime.Kind != DateTimeKind.Utc || utcDataEndTime.Kind != DateTimeKind.Utc)
throw new Exception("Report period time should be set to UTC");
throw new Exception("Report period time has to be set to UTC");
if (maxDateRangeDays > 0 && (utcDataEndTime - utcDataStartTime).TotalDays > maxDateRangeDays)
throw new Exception("Date range for report is greater than the maximum allowable");
if (maxDataAgeDays < 0)
{
throw new Exception("Max data age in days cannot be less than zero");
}
//else if(maxDataAgeDays > 0)
//{
// if (utcDataStartTime < DateTime.UtcNow.AddDays(maxDataAgeDays * -1))
// {
// throw new Exception("Max historical data for " + reportType.ToString() + " is " + maxDataAgeDays + " days");
// }
//}
var specification = new ParameterCreateReportSpecification();
specification.marketplaceIds = this.MarketPlaceIds;
specification.reportType = reportType;
@@ -81,7 +123,11 @@ namespace bnhtrade.Core.Data.Amazon.Report
DownloadReport(specification, false);
}
protected void DownloadSnapshotReport(int snapshotMaxAge)
/// <summary>
/// Use this to download reports that do not have a time period element, they are as things stand now.
/// </summary>
/// <param name="snapshotMaxAge">In minutes, the minimum time between report requests. Amazon will return 'FATAL' if a report is re-requested in too short a time period </param>
protected void DownloadReport(int snapshotMaxAge)
{
var specification = new ParameterCreateReportSpecification();
specification.marketplaceIds = this.MarketPlaceIds;
@@ -90,64 +136,120 @@ namespace bnhtrade.Core.Data.Amazon.Report
DownloadReport(specification, true, snapshotMaxAge);
}
/// <summary>
/// The main body of the class, where the all the work is done
/// </summary>
/// <param name="specification">the specification built by the supporting methods</param>
/// <param name="isSnapshotReport">ie not a time period report, but an 'as things stand now' report</param>
/// <param name="snapshotMaxAge">time in minutes</param>
/// <exception cref="Exception"></exception>
private void DownloadReport(ParameterCreateReportSpecification specification, bool isSnapshotReport, int snapshotMaxAge = 0)
{
log.LogInformation("Starting report requesting from Amazon SP-API for " + specification.reportType.ToString());
// Amazon create report is throttled to 1 report every 15 minutes
Innit();
Init();
// check for existing report with same specification
string reportId = ExistingReportSearch(specification);
string reportId = ExistingReportCheck(specification);
// no matching report? then create one
if (reportId == null)
{ reportId = amznConn.Reports.CreateReport(specification); }
var filePath = amznConn.Reports.GetReportFile(reportId);
var report = amznConn.Reports.GetReport(reportId); // filePath and report need to be called in this order
WaitWhileProcessing(reportId);
if (!string.IsNullOrWhiteSpace(filePath))
// some real time report will return 'fatal' if the report has already recently been requested, test for this
if (isSnapshotReport && report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
SetFilePath(report, filePath);
bool aSuitableReportExists = SnapshotReportThrottleHanderler(ref reportId, specification, snapshotMaxAge);
if (aSuitableReportExists == true)
{
log.LogWarning("Create amazon report returned 'FATAL' due to a report with the same parameters already existing, requesting the existing report");
WaitWhileProcessing(reportId);
}
}
// test for processing status
if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.DONE)
{
ReportProcessingStatus = ProcessingStatus.DONE;
log.LogInformation("Report proccessing status is 'DONE' (ReportId:" + report.ReportId + ").");
if (string.IsNullOrEmpty(report.ReportDocumentId))
throw new Exception("Report processing done, yet there's no report document. Write code to handle this");
}
else if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED)
{
ReportProcessingStatus = ProcessingStatus.CANCELLED;
// From SPAPI Documentation: The report was cancelled. There are two ways a report can be cancelled:
// an explicit cancellation request before the report starts processing, or an automatic cancellation
// if there is no data to return.
log.Initialise();
log.LogInformation("ReportID:" + reportId + " returned 'CANCELLED', if a cancel request hasn't been made then there is no data in the report.");
ReportDoneNoData = true;
return;
}
else
else if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
// test for 'Fatal' return when report has recently been requested.
report = amznConn.Reports.GetReport(reportId);
if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED)
ReportProcessingStatus = ProcessingStatus.FATAL;
// AMazon does sometime return a file with information as to why fatal was returned contained within, test for this
if (string.IsNullOrEmpty(report.ReportDocumentId))
{
// From SPAPI Documentation: The report was cancelled. There are two ways a report can be cancelled:
// an explicit cancellation request before the report starts processing, or an automatic cancellation
// if there is no data to return.
log.Initialise();
log.LogInformation("ReportID:" + reportId + " returned 'CANCELLED' status (no data).");
ReportDoneNoData = true;
log.LogError("ReportID:" + reportId + " returned 'FATAL', no further information was recived.");
return;
}
else if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
if (isSnapshotReport)
{
SnapahotThrottleHanderler(ref report, specification, snapshotMaxAge);
filePath = amznConn.Reports.GetReportFile(report.ReportId);
if (string.IsNullOrWhiteSpace(filePath))
{
LogReportError(report, "Error while retriving report " + reportType.ToString());
throw new Exception("Error while retriving report " + reportType.ToString());
}
SetFilePath(report, filePath);
return;
}
else
{
throw new Exception("Report processing status returned 'FATAL' report#" + reportType.ToString());
}
}
}
throw new Exception("Error while retriving " + reportType.ToString() + " report, nothing should be getting here!!");
// if we get here, onto downloading the file
if (string.IsNullOrEmpty(report.ReportDocumentId))
throw new Exception("ReportDocumentId field is null or empty.");
// as file url expires after 5 minutes, request it just before download
UI.Console.WriteLine("Requesting download url for Amazon report (ReportId:" + reportId + ").");
var amazonFileInfo = amznConn.Reports.GetReportDocument(report.ReportDocumentId);
// download report from url
log.LogInformation("Downloading Amazon report #" + reportId, "Report Document ID: " + amazonFileInfo.ReportDocumentId);
byte[] response = null;
using (var webClient = new System.Net.WebClient())
{
response = webClient.DownloadData(amazonFileInfo.Url);
}
// decrypt report
UI.Console.WriteLine("Processing download (ReportId:" + reportId + ").");
if (amazonFileInfo.EncryptionDetails != null)
{
UI.Console.WriteLine("Decrypting report ReportId:" + reportId + ").", false);
byte[] key = Encoding.ASCII.GetBytes(amazonFileInfo.EncryptionDetails.Key);
byte[] iv = Encoding.ASCII.GetBytes(amazonFileInfo.EncryptionDetails.InitializationVector);
response = Logic.Utilities.File.DecryptByte(key, iv, response);
}
// decompress
if (amazonFileInfo.CompressionAlgorithm != null)
{
UI.Console.WriteLine("Decompressing report ReportId:" + reportId + ").", false);
response = Logic.Utilities.File.Decompress(response);
}
string reportString = Encoding.ASCII.GetString(response);
// if fatal returned, give file contents in log
if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
log.LogError("Downloading reportId:" + report.ReportId + " returned 'FATAL'. See long detail for further details", reportString);
return;
}
// save to file
string reportFilePath = Config.GetTempFileDirectoryPath() + @"\SP-API-Reports\ " + report.ReportType.ToString() + " reportId_" + reportId + ".txt";
System.IO.File.WriteAllText(reportFilePath, reportString);
log.LogInformation("Amazon report #" + reportId + " sucessfully saved to disk.");
this.ReportFilePath = reportFilePath;
}
/// <summary>
@@ -155,12 +257,12 @@ namespace bnhtrade.Core.Data.Amazon.Report
/// </summary>
/// <param name="report">Report to test for throttled response</param>
/// <param name="specification">The specification that created to throttle report.</param>
private void SnapahotThrottleHanderler(ref FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, ParameterCreateReportSpecification specification, int snapshotMaxAge)
private bool SnapshotReportThrottleHanderler(ref string reportId, ParameterCreateReportSpecification specification, int snapshotMaxAgeMinutes)
{
if (report.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
return;
throw new Exception("Incorrect use of class, processing status must be fatal");
if (snapshotMaxAge <= 0)
if (snapshotMaxAgeMinutes <= 0)
{
// report not avaiable
throw new Exception( reportType.ToString() + " report not avaibale for requested timeframe");
@@ -169,26 +271,31 @@ namespace bnhtrade.Core.Data.Amazon.Report
// search for valid reports with required timeframe
var parameters = new ParameterReportList();
parameters.reportTypes = new List<ReportTypes> { specification.reportType };
parameters.createdSince = report.CreatedTime.Value.AddMinutes(-snapshotMaxAge);
parameters.createdSince = report.CreatedTime.Value.AddMinutes(-snapshotMaxAgeMinutes);
parameters.marketplaceIds = specification.marketplaceIds;
var reports = amznConn.Reports.GetReports(parameters);
if (reports == null || !reports.Any())
{
return;
return false;
}
foreach (var item in reports)
{
if (item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED
&& item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
if (item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.DONE
|| item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INPROGRESS
|| item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INQUEUE)
{
log.LogInformation("Amazon declinded requested report:" + item.ReportType.ToString() + " as another with same parameters already existes, substituting reportId " + reportId + " for " + item.ReportId);
reportId = item.ReportId;
report = item;
return true;
}
}
return false;
}
private string ExistingReportSearch(ParameterCreateReportSpecification specification)
private string ExistingReportCheck(ParameterCreateReportSpecification specification)
{
// amazon may return 'fatal' due to report already existing and/or report request matches an recent existing request
@@ -215,6 +322,44 @@ namespace bnhtrade.Core.Data.Amazon.Report
return null;
}
private void WaitWhileProcessing(string reportId)
{
// set accordingly
int waitPeriodIncrement = (1000 * 10);
int waitPeriodIncrementMax = (1000 * 60);
int waitPeriod = 0;
int waitPeriodTotal = 0;
int waitPeriodTotalTimeout = (1000 * 1200); // 20 minutes
while (waitPeriodTotal < waitPeriodTotalTimeout)
{
report = amznConn.Reports.GetReport(reportId);
if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INQUEUE)
{
ReportProcessingStatus = ProcessingStatus.INQUEUE;
}
else if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INPROGRESS)
{
ReportProcessingStatus = ProcessingStatus.INPROGRESS;
}
else
{
return;
}
waitPeriod = waitPeriod + waitPeriodIncrement;
if (waitPeriod > waitPeriodIncrementMax)
waitPeriod = waitPeriodIncrementMax;
UI.Console.Wait("Report processing status " + ReportProcessingStatus + ". Check in {0} seconds...", waitPeriod);
waitPeriodTotal = waitPeriodTotal + waitPeriod;
}
throw new Exception("Amazon report processing for reportId:" + report.ReportId + " timeout after " + (waitPeriodTotal / 60000) + " minutes.");
}
private void LogReportError(FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, string errorTitle)
{
log.Initialise();

View File

@@ -1,122 +0,0 @@
////using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Services;
//using FikaAmazonAPI.Services;
//using System;
//using System.Collections.Generic;
//using System.Text;
//namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
//{
// public class AmazonConnection
// {
// private AmazonCredential Credentials { get; set; }
// public FbaInboundService FbaInbound => this._FbaInbound ?? throw _NoCredentials;
// public FbaInventoryService FbaInventory => this._FbaInventory ?? throw _NoCredentials;
// public FulFillmentInboundService FulFillmentInbound => this._FulFillmentInbound ?? throw _NoCredentials;
// public ProductFeeService ProductFee => this._ProductFee ?? throw _NoCredentials;
// public ProductPricingService ProductPricing => this._ProductPricing ?? throw _NoCredentials;
// public ReportService Reports => this._Reports ?? throw _NoCredentials;
// //public AplusContentService AplusContent => this._AplusContent ?? throw _NoCredentials;
// //public AuthorizationService Authorization => this._Authorization ?? throw _NoCredentials;
// //public CatalogItemService CatalogItem => this._CatalogItems ?? throw _NoCredentials;
// //public FbaInboundEligibilityService FbaInboundEligibility => this._FbaInboundEligibility ?? throw _NoCredentials;
// //public FbaOutboundService FbaOutbound => this._FbaOutbound ?? throw _NoCredentials;
// //public FbaSmallandLightService FbaSmallandLight => this._FbaSmallandLight ?? throw _NoCredentials;
// //public FeedService Feed => this._Feed ?? throw _NoCredentials;
// //public FinancialService Financial => this._Financials ?? throw _NoCredentials;
// //public FulFillmentOutboundService FulFillmentOutbound => this._FulFillmentOutbound ?? throw _NoCredentials;
// //public ListingsItemService ListingsItem => this._ListingsItem ?? throw _NoCredentials;
// //public MerchantFulfillmentService MerchantFulfillment => this._MerchantFulfillment ?? throw _NoCredentials;
// //public MessagingService Messaging => this._Messaging ?? throw _NoCredentials;
// //public NotificationService Notification => this._Notification ?? throw _NoCredentials;
// //public OrderService Orders => this._Orders ?? throw _NoCredentials;
// //public SalesService Sales => this._Sales ?? throw _NoCredentials;
// //public SellerService Seller => this._Seller ?? throw _NoCredentials;
// //public ServicesService Services => this._Services ?? throw _NoCredentials;
// //public ShipmentInvoicingService ShipmentInvoicing => this._ShipmentInvoicing ?? throw _NoCredentials;
// //public ShippingService Shipping => this._Shipping ?? throw _NoCredentials;
// //public SolicitationService Solicitations => this._Solicitations ?? throw _NoCredentials;
// //public TokenService Tokens => this._Tokens ?? throw _NoCredentials;
// //public UploadService Upload => this._Upload ?? throw _NoCredentials;
// private FbaInboundService _FbaInbound { get; set; }
// private FbaInventoryService _FbaInventory { get; set; }
// private FulFillmentInboundService _FulFillmentInbound { get; set; }
// private ProductFeeService _ProductFee { get; set; }
// private ProductPricingService _ProductPricing { get; set; }
// private ReportService _Reports { get; set; }
// //private AplusContentService _AplusContent { get; set; }
// //private AuthorizationService _Authorization { get; set; }
// //private CatalogItemService _CatalogItems { get; set; }
// //private FbaInboundEligibilityService _FbaInboundEligibility { get; set; }
// //private FbaOutboundService _FbaOutbound { get; set; }
// //private FbaSmallandLightService _FbaSmallandLight { get; set; }
// private FeedService _Feed { get; set; }
// //private FinancialService _Financials { get; set; }
// //private FulFillmentOutboundService _FulFillmentOutbound { get; set; }
// //private ListingsItemService _ListingsItem { get; set; }
// //private MerchantFulfillmentService _MerchantFulfillment { get; set; }
// //private MessagingService _Messaging { get; set; }
// //private NotificationService _Notification { get; set; }
// //private OrderService _Orders { get; set; }
// //private SalesService _Sales { get; set; }
// //private SellerService _Seller { get; set; }
// //private ServicesService _Services { get; set; }
// //private ShipmentInvoicingService _ShipmentInvoicing { get; set; }
// //private ShippingService _Shipping { get; set; }
// //private SolicitationService _Solicitations { get; set; }
// //private TokenService _Tokens { get; set; }
// //private UploadService _Upload { get; set; }
// private UnauthorizedAccessException _NoCredentials = new UnauthorizedAccessException($"Error, you cannot make calls to Amazon without credentials!");
// public AmazonConnection(AmazonCredential Credentials)
// {
// this.Authenticate(Credentials);
// }
// public void Authenticate(AmazonCredential Credentials)
// {
// if (this.Credentials == default(AmazonCredential))
// Init(Credentials);
// else
// throw new InvalidOperationException("Error, you are already authenticated to amazon in this AmazonConnection, dispose of this connection and create a new one to connect to a different account.");
// }
// private void Init(AmazonCredential Credentials)
// {
// this.Credentials = Credentials;
// this._FbaInbound = new FbaInboundService(this.Credentials);
// this._FbaInventory = new FbaInventoryService(this.Credentials);
// this._FulFillmentInbound = new FulFillmentInboundService(this.Credentials);
// this._ProductFee = new ProductFeeService(this.Credentials);
// this._ProductPricing = new ProductPricingService(this.Credentials);
// this._Reports = new ReportService(this.Credentials);
// //this._AplusContent = new AplusContentService(this.Credentials);
// //this._CatalogItems = new CatalogItemService(this.Credentials);
// //this._FbaInboundEligibility = new FbaInboundEligibilityService(this.Credentials);
// //this._FbaOutbound = new FbaOutboundService(this.Credentials);
// //this._FbaSmallandLight = new FbaSmallandLightService(this.Credentials);
// this._Feed = new FeedService(this.Credentials);
// //this._Financials = new FinancialService(this.Credentials);
// //this._FulFillmentOutbound= new FulFillmentOutboundService(this.Credentials);
// //this._ListingsItem = new ListingsItemService(this.Credentials);
// //this._MerchantFulfillment = new MerchantFulfillmentService(this.Credentials);
// //this._Messaging= new MessagingService(this.Credentials);
// //this._Notification= new NotificationService(this.Credentials);
// //this._Orders = new OrderService(this.Credentials);
// //this._Sales= new SalesService(this.Credentials);
// //this._Seller= new SellerService(this.Credentials);
// //this._Services= new ServicesService(this.Credentials);
// //this._ShipmentInvoicing= new ShipmentInvoicingService(this.Credentials);
// //this._Shipping= new ShippingService(this.Credentials);
// //this._Solicitations = new SolicitationService(this.Credentials);
// //this._Tokens= new TokenService(this.Credentials);
// //this._Upload= new UploadService(this.Credentials);
// }
// }
//}

View File

@@ -1,103 +0,0 @@
//using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.SDK.Models.Token;
//using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Utils;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Token;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
using static FikaAmazonAPI.AmazonSpApiSDK.Models.Token.CacheTokenData;
using static FikaAmazonAPI.Utils.Constants;
//using static bnhtrade.Core.Data.Amazon.SellingPartnerAPI.SDK.Models.Token.CacheTokenData;
//using static bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
public class AmazonCredential
{
public string AccessKey { get; set; }
public string SecretKey { get; set; }
public string RoleArn { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string RefreshToken { get; set; }
public MarketPlace MarketPlace { get; set; }
private CacheTokenData CacheTokenData { get; set; } = new CacheTokenData();
public bool IsActiveLimitRate { get; set; } = true;
public Environments Environment { get; set; } = Environments.Production;
public AmazonCredential()
{
// attempt to retrive credentials from app.local.config
try
{
Innit(ConfigurationManager.AppSettings["SpapiAccessKey"]
, ConfigurationManager.AppSettings["SpapiSecretKey"]
, ConfigurationManager.AppSettings["SpapiRoleArn"]
, ConfigurationManager.AppSettings["SpapiClientId"]
, ConfigurationManager.AppSettings["SpapiClientSecret"]
, ConfigurationManager.AppSettings["SpapiRefreshToken"]);
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["SpapiMarketplaceId"]))
{
this.MarketPlace = MarketPlace.UnitedKingdom;
}
}
catch (Exception ex)
{
throw new Exception("Unable to retirve Amazon SP API credentials: " + ex.Message);
}
}
private AmazonCredential(string accessKey, string secretKey, string roleArn, string clientId, string clientSecret, string refreshToken)
{
// Use other method by default, however can change this method back to public is the need arises.
Innit(accessKey
, secretKey
, roleArn
, clientId
, clientSecret
, refreshToken);
}
public AmazonCredential(Core.Model.Credentials.AmazonSPAPI userCredentials)
{
Innit(userCredentials.AccessKey
, userCredentials.SecretKey
, userCredentials.RoleArn
, userCredentials.ClientId
, userCredentials.ClientSecret
, userCredentials.RefreshToken);
}
private void Innit(string accessKey, string secretKey, string roleArn, string clientId, string clientSecret, string refreshToken)
{
this.AccessKey = accessKey;
this.SecretKey = secretKey;
this.RoleArn = roleArn;
this.ClientId = clientId;
this.ClientSecret = clientSecret;
this.RefreshToken = refreshToken;
}
public TokenResponse GetToken(TokenDataType tokenDataType)
{
return CacheTokenData.GetToken(tokenDataType);
}
public void SetToken(TokenDataType tokenDataType, TokenResponse token)
{
CacheTokenData.SetToken(tokenDataType, token);
}
public AWSAuthenticationTokenData GetAWSAuthenticationTokenData()
{
return CacheTokenData.GetAWSAuthenticationTokenData();
}
public void SetAWSAuthenticationTokenData(AWSAuthenticationTokenData tokenData)
{
CacheTokenData.SetAWSAuthenticationTokenData(tokenData);
}
}
}

View File

@@ -12,11 +12,12 @@ namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
public MarketPlace MarketPlaceId()
{
return MarketPlace.GetMarketPlaceByID(ConfigurationManager.AppSettings["SpapiMarketplaceId"]);
return MarketPlace.GetMarketPlaceByID(MarketPlaceIdAsString());
}
public string MarketPlaceIdAsString()
{
return ConfigurationManager.AppSettings["SpapiMarketplaceId"];
var config = new Config().GetConfiguration();
return config.AppSettings.Settings["SpapiMarketplaceId"].Value;
}
}
}

View File

@@ -7,13 +7,13 @@
//{
// public class ReportService : RequestService
// {
// private Dictionary<string, RestSharp.RestResponse<SDK.Models.Reports.Report>> reportList;
// private Dictionary<string, RestSharp.RestResponse<FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report>> reportList;
// private Dictionary<string, string> filePath;
// private bool fatalEncounter = false;
// protected Logic.Log.LogEvent log = new Logic.Log.LogEvent();
// private int reportRequestCount = 0;
// public ReportService() : base (new AmazonCredential())
// public ReportService() : base(new AmazonCredential())
// {
// Innit();
// }
@@ -260,25 +260,25 @@
// // as file url expires after 5 minutes, request just before download
// UI.Console.WriteLine("Requesting download url for Amazon report (ReportId:" + reportId + ").");
// var reportDocument = GetReportDocument(reportList[reportId].Data.ReportDocumentId);
// var amazonFileInfo = GetReportDocument(reportList[reportId].Data.ReportDocumentId);
// // download report from url
// log.LogInformation("Downloading Amazon report #" + reportId, "Report Document ID: " + reportDocument.ReportDocumentId);
// log.LogInformation("Downloading Amazon report #" + reportId, "Report Document ID: " + amazonFileInfo.ReportDocumentId);
// var response = new byte[0];
// using (var webClient = new System.Net.WebClient())
// {
// response = webClient.DownloadData(reportDocument.Url);
// response = webClient.DownloadData(amazonFileInfo.Url);
// }
// string report = null;
// // decrypt report
// UI.Console.WriteLine("Processing download (ReportId:" + reportId + ").");
// if (reportDocument.EncryptionDetails != null)
// if (amazonFileInfo.EncryptionDetails != null)
// {
// byte[] key = Encoding.ASCII.GetBytes(reportDocument.EncryptionDetails.Key);
// byte[] iv = Encoding.ASCII.GetBytes(reportDocument.EncryptionDetails.InitializationVector);
// report = Logic.Utilities.FileTransform.DecryptString(key, iv, response);
// byte[] key = Encoding.ASCII.GetBytes(amazonFileInfo.EncryptionDetails.Key);
// byte[] iv = Encoding.ASCII.GetBytes(amazonFileInfo.EncryptionDetails.InitializationVector);
// report = Logic.Utilities.File.DecryptString(key, iv, response);
// }
// else
// {
@@ -286,9 +286,9 @@
// }
// // decompress
// if (reportDocument.CompressionAlgorithm != null)
// if (amazonFileInfo.CompressionAlgorithm != null)
// {
// report = Logic.Utilities.FileTransform.Decompress(report);
// report = Logic.Utilities.File.Decompress(report);
// }
// // save to file

View File

@@ -26,17 +26,20 @@ namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
// attempt to create credential object from app.local.config
var credential = new FikaAmazonAPI.AmazonCredential();
var config = new Config().GetConfiguration();
try
{
string dataSource = config.AppSettings.Settings["DbDataSource"].Value;
credential = new FikaAmazonAPI.AmazonCredential();
credential.AccessKey = ConfigurationManager.AppSettings["SpapiAccessKey"];
credential.SecretKey = ConfigurationManager.AppSettings["SpapiSecretKey"];
credential.RoleArn = ConfigurationManager.AppSettings["SpapiRoleArn"];
credential.ClientId = ConfigurationManager.AppSettings["SpapiClientId"];
credential.ClientSecret = ConfigurationManager.AppSettings["SpapiClientSecret"];
credential.RefreshToken = ConfigurationManager.AppSettings["SpapiRefreshToken"];
credential.MarketPlaceID = ConfigurationManager.AppSettings["SpapiMarketplaceId"];
credential.IsDebugMode = true;
//credential.AccessKey = config.AppSettings.Settings["SpapiAccessKey"].Value;
//credential.SecretKey = config.AppSettings.Settings["SpapiSecretKey"].Value;
//credential.RoleArn = config.AppSettings.Settings["SpapiRoleArn"].Value;
credential.ClientId = config.AppSettings.Settings["SpapiClientId"].Value;
credential.ClientSecret = config.AppSettings.Settings["SpapiClientSecret"].Value;
credential.RefreshToken = config.AppSettings.Settings["SpapiRefreshToken"].Value;
credential.MarketPlaceID = config.AppSettings.Settings["SpapiMarketplaceId"].Value;
//credential.IsDebugMode = true;
credential.MaxThrottledRetryCount = 3;
}
catch (Exception ex)

View File

@@ -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 = @"

View File

@@ -39,7 +39,7 @@ namespace bnhtrade.Core.Data.Database.AmazonShipment
{
if (skuIdLoopkup == null)
{
skuIdLoopkup = new Sku.GetSkuId(SqlConnectionString);
skuIdLoopkup = new Sku.GetSkuId();
}
return skuIdLoopkup;
}

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -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()
);

View File

@@ -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()
);

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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");
}
}
}
}
}

View File

@@ -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()
);

View File

@@ -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();
}
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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>();

View File

@@ -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");
}
}
}

View File

@@ -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());

View File

@@ -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;
}
}
}
}

View 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;
}
}
}
}

View File

@@ -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
{

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View 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;
}
}
}

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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");
}
}
}
}
}
}

View File

@@ -10,13 +10,11 @@ namespace bnhtrade.Core.Logic.Export
{
public class AmazonSettlement
{
private string sqlConnectionString;
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
private List<string> lineItemCodeList = new List<string>();
public AmazonSettlement(string sqlConnectionString)
public AmazonSettlement()
{
this.sqlConnectionString = sqlConnectionString;
}
public void ToInvoice()
@@ -292,7 +290,7 @@ namespace bnhtrade.Core.Logic.Export
{
try
{
var saveInv = new Logic.Export.SalesInvoice(sqlConnectionString);
var saveInv = new Logic.Export.SalesInvoice();
// add temp invoice numbers
saveInv.AddTempInvoiceNumber(invoiceList, true);

View File

@@ -8,12 +8,10 @@ namespace bnhtrade.Core.Logic.Export
{
public class SalesInvoice
{
private string sqlConnectionString;
private Logic.Log.LogEvent log = new Log.LogEvent();
public SalesInvoice(string sqlConnectionString)
public SalesInvoice()
{
this.sqlConnectionString = sqlConnectionString;
}
public string GetNextTempInvoiceNumber()

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Import
{
public class Amazon
{
Log.LogEvent log = new Log.LogEvent();
public void SyncAllWithDatabase()
{
bool fbaInventoryLedgerDetail = false;
bool fbaReimbursement = false;
bool settlement = false;
bool fbaInventory = false;
bool fbaRemovalOrder = false;
bool fbaSaleShipment = false;
bool fbaCustomerReturn = false;
while (true)
{
try
{
if (fbaInventoryLedgerDetail == false) { fbaInventoryLedgerDetail = true; new Logic.Import.AmazonFbaInventoryLedgerDetail().SyncDatabaseWithAmazon(); }
if (fbaReimbursement == false) { fbaReimbursement = true; new Logic.Import.AmazonFbaReimbursement().SyncDatabaseWithAmazon(); }
if (settlement == false) { settlement = true; new Logic.Import.AmazonSettlement().SyncDatabase(); }
if (fbaInventory == false) { fbaInventory = true; new Logic.Import.AmazonFbaInventory().SyncDatabaseWithAmazon(); }
if (fbaRemovalOrder == false) { fbaRemovalOrder = true; new Logic.Import.AmazonFbaRemovalOrder().SyncDatabaseWithAmazon(); }
if (fbaSaleShipment == false) { fbaSaleShipment = true; new Logic.Import.AmazonFbaSaleShipment().SyncDatabaseWithAmazon(); }
if (fbaCustomerReturn == false) { fbaCustomerReturn = true; new Logic.Import.AmazonFbaCustomerReturn().SyncDatabaseWithAmazon(); }
break;
// depreciated reports
if (false)
{
new Logic.Import.AmazonFbaInventoryAdjustment().SyncDatabaseWithAmazon();
new Logic.Import.AmazonFbaInventoryAge().SyncDatabaseWithAmazon();
new Logic.Import.AmazonFbaInventoryReceipt().SyncDatabaseWithAmazon();
}
}
catch (Exception ex)
{
log.LogError(
"Exception caught during database sync with Amazon (reports), see for further details",
ex.ToString()
);
}
}
}
}
}

View File

@@ -3,11 +3,15 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaCustomerReturn
{
private Log.LogEvent log = new Log.LogEvent();
private string reportName = "GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA";
public void SyncDatabaseWithAmazon()
{
/*
@@ -16,23 +20,32 @@ namespace bnhtrade.Core.Logic.Import
* To disambiguate duplicate row, I will use combination of date, orderid, fnsku, quantity, LPN#, disposition, and reason.
*/
// get most recent record from db
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
// get the last report check from log
var dateLog = new Data.Database.Log.DateTimeLog();
var utcStartDate = dateLog.GetDateTimeUtc(reportName);
var utcEndDate = DateTime.UtcNow;
var db = new Data.Database.Import.AmazonFbaCustomerReturn();
var startDate = db.ReadRecentDate().AddDays(-14);
var getFile = new Data.Amazon.Report.FbaCustomerReturn();
getFile.GetReport(startDate, DateTime.UtcNow);
getFile.GetReport(utcStartDate.AddDays(-14), utcEndDate);
if (!getFile.ReportFilePathIsSet)
if (!getFile.IsSetReportFilePath)
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
log.LogError(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}
db.UpdateByFlatFile(getFile.ReportFilePath);
using (var scope = new TransactionScope())
{
db.UpdateByFlatFile(getFile.ReportFilePath);
dateLog.SetDateTimeUtc(reportName, utcEndDate);
scope.Complete();
}
log.LogInformation("Amazon report '" + reportName + "' sync with database comlpete.");
}
}
}

View File

@@ -8,21 +8,27 @@ namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaInventory
{
Logic.Log.LogEvent log = new Log.LogEvent();
string reportName = "GET_FBA_MYI_ALL_INVENTORY_DATA";
public void SyncDatabaseWithAmazon()
{
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
var getFile = new Data.Amazon.Report.FbaInventory();
getFile.GetReport();
if (!getFile.ReportFilePathIsSet)
if (!getFile.IsSetReportFilePath)
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
log.LogWarning(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}
new Data.Database.Import.AmazonFbaInventoryData().InsertByFlatFile(getFile.ReportFilePath);
log.LogInformation("Amazon report '" + reportName + "' sync with database comlpete.");
}
}
}

View File

@@ -8,8 +8,12 @@ namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaInventoryAdjustment
{
private Logic.Log.LogEvent log = new Log.LogEvent();
public void SyncDatabaseWithAmazon()
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
// get most recent record from db
var db = new Data.Database.Import.AmazonFbaInventoryAdjustment();
var startDate = db.ReadRecentDate().AddDays(-3);
@@ -17,11 +21,10 @@ namespace bnhtrade.Core.Logic.Import
var getFile = new Data.Amazon.Report.FbaInventoryAdustment();
getFile.GetReport(startDate, DateTime.UtcNow);
if (!getFile.ReportFilePathIsSet)
if (!getFile.IsSetReportFilePath)
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
log.LogWarning(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}

View File

@@ -8,16 +8,19 @@ namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaInventoryAge
{
private Logic.Log.LogEvent log = new Log.LogEvent();
public void SyncDatabaseWithAmazon()
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
var getFile = new Data.Amazon.Report.FbaInventoryAge();
getFile.GetReport();
if (!getFile.ReportFilePathIsSet)
if (!getFile.IsSetReportFilePath)
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
log.LogWarning(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}

View File

@@ -0,0 +1,96 @@
using Amazon.SQS.Model;
using Amazon.Util.Internal.PlatformServices;
using bnhtrade.Core.Data.Database.Log;
using FikaAmazonAPI.ConstructFeed.Messages;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaInventoryLedgerDetail : Validate.Validate
{
Log.LogEvent log = new Log.LogEvent();
private string reportName = "GET_LEDGER_DETAIL_VIEW_DATA";
public void SyncDatabaseWithAmazon()
{
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
var db = new Data.Database.Import.AmazonFbaInventoryLedgerDetail();
// get the last report check from log
var dateLog = new Data.Database.Log.DateTimeLog();
var utcStartDate = dateLog.GetDateTimeUtc(reportName);
var utcEndDate = DateTime.UtcNow;
// get data from amazon starting at the recent date, to now...
var amazon = new Data.Amazon.Report.FbaInventoryLedgerDetailed();
amazon.GetReport(utcStartDate.AddDays(-7), utcEndDate);
if (amazon.ReportDoneNoData)
{
log.LogInformation(reportName + " sync complete, amazon returned no data");
return;
}
else if (amazon.IsSetResultList == false)
{
string errorMessage = reportName + " did not return done. Unhandled error";
log.LogError(errorMessage);
throw new Exception(errorMessage);
}
var listAmazon = amazon.ResultList;
// validate amazons result
foreach (var item in listAmazon)
{
if (!IsValid(item))
{
throw new Exception(ValidationResultListToString());
}
}
log.LogInformation(listAmazon.Count + " records sucsefully downloaded from Amazon and validated");
// reverse the list to oldest first, the records will then be in datetime order in the db
listAmazon.Reverse();
using (TransactionScope scope = new TransactionScope())
{
// read recent data from db
log.LogInformation("Comparing against database and commiting new records.");
var listDb = db.Read(utcStartDate.AddDays(-10)).Values.ToList();
// remove line from amazon data that already exist in the db.
int removed = 0;
for (var i = 0; i < listAmazon.Count; i++)
{
for (var j = 0; j < listDb.Count; j++)
{
// compare objects
var a = JsonConvert.SerializeObject(listAmazon[i]);
var b = JsonConvert.SerializeObject(listDb[j]);
if (a == b)
{
removed++;
listAmazon.RemoveAt(i);
listDb.RemoveAt(j);
i--;
j--;
break;
}
}
}
// write any remaining data to db
var dbResult = db.Insert(listAmazon);
// set date in log
dateLog.SetDateTimeUtc(reportName, utcEndDate);
scope.Complete();
log.LogInformation(String.Format(reportName + " sync operation complete. {0} records already existed in database, {1} new records committed.", removed, listAmazon.Count));
}
}
}
}

View File

@@ -8,8 +8,12 @@ namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaInventoryReceipt
{
private Logic.Log.LogEvent log = new Log.LogEvent();
public void SyncDatabaseWithAmazon()
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
// get most recent record from db
var db = new Data.Database.Import.AmazonFbaInventoryReceipt();
var startDate = db.ReadRecentDate().AddSeconds(1);
@@ -17,11 +21,10 @@ namespace bnhtrade.Core.Logic.Import
var getReport = new Data.Amazon.Report.FbaInventoryReceipt();
getReport.GetReport(startDate, DateTime.UtcNow);
if (!getReport.ReportFilePathIsSet)
if (!getReport.IsSetReportFilePath)
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
log.LogWarning(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}

View File

@@ -3,30 +3,45 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaReimbursement
{
Log.LogEvent log = new Log.LogEvent();
private string reportName = "GET_FBA_REIMBURSEMENTS_DATA";
public void SyncDatabaseWithAmazon()
{
// get most recent record from db
var db = new Data.Database.Import.AmazonFbaReimbursement();
var startDate = db.ReadRecentDate().AddDays(-3);
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
var getFile = new Data.Amazon.Report.FbaReimbursement();
getFile.GetReport(startDate, DateTime.UtcNow);
// get the last report check date from log
var dateLog = new Data.Database.Log.DateTimeLog();
var utcStartDate = dateLog.GetDateTimeUtc(reportName);
var utcEndDate = DateTime.UtcNow;
if (!getFile.ReportFilePathIsSet)
using (var scope = new TransactionScope())
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
);
return;
}
var db = new Data.Database.Import.AmazonFbaReimbursement();
db.InsertByFlatFile(getFile.ReportFilePath);
var getFile = new Data.Amazon.Report.FbaReimbursement();
getFile.GetReport(utcStartDate.AddDays(-3), utcEndDate);
if (!getFile.IsSetReportFilePath)
{
log.LogError(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}
db.InsertByFlatFile(getFile.ReportFilePath);
dateLog.SetDateTimeUtc(reportName, utcEndDate);
scope.Complete();
log.LogInformation("Amazon report '" + reportName + "' sync with database comlpete.");
}
}
}
}

View File

@@ -3,11 +3,15 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaRemovalOrder
{
Log.LogEvent log = new Log.LogEvent();
private string reportName = "GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA";
public void SyncDatabaseWithAmazon()
{
/*
@@ -17,23 +21,33 @@ namespace bnhtrade.Core.Logic.Import
* Overlap report by 3 days. To disambiguate duplicate shipment reports, use the ShipmentItemId (not the OrderId or the OrderItemId)
*/
// get most recent record from db
var db = new Data.Database.Import.AmazonFbaRemovalOrder();
var startDate = db.ReadRecentDate().AddDays(-30);
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
var getFile = new Data.Amazon.Report.FbaRemovalOrder();
getFile.GetReport(startDate, DateTime.UtcNow);
// get the last report check from log
var dateLog = new Data.Database.Log.DateTimeLog();
var utcStartDate = dateLog.GetDateTimeUtc(reportName);
var utcEndDate = DateTime.UtcNow;
if (!getFile.ReportFilePathIsSet)
using (var scope = new TransactionScope())
{
new Logic.Log.LogEvent().EventLogInsert(
"Something went wrong retriving report from Amazon SP API. Operation cancelled.",
2
);
return;
}
var db = new Data.Database.Import.AmazonFbaRemovalOrder();
db.InsertByFlatFile(getFile.ReportFilePath);
var getFile = new Data.Amazon.Report.FbaRemovalOrder();
getFile.GetReport(utcStartDate.AddDays(-30), utcEndDate);
if (!getFile.IsSetReportFilePath)
{
log.LogError(
"Something went wrong retriving report from Amazon SP API. Operation cancelled."
);
return;
}
db.InsertByFlatFile(getFile.ReportFilePath);
dateLog.SetDateTimeUtc(reportName, utcEndDate);
scope.Complete();
log.LogInformation("Amazon report '" + reportName + "' sync with database comlpete.");
}
}
}
}

View File

@@ -3,11 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonFbaSaleShipment
{
Log.LogEvent log = new Log.LogEvent();
private string reportName = "GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL";
private int maxTimePeriodDay = 30;
public void SyncDatabaseWithAmazon()
{
@@ -18,10 +21,16 @@ namespace bnhtrade.Core.Logic.Import
* Overlap report by 3 days. To disambiguate duplicate shipment reports, use the ShipmentItemId (not the OrderId or the OrderItemId)
*/
// get most recent record from db
log.LogInformation("Starting Amazon report '" + reportName + "' sync with database.");
// get the last report check from log
var dateLog = new Data.Database.Log.DateTimeLog();
var utcStartDate = dateLog.GetDateTimeUtc(reportName);
var utcEndDate = DateTime.UtcNow;
var db = new Data.Database.Import.AmazonFbaSaleShipment();
var dataSart = db.ReadRecentDate().AddDays(-3);
var dataEnd = DateTime.UtcNow;
var dataSart = utcStartDate.AddDays(-3);
var dataEnd = utcEndDate;
// error check
if (dataSart >= dataEnd)
@@ -35,38 +44,45 @@ namespace bnhtrade.Core.Logic.Import
do
{
var getFile = new Data.Amazon.Report.FbaSaleShipment();
getFile.GetReport(requestStart, requestEnd);
using (var scope = new TransactionScope())
{
var getFile = new Data.Amazon.Report.FbaSaleShipment();
getFile.GetReport(requestStart, requestEnd);
if (getFile.ReportDoneNoData)
{
// continue
}
else if (getFile.ReportFilePathIsSet)
{
db.InsertByFlatFile(getFile.ReportFilePath);
}
else
{
throw new Exception("no report returned");
}
if (getFile.ReportDoneNoData)
{
// continue
}
else if (getFile.IsSetReportFilePath)
{
db.InsertByFlatFile(getFile.ReportFilePath);
}
else
{
throw new Exception("no report returned");
}
// increment requests times and test for end
if (requestEnd == dataEnd)
{
doLoop = false;
}
else
{
requestStart = requestEnd;
requestEnd = requestStart.AddDays(maxTimePeriodDay);
if (requestEnd > dataEnd)
requestEnd = dataEnd;
if (requestStart == requestEnd)
// increment requests times and test for end
if (requestEnd == dataEnd)
{
doLoop = false;
}
else
{
requestStart = requestEnd;
requestEnd = requestStart.AddDays(maxTimePeriodDay);
if (requestEnd > dataEnd)
requestEnd = dataEnd;
if (requestStart == requestEnd)
doLoop = false;
}
dateLog.SetDateTimeUtc(reportName, requestEnd);
scope.Complete();
}
}
while (doLoop);
log.LogInformation("Amazon report '" + reportName + "' sync with database comlpete.");
}
}
}

View File

@@ -4,18 +4,19 @@ namespace bnhtrade.Core.Logic.Import
{
public class AmazonSettlement
{
Data.Amazon.Report.SettlementReport amazonReport;
private Data.Amazon.Report.SettlementReport amazonReport;
private Logic.Log.LogEvent log = new Log.LogEvent();
public AmazonSettlement(Model.Credentials.AmazonSPAPI spapiCredentials)
public AmazonSettlement()
{
amazonReport = new Data.Amazon.Report.SettlementReport();
}
public void SyncDatabase(string sqlConnectionString)
public void SyncDatabase()
{
string operation = "Import Amazon Settlement Reports";
new Logic.Log.LogEvent().EventLogInsert("Started '" + operation + "' operation.");
log.LogInformation("Started '" + operation + "' operation.");
// get avaiable reports from amazon api
var spapiReportIdList = amazonReport.ListAvaliableReports();
@@ -23,7 +24,7 @@ namespace bnhtrade.Core.Logic.Import
if (reportCount == 0)
{
new Logic.Log.LogEvent().EventLogInsert("Exiting '" + operation + "' operation. No settlement reports availble on Amazon SP-API.");
log.LogInformation("Exiting '" + operation + "' operation. No settlement reports availble on Amazon SP-API.");
return;
}
@@ -47,7 +48,7 @@ namespace bnhtrade.Core.Logic.Import
if (!spapiReportIdList.Any())
{
new Logic.Log.LogEvent().EventLogInsert("Exiting '" + operation + "' operation. No new reports to import (" + reportCount + " avaibale).");
log.LogInformation("Exiting '" + operation + "' operation. No new reports to import (" + reportCount + " avaibale).");
return;
}
@@ -58,7 +59,7 @@ namespace bnhtrade.Core.Logic.Import
UI.Console.WriteLine("Importing settlement report " + (i + 1) + " of " + spapiReportIdList.Count() + " (ReportID:" + spapiReportIdList[i] + ").");
var filePath = amazonReport.GetFile(spapiReportIdList[i]);
bool ack = dbImport.ByFlatFile(filePath, spapiReportIdList[i]);
new Logic.Log.LogEvent().EventLogInsert("Settlment Report imported (ReportID:" + spapiReportIdList[i] + ").");
log.LogInformation("Settlment Report imported (ReportID:" + spapiReportIdList[i] + ").");
}
return;

View File

@@ -74,22 +74,6 @@ namespace bnhtrade.Core.Logic.Log
{ eventDateTimeUtc = null; }
}
public void LogAuditFailure(string detailShort, string detailLong = null)
{
eventType = 5;
DetailShort = detailShort;
DetailLong = detailLong;
Execute();
}
public void LogAuditSuccess(string detailShort, string detailLong = null)
{
eventType = 4;
DetailShort = detailShort;
DetailLong = detailLong;
Execute();
}
public void LogError(string detailShort, string detailLong = null)
{
eventType = 1;
@@ -114,22 +98,6 @@ namespace bnhtrade.Core.Logic.Log
Execute();
}
/// <summary>
/// Depreciated, do not use!
/// </summary>
public void EventLogInsert(string detailShort = "", int eventType = 3, string detailLong = "", DateTime eventDateTime = default(DateTime), bool consolePrint = true)
{
this.eventType = eventType;
DetailShort = detailShort;
if (!string.IsNullOrEmpty(detailLong))
DetailLong = detailLong;
if (!(eventDateTime == default(DateTime)))
this.eventDateTimeUtc = eventDateTime;
this.printToConsole = consolePrint;
Execute();
Initialise();
}
public void Initialise()
{
eventDateTimeUtc = null;

View File

@@ -0,0 +1,36 @@
using System;
using System.Data.SqlClient;
using System.Transactions;
namespace bnhtrade.Core.Logic.Sku
{
public class GetSkuId
{
/// <summary>
/// Used for retriving an SKU ID by parameters. If no match, can create a new SKU if required.
/// </summary>
/// <param name="productId">The product Id for the SKU</param>
/// <param name="conditionId">The condition Id for the SKU</param>
/// <param name="accountTaxCodeId">The tax code Id for the SKU</param>
/// <param name="noMatchCreateNew">When set to true, if no match is made, function will create a new sku and return the id for that</param>
/// <returns>Return the id for the new or existing sku or, dependant on set parameters, 0 if not found</returns>
/// <exception cref="Exception"></exception>
public int Request(int productId, int conditionId, int accountTaxCodeId, bool noMatchCreateNew)
{
using (TransactionScope scope = new TransactionScope())
{
int? skuId = new Data.Database.Sku.GetSkuId().ByParameters(productId, conditionId, accountTaxCodeId);
if (skuId != null)
{
return (int)skuId;
}
else if (noMatchCreateNew == false)
{
return 0;
}
return new Data.Database.Sku.InsertSku().InsertNew(productId, conditionId, accountTaxCodeId);
}
}
}
}

View File

@@ -1,121 +0,0 @@
using System;
using System.Data.SqlClient;
using System.Transactions;
namespace bnhtrade.Core.Logic.Sku
{
class GetSkuIdByType
{
// used for retriving SKU that matched parameters, creates new if required, returns 0 if not found
public static int Request(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, bool noMatchInsertNew)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
// look for existing entry
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblSku.skuSkuID
FROM
tblSku
WHERE
(((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId));
", conn))
{
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
object obj = cmd.ExecuteScalar();
if (obj != null)
{
return (int)obj;
}
}
// value check insert bool
if (noMatchInsertNew == false)
{
return 0;
}
else
{
// get this far, check tax code id is a valid for SKU
using (SqlCommand cmd = new SqlCommand(@"
SELECT tblAccountTaxCode.InvoiceSales
FROM tblAccountTaxCode
WHERE (((tblAccountTaxCode.AccountTaxCodeID)=@accountTaxCodeId));
", conn))
{
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
object obj = cmd.ExecuteScalar();
if (obj == null)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!");
}
else
{
bool result = (bool)obj;
if (result == false)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU.");
}
}
}
// get info to create sku number
int skuCount;
int skuSuffix;
using (SqlCommand cmd = new SqlCommand("SELECT NEXT VALUE FOR SkuCountSequence;", conn))
{
skuCount = (int)cmd.ExecuteScalar();
}
using (SqlCommand cmd = new SqlCommand(@"
SELECT tblSkuCondition.scnSkuNumberSuffix
FROM tblSkuCondition
WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId));
", conn))
{
cmd.Parameters.AddWithValue("@conditionId", conditionId);
try
{
skuSuffix = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." +
System.Environment.NewLine + "Error Message: " + ex.Message);
}
}
string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2");
// insert new sku
int skuId;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblSku
(skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID)
OUTPUT INSERTED.skuSkuID
VALUES
(@skuNumber, @productId, @conditionId, @accountTaxCodeId)
", conn))
{
cmd.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
skuId = (int)cmd.ExecuteScalar();
}
scope.Complete();
return skuId;
}
}
}
}
}

View File

@@ -25,7 +25,7 @@ namespace bnhtrade.Core.Logic.Sku.Price
private Logic.Account.TaxCalculation taxCalc;
private decimal marginSchemeMargin;
public FbaPricing(string sqlConnectionString)
public FbaPricing()
{
// was part of a fba repricing feature, that, for now, is being abandoned
throw new NotImplementedException();

View File

@@ -1,27 +1,27 @@
using System;
using bnhtrade.Core.Data.Database;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Stock
{
public class SkuTransactionPersistance
public class SkuTransactionCrud
{
private string err = "Sku Transaction Persistance Error; ";
private string sqlConnectionString;
private Data.Database.Stock.DeleteSkuTransaction dbSkuTransDelete;
private Data.Database.Stock.CreateSkuTransaction dbSkuTransCreate;
private Data.Database.Stock.InsertSkuTransaction dbSkuTransCreate;
private Data.Database.Stock.ReadSkuTransaction dbSkuTransRead;
private Data.Database.Stock.UpdateSkuTransaction dbSkuTransUpdate;
private Logic.Validate.SkuTransaction validateSkuTrans;
private Logic.Log.LogEvent log;
private Logic.Log.LogEvent log = new Log.LogEvent();
public SkuTransactionPersistance(string sqlConnectionString)
public SkuTransactionCrud()
{
this.sqlConnectionString = sqlConnectionString;
log = new Log.LogEvent();
}
/// <summary>
@@ -58,11 +58,11 @@ namespace bnhtrade.Core.Logic.Stock
return dbSkuTransDelete;
}
private Data.Database.Stock.CreateSkuTransaction DatabaseSkuTransInsert(bool forceNew = false)
private Data.Database.Stock.InsertSkuTransaction DatabaseSkuTransInsert(bool forceNew = false)
{
if (dbSkuTransCreate == null || forceNew)
{
dbSkuTransCreate = new Data.Database.Stock.CreateSkuTransaction();
dbSkuTransCreate = new Data.Database.Stock.InsertSkuTransaction();
}
return dbSkuTransCreate;
}
@@ -104,7 +104,7 @@ namespace bnhtrade.Core.Logic.Stock
int? journalId = DatabaseSkuTransRead().GetJournalId(skuTransactionId);
if (journalId != null)
{
Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, (int)journalId);
new Data.Database.Stock.JournalCrud().StockJournalDelete((int)journalId);
}
DatabaseSkuTransDelete().ByTransactionId(skuTransactionId);
@@ -118,25 +118,116 @@ namespace bnhtrade.Core.Logic.Stock
}
}
/// <summary>
/// Creates a Stock SKU Transaction. Implements validation check.
/// </summary>
/// <param name="skuTransaction">Input data/object</param>
/// <returns>Stock SKU Transaction Id of new record</returns>
/// <exception cref="Exception"></exception>
public int Create(Model.Stock.SkuTransactionCreate skuTransaction)
{
// need to add function to check if transaction type exists, if not, create a new one.
throw new NotImplementedException();
if (skuTransaction == null)
{
throw new Exception(err + "Object was null");
}
Validate().Init();
if (!Validate().DatabaseInsert(skuTransaction))
{
log.LogWarning(err + "Validation failed", Validate().ValidationResultListToString());
throw new Exception(err + "Validation failed");
}
// write to database
return DatabaseSkuTransInsert().Insert(skuTransaction);
}
/// <summary>
/// Deletes an attached journal entry, if one is present.
///
/// </summary>
/// <param name="skuTransactionId">Stock SKU Transaction ID</param>
public void DeleteJournalEntry(int skuTransactionId)
/// <param name="retriveTransactionTypeInfo">Retrive and include transaction type model class</param>
public List<Model.Stock.SkuTransaction> Read()
{
var dbRead = DatabaseSkuTransRead();
dbRead.Init();
dbRead.IsReconciled = IsReconciled;
dbRead.StockTransactionTypeCode = StockTransactionTypeCode;
dbRead.StockTransactionTypeName = StockTransactionTypeName;
var resultList = dbRead.Read();
dbRead.Init();
return resultList;
}
/// <summary>
/// Updates a transaction quantity (must be less than) and creates a new transaction with the remaining quantity
/// </summary>
/// <param name="skuTransactionId">Stock SKU Transaction Id of the transaction to split</param>
/// <param name="newQuantity">Required quantity of the existing transaction</param>
/// <returns>Stock SKU Transaction Id of the newly created transaction</returns>
/// <exception cref="ArgumentException">Incorrect parameters passed to function</exception>
/// <exception cref="InvalidOperationException">transaction isProcessed error</exception>
public int SplitTransaction(int skuTransactionId, int newQuantity)
{
using (var scope = new TransactionScope())
{
try
{
// comfirm there is a journal entry attached
int? journalId = DatabaseSkuTransRead().GetJournalId(skuTransactionId);
if (journalId != null)
// get transaction
var transList = DatabaseSkuTransRead().Read(new List<int> { skuTransactionId });
if (!transList.Any())
throw new ArgumentException("sku transaction id:" + skuTransactionId + "does appear to exist");
// Checks and new quanatity calculation
int quantity2 = 0;
var trans = transList[0];
if (trans.IsProcessed)
throw new InvalidOperationException("Invalid operation: SKU Transaction is set to IsProcessed");
if (newQuantity == 0)
throw new ArgumentException("Quantity parameter cannot be zero");
if (trans.Quantity == newQuantity)
throw new ArgumentException("The new quanity is equal to the existing quantity");
if (trans.Quantity < 0 )
{
DatabaseSkuTransUpdate().Update(skuTransactionId, null);
Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, (int)journalId);
// -ve <------ no transaction is less than 0, negative number are converted to posistive before entry to the table
throw new Exception("sku transaction quantity cannot be negative");
if (newQuantity > 0)
throw new ArgumentException("Quantity parameter is +ve when it should be -ve");
if (newQuantity < trans.Quantity)
throw new ArgumentException("Quantity parameter is greater than transaction quantity");
quantity2 = trans.Quantity - newQuantity;
}
else if (trans.Quantity > 0)
{
// +ve
if (newQuantity < 0)
throw new ArgumentException("Quantity parameter is -ve when it should be +ve");
if (newQuantity > trans.Quantity)
throw new ArgumentException("Quantity parameter is greater than transaction quantity");
quantity2 = trans.Quantity - newQuantity;
}
else
{
throw new ArgumentException("sku transaction quantity is zero");
}
// clone transaction, add to database and update quantities
var newTrans = trans.Clone();
int NewTransId = DatabaseSkuTransInsert().Insert(newTrans);
UpdateQuanitity(skuTransactionId, newQuantity);
UpdateQuanitity(NewTransId, quantity2);
scope.Complete();
return NewTransId;
}
catch (Exception ex)
{
@@ -146,66 +237,18 @@ namespace bnhtrade.Core.Logic.Stock
}
}
/// <summary>
/// Validates and then creates a Stock SKU Tranaction
/// </summary>
/// <param name="skuTransaction">'Stock SKU Transaction' model</param>
public void Create(Model.Stock.SkuTransaction skuTransaction)
{
if (skuTransaction == null)
{
throw new Exception(err + "Object was null");
}
Validate().Innit();
if (!Validate().DatabaseInsert(skuTransaction))
{
log.LogWarning(err + "Validation failed", Validate().ValidationResultListToString());
throw new Exception(err + "Validation failed");
}
// write to database
DatabaseSkuTransInsert().Create(skuTransaction);
}
/// <summary>
///
/// </summary>
/// <param name="retriveTransactionTypeInfo">Retrive and include transaction type model class</param>
public List<Model.Stock.SkuTransaction> Read(bool retriveTransactionTypeInfo = true)
{
var dbRead = new Data.Database.Stock.ReadSkuTransaction();
dbRead.IsReconciled = IsReconciled;
dbRead.StockTransactionTypeCode = StockTransactionTypeCode;
dbRead.StockTransactionTypeName = StockTransactionTypeName;
var resultList = dbRead.Read();
if (retriveTransactionTypeInfo)
{
var dbReadType = new Logic.Stock.SkuTransactionTypePersistance(sqlConnectionString);
dbReadType.GetBySkuTransaction(resultList);
}
return resultList;
}
/// <summary>
/// Retrive SKU Transaction by ID
/// </summary>
/// <param name="SkuTransactionId">SKU Transaction ID</param>
/// <param name="retriveTransactionTypeInfo"></param>
/// <returns></returns>
public List<Model.Stock.SkuTransaction> Read(List<int> SkuTransactionId, bool retriveTransactionTypeInfo = true)
public List<Model.Stock.SkuTransaction> Read(List<int> SkuTransactionId)
{
var dbRead = new Data.Database.Stock.ReadSkuTransaction();
var dbRead = DatabaseSkuTransRead();
dbRead.Init();
var resultList = dbRead.Read(SkuTransactionId);
if (retriveTransactionTypeInfo)
{
var dbReadType = new Logic.Stock.SkuTransactionTypePersistance(sqlConnectionString);
dbReadType.GetBySkuTransaction(resultList);
}
dbRead.Init();
return resultList;
}
@@ -220,27 +263,26 @@ namespace bnhtrade.Core.Logic.Stock
throw new Exception(err + "Object was null");
}
Validate().Innit();
Validate().Init();
if (!Validate().DatabaseUpdate(skuTransaction))
{
log.LogWarning(err + "Validation failed", Validate().ValidationResultListToString());
throw new Exception(err + "Validation failed");
}
using (var scope = new TransactionScope())
{
// is there an existing journal id that is changing
int? journalId = DatabaseSkuTransRead().GetJournalId(skuTransaction.SkuTransactionId);
if (journalId != null && skuTransaction.IsSetStockJournalId)
{
if (journalId != skuTransaction.StockJournalId)
{
DeleteJournalEntry(skuTransaction.SkuTransactionId);
}
}
DatabaseSkuTransUpdate().Update(skuTransaction);
scope.Complete();
}
DatabaseSkuTransUpdate().Update(skuTransaction);
}
public void UpdateIsProcessed(int skuTransactionId, bool isProcessed, int? stockJournalId, bool enableJournalDelete = false)
{
// consistancy logic done on data level
DatabaseSkuTransUpdate().UpdateIsProcessed(skuTransactionId, isProcessed, stockJournalId, enableJournalDelete);
}
public void UpdateQuanitity(int skuTransactionId, int quantity)
{
// consistancy logic done on data level
DatabaseSkuTransUpdate().UpdateQuanitity(skuTransactionId, quantity);
}
}
}

View File

@@ -0,0 +1,395 @@
using Amazon.Runtime.Internal.Transform;
using bnhtrade.Core.Model.Stock;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Restrictions;
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.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 data required for reconcilation, into the sku transaction table.
/// </summary>
public void ImportAll()
{
bool inventoryLedgerDetail = false;
bool reimbursement = false;
while (true)
{
try
{
if (true)
{
if (inventoryLedgerDetail == false) { inventoryLedgerDetail = true; ImportAmazonFbaLedgerDetail(); }
if (reimbursement == false) { reimbursement = true; ImportAmazonFbaReimbursement(); }
}
break;
}
catch (Exception ex)
{
log.LogError(
"Exception caught running Importing amazon reports in the SKU transaction table, see for further details",
ex.ToString()
);
}
}
}
/// <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()
{
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("Starting TransposeFbaRemovalOrderReport()");
int transposeCount = 0;
int transposeSkip = 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)
{
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("Cannot complete ImportAmazonFbaReimbursement, 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("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("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);
transposeCount = transposeCount + 1;
}
// drop out of loop
scope.Complete();
}
Console.Write("\r");
log.LogInformation("ProcessFbaReimbursementData() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped.");
}
catch (Exception ex)
{
log.LogError("Exception catch, aborting ProcessFbaReimbursementData(), see detailed info. "
+ transposeCount + " total records completed, " + transposeSkip + " records skipped.", ex.ToString());
}
}
/// <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()
{
// Done but needs testing!!
throw new NotImplementedException("Done but needs testing!!");
log.LogInformation("Starting TransposeFbaAdustmentReport()");
int transposeCount = 0;
int transposeSkip = 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)
{
// 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, and add them if ther are
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);
}
scope.Complete();
log.LogInformation(
"TransposeFbaAdustmentReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."
);
if (transposeSkip > 0)
{
log.LogInformation(
transposeSkip + " number records skipped during TransposeFbaAdustmentReport() operation."
);
}
}
catch (Exception ex)
{
scope.Dispose();
log.LogError(
"Exception catch, aborting TransposeFbaAdustmentReport(), see detailed info. "
+ transposeCount + " total records completed, " + transposeSkip + " records skipped."
, ex.ToString()
);
}
}
return;
}
}
}

View File

@@ -1,33 +1,31 @@
using System;
using bnhtrade.Core.Data.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using System.Web.UI;
namespace bnhtrade.Core.Logic.Stock
{
public class SkuTransactionReconcile
{
private string sqlConnectionString;
private Data.Database.AmazonShipment.ReadShipmentInfo readShipmentInfo;
private Logic.Stock.SkuTransactionPersistance dbSkuTransaction;
private Logic.Stock.SkuTransactionTypePersistance dbSkuTransactionType;
private Logic.Stock.SkuTransactionCrud dbSkuTransaction;
private Logic.Validate.SkuTransaction validateSkuTrans;
private Logic.Stock.StatusReallocate stockReallocate;
private Logic.Log.LogEvent logEvent;
private Logic.Log.LogEvent log;
private string err = "Reconcile Sku Transaction Exception: ";
public SkuTransactionReconcile(string sqlConnectionString)
public SkuTransactionReconcile()
{
Innit();
this.sqlConnectionString = sqlConnectionString;
dbSkuTransaction = new SkuTransactionPersistance(sqlConnectionString);
dbSkuTransactionType = new SkuTransactionTypePersistance(sqlConnectionString);
dbSkuTransaction = new SkuTransactionCrud();
readShipmentInfo = new Data.Database.AmazonShipment.ReadShipmentInfo();
validateSkuTrans = new Validate.SkuTransaction();
stockReallocate = new Logic.Stock.StatusReallocate(sqlConnectionString);
logEvent = new Log.LogEvent();
stockReallocate = new Logic.Stock.StatusReallocate();
log = new Log.LogEvent();
}
public int ItemsCompleted { get; private set; }
@@ -58,12 +56,14 @@ namespace bnhtrade.Core.Logic.Stock
}
/// <summary>
/// Iterates through the stock transaction table and inserts stock journal entries, where applicable
/// N.B. This function does not make allowances for status' that can create stock (i.e. if a status does not have stock available, this function will halt processing rows)
/// Iterates through the stock transaction table and creates stock journal entries, if required
/// N.B. This function does not make allowances for status' that can create stock (i.e. if a status does not have stock available,
/// this function will halt processing rows)
/// </summary>
/// <param name="updateTransactions">Download and process Amazon reports before starting process</param>
/// <param name="updateTransactions">Process Amazon reports before starting process</param>
/// <param name="downloadAmaozn">Download reports from Amazon before starting process</param>
/// <returns></returns>
public void ReconcileStockTransactions(bool updateTransactions)
public void ReconcileStockTransactions(bool updateTransactions, bool downloadAmazon = false)
{
Innit();
string currentMethodName = nameof(ReconcileStockTransactions);
@@ -73,8 +73,12 @@ namespace bnhtrade.Core.Logic.Stock
{
try
{
var preCheck = new bnhtrade.Core.Stock.StockReconciliation();
preCheck.ProcessFbaStockImportData(sqlConnectionString);
if (downloadAmazon)
{
new bnhtrade.Core.Logic.Import.AmazonFbaReimbursement().SyncDatabaseWithAmazon();
new bnhtrade.Core.Logic.Import.AmazonFbaInventoryLedgerDetail().SyncDatabaseWithAmazon();
}
new bnhtrade.Core.Logic.Stock.SkuTransactionImport().ImportAll();
}
catch (Exception ex)
{
@@ -83,10 +87,10 @@ namespace bnhtrade.Core.Logic.Stock
}
}
logEvent.LogInformation("Starting ReconcileStockTransactions()");
log.LogInformation("Starting ReconcileStockTransactions()");
int recordSkip = 0;
ReconcileLostAndFound();
ReconcileFoundAndLost();
// get list of sku transactions to reconcile
dbSkuTransaction.Init();
@@ -96,27 +100,37 @@ namespace bnhtrade.Core.Logic.Stock
ItemsRemaining = transList.Count;
ItemsCompleted = 0;
// get list of sku transaction types
var codeList = new List<string>();
foreach(var item in transList)
{
codeList.Add(item.SkuTransactionTypeCode);
}
var transTypeDict = new Logic.Stock.SkuTransactionTypeCrud().GetByTypeCode(codeList);
try
{
// loop through transaction list
for (int i = 0; i < transList.Count; i++)
//for (int i = 0; i < transList.Count; i++)
foreach (var transaction in transList)
{
using (var scope = new TransactionScope())
{
Console.Write("\rProcessing record: {0} ({1} skipped)", (i + 1 + recordSkip), recordSkip);
Console.Write("\rProcessing record: {0} ({1} skipped)", (ItemsCompleted + 1 + recordSkip), recordSkip);
// setup return values
CurrentSkuTransaction = transList[i];
CurrentTransactionId = transList[i].SkuTransactionId;
CurrentTransactionTypeCode = transList[i].SkuTransactionType.TypeCode;
LastItemDateTime = transList[i].TransactionDate;
CurrentSkuTransaction = transaction;
CurrentTransactionId = transaction.SkuTransactionId;
CurrentTransactionTypeCode = transaction.SkuTransactionTypeCode;
LastItemDateTime = transaction.TransactionDate;
// load type into variable
//var transType = dbSkuTransactionType.GetByTypeName(transList[i].SkuTransactionTypeName);
// setup variables
var transactionType = transTypeDict[transaction.SkuTransactionTypeCode].Clone();
// stop if a new transactiontype is encountered
if (transList[i].SkuTransactionType.IsNewReviewRequired)
if (transactionType.IsNewReviewRequired)
{
ProgressMessage = "New 'Transaction-Type' encountered";
//Console.Write("\r");
@@ -124,51 +138,52 @@ namespace bnhtrade.Core.Logic.Stock
break;
}
else if (transList[i].SkuTransactionType.StockJournalEntryEnabled == false)
else if (transactionType.StockJournalEntryEnabled == false)
{
transList[i].IsProcessed = true;
dbSkuTransaction.Update(transList[i]);
//transList[i].IsProcessed = true;
ReconcileTransaction(transaction.SkuTransactionId);
}
// stock journal entry is enabled
else
{
// check debit/credits
if (transList[i].SkuTransactionType.DebitStockStatusId.GetValueOrDefault() == 0
|| transList[i].SkuTransactionType.CreditStockStatusId.GetValueOrDefault() == 0)
if (transactionType.DebitStockStatusId.GetValueOrDefault() == 0
|| transactionType.CreditStockStatusId.GetValueOrDefault() == 0)
{
// special case FBA Shipment Receipt +ve
if (transList[i].SkuTransactionType.TypeCode == "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>"
|| transList[i].SkuTransactionType.TypeCode == "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><-ve>")
if (transactionType.StockJournalTypeId == (int)Constants.StockJournalType.SkuReconciliationFbaReceipt)
//transactionType.TypeCode == "<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Receipt><+ve>"
//|| transactionType.TypeCode == "<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Receipt><-ve>")
{
Model.AmazonFba.ShipmentInfo shipmentInfo = null;
if (!shipmentInfoDic.ContainsKey(transList[i].Reference))
if (!shipmentInfoDic.ContainsKey(transaction.Reference))
{
shipmentInfo = readShipmentInfo.HeaderByFbaShipmentId(transList[i].Reference);
shipmentInfo = readShipmentInfo.HeaderByFbaShipmentId(transaction.Reference);
if (shipmentInfo == null)
{
throw new Exception("Unable to retrive shipment info for reference '" + transList[i].Reference + "'.");
throw new Exception("Unable to retrive shipment info for reference '" + transaction.Reference + "'.");
}
else
{
shipmentInfoDic.Add(transList[i].Reference, shipmentInfo);
shipmentInfoDic.Add(transaction.Reference, shipmentInfo);
}
}
if (shipmentInfo.IsSetShipmentStockStatusId())
{
// +ve shipment receipt
if (transList[i].SkuTransactionType.CreditStockStatusId == null
&& transList[i].SkuTransactionType.DebitStockStatusId > 0)
if (transactionType.CreditStockStatusId == null
&& transactionType.DebitStockStatusId > 0)
{
transList[i].SkuTransactionType.CreditStockStatusId = shipmentInfo.ShipmentStockStatusId;
transactionType.CreditStockStatusId = shipmentInfo.ShipmentStockStatusId;
}
// -ve shipment receipt
else if (transList[i].SkuTransactionType.DebitStockStatusId == null
&& transList[i].SkuTransactionType.CreditStockStatusId > 0)
else if (transactionType.DebitStockStatusId == null
&& transactionType.CreditStockStatusId > 0)
{
transList[i].SkuTransactionType.DebitStockStatusId = shipmentInfo.ShipmentStockStatusId;
transactionType.DebitStockStatusId = shipmentInfo.ShipmentStockStatusId;
}
// something went wrong, raise error
@@ -195,28 +210,28 @@ namespace bnhtrade.Core.Logic.Stock
// make the journal entries
var journalList = new List<(int StockJournalId, int Quantity)>();
if (transList[i].SkuTransactionType.FilterStockOnDateTime)
if (transactionType.FilterStockOnDateTime)
{
journalList = stockReallocate.BySkuNumber(
transList[i].TransactionDate,
transList[i].SkuTransactionType.StockJournalTypeId,
transList[i].SkuNumber,
transList[i].Quantity,
transList[i].SkuTransactionType.DebitStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.CreditStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.FirstInFirstOut,
transaction.TransactionDate,
transactionType.StockJournalTypeId,
transaction.SkuNumber,
transaction.Quantity,
transactionType.DebitStockStatusId.GetValueOrDefault(),
transactionType.CreditStockStatusId.GetValueOrDefault(),
transactionType.FirstInFirstOut,
true);
}
else
{
journalList = stockReallocate.BySkuNumber(
DateTime.UtcNow,
transList[i].SkuTransactionType.StockJournalTypeId,
transList[i].SkuNumber,
transList[i].Quantity,
transList[i].SkuTransactionType.DebitStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.CreditStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.FirstInFirstOut,
transactionType.StockJournalTypeId,
transaction.SkuNumber,
transaction.Quantity,
transactionType.DebitStockStatusId.GetValueOrDefault(),
transactionType.CreditStockStatusId.GetValueOrDefault(),
transactionType.FirstInFirstOut,
true);
}
@@ -224,7 +239,8 @@ namespace bnhtrade.Core.Logic.Stock
if (!journalList.Any())
{
// in special case (found inventory), continue
if (transList[i].SkuTransactionType.TypeCode.Contains("<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><F>"))
if (transactionType.TypeCode.Contains("<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Adjustment><F>")
|| transactionType.TypeCode.Contains("<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Adjustment><N>"))
{
ItemsCompleted++;
ItemsRemaining--;
@@ -239,56 +255,61 @@ namespace bnhtrade.Core.Logic.Stock
}
// fail safe
int qtyAllocated = journalList.Sum(c => c.Quantity);
if (qtyAllocated > transList[i].Quantity)
int qtyUnallocated = journalList.Sum(c => c.Quantity);
if (qtyUnallocated > transaction.Quantity)
{
throw new Exception(
currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function"
+ transList[i].SkuTransactionId);
+ transaction.SkuTransactionId);
}
// update sku transaction table
int qtyRemain = qtyAllocated;
var newRecordList = new List<Model.Stock.SkuTransaction>();
for (int j = 0; j < journalList.Count; j++)
{
// update existing record
// update existing record to reconciled
if (j == 0)
{
transList[i].Quantity = (short)journalList[j].Quantity;
transList[i].StockJournalId = journalList[j].StockJournalId;
transList[i].IsProcessed = true;
dbSkuTransaction.UpdateQuanitity(transaction.SkuTransactionId, journalList[j].Quantity);
dbSkuTransaction.UpdateIsProcessed(transaction.SkuTransactionId, true, journalList[j].StockJournalId);
dbSkuTransaction.Update(transList[i]);
}
// new record
// create new reconciled record
else
{
var newRecord = transList[i].Clone();
newRecord.Quantity = (short)journalList[j].Quantity;
newRecord.IsProcessed = true;
newRecord.StockJournalId = journalList[j].StockJournalId;
newRecordList.Add(newRecord);
var newTransaction = new Model.Stock.SkuTransactionCreate(
transaction.TransactionDate
, transaction.SkuTransactionTypeCode
, transaction.ForeignKey
, transaction.Reference
, transaction.Detail
, transaction.SkuNumber
, journalList[j].Quantity
);
int newId = dbSkuTransaction.Create(newTransaction);
dbSkuTransaction.UpdateIsProcessed(newId, true, journalList[j].StockJournalId);
}
qtyRemain = qtyRemain - journalList[j].Quantity;
qtyUnallocated = qtyUnallocated - journalList[j].Quantity;
}
// new record for unallocated quantity
if (qtyRemain > 0)
// create new record for unreconciled quantity
if (qtyUnallocated > 0)
{
var newRecord = transList[i].Clone();
newRecord.Quantity = (short)qtyRemain;
newRecord.IsProcessed = false;
var newTransaction = new Model.Stock.SkuTransactionCreate(
transaction.TransactionDate
, transaction.SkuTransactionTypeCode
, transaction.ForeignKey
, transaction.Reference
, transaction.Detail
, transaction.SkuNumber
, qtyUnallocated
);
int newId = dbSkuTransaction.Create(newTransaction);
newRecordList.Add(newRecord);
}
// add new transactions to table
for (int j = 0; j < newRecordList.Count; j++)
{
dbSkuTransaction.Create(newRecordList[j]);
ProgressMessage = "Transaction could not be fully reconcoiled. Unallocated quanity remaing:" + qtyUnallocated;
recordSkip = recordSkip + 1;
break;
}
}
@@ -325,144 +346,146 @@ namespace bnhtrade.Core.Logic.Stock
/// <summary>
///
/// </summary>
public void ReconcileLostAndFound()
public void ReconcileFoundAndLost()
{
/* Amazon can find a item before they lost it. In this senario the found item will not reconcile. Even when the lost transaction comes
* though, it will be dated after the found transaction, so it also will not reconcile.
*
* This method tackles this. Instead of journal entries for found before lost, just cancel then out (set IsProcessed=true) for
* both transactions.
*
* In the main reconcile method, if the porcdure hits an unreconciable found transaction, it will ignore it and carry on. Everything will still
* tally at my end, even if Amazon thinks i've got more than I actually have
*/
using (var scope = new TransactionScope())
{
// need to loop though table and cancel out any found before they are lost (in reality they were never
// lost, therefore should not be entered into journal as lost)
string lost = "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><M><-ve><InventoryMisplaced><SELLABLE>";
string found = "<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><F><+ve><InventoryFound><SELLABLE>";
var codeList = new List<string>();
codeList.Add(lost);
codeList.Add(found);
// get list of sku transactions to reconcile
dbSkuTransaction.Init();
dbSkuTransaction.IsReconciled = false;
dbSkuTransaction.StockTransactionTypeCode = codeList;
var transList = dbSkuTransaction.Read();
ItemsRemaining = transList.Count;
ItemsCompleted = 0;
for (int i = 0; i < transList.Count; i++)
try
{
if (transList[i].SkuTransactionTypeCode == found && !transList[i].IsProcessed)
var lostQueryString = new List<string>();
lostQueryString.Add("<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Adjustments><M><-ve><SELLABLE>");
var foundQueryString = new List<string>();
foundQueryString.Add("<AmazonReport><GET_LEDGER_DETAIL_VIEW_DATA><Adjustments><F><+ve><SELLABLE>");
dbSkuTransaction.Init();
dbSkuTransaction.IsReconciled = false;
dbSkuTransaction.StockTransactionTypeCode = lostQueryString;
var lostList = dbSkuTransaction.Read();
dbSkuTransaction.Init();
dbSkuTransaction.IsReconciled = false;
dbSkuTransaction.StockTransactionTypeCode = foundQueryString;
var foundList = dbSkuTransaction.Read();
ItemsRemaining = foundList.Count;
ItemsCompleted = 0;
for (int i = 0; i < foundList.Count; i++)
{
string sku = transList[i].SkuNumber;
int foundQty = transList[i].Quantity;
int foundQtyUnAllocated = foundQty;
// loop though list and find matching missing
for (int j = 0; j < transList.Count; j++)
for (int j = 0; j < lostList.Count; j++)
{
// update the 'lost' transaction
if (transList[j].SkuNumber == sku
&& transList[j].IsProcessed == false
&& transList[j].SkuTransactionTypeCode == lost)
if (foundList[i].SkuNumber == lostList[j].SkuNumber)
{
// split 'lost' transaction
if (foundQtyUnAllocated - transList[j].Quantity < 0)
// notes. isProcessed items need to be removed from the 'lost' list as we'll be looping over this multiple times, the
// 'found' list we only loop though once
//
// when an sku match is found there is only 3 possible routes
// 1. Lost == Found
if (foundList[i].Quantity == lostList[j].Quantity)
{
// create 'reconciled' clone
var clone = transList[j].Clone();
clone.IsProcessed = true;
clone.Quantity = (short)foundQtyUnAllocated;
// mark reconciled transaction as isProcessed
dbSkuTransaction.UpdateIsProcessed(foundList[i].SkuTransactionId, true, null);
dbSkuTransaction.UpdateIsProcessed(lostList[j].SkuTransactionId, true, null);
// modifiy and validate existing record
transList[j].IsProcessed = false;
transList[j].Quantity = (short)(transList[j].Quantity - foundQtyUnAllocated);
// delete reconciled from 'lost' list
lostList.RemoveAt(j);
// fail safe check
if (clone.IsProcessed)
{
foundQtyUnAllocated -= clone.Quantity;
}
if (transList[j].IsProcessed)
{
foundQtyUnAllocated -= transList[j].Quantity;
}
if (foundQtyUnAllocated != 0)
{
throw new Exception("Unallocated quantity should equal zero.");
}
// submitt to database
dbSkuTransaction.Create(clone);
dbSkuTransaction.Update(transList[j]);
}
// set as isprocessed and continue
else
{
foundQtyUnAllocated = foundQtyUnAllocated - transList[j].Quantity;
transList[j].IsProcessed = true;
dbSkuTransaction.Update(transList[j]);
}
// break?
if (foundQtyUnAllocated == 0)
{
ItemsCompleted++;
break;
}
}
}
// drop out of the 'find lost' loop
// 2. Lost < Found
else if (foundList[i].Quantity < lostList[j].Quantity)
{
// split the lost transaction
int newTransId = dbSkuTransaction.SplitTransaction(lostList[j].SkuTransactionId, foundList[i].Quantity);
// update the 'found' record
if (foundQty != foundQtyUnAllocated)
{
// set isprocess = true
if (foundQtyUnAllocated == 0)
{
transList[i].IsProcessed = true;
dbSkuTransaction.Update(transList[i]);
}
// split record
else if (foundQtyUnAllocated > 0)
{
// create 'reconciled' clone
var clone = transList[i].Clone();
clone.IsProcessed = true;
clone.Quantity = (short)(clone.Quantity - foundQtyUnAllocated);
// mark reconciled transaction as isProcessed
dbSkuTransaction.UpdateIsProcessed(foundList[i].SkuTransactionId, true, null);
dbSkuTransaction.UpdateIsProcessed(lostList[j].SkuTransactionId, true, null);
// modifiy existing record
transList[i].IsProcessed = false;
transList[i].Quantity = (short)foundQtyUnAllocated;
// delete reconciled from 'lost' list
lostList.RemoveAt(j);
// submitt to database
dbSkuTransaction.Create(clone);
dbSkuTransaction.Update(transList[i]);
}
// this shouldn't happen
else
{
throw new Exception("Quantity unallocated is negative number");
// retrieve the new split transaction
var newTransactionList = dbSkuTransaction.Read(new List<int> { newTransId });
if (!newTransactionList.Any())
throw new Exception("Something went wrong, this should not happen.");
var newTransaction = newTransactionList[0];
// insert new split 'lost' record into the list
lostList.Insert(j, newTransaction);
ItemsCompleted++;
break;
}
// 3. Lost > Found
else if (foundList[i].Quantity > lostList[j].Quantity)
{
// split the found transaction
int newTransId = dbSkuTransaction.SplitTransaction(lostList[i].SkuTransactionId, foundList[j].Quantity);
// mark reconciled transaction as isProcessed
dbSkuTransaction.UpdateIsProcessed(foundList[i].SkuTransactionId, true, null);
dbSkuTransaction.UpdateIsProcessed(lostList[j].SkuTransactionId, true, null);
// delete reconciled from 'lost' list
lostList.RemoveAt(j);
// retrive the new split transaction
var newTransactionList = dbSkuTransaction.Read(new List<int> { newTransId });
if (!newTransactionList.Any())
throw new Exception("Something went wrong, this should not happen.");
var newTransaction = newTransactionList[0];
// // insert new split 'found' record into the list, in the next position
foundList.Insert((i + 1), newTransaction);
ItemsCompleted++;
ItemsRemaining++;
break;
}
else
{
throw new Exception("Something went wrong, this should not happen.");
}
}
}
}
}
// drop out of the 'find found' loop
scope.Complete();
scope.Complete();
}
catch (Exception ex)
{
scope.Dispose();
Console.Write("\r");
ProgressMessage = ex.Message;
return;
}
}
}
/// <summary>
/// Marks the transaction as reconciled/isprocessed with no stock journal entry required
/// </summary>
/// <param name="skuTransactionId"></param>
public void ReconcileTransaction(int skuTransactionId)
{
new Data.Database.Stock.UpdateSkuTransaction().UpdateIsProcessed(skuTransactionId, true, null);
}
public void UnReconcileTransaction(int skuTransactionId)
{
var trans = dbSkuTransaction.Read(new List<int> { skuTransactionId }, false).FirstOrDefault();
if (trans == null) { return; }
// test if journal entry needs deleting, or just set to isprocessed = false
if (trans.IsProcessed == true && trans.IsSetStockJournalId)
{
dbSkuTransaction.DeleteJournalEntry(skuTransactionId);
}
else if (trans.IsProcessed == true)
{
new Data.Database.Stock.UpdateSkuTransaction().Update(skuTransactionId, false);
}
new Data.Database.Stock.UpdateSkuTransaction().UpdateIsProcessed(skuTransactionId, false, null, true);
}
}
}

View File

@@ -0,0 +1,106 @@
using bnhtrade.Core.Data.Database;
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.Logic.Stock
{
public class SkuTransactionTypeCrud : Connection // this inheritance can be removed when old code is removed below
{
private Data.Database.Stock.ReadSkuTransactionType dbRead;
public SkuTransactionTypeCrud()
{
dbRead = new Data.Database.Stock.ReadSkuTransactionType();
}
/// <summary>
/// Creates a new SKU Transaction Type with default attributes and 'New' status.
/// </summary>
/// <param name="skuTransactionTypeCode">New identifier to be created</param>
/// <param name="stockJournalTypeId"></param>
/// <returns>Id for new record entry</returns>
/// <exception cref="InvalidOperationException">Transaction type code already exists</exception>
public int Create(string skuTransactionTypeCode, int stockJournalTypeId)
{
//check to see if type already exists
var result = dbRead.ByTypeCode(new List<string> { skuTransactionTypeCode });
if (result.Any())
throw new InvalidOperationException("Create SKU Transaction Type failed, typecode already exists failed");
// okay to proceed
int id = new Data.Database.Stock.InsertSkuTransactionType().Create(skuTransactionTypeCode, stockJournalTypeId);
return id;
}
/// <summary>
///
/// </summary>
/// <param name="typeCode"></param>
/// <returns>The object, or null</returns>
public Model.Stock.SkuTransactionType GetByTypeCode(string typeCode)
{
if (string.IsNullOrWhiteSpace(typeCode))
{
return null;
}
var result = dbRead.ByTypeCode(new List<string> { typeCode });
if (result.Any())
{
return result[0];
}
else
{
return null;
}
}
/// <summary>
/// Retrives transaction-type object from database
/// </summary>
/// <param name="typeCodeList">list of transaction type codes</param>
/// <returns>DIctionary key=transactionTypeCode, value=transactionType object</returns>
public Dictionary<string, Model.Stock.SkuTransactionType> GetByTypeCode(List<string> typeCodeList)
{
var returnDict = new Dictionary<string, Model.Stock.SkuTransactionType>();
if (!typeCodeList.Any())
{
return returnDict;
}
var dbResult = dbRead.ByTypeCode(typeCodeList);
foreach(var item in dbResult)
{
returnDict.Add(item.TypeCode, item);
}
return returnDict;
}
public Model.Stock.SkuTransactionType GetByTypeName(string typeName)
{
if (string.IsNullOrWhiteSpace(typeName))
{
return null;
}
var result = dbRead.ByTypeName(new List<string> { typeName });
if (result.Any())
{
return result[0];
}
else
{
return null;
}
}
}
}

View File

@@ -1,161 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Stock
{
public class SkuTransactionTypePersistance
{
private string sqlConnectionString;
private List<Model.Stock.SkuTransactionType> cache;
private Data.Database.Stock.ReadSkuTransactionType dbRead;
public SkuTransactionTypePersistance(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
dbRead = new Data.Database.Stock.ReadSkuTransactionType();
CacheInnit();
}
public void CacheInnit()
{
cache = new List<Model.Stock.SkuTransactionType>();
}
public void CacheFillByTypeName(List<string> typeNameList)
{
CacheInnit();
if (typeNameList == null || !typeNameList.Any())
{
return;
}
//fill cache
cache = dbRead.ByTypeName(typeNameList.Distinct().ToList());
}
public void CacheFillByTypeCode(List<string> typeCodeList)
{
CacheInnit();
typeCodeList.RemoveAll(string.IsNullOrWhiteSpace);
if (typeCodeList == null || !typeCodeList.Any())
{
return;
}
//fill cache
cache = dbRead.ByTypeCode(typeCodeList.Distinct().ToList());
}
/// <summary>
/// Using 'SKU Transaction Type Code', adds Sku Transaction Type info to a list of Stock SKU Transactions.
/// </summary>
/// <param name="skuTransactionList">Stock SKU Transaction list</param>
/// <param name="clearCache">Force database read</param>
/// <returns>Returns false if a 'Type Code' is not found, otherwise true</returns>
public bool GetBySkuTransaction(List<Model.Stock.SkuTransaction> skuTransactionList)
{
bool allCodesFound = true;
if (skuTransactionList == null || !skuTransactionList.Any())
{
return allCodesFound;
}
CacheFillByTypeCode(skuTransactionList.Select(x => x.SkuTransactionTypeCode).Distinct().ToList());
for (int i = 0; i < skuTransactionList.Count(); i++)
{
if (skuTransactionList[i].IsSetSkuTransactionTypeCode)
{
var transType = GetByTypeCode(skuTransactionList[i].SkuTransactionTypeCode);
if (transType == null)
{
allCodesFound = false;
}
else
{
skuTransactionList[i].SkuTransactionType = transType;
}
}
}
return allCodesFound;
}
public Model.Stock.SkuTransactionType GetByTypeCode(string typeCode, bool clearCache = false)
{
if (string.IsNullOrWhiteSpace(typeCode))
{
return null;
}
if (clearCache)
{
CacheInnit();
}
else
{
for (int i = 0; i < cache.Count; i++)
{
if (cache[i].TypeCode == typeCode)
{
return cache[i];
}
}
}
var result = dbRead.ByTypeCode(new List<string> { typeCode });
if (result.Any())
{
cache.Add(result[0]);
return result[0];
}
else
{
return null;
}
}
public Model.Stock.SkuTransactionType GetByTypeName(string typeName, bool clearCache = false)
{
if (string.IsNullOrWhiteSpace(typeName))
{
return null;
}
if (clearCache)
{
CacheInnit();
}
else
{
for (int i = 0; i < cache.Count; i++)
{
if (cache[i].TypeName == typeName)
{
return cache[i];
}
}
}
var result = dbRead.ByTypeName(new List<string> { typeName });
if (result.Any())
{
cache.Add(result[0]);
return result[0];
}
else
{
return null;
}
}
}
}

View File

@@ -8,11 +8,8 @@ namespace bnhtrade.Core.Logic.Stock
{
public class StatusBalance
{
private string sqlConnectionString;
public StatusBalance(string sqlConnectionString)
public StatusBalance()
{
this.sqlConnectionString = sqlConnectionString;
}
/// <summary>

View File

@@ -9,11 +9,8 @@ namespace bnhtrade.Core.Logic.Stock
{
public class StatusReallocate
{
private string sqlConnectionString;
public StatusReallocate(string sqlConnectionString)
public StatusReallocate()
{
this.sqlConnectionString = sqlConnectionString;
}
/// <summary>
@@ -25,7 +22,7 @@ namespace bnhtrade.Core.Logic.Stock
/// <param name="debitStatusId"></param>
/// <param name="creditStatusId"></param>
/// <param name="entryDate"></param>
/// <returns>Return newly created stock journal Id</returns>
/// <returns>Returns newly created stock journal Id</returns>
public int ByStockId(DateTime entryDate, int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId)
{
if (entryDate == default(DateTime))
@@ -39,7 +36,8 @@ namespace bnhtrade.Core.Logic.Stock
posts.Add((creditStatusId, (quantity * -1)));
// execute
return Core.Stock.StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false);
// return Core.Stock.StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false);
return new Data.Database.Stock.JournalCrud().StockJournalInsert(journalTypeId, stockId, posts, entryDate, false);
}
/// <summary>
@@ -53,14 +51,14 @@ namespace bnhtrade.Core.Logic.Stock
/// <param name="creditStatusId">Status to move SKU from</param>
/// <param name="firstInFirstOut">Move stock on first in first out basis</param>
/// <param name="reallocatePartialQuantity">Reallocate patial quantity if the full quantity is not available</param>
/// <returns></returns>
/// <returns>List of StockJournalId and quantity</returns>
public List<(int StockJournalId, int Quantity)> BySkuNumber(DateTime entryDate, int journalTypeId, string skuNumber, int quantity, int debitStatusId, int creditStatusId,
bool firstInFirstOut = true, bool reallocatePartialQuantity = false)
{
var returnList = new List<(int StockJournalId, int Quantity)>();
// get balance of status and check for avaliable quantity
var statusBalance = new Logic.Stock.StatusBalance(sqlConnectionString).GetBySku(skuNumber, creditStatusId);
var statusBalance = new Logic.Stock.StatusBalance().GetBySku(skuNumber, creditStatusId);
if (statusBalance.GetAvaliableQuantity(entryDate) <= 0
|| (statusBalance.CheckAvaliableQuantity(quantity, entryDate) == false && reallocatePartialQuantity == false
@@ -71,7 +69,6 @@ namespace bnhtrade.Core.Logic.Stock
// temp code start
// until use of stockId is designed out of application
var getStockId = new Data.Database.Stock.ReadStockId();
var stockIdDictionary = new Dictionary<int, int>();
foreach (var item in statusBalance.ByDateList)
{
@@ -80,6 +77,7 @@ namespace bnhtrade.Core.Logic.Stock
stockIdDictionary.Add(item.StockNumber, 0);
}
}
var getStockId = new Data.Database.Stock.ReadStockId();
stockIdDictionary = getStockId.ByStockNumber(stockIdDictionary.Keys.ToList());
// temp code finish

View File

@@ -0,0 +1,115 @@
using FikaAmazonAPI.AmazonSpApiSDK.Models.Finances;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
namespace bnhtrade.Core.Logic.Utilities
{
public class File
{
public static string DecryptString(byte[] key, byte[] iv, byte[] cipherText)
{
byte[] buffer = cipherText;
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
public static byte[] DecryptByte(byte[] key, byte[] iv, byte[] cipherText)
{
// untested, don't know if this works
byte[] buffer = cipherText;
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(cipherText, 0, cipherText.Length);
return memoryStream.ToArray();
//return decryptedData;
}
}
}
}
public static string Decompress(string fileName)
{
FileInfo fileInfo = new FileInfo(fileName);
using (FileStream originalFileStream = fileInfo.OpenRead())
{
string currentFileName = fileInfo.FullName;
string newFileName = currentFileName.Remove(currentFileName.Length - fileInfo.Extension.Length);
using (FileStream decompressedFileStream = System.IO.File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedFileStream);
Console.WriteLine($"Decompressed: {fileInfo.Name}");
}
return decompressedFileStream.Name;
}
}
}
public static byte[] Decompress(byte[] data)
{
using (var compressedStream = new MemoryStream(data))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
public static string DecompressString(string fileName)
{
FileInfo fileInfo = new FileInfo(fileName);
using (FileStream originalFileStream = fileInfo.OpenRead())
{
string currentFileName = fileInfo.FullName;
string newFileName = currentFileName.Remove(currentFileName.Length - fileInfo.Extension.Length);
using (FileStream decompressedFileStream = System.IO.File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedFileStream);
Console.WriteLine($"Decompressed: {fileInfo.Name}");
}
return decompressedFileStream.Name;
}
}
}
}
}

View File

@@ -1,57 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
namespace bnhtrade.Core.Logic.Utilities
{
public class FileTransform
{
public static string DecryptString(byte[] key, byte[] iv, byte[] cipherText)
{
byte[] buffer = cipherText;
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
public static string Decompress(string fileName)
{
FileInfo fileInfo = new FileInfo(fileName);
using (FileStream originalFileStream = fileInfo.OpenRead())
{
string currentFileName = fileInfo.FullName;
string newFileName = currentFileName.Remove(currentFileName.Length - fileInfo.Extension.Length);
using (FileStream decompressedFileStream = File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedFileStream);
Console.WriteLine($"Decompressed: {fileInfo.Name}");
}
return decompressedFileStream.Name;
}
}
}
}
}

View File

@@ -8,35 +8,27 @@ namespace bnhtrade.Core.Logic.Utilities
{
public class NightlyRoutine
{
private Model.Credentials.AmazonSPAPI amznCredentials;
private Model.Credentials.bnhtradeDB dbCredentials;
private Logic.Log.LogEvent log = new Log.LogEvent();
public NightlyRoutine(Model.Credentials.AmazonSPAPI amznCredentials, Model.Credentials.bnhtradeDB dbCredentials)
public NightlyRoutine()
{
this.amznCredentials = amznCredentials;
this.dbCredentials = dbCredentials;
}
public void DownloadAll()
{
new Logic.Log.LogEvent().EventLogInsert("Nightly scheduled tasks started.");
log.LogInformation("Nightly scheduled tasks started.");
var stock = new bnhtrade.Core.Stock.StockReconciliation();
var export = new bnhtrade.Core.Logic.Export.AmazonSettlement(dbCredentials.ConnectionString);
var export = new bnhtrade.Core.Logic.Export.AmazonSettlement();
bool accountUpdate = false;
bool stockUpdate = false;
bool accountProcess = false;
bool stockProcess = false;
while (true)
{
try
{
if (accountUpdate == false) { accountUpdate = true; new Logic.Import.AmazonSettlement(amznCredentials).SyncDatabase(dbCredentials.ConnectionString); }
if (stockUpdate == false) { stockUpdate = true; new bnhtrade.Core.Logic.Import.Amazon().SyncAllWithDatabase(); ; }
if (accountProcess == false) { accountProcess = true; export.ToInvoice(); }
if (stockUpdate == false) { stockUpdate = true; stock.UpdateFbaStockImportData(dbCredentials.ConnectionString); }
// if (stockProcess == false) { stockProcess = true; stock.ProcessFbaStockImportData(); }
// ^^^^^^ best to process manually, case, fba inventory recepts, if a correction is made days later (ie -1) the already incorrect value
@@ -46,14 +38,13 @@ namespace bnhtrade.Core.Logic.Utilities
}
catch (Exception ex)
{
new Logic.Log.LogEvent().EventLogInsert(
log.LogInformation(
"Exception caught running all report get method, see for further details",
1,
ex.ToString()
);
}
}
new Logic.Log.LogEvent().EventLogInsert("Nightly scheduled tasks finished.");
log.LogInformation("Nightly scheduled tasks finished.");
}
}
}

View File

@@ -12,7 +12,7 @@ namespace bnhtrade.Core.Logic.Utilities
public bool AllowWhiteSpace { get; set; } = false;
public void ResetToDefault()
{
Innit();
Init();
AllowEmpty = false;
AllowWhiteSpace = false;
}

View File

@@ -12,7 +12,7 @@ namespace bnhtrade.Core.Logic.Validate
public new void Innit()
{
base.Innit();
base.Init();
stringCheck = new Logic.Utilities.StringCheck();
}
public bool IsValidAccountCodeId(int accountCode)

View File

@@ -22,11 +22,11 @@ namespace bnhtrade.Core.Logic.Validate
public new void Innit()
{
base.Innit();
timeCheck.Innit();
stringCheck.Innit();
base.Init();
timeCheck.Init();
stringCheck.Init();
currencyCheck.Innit();
decimalCheck.Innit();
decimalCheck.Init();
}
public bool IsValid(Model.Import.AmazonSettlement settlement)

View File

@@ -12,7 +12,7 @@ namespace bnhtrade.Core.Logic.Validate
private Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck();
public new void Innit()
{
base.Innit();
base.Init();
stringCheck = new Logic.Utilities.StringCheck();
}
public bool IsValidCurrencyCode(string currencyCode)

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Validate
{
public static class Format
{
/// <summary>
/// Validates that an sku number string is the correct format i.e. 000000-00
/// </summary>
/// <param name="skuNumber"></param>
/// <returns></returns>
public static bool SkuNumber(string skuNumber)
{
if (string.IsNullOrEmpty(skuNumber)) { return false;}
int count = 0;
foreach (char c in skuNumber)
{
count++;
if (count == 7)
{
string hyphen = "-";
if (c != hyphen[0])
{
return false;
}
}
else if (count > 9)
{
return false;
}
else if (!char.IsNumber(c))
{
return false;
}
}
count = 0;
return true;
}
/// <summary>
/// Checks the datetime is not default and is utc
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public static bool DateTime(DateTime dateTime)
{
if (dateTime == default(DateTime))
{ return false; }
else if (dateTime.Kind != DateTimeKind.Utc)
{ return false; }
else
{ return true; }
}
}
}

View File

@@ -11,12 +11,12 @@ namespace bnhtrade.Core.Logic.Validate
{
public SkuPriceInfo()
{
Innit();
Init();
}
public bool IsValidDatabaseCreate(List<Model.Sku.Price.PriceInfo> priceInfoList)
{
Innit();
Init();
if (!IsValid(priceInfoList))
{

View File

@@ -19,24 +19,15 @@ namespace bnhtrade.Core.Logic.Validate
{
return false;
}
for (int i = 0; i < skuTransactionList.Count; i++)
{
if (!skuTransactionList[i].IsSetSkuTransactionId)
{
ValidationResultAdd("StockTransactionId is required");
}
}
return IsValidResult;
}
public bool DatabaseInsert(Model.Stock.SkuTransaction skuTransaction)
public bool DatabaseInsert(Model.Stock.SkuTransactionCreate skuTransaction)
{
return IsValid(new List<Model.Stock.SkuTransaction> { skuTransaction });
return IsValid(new List<Model.Stock.SkuTransactionCreate> { skuTransaction });
}
public bool DatabaseInsert(List<Model.Stock.SkuTransaction> skuTransactionList)
public bool DatabaseInsert(List<Model.Stock.SkuTransactionCreate> skuTransactionList)
{
return IsValid(skuTransactionList);
}

View File

@@ -20,7 +20,7 @@ namespace bnhtrade.Core.Logic.Validate
}
}
public void Innit()
public void Init()
{
ValidationResult = new List<ValidationResult>();
}

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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ namespace bnhtrade.Core.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -22,23 +22,5 @@ namespace bnhtrade.Core.Properties {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("%USERPROFILE%\\Desktop\\e2A_Client\\Archive\\")]
public string DocArchivePath {
get {
return ((string)(this["DocArchivePath"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("%USERPROFILE%\\Desktop\\e2A_Client\\Processing\\")]
public string DocProcessingPath {
get {
return ((string)(this["DocProcessingPath"]));
}
}
}
}

View File

@@ -1,12 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="bnhtrade.Core.Properties" GeneratedClassName="Settings">
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles />
<Settings>
<Setting Name="DocArchivePath" Type="System.String" Scope="Application">
<Value Profile="(Default)">%USERPROFILE%\Desktop\e2A_Client\Archive\</Value>
</Setting>
<Setting Name="DocProcessingPath" Type="System.String" Scope="Application">
<Value Profile="(Default)">%USERPROFILE%\Desktop\e2A_Client\Processing\</Value>
</Setting>
</Settings>
<Settings />
</SettingsFile>

View File

@@ -8,7 +8,7 @@ namespace bnhtrade.Core.Test.Account
{
public class Account
{
public Account(string sqlConnectionString)
public Account()
{
//var inst = new Data.Database.Account.GetTaxCode(sqlConnectionString);
//inst.

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Test.Amazon.MWS
{
public class Report
{
private string sqlConnectionString;
public Report(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
// method you want to start here
GetRport();
}
public void GetRport()
{
string mwsReportEnum = "_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_";
DateTime start = new DateTime(2020, 10, 01);
DateTime finish = new DateTime(2020, 11, 03);
}
}
}

View File

@@ -0,0 +1,61 @@
using CsvHelper;
using CsvHelper.Configuration;
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Test.Amazon.SP_API
{
public class Reports
{
public Reports()
{
sync_GET_LEDGER_DETAIL_VIEW_DATA();
}
public void download_GET_LEDGER_DETAIL_VIEW_DATA()
{
var report = new Data.Amazon.Report.FbaInventoryLedgerDetailed();
report.GetReport(DateTime.UtcNow.AddMonths(-17), DateTime.UtcNow);
if (report.IsSetResultList)
{
List<Model.Import.AmazonFbaInventoryLedgerDetail> lsdkfjl = report.ResultList;
int a = 1;
}
}
public void sync_GET_LEDGER_DETAIL_VIEW_DATA()
{
var logic = new bnhtrade.Core.Logic.Import.AmazonFbaInventoryLedgerDetail();
logic.SyncDatabaseWithAmazon();
}
public void CsvHelper()
{
using (var reader = new StreamReader("C:\\Users\\Bobbie\\AppData\\Local\\Temp\\_bnhtrade.Core\\File\\SP-API-Report GET_LEDGER_DETAIL_VIEW_DATA reportId_902635019835.txt"))
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = "\t",
};
using (var csvreader = new CsvReader(reader, config))
{
csvreader.Read();
csvreader.ReadHeader();
int columns = csvreader.HeaderRecord.Count();
if (columns != 15)
throw new Exception("New column detected in GET_LEDGER_DETAIL_VIEW_DATA");
var resultList = csvreader.GetRecords<Model.Import.AmazonFbaInventoryLedgerDetail>().ToList();
int d = 1;
}
}
}
}
}

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Test.AmazonMWS
{
public class Report
{
private string sqlConnectionString;
public Report(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
// method you want to start here
GetRport();
}
public void GetRport()
{
string mwsReportEnum = "_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_";
DateTime start = new DateTime(2020, 10, 01);
DateTime finish = new DateTime(2020, 11, 03);
var result = new bnhtrade.Core.AmazonReport().GetMwsReportByPeriod(mwsReportEnum, start, finish, 12, 30);
}
}
}

View File

@@ -8,18 +8,14 @@ namespace bnhtrade.Core.Test
{
public class AutoExec
{
private string sqlConnectionString;
public AutoExec(string sqlConnectionString)
public AutoExec()
{
this.sqlConnectionString = sqlConnectionString;
// --------------- start this ------------------- //
AmazonSettlement();
}
private void AmazonSettlement()
{
var instance = new Core.Logic.Export.AmazonSettlement(sqlConnectionString);
var instance = new Core.Logic.Export.AmazonSettlement();
instance.ToInvoice();
}
}

View File

@@ -8,15 +8,8 @@ namespace bnhtrade.Core.Test.Import
{
public class Report
{
private Model.Credentials.bnhtradeDB dbCredentials;
private string sqlConnectionString;
private Model.Credentials.AmazonSPAPI spapiCredentials;
public Report(Model.Credentials.bnhtradeDB dbCredentials, Model.Credentials.AmazonSPAPI spapiCredentials)
public Report()
{
this.dbCredentials = dbCredentials;
this.sqlConnectionString = dbCredentials.ConnectionString;
this.spapiCredentials = spapiCredentials;
FBAInventoryAge();
}
@@ -29,8 +22,8 @@ namespace bnhtrade.Core.Test.Import
public void GetFromSPAPI()
{
var hhhhhjjjjj = new Core.Logic.Import.AmazonSettlement(spapiCredentials);
hhhhhjjjjj.SyncDatabase(sqlConnectionString);
var hhhhhjjjjj = new Core.Logic.Import.AmazonSettlement();
hhhhhjjjjj.SyncDatabase();
}
public void GetReportDocumentByReportId()

View File

@@ -8,18 +8,15 @@ namespace bnhtrade.Core.Test.Logic
{
public class Logic
{
private string sqlConnectionString;
public Logic(string sqlConnectionString)
public Logic()
{
this.sqlConnectionString = sqlConnectionString;
// method you want to start here
UpdateXeroWithAmzonSettlementData();
}
public void UpdateXeroWithAmzonSettlementData()
{
var instance = new bnhtrade.Core.Logic.Export.AmazonSettlement(sqlConnectionString);
var instance = new bnhtrade.Core.Logic.Export.AmazonSettlement();
instance.ToInvoice();
}
}

View File

@@ -21,7 +21,7 @@ namespace bnhtrade.Core.Test.Sku
public void UpdateFbaPricing()
{
var instance = new bnhtrade.Core.Logic.Sku.Price.FbaPricing(sqlConnectionString);
var instance = new bnhtrade.Core.Logic.Sku.Price.FbaPricing();
instance.Update();
}

View File

@@ -8,13 +8,9 @@ namespace bnhtrade.Core.Test.Stock
{
public class Stock
{
private string sqlConnectionString;
public Stock(string sqlConnectionString)
public Stock()
{
this.sqlConnectionString = sqlConnectionString;
// method you want to start here
UnreconcileSkuTrnasction(79808);
}
public void ReadStatusBalance()
@@ -30,7 +26,7 @@ namespace bnhtrade.Core.Test.Stock
var atDate = new DateTime(2017, 02, 01, 21, 54, 30);
DateTime.TryParse("22/12/2017 16:35:58", out atDate);
var result = new Core.Logic.Stock.StatusBalance(sqlConnectionString).GetBySku(sku, statusId);
var result = new Core.Logic.Stock.StatusBalance().GetBySku(sku, statusId);
}
public void ReadStockId()
@@ -44,21 +40,12 @@ namespace bnhtrade.Core.Test.Stock
public void SkuTransactionAdd()
{
var trans = new bnhtrade.Core.Model.Stock.SkuTransaction();
trans.IsProcessed = false;
trans.Quantity = 1;
//trans.Reference
trans.SkuNumber = "005642-41";
trans.SkuTransactionTypeCode = "ManualAdjustment005";
//trans.StockJournalId;
trans.TransactionDate = new DateTime(2020, 01, 29, 17, 00, 00);
new bnhtrade.Core.Logic.Stock.SkuTransactionPersistance(sqlConnectionString).Create(trans);
throw new NotImplementedException();
}
public void UnreconcileSkuTrnasction(int transactoinId)
{
new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile(sqlConnectionString).UnReconcileTransaction(transactoinId);
new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile().UnReconcileTransaction(transactoinId);
}
}
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\NUnit.3.13.2\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.13.2\build\NUnit.props')" />
<Import Project="..\..\packages\NUnit.4.1.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.4.1.0\build\NUnit.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -22,7 +22,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\artifiacts\Debug\</OutputPath>
<OutputPath>..\..\bin\Debug\core\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@@ -31,7 +31,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\artifiacts\Release\</OutputPath>
<OutputPath>..\..\bin\Release\core\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@@ -41,34 +41,40 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
<HintPath>..\..\packages\AWSSDK.Core.3.7.103.14\lib\net45\AWSSDK.Core.dll</HintPath>
<HintPath>..\..\packages\AWSSDK.Core.3.7.303.15\lib\net45\AWSSDK.Core.dll</HintPath>
</Reference>
<Reference Include="AWSSDK.SecurityToken, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
<HintPath>..\..\packages\AWSSDK.SecurityToken.3.7.100.52\lib\net45\AWSSDK.SecurityToken.dll</HintPath>
<HintPath>..\..\packages\AWSSDK.SecurityToken.3.7.300.76\lib\net45\AWSSDK.SecurityToken.dll</HintPath>
</Reference>
<Reference Include="AWSSDK.SQS, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
<HintPath>..\..\packages\AWSSDK.SQS.3.7.100.52\lib\net45\AWSSDK.SQS.dll</HintPath>
<HintPath>..\..\packages\AWSSDK.SQS.3.7.300.75\lib\net45\AWSSDK.SQS.dll</HintPath>
</Reference>
<Reference Include="CsvHelper, Version=15.0.0.0, Culture=neutral, PublicKeyToken=8c4959082be5c823, processorArchitecture=MSIL">
<HintPath>..\..\packages\CsvHelper.15.0.0\lib\net47\CsvHelper.dll</HintPath>
<Reference Include="CsvHelper, Version=31.0.0.0, Culture=neutral, PublicKeyToken=8c4959082be5c823, processorArchitecture=MSIL">
<HintPath>..\..\packages\CsvHelper.31.0.4\lib\net47\CsvHelper.dll</HintPath>
</Reference>
<Reference Include="Dapper, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Dapper.2.0.30\lib\net461\Dapper.dll</HintPath>
<HintPath>..\..\packages\Dapper.2.1.35\lib\net461\Dapper.dll</HintPath>
</Reference>
<Reference Include="Dapper.Contrib, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Dapper.Contrib.2.0.30\lib\net461\Dapper.Contrib.dll</HintPath>
<HintPath>..\..\packages\Dapper.Contrib.2.0.78\lib\net461\Dapper.Contrib.dll</HintPath>
</Reference>
<Reference Include="FikaAmazonAPI, Version=1.7.17.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\CSharpAmazonSpAPI.1.7.17\lib\netstandard2.0\FikaAmazonAPI.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.HashCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.13.2.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\..\packages\NUnit.3.13.2\lib\net45\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=4.0.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\..\packages\NUnit.4.1.0\lib\net462\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="nunit.framework.legacy, Version=4.0.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\..\packages\NUnit.4.1.0\lib\net462\nunit.framework.legacy.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=110.2.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>..\..\packages\RestSharp.110.2.0\lib\net471\RestSharp.dll</HintPath>
@@ -76,8 +82,8 @@
<Reference Include="RestSharp.Serializers.NewtonsoftJson, Version=110.2.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>..\..\packages\RestSharp.Serializers.NewtonsoftJson.110.2.0\lib\net471\RestSharp.Serializers.NewtonsoftJson.dll</HintPath>
</Reference>
<Reference Include="StandardSocketsHttpHandler, Version=2.2.0.4, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\StandardSocketsHttpHandler.2.2.0.4\lib\netstandard2.0\StandardSocketsHttpHandler.dll</HintPath>
<Reference Include="StandardSocketsHttpHandler, Version=2.2.0.8, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\StandardSocketsHttpHandler.2.2.0.8\lib\netstandard2.0\StandardSocketsHttpHandler.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
@@ -106,11 +112,11 @@
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Text.Encodings.Web, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Text.Encodings.Web.7.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=7.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Text.Json.7.0.2\lib\net462\System.Text.Json.dll</HintPath>
<Reference Include="System.Text.Json, Version=8.0.0.3, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Text.Json.8.0.3\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
@@ -142,17 +148,17 @@
<Compile Include="Data\Amazon\Report\FbaInventory.cs" />
<Compile Include="Data\Amazon\Report\FbaInventoryReceipt.cs" />
<Compile Include="Data\Amazon\Report\FbaCustomerReturn.cs" />
<Compile Include="Data\Amazon\Report\FbaInventoryLedgerDetailed.cs" />
<Compile Include="Data\Amazon\Report\FbaReimbursement.cs" />
<Compile Include="Data\Amazon\Report\FbaRemovalOrder.cs" />
<Compile Include="Data\Amazon\Report\FbaSaleShipment.cs" />
<Compile Include="Data\Amazon\Report\ReportLogic.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\AmazonConnection.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\AmazonCredential.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\SpApiConnection.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\Defaults.cs" />
<Compile Include="Data\Amazon\Report\SettlementReport.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\Services\ReportService.cs" />
<Compile Include="Data\Amazon\SellingPartnerAPI\Utils\CurrentDateTime.cs" />
<Compile Include="Config.cs" />
<Compile Include="Data\Database\Account\CreateInvoiceLineItem.cs" />
<Compile Include="Data\Database\Account\ReadAccountCode.cs" />
<Compile Include="Data\Database\Account\ReadTaxCode.cs" />
@@ -168,12 +174,17 @@
<Compile Include="Data\Database\AmazonFba\ReadShipmentPrimaryKey.cs" />
<Compile Include="Data\Database\AmazonFba\SetShipmentInfo.cs" />
<Compile Include="Data\Database\Import\AmazonFbaInventoryAdjustment.cs" />
<Compile Include="Data\Database\Import\AmazonFbaInventoryLedgerDetail.cs" />
<Compile Include="Data\Database\Product\ReadProduct.cs" />
<Compile Include="Data\Database\Product\ReadProductId.cs" />
<Compile Include="Data\Database\ReadRandomData.cs" />
<Compile Include="Data\Database\Sku\InsertSku.cs" />
<Compile Include="Data\Database\Sku\ReadSku.cs" />
<Compile Include="Data\Database\Stock\InsertSkuTransactionType.cs" />
<Compile Include="Data\Database\Stock\JournalCrud.cs" />
<Compile Include="Data\Database\Stock\ReadStatusTypeBalance.cs" />
<Compile Include="Logic\Amazon\Fba\Fnsku.cs" />
<Compile Include="Logic\Import\Amazon.cs" />
<Compile Include="Logic\Import\AmazonFbaInventoryAdjustment.cs" />
<Compile Include="Data\Database\Import\AmazonFbaInventoryAgeData.cs" />
<Compile Include="Data\Database\Import\AmazonFbaInventoryData.cs" />
@@ -196,7 +207,7 @@
<Compile Include="Data\Database\Log\LogEvent.cs" />
<Compile Include="Data\Database\Programmability\Sequence.cs" />
<Compile Include="Data\Database\Sku\ReadSkuConditionInfo.cs" />
<Compile Include="Data\Database\Stock\CreateSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\InsertSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\DeleteSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\ReadSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\ReadSkuTransactionType.cs" />
@@ -212,6 +223,7 @@
<Compile Include="Logic\Account\GetTaxCodeInfo.cs" />
<Compile Include="Logic\Import\AmazonFbaInventory.cs" />
<Compile Include="Logic\Import\AmazonFbaInventoryAge.cs" />
<Compile Include="Logic\Import\AmazonFbaInventoryLedgerDetail.cs" />
<Compile Include="Logic\Import\AmazonFbaInventoryReceipt.cs" />
<Compile Include="Logic\Import\AmazonFbaCustomerReturn.cs" />
<Compile Include="Logic\Import\AmazonFbaReimbursement.cs" />
@@ -223,9 +235,10 @@
<Compile Include="Logic\Product\GetProductInfo.cs" />
<Compile Include="Logic\Sku\GetSkuInfo.cs" />
<Compile Include="Logic\Stock\GetStatusTypeBalance.cs" />
<Compile Include="Logic\Stock\SkuTransactionImport.cs" />
<Compile Include="Logic\Stock\StatusBalance.cs" />
<Compile Include="Logic\Utilities\EasyMD5.cs" />
<Compile Include="Logic\Utilities\FileTransform.cs" />
<Compile Include="Logic\Utilities\File.cs" />
<Compile Include="Logic\Utilities\NightlyRoutine.cs" />
<Compile Include="Logic\Validate\AccountCode.cs" />
<Compile Include="Logic\Validate\CurrencyCode.cs" />
@@ -236,8 +249,8 @@
<Compile Include="Logic\Sku\GetSkuConditionInfo.cs" />
<Compile Include="Logic\Stock\StatusReallocate.cs" />
<Compile Include="Logic\Stock\SkuTransactionReconcile.cs" />
<Compile Include="Logic\Stock\SkuTransactionPersistance.cs" />
<Compile Include="Logic\Stock\SkuTransactionTypePersistance.cs" />
<Compile Include="Logic\Stock\SkuTransactionCrud.cs" />
<Compile Include="Logic\Stock\SkuTransactionTypeCrud.cs" />
<Compile Include="Logic\Export\SalesInvoice.cs" />
<Compile Include="Logic\Export\AmazonSettlement.cs" />
<Compile Include="Logic\Validate\AmazonSettlement.cs" />
@@ -247,6 +260,7 @@
<Compile Include="Logic\Utilities\CalculateMD5.cs" />
<Compile Include="Logic\Utilities\DateTimeParse.cs" />
<Compile Include="Logic\Validate\AmazonIventoryLoaderFile.cs" />
<Compile Include="Logic\Validate\Format.cs" />
<Compile Include="Logic\Validate\SkuTransaction.cs" />
<Compile Include="Logic\Validate\TaxCodeInfo.cs" />
<Compile Include="Logic\Validate\Validate.cs" />
@@ -270,6 +284,8 @@
<Compile Include="Model\Data\DatabaseFileStream.cs" />
<Compile Include="Model\Export\AmazonFeedSubmission.cs" />
<Compile Include="Model\Export\AmazonIventoryLoaderFile.cs" />
<Compile Include="Model\Import\AmazonFbaInventoryLedgerDetail.cs" />
<Compile Include="Model\Import\AmazonFbaReimbursement.cs" />
<Compile Include="Model\Import\AmazonSettlement.cs" />
<Compile Include="Model\Import\AmazonSettlementHeader.cs" />
<Compile Include="Model\Product\CompetitivePrice.cs" />
@@ -283,13 +299,15 @@
<Compile Include="Model\Sku\Sku.cs" />
<Compile Include="Model\Sku\SkuConditionInfo.cs" />
<Compile Include="Model\Stock\JournalEntry.cs" />
<Compile Include="Model\Stock\SkuTransactionDepreciated.cs" />
<Compile Include="Model\Stock\SkuTransactionCreate.cs" />
<Compile Include="Model\Stock\SkuTransactionType.cs" />
<Compile Include="Model\Stock\SkuTransaction.cs" />
<Compile Include="Model\Stock\StatusBalance.cs" />
<Compile Include="Model\Stock\StatusTransaction.cs" />
<Compile Include="Test\Account\Account.cs" />
<Compile Include="Test\Amazon\MWS\Report.cs" />
<Compile Include="Test\Amazon\SP-API\FulfillmentInboundV0.cs" />
<Compile Include="Test\Amazon\SP-API\Reports.cs" />
<Compile Include="Test\Amazon\SP-API\VariousCalls.cs" />
<Compile Include="Test\AutoExec.cs" />
<Compile Include="Test\Export\Export.cs" />
@@ -313,7 +331,7 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="Logic\Sku\GetSkuIdByType.cs" />
<Compile Include="Logic\Sku\GetSkuId.cs" />
<Compile Include="Data\Database\Sku\GetSkuId.cs" />
<Compile Include="UI\ConsoleProgressBar.cs" />
</ItemGroup>
@@ -332,15 +350,17 @@
<Folder Include="Test\Product\" />
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\..\packages\AWSSDK.SecurityToken.3.7.100.52\analyzers\dotnet\cs\AWSSDK.SecurityToken.CodeAnalysis.dll" />
<Analyzer Include="..\..\packages\AWSSDK.SQS.3.7.100.52\analyzers\dotnet\cs\AWSSDK.SQS.CodeAnalysis.dll" />
<Analyzer Include="..\..\packages\AWSSDK.SecurityToken.3.7.300.76\analyzers\dotnet\cs\AWSSDK.SecurityToken.CodeAnalysis.dll" />
<Analyzer Include="..\..\packages\AWSSDK.SecurityToken.3.7.300.76\analyzers\dotnet\cs\SharedAnalysisCode.dll" />
<Analyzer Include="..\..\packages\AWSSDK.SQS.3.7.300.75\analyzers\dotnet\cs\AWSSDK.SQS.CodeAnalysis.dll" />
<Analyzer Include="..\..\packages\AWSSDK.SQS.3.7.300.75\analyzers\dotnet\cs\SharedAnalysisCode.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\NUnit.3.13.2\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.3.13.2\build\NUnit.props'))" />
<Error Condition="!Exists('..\..\packages\NUnit.4.1.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\NUnit.4.1.0\build\NUnit.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ABrain.AmazonMWS" version="1.0.1.6" targetFramework="net452" />
<package id="AWSSDK.Core" version="3.7.103.14" targetFramework="net472" />
<package id="AWSSDK.SecurityToken" version="3.7.100.52" targetFramework="net472" />
<package id="AWSSDK.SQS" version="3.7.100.52" targetFramework="net472" />
<package id="AWSSDK.Core" version="3.7.303.15" targetFramework="net472" />
<package id="AWSSDK.SecurityToken" version="3.7.300.76" targetFramework="net472" />
<package id="AWSSDK.SQS" version="3.7.300.75" targetFramework="net472" />
<package id="CSharpAmazonSpAPI" version="1.7.17" targetFramework="net472" />
<package id="CsvHelper" version="15.0.0" targetFramework="net471" />
<package id="Dapper" version="2.0.30" targetFramework="net471" />
<package id="Dapper.Contrib" version="2.0.30" targetFramework="net471" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="7.0.0" targetFramework="net472" />
<package id="CsvHelper" version="31.0.4" targetFramework="net472" />
<package id="Dapper" version="2.1.35" targetFramework="net472" />
<package id="Dapper.Contrib" version="2.0.78" targetFramework="net472" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net472" />
<package id="Microsoft.Bcl.HashCode" version="1.1.1" targetFramework="net472" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net471" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
<package id="NUnit" version="3.13.2" targetFramework="net471" />
<package id="NUnit" version="4.1.0" targetFramework="net472" />
<package id="RestSharp" version="110.2.0" targetFramework="net472" />
<package id="RestSharp.Serializers.NewtonsoftJson" version="110.2.0" targetFramework="net472" />
<package id="StandardSocketsHttpHandler" version="2.2.0.4" targetFramework="net472" />
<package id="StandardSocketsHttpHandler" version="2.2.0.8" targetFramework="net472" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.Collections" version="4.3.0" targetFramework="net472" />
<package id="System.ComponentModel.Annotations" version="5.0.0" targetFramework="net472" />
@@ -22,8 +22,8 @@
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
<package id="System.Reflection" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net471" />
<package id="System.Text.Encodings.Web" version="7.0.0" targetFramework="net472" />
<package id="System.Text.Json" version="7.0.2" targetFramework="net472" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net472" />
<package id="System.Text.Json" version="8.0.3" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net471" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
</packages>