From 43d61c2ef839bd342d667d11f84400e3d8b5ddc3 Mon Sep 17 00:00:00 2001 From: Bobbie Hodgetts Date: Fri, 1 May 2020 09:08:23 +0100 Subject: [PATCH] Feature repricing min max (#10) amazon settlement import/export improvements --- build/bnhtrade.ComTypeLib.RegAsmInstall.bat | 8 +- build/bnhtrade.ComTypeLib.RegAsmUninstall.bat | 12 +- src/bnhtrade.ComTypeLib/ILMerge.props | 67 + src/bnhtrade.ComTypeLib/ILMergeOrder.txt | 4 + src/bnhtrade.ComTypeLib/Product/Product.cs | 18 +- src/bnhtrade.ComTypeLib/Stock/Stock.cs | 13 +- src/bnhtrade.ComTypeLib/app.config | 11 + .../bnhtrade.ComTypeLib.csproj | 23 +- src/bnhtrade.ComTypeLib/packages.config | 5 + src/bnhtrade.Core/App.config | 16 +- .../Data/AmazonMWS/CredentialMws.cs | 20 +- .../FBAInbound/ListInboundShipmentItems.cs | 12 +- .../FBAInbound/ListInboundShipments.cs | 16 +- .../AmazonMWS/Feeds/GetFeedSubmissions.cs | 135 ++ .../Data/AmazonMWS/Feeds/SubmitFeed.cs | 120 ++ src/bnhtrade.Core/Data/AmazonMWS/Service.cs | 15 +- .../Database/Account/CreateInvoiceLineItem.cs | 43 + .../Data/Database/Account/ReadAccountCode.cs | 107 +- .../Database/Account/ReadInvoiceLineItem.cs | 113 ++ .../Account/ReadInvoiceLineItemCode.cs | 148 --- .../Data/Database/Account/ReadTaxCode.cs | 333 +++-- .../Database/AmazonFba/ReadShipmentInfo.cs | 148 +++ .../ReadShipmentPrimaryKey.cs} | 14 +- .../SetShipmentInfo.cs | 42 +- src/bnhtrade.Core/Data/Database/Connection.cs | 7 +- src/bnhtrade.Core/Data/Database/Constants.cs | 16 + .../Export/CreateAmazonFeedSubmission.cs | 74 ++ .../Database/Export/CreateSalesInvoice.cs | 93 +- .../Export/ReadAmazonFeedSubmission.cs | 125 ++ .../Export/UpdateAmazonFeedSubmission.cs | 109 ++ .../FBAInbound/GetShipmentHeaderInfo.cs | 157 --- .../Database/Import/ReadFbaInventoryAge.cs | 92 ++ .../Database/Import/ReadFbaSaleShipment.cs | 117 ++ .../Product/CreateCompetitivePrice.cs | 78 ++ .../Database/Product/ReadCompetitivePrice.cs | 131 ++ .../Data/Database/SKU/GetSKUId.cs | 2 +- src/bnhtrade.Core/Data/Database/SKU/GetSku.cs | 2 +- .../Database/SKU/Price/CreatePricingDetail.cs | 99 ++ .../Data/Database/SKU/Price/ReadParameter.cs | 98 ++ .../Database/SKU/Price/ReadPricingDetail.cs | 68 + .../Data/Database/SKU/ReadSkuConditionInfo.cs | 51 + .../Database/Stock/CreateSkuTransaction.cs | 78 ++ .../Database/Stock/DeleteSkuTransaction.cs | 36 + .../Data/Database/Stock/ReadSkuTransaction.cs | 104 ++ .../Database/Stock/ReadSkuTransactionType.cs | 153 +++ .../Database/Stock/UpdateSkuTransaction.cs | 198 +++ .../Data/Database/WhereBuilder.cs | 94 ++ src/bnhtrade.Core/Extensions.cs | 19 + .../Logic/Account/GetAccountCodeInfo.cs | 83 ++ .../Logic/Account/GetInvoiceLineItem.cs | 164 +++ .../Logic/Account/GetTaxCodeInfo.cs | 141 +++ .../Logic/Account/TaxCalculation.cs | 86 ++ .../Logic/Account/ValidateInvoice.cs | 267 ---- .../Logic/Account/ValidateSalesInvoice.cs | 34 - .../Logic/Account/ValidateTaxCode.cs | 145 --- .../UpdateDatabaseShipmentInfo.cs | 19 +- .../Logic/Export/AmazonSettlement.cs | 135 +- .../Logic/Export/AmazonSubmitFile.cs | 124 ++ .../Logic/Export/AmazonSubmitFileStatus.cs | 59 + .../Logic/Export/SalesInvoice.cs | 53 + .../Logic/Export/ValidateSalesInvoice.cs | 134 -- .../Logic/Product/GetCompetitivePrice.cs | 261 ++++ .../Logic/Sku/GetSkuConditionInfo.cs | 30 + .../Logic/Sku/Price/FbaPricing.cs | 386 ++++++ .../Logic/Sku/Price/UpdateRepricingValues.cs | 787 ++++++++++++ src/bnhtrade.Core/Logic/Stock/Reallocate.cs | 86 ++ .../Logic/Stock/SkuTransactionPersistance.cs | 167 +++ .../Logic/Stock/SkuTransactionReconcile.cs | 398 ++++++ .../Stock/SkuTransactionTypePersistance.cs | 98 ++ .../Logic/Utilities/CalculateMD5.cs | 31 + .../Logic/Utilities/DateTimeCheck.cs | 10 +- .../Logic/Utilities/DateTimeParse.cs | 23 + .../Logic/Utilities/DecimalCheck.cs | 6 +- .../Logic/Utilities/StringCheck.cs | 30 +- src/bnhtrade.Core/Logic/Validate.cs | 56 - .../AccountCode.cs} | 14 +- .../Validate/AmazonIventoryLoaderFile.cs | 21 + .../AmazonSettlement.cs} | 98 +- .../CurrencyCode.cs} | 6 +- .../Logic/Validate/SalesInvoice.cs | 43 + .../Logic/Validate/SkuPriceInfo.cs | 29 + .../Logic/Validate/SkuTransaction.cs | 44 + .../Logic/Validate/TaxCodeInfo.cs | 17 + src/bnhtrade.Core/Logic/Validate/Validate.cs | 94 ++ .../Model/Account/AccountCode.cs | 30 +- src/bnhtrade.Core/Model/Account/Invoice.cs | 271 ++-- .../Model/Account/InvoiceHeader.cs | 136 +- .../Model/Account/InvoiceLineItem.cs | 31 +- src/bnhtrade.Core/Model/Account/TaxCode.cs | 102 -- .../Model/Account/TaxCodeInfo.cs | 72 ++ .../ShipmentInfo.cs | 46 +- .../ShipmentItemInfo.cs | 11 +- .../Model/Data/DatabaseFileStream.cs | 98 ++ .../Model/Export/AmazonFeedSubmission.cs | 124 ++ .../Model/Export/AmazonIventoryLoaderFile.cs | 136 ++ .../Model/Product/CompetitivePrice.cs | 53 + src/bnhtrade.Core/Model/SKU/Sku.cs | 85 +- .../Model/SKU/SkuConditionInfo.cs | 35 + .../Model/Sku/Price/DetailRequest.cs | 41 + .../Model/Sku/Price/DetailResponce.cs | 71 ++ .../Model/Sku/Price/PriceInfo.cs | 98 ++ .../Model/Sku/Price/SkuPriceParameter.cs | 53 + .../Model/Stock/SkuTransaction.cs | 189 +++ .../Model/Stock/SkuTransactionType.cs | 63 + src/bnhtrade.Core/Program.cs | 1116 ++--------------- .../Account/{GetTaxInfo.cs => Account.cs} | 4 +- src/bnhtrade.Core/Test/AutoExec.cs | 2 +- src/bnhtrade.Core/Test/Export/Export.cs | 44 + .../Test/Import/AmazonSettlement.cs | 4 +- src/bnhtrade.Core/Test/InboundShipmentInfo.cs | 16 +- src/bnhtrade.Core/Test/Logic/Export.cs | 4 +- src/bnhtrade.Core/Test/Sku/Sku.cs | 26 + src/bnhtrade.Core/bnhtrade.Core.csproj | 116 +- src/bnhtrade.Core/packages.config | 7 + src/bnhtrade.ScheduledTasks/App.config | 13 +- src/bnhtrade.ScheduledTasks/Program.cs | 215 +--- .../bnhtrade.ScheduledTasks.csproj | 12 +- src/bnhtrade.ScheduledTasks/packages.config | 4 + 118 files changed, 7930 insertions(+), 3021 deletions(-) create mode 100644 src/bnhtrade.ComTypeLib/ILMerge.props create mode 100644 src/bnhtrade.ComTypeLib/ILMergeOrder.txt create mode 100644 src/bnhtrade.ComTypeLib/app.config create mode 100644 src/bnhtrade.ComTypeLib/packages.config create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/Feeds/GetFeedSubmissions.cs create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/Feeds/SubmitFeed.cs create mode 100644 src/bnhtrade.Core/Data/Database/Account/CreateInvoiceLineItem.cs create mode 100644 src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItem.cs delete mode 100644 src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItemCode.cs create mode 100644 src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentInfo.cs rename src/bnhtrade.Core/Data/Database/{FBAInbound/GetShipmentPrimaryKey.cs => AmazonFba/ReadShipmentPrimaryKey.cs} (94%) rename src/bnhtrade.Core/Data/Database/{FBAInbound => AmazonFba}/SetShipmentInfo.cs (88%) create mode 100644 src/bnhtrade.Core/Data/Database/Constants.cs create mode 100644 src/bnhtrade.Core/Data/Database/Export/CreateAmazonFeedSubmission.cs create mode 100644 src/bnhtrade.Core/Data/Database/Export/ReadAmazonFeedSubmission.cs create mode 100644 src/bnhtrade.Core/Data/Database/Export/UpdateAmazonFeedSubmission.cs delete mode 100644 src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs create mode 100644 src/bnhtrade.Core/Data/Database/Import/ReadFbaInventoryAge.cs create mode 100644 src/bnhtrade.Core/Data/Database/Import/ReadFbaSaleShipment.cs create mode 100644 src/bnhtrade.Core/Data/Database/Product/CreateCompetitivePrice.cs create mode 100644 src/bnhtrade.Core/Data/Database/Product/ReadCompetitivePrice.cs create mode 100644 src/bnhtrade.Core/Data/Database/SKU/Price/CreatePricingDetail.cs create mode 100644 src/bnhtrade.Core/Data/Database/SKU/Price/ReadParameter.cs create mode 100644 src/bnhtrade.Core/Data/Database/SKU/Price/ReadPricingDetail.cs create mode 100644 src/bnhtrade.Core/Data/Database/SKU/ReadSkuConditionInfo.cs create mode 100644 src/bnhtrade.Core/Data/Database/Stock/CreateSkuTransaction.cs create mode 100644 src/bnhtrade.Core/Data/Database/Stock/DeleteSkuTransaction.cs create mode 100644 src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransaction.cs create mode 100644 src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransactionType.cs create mode 100644 src/bnhtrade.Core/Data/Database/Stock/UpdateSkuTransaction.cs create mode 100644 src/bnhtrade.Core/Data/Database/WhereBuilder.cs create mode 100644 src/bnhtrade.Core/Extensions.cs create mode 100644 src/bnhtrade.Core/Logic/Account/GetAccountCodeInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Account/GetInvoiceLineItem.cs create mode 100644 src/bnhtrade.Core/Logic/Account/GetTaxCodeInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Account/TaxCalculation.cs delete mode 100644 src/bnhtrade.Core/Logic/Account/ValidateInvoice.cs delete mode 100644 src/bnhtrade.Core/Logic/Account/ValidateSalesInvoice.cs delete mode 100644 src/bnhtrade.Core/Logic/Account/ValidateTaxCode.cs create mode 100644 src/bnhtrade.Core/Logic/Export/AmazonSubmitFile.cs create mode 100644 src/bnhtrade.Core/Logic/Export/AmazonSubmitFileStatus.cs create mode 100644 src/bnhtrade.Core/Logic/Export/SalesInvoice.cs delete mode 100644 src/bnhtrade.Core/Logic/Export/ValidateSalesInvoice.cs create mode 100644 src/bnhtrade.Core/Logic/Product/GetCompetitivePrice.cs create mode 100644 src/bnhtrade.Core/Logic/Sku/GetSkuConditionInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Sku/Price/FbaPricing.cs create mode 100644 src/bnhtrade.Core/Logic/Sku/Price/UpdateRepricingValues.cs create mode 100644 src/bnhtrade.Core/Logic/Stock/Reallocate.cs create mode 100644 src/bnhtrade.Core/Logic/Stock/SkuTransactionPersistance.cs create mode 100644 src/bnhtrade.Core/Logic/Stock/SkuTransactionReconcile.cs create mode 100644 src/bnhtrade.Core/Logic/Stock/SkuTransactionTypePersistance.cs create mode 100644 src/bnhtrade.Core/Logic/Utilities/CalculateMD5.cs create mode 100644 src/bnhtrade.Core/Logic/Utilities/DateTimeParse.cs delete mode 100644 src/bnhtrade.Core/Logic/Validate.cs rename src/bnhtrade.Core/Logic/{Account/ValidateAccountCode.cs => Validate/AccountCode.cs} (79%) create mode 100644 src/bnhtrade.Core/Logic/Validate/AmazonIventoryLoaderFile.cs rename src/bnhtrade.Core/Logic/{Import/ValidateAmazonSettlement.cs => Validate/AmazonSettlement.cs} (71%) rename src/bnhtrade.Core/Logic/{Account/ValidateCurrencyCode.cs => Validate/CurrencyCode.cs} (82%) create mode 100644 src/bnhtrade.Core/Logic/Validate/SalesInvoice.cs create mode 100644 src/bnhtrade.Core/Logic/Validate/SkuPriceInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Validate/SkuTransaction.cs create mode 100644 src/bnhtrade.Core/Logic/Validate/TaxCodeInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Validate/Validate.cs delete mode 100644 src/bnhtrade.Core/Model/Account/TaxCode.cs create mode 100644 src/bnhtrade.Core/Model/Account/TaxCodeInfo.cs rename src/bnhtrade.Core/Model/{AmazonFBAInbound => AmazonFba}/ShipmentInfo.cs (86%) rename src/bnhtrade.Core/Model/{AmazonFBAInbound => AmazonFba}/ShipmentItemInfo.cs (97%) create mode 100644 src/bnhtrade.Core/Model/Data/DatabaseFileStream.cs create mode 100644 src/bnhtrade.Core/Model/Export/AmazonFeedSubmission.cs create mode 100644 src/bnhtrade.Core/Model/Export/AmazonIventoryLoaderFile.cs create mode 100644 src/bnhtrade.Core/Model/Product/CompetitivePrice.cs create mode 100644 src/bnhtrade.Core/Model/SKU/SkuConditionInfo.cs create mode 100644 src/bnhtrade.Core/Model/Sku/Price/DetailRequest.cs create mode 100644 src/bnhtrade.Core/Model/Sku/Price/DetailResponce.cs create mode 100644 src/bnhtrade.Core/Model/Sku/Price/PriceInfo.cs create mode 100644 src/bnhtrade.Core/Model/Sku/Price/SkuPriceParameter.cs create mode 100644 src/bnhtrade.Core/Model/Stock/SkuTransaction.cs create mode 100644 src/bnhtrade.Core/Model/Stock/SkuTransactionType.cs rename src/bnhtrade.Core/Test/Account/{GetTaxInfo.cs => Account.cs} (80%) create mode 100644 src/bnhtrade.Core/Test/Export/Export.cs create mode 100644 src/bnhtrade.Core/Test/Sku/Sku.cs create mode 100644 src/bnhtrade.ScheduledTasks/packages.config diff --git a/build/bnhtrade.ComTypeLib.RegAsmInstall.bat b/build/bnhtrade.ComTypeLib.RegAsmInstall.bat index 1d9262b..7007419 100644 --- a/build/bnhtrade.ComTypeLib.RegAsmInstall.bat +++ b/build/bnhtrade.ComTypeLib.RegAsmInstall.bat @@ -2,13 +2,13 @@ @set dllpath=%batchpath% ::bnhtrade Database Client\bin\Release\ -@copy "%dllpath%bnhtrade.Core.dll" "%SYSTEMROOT%\SysWOW64\bnhtrade.Core.dll" +rem @copy "%dllpath%bnhtrade.Core.dll" "%SYSTEMROOT%\SysWOW64\bnhtrade.Core.dll" @copy "%dllpath%bnhtradeCOM.dll" "%SYSTEMROOT%\SysWOW64\bnhtradeCOM.dll" -@copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" +rem @copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" -@copy "%dllpath%bnhtrade.Core.dll" "%SYSTEMROOT%\System32\bnhtrade.Core.dll" +rem @copy "%dllpath%bnhtrade.Core.dll" "%SYSTEMROOT%\System32\bnhtrade.Core.dll" @copy "%dllpath%bnhtradeCOM.dll" "%SYSTEMROOT%\System32\bnhtradeCOM.dll" -@copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" +rem @copy "%dllpath%ABrain.AmazonMWS.dll" "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" @c: @cd\Windows\Microsoft.NET\Framework\v4.* diff --git a/build/bnhtrade.ComTypeLib.RegAsmUninstall.bat b/build/bnhtrade.ComTypeLib.RegAsmUninstall.bat index 13dc795..ececa7b 100644 --- a/build/bnhtrade.ComTypeLib.RegAsmUninstall.bat +++ b/build/bnhtrade.ComTypeLib.RegAsmUninstall.bat @@ -8,18 +8,18 @@ rem regasm.exe /u "%SYSTEMROOT%\System32\bnhtrade.Core.dll" regasm.exe /u "%SYSTEMROOT%\SysWOW64\bnhtradeCOM.dll" rem regasm.exe /u "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" cd -@del /q "%SYSTEMROOT%\SysWOW64\bnhtrade.Core.dll" +rem @del /q "%SYSTEMROOT%\SysWOW64\bnhtrade.Core.dll" rem @del /q "%SYSTEMROOT%\SysWOW64\bnhtrade.Core.tlb" @del /q "%SYSTEMROOT%\SysWOW64\bnhtradeCOM.dll" -@del /q "%SYSTEMROOT%\SysWOW64\bnhtradeCOM.tlb" -@del /q "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" +rem @del /q "%SYSTEMROOT%\SysWOW64\bnhtradeCOM.tlb" +rem @del /q "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.dll" rem @del /q "%SYSTEMROOT%\SysWOW64\ABrain.AmazonMWS.tlb" -@del /q "%SYSTEMROOT%\System32\bnhtrade.Core.dll" +rem @del /q "%SYSTEMROOT%\System32\bnhtrade.Core.dll" rem @del /q "%SYSTEMROOT%\System32\bnhtrade.Core.tlb" @del /q "%SYSTEMROOT%\System32\bnhtradeCOM.dll" -@del /q "%SYSTEMROOT%\System32\bnhtradeCOM.tlb" -@del /q "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" +rem @del /q "%SYSTEMROOT%\System32\bnhtradeCOM.tlb" +rem @del /q "%SYSTEMROOT%\System32\ABrain.AmazonMWS.dll" rem @del /q "%SYSTEMROOT%\System32\ABrain.AmazonMWS.tlb" @echo. diff --git a/src/bnhtrade.ComTypeLib/ILMerge.props b/src/bnhtrade.ComTypeLib/ILMerge.props new file mode 100644 index 0000000..b0fc9d2 --- /dev/null +++ b/src/bnhtrade.ComTypeLib/ILMerge.props @@ -0,0 +1,67 @@ + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/bnhtrade.ComTypeLib/ILMergeOrder.txt b/src/bnhtrade.ComTypeLib/ILMergeOrder.txt new file mode 100644 index 0000000..3fda7f5 --- /dev/null +++ b/src/bnhtrade.ComTypeLib/ILMergeOrder.txt @@ -0,0 +1,4 @@ +# this file contains the partial list of the merged assemblies in the merge order +# you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build +# and finetune merge order to your satisfaction + diff --git a/src/bnhtrade.ComTypeLib/Product/Product.cs b/src/bnhtrade.ComTypeLib/Product/Product.cs index f4460c4..47f52d3 100644 --- a/src/bnhtrade.ComTypeLib/Product/Product.cs +++ b/src/bnhtrade.ComTypeLib/Product/Product.cs @@ -64,22 +64,24 @@ namespace bnhtrade.ComTypeLib public string ProductCompetitivePriceGet(int productId, int conditionId, ConnectionCredential sqlConnCred) { - var request = new Core.Product.ProductQuery(); - (decimal? price, DateTime? priceDate) result = request.ProductCompetitivePriceGet(sqlConnCred.ConnectionString, productId, conditionId); - if (result.price == null || result.priceDate == null) + var compPrice = new Core.Logic.Product.GetCompetitivePrice(sqlConnCred.ConnectionString).Execute(productId, conditionId); + + if (compPrice == null) { return ""; } else { - DateTime priceDate2 = result.priceDate.Value; - return result.price.ToString() + ";" + priceDate2.ToOADate(); + return compPrice.Price + ";" + compPrice.PriceDatetime.ToOADate(); } } - public int ProductCompetitivePriceSet(int productId, int conditionId, [MarshalAs(UnmanagedType.Currency)] decimal price, bool isBuyBoxPrice, DateTime priceDate, ConnectionCredential sqlConnCred) + + public int ProductCompetitivePriceSet(int productId, int conditionId, [MarshalAs(UnmanagedType.Currency)] decimal price, bool isBuyBoxPrice, DateTime priceDateLocal, ConnectionCredential sqlConnCred) { - var request = new Core.Product.ProductQuery(); - return request.ProductCompetitivePriceSet(sqlConnCred.ConnectionString, productId, conditionId, price, isBuyBoxPrice, priceDate); + priceDateLocal = DateTime.SpecifyKind(priceDateLocal, DateTimeKind.Local); + + return new Core.Data.Database.Product.CreateCompetitivePrice(sqlConnCred.ConnectionString) + .ProductCompetitivePriceSet(productId, conditionId, price, isBuyBoxPrice, priceDateLocal); } public void ProductUpdateAmazonEstimateFee(ConnectionCredential sqlConnCred, object inputList) diff --git a/src/bnhtrade.ComTypeLib/Stock/Stock.cs b/src/bnhtrade.ComTypeLib/Stock/Stock.cs index 13e16c1..2bfd914 100644 --- a/src/bnhtrade.ComTypeLib/Stock/Stock.cs +++ b/src/bnhtrade.ComTypeLib/Stock/Stock.cs @@ -61,7 +61,7 @@ namespace bnhtrade.ComTypeLib { entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); - return Core.Stock.StockJournal.StockReallocateByStockId(sqlConnCred.ConnectionString, 4, stockId, quantity, debitStatusId, creditStatusId, entryDate); + return new Core.Logic.Stock.Reallocate(sqlConnCred.ConnectionString).StockReallocateByStockId(4, stockId, quantity, debitStatusId, creditStatusId, entryDate); } public void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId) @@ -71,10 +71,11 @@ namespace bnhtrade.ComTypeLib public object ReconcileStockTransactions(ConnectionCredential sqlConnCred) { - var request = new Core.Stock.StockReconciliation(); - var result = new Core.Stock.StockReconciliation.ReconcileStockTransactionsResult(); + //var request = new Core.Stock.StockReconciliation(); + //var result = new Core.Stock.StockReconciliation.ReconcileStockTransactionsResult(); - result = request.ReconcileStockTransactions(sqlConnCred.ConnectionString, false); + var result = new Core.Logic.Stock.SkuTransactionReconcile(sqlConnCred.ConnectionString); + result.ReconcileStockTransactions(false); //ReconcileStockTransactionsResult returnObject = new ReconcileStockTransactionsResult(); @@ -106,8 +107,8 @@ namespace bnhtrade.ComTypeLib object[] returnArray = new object[7]; returnArray[0] = result.ReconciliationComplete; returnArray[1] = result.ProgressMessage; - returnArray[2] = result.StockTransactionId; - returnArray[3] = result.StockTransactionTypeId; + returnArray[2] = result.CurrentTransactionId; + returnArray[3] = result.CurrentTransactionTypeId; returnArray[4] = result.LastItemDateTime; returnArray[5] = result.ItemsCompleted; returnArray[6] = result.ItemsRemaining; diff --git a/src/bnhtrade.ComTypeLib/app.config b/src/bnhtrade.ComTypeLib/app.config new file mode 100644 index 0000000..8d5ec5f --- /dev/null +++ b/src/bnhtrade.ComTypeLib/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/bnhtrade.ComTypeLib/bnhtrade.ComTypeLib.csproj b/src/bnhtrade.ComTypeLib/bnhtrade.ComTypeLib.csproj index 8e41b4a..c840d73 100644 --- a/src/bnhtrade.ComTypeLib/bnhtrade.ComTypeLib.csproj +++ b/src/bnhtrade.ComTypeLib/bnhtrade.ComTypeLib.csproj @@ -1,5 +1,7 @@  + + Debug @@ -13,6 +15,8 @@ 512 true + + true @@ -30,6 +34,7 @@ TRACE prompt 4 + true Always @@ -54,13 +59,20 @@ - + + + + + {339d7413-3da7-46ea-a55c-255a9a6b95eb} bnhtrade.Core + + + @@ -71,4 +83,13 @@ copy "$(SolutionDir)build\bnhtrade.ComTypeLib.RegAsmRefresh.bat" "$(TargetDir)bnhtrade.ComTypeLib.RegAsmRefresh.bat" copy "$(SolutionDir)build\bnhtrade.ComTypeLib.RegAsmUninstall.bat" "$(TargetDir)bnhtrade.ComTypeLib.RegAsmUninstall.bat" + + + 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}. + + + + + + \ No newline at end of file diff --git a/src/bnhtrade.ComTypeLib/packages.config b/src/bnhtrade.ComTypeLib/packages.config new file mode 100644 index 0000000..b5c3442 --- /dev/null +++ b/src/bnhtrade.ComTypeLib/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/bnhtrade.Core/App.config b/src/bnhtrade.Core/App.config index affa224..b035ea2 100644 --- a/src/bnhtrade.Core/App.config +++ b/src/bnhtrade.Core/App.config @@ -1,15 +1,15 @@ - + -
+
- + - + @@ -21,4 +21,12 @@ + + + + + + + + diff --git a/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs b/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs index 5bc8d77..f6cd6a6 100644 --- a/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs +++ b/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs @@ -8,12 +8,18 @@ namespace bnhtrade.Core.Data.AmazonMWS { public class CredentialMws { - public string merchantId { get { return "A3RUYNKLWWM5KW"; } } - public string marketPlaceId { get { return "A1F83G8C2ARO7P"; } } // Amazon.co.uk - public string accessKeyId { get { return "AKIAJU45WSYVINEN45UA"; } } - public string secretAccessKey { get { return "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"; } } - public string applicationName { get { return "bnhtrade.Core"; } } - public string applicationVersion { get { return "0.1"; } } - public string serviceURL { get { return "https://mws.amazonservices.co.uk"; } } + public string MerchantId { get { return "A3RUYNKLWWM5KW"; } } + + public string MarketPlaceIdUK { get { return "A1F83G8C2ARO7P"; } } // Amazon.co.uk + + public string AccessKeyId { get { return "AKIAJU45WSYVINEN45UA"; } } + + public string SecretAccessKey { get { return "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"; } } + + public string ApplicationName { get { return "bnhtrade.Core"; } } + + public string ApplicationVersion { get { return "0.1"; } } + + public string ServiceURL { get { return "https://mws.amazonservices.co.uk"; } } } } diff --git a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs index 71a30ef..3863061 100644 --- a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs +++ b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs @@ -27,7 +27,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound return LastUpdatedBefore != null; } - public List GetByAmazonShipmentId(string amazonShipmentId) + public List GetByAmazonShipmentId(string amazonShipmentId) { // checks if (amazonShipmentId.Length < 9) @@ -43,7 +43,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound return ListInboundShipmentItemsGet(request); } - public List GetByDates(DateTime lastUpdatedAfter, DateTime lastUpdatedBefore) + public List GetByDates(DateTime lastUpdatedAfter, DateTime lastUpdatedBefore) { //checks if (lastUpdatedAfter >= lastUpdatedBefore) @@ -61,7 +61,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound return ListInboundShipmentItemsGet(request); } - private List ListInboundShipmentItemsGet(ListInboundShipmentItemsRequest request) + private List ListInboundShipmentItemsGet(ListInboundShipmentItemsRequest request) { // variables int mwsPollFrequency = 500; @@ -72,7 +72,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound if (!request.IsSetSellerId()) { var cred = new AmazonMWS.CredentialMws(); - request.SellerId = cred.merchantId; + request.SellerId = cred.MerchantId; } // checks @@ -108,7 +108,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound } // create the return list - var returnList = new List(); + var returnList = new List(); // check a result was returned, return empty list on no results if (!result.IsSetItemData()) @@ -171,7 +171,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound // load data set into returnList foreach (var item in infoList) { - var returnItem = new Model.AmazonFBAInbound.ShipmentItemInfo(); + var returnItem = new Model.AmazonFba.ShipmentItemInfo(); returnItem.AmazonShipmentId = item.ShipmentId; returnItem.SKUNumber = item.SellerSKU; returnItem.AmazonFNSKU = item.FulfillmentNetworkSKU; diff --git a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs index 8d13c3b..7261236 100644 --- a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs +++ b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs @@ -14,31 +14,37 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound /// List of Shipment Status' to return. Default is all status' returned. /// public List ShipmentStatusList { get; set; } + /// /// List of Shipment Id to return. /// public List ShipmentIdList { get; set; } + public DateTime LastUpdatedAfter { get; set; } + public DateTime LastUpdatedBefore { get; set; } public bool IsSetShipmentStatusList() { return ShipmentStatusList != null; } + public bool IsSetShipmentIdList() { return ShipmentIdList != null; } + public bool IsSetLastUpdatedAfter() { return LastUpdatedAfter != null; } + public bool IsSetLastUpdatedBefore() { return LastUpdatedBefore != null; } - public List GetShipmentInfo() + public List GetShipmentInfo() { // variables int mwsPollFrequency = 500; // restore rate of two requests every second @@ -72,7 +78,7 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound var request = new ListInboundShipmentsRequest(); var cred = new AmazonMWS.CredentialMws(); - request.SellerId = cred.merchantId; + request.SellerId = cred.MerchantId; // add shipment status to request if (!IsSetShipmentStatusList() && !IsSetShipmentIdList()) @@ -204,12 +210,12 @@ namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound } // build return value - var returnItem = new List(); + var returnItem = new List(); //var lastUpdated = infoList. foreach( InboundShipmentInfo item in infoList) { - var listItem = new Core.Model.AmazonFBAInbound.ShipmentInfo(); - listItem.AmazonShipmentId = item.ShipmentId; + var listItem = new Core.Model.AmazonFba.ShipmentInfo(); + listItem.FbaShipmentId = item.ShipmentId; listItem.DestinationFulfillmentCenterId = item.DestinationFulfillmentCenterId; listItem.ShipmentName = item.ShipmentName; listItem.ShipmentStatus = item.ShipmentStatus; diff --git a/src/bnhtrade.Core/Data/AmazonMWS/Feeds/GetFeedSubmissions.cs b/src/bnhtrade.Core/Data/AmazonMWS/Feeds/GetFeedSubmissions.cs new file mode 100644 index 0000000..7b606e5 --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/Feeds/GetFeedSubmissions.cs @@ -0,0 +1,135 @@ +using MarketplaceWebService; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.AmazonMWS.Feeds +{ + public class GetFeedSubmissions + { + private Logic.Log.LogEvent logEvent = new Logic.Log.LogEvent(); + + public List FeedSubmissionIdList { get; set; } = new List(); + + public int MaxCount { get; set; } = 100; + + public List Invoke() + { + //build the request + var cred = new AmazonMWS.CredentialMws(); + var request = new MarketplaceWebService.Model.GetFeedSubmissionListRequest(); + request.MaxCount = MaxCount; + request.Merchant = cred.MerchantId; + + if (FeedSubmissionIdList.Any()) + { + var idList = new MarketplaceWebService.Model.IdList(); + idList.Id = FeedSubmissionIdList; + request.FeedSubmissionIdList = idList; + } + + string error = "GetFeedSubmissionList failed: "; + string errorLong = null; + int i = 0; + int loopMax = 100; + + try + { + var service = new Data.AmazonMWS.Service().MarketPlaceWeb; + + // set the return list + var feedInfoList = new List(); + + string nextToken = null; + while (i < loopMax) + { + i++; + try + { + if (nextToken == null) + { + var responseList = service.GetFeedSubmissionList(request); + if (responseList.IsSetGetFeedSubmissionListResult()) + { + var getFeedListResult = responseList.GetFeedSubmissionListResult; + feedInfoList = getFeedListResult.FeedSubmissionInfo; + if (getFeedListResult.HasNext) + { + nextToken = getFeedListResult.NextToken; + } + else + { + return feedInfoList; + } + } + else + { + errorLong = responseList.ToXML(); + throw new Exception("FeedSubmissionListResult was not set"); + } + if (nextToken == null) + break; + } + else + { + var requestToken = new MarketplaceWebService.Model.GetFeedSubmissionListByNextTokenRequest(); + requestToken.NextToken = nextToken; + requestToken.Merchant = cred.MerchantId; + + var responseList = service.GetFeedSubmissionListByNextToken(requestToken); + if (responseList.IsSetGetFeedSubmissionListByNextTokenResult()) + { + var getFeedListResult = responseList.GetFeedSubmissionListByNextTokenResult; + feedInfoList.AddRange(getFeedListResult.FeedSubmissionInfo); + if (getFeedListResult.HasNext) + { + nextToken = getFeedListResult.NextToken; + } + else + { + return feedInfoList; + } + } + else + { + errorLong = responseList.ToXML(); + throw new Exception("FeedSubmissionListResult was not set"); + } + } + } + catch (MarketplaceWebServiceException ex) when (ex.ErrorCode == "RequestThrottled") + { + if (nextToken == null) { MiscFunction.MwsThrottleWait(60); } // 10 intial requests, 1 restore every 45 seconds + else { MiscFunction.MwsThrottleWait(5); } // 30 intial requests, 1 restore every 2 seconds + } + catch (MarketplaceWebServiceException ex) + { + errorLong = "Caught Exception: " + ex.Message + + "\r\nResponse Status Code: " + ex.StatusCode + + "\r\nError Code: " + ex.ErrorCode + + "\r\nError Type: " + ex.ErrorType + + "\r\nRequest ID: " + ex.RequestId + + "\r\nResponseHeaderMetadata: " + ex.ResponseHeaderMetadata + + "\r\nXML:\r\n" + ex.XML; + + throw new Exception("MarketplaceWebServiceException"); + } + } + } + catch (Exception ex) + { + error = error + ex.Message; + } + + // should never get here + if (i == loopMax) + error += "Timeout"; + + logEvent.LogError(error, errorLong); + throw new Exception(error); + } + + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/Feeds/SubmitFeed.cs b/src/bnhtrade.Core/Data/AmazonMWS/Feeds/SubmitFeed.cs new file mode 100644 index 0000000..d160221 --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/Feeds/SubmitFeed.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MarketplaceWebService; +using bnhtrade.Core.Logic; + +namespace bnhtrade.Core.Data.AmazonMWS.Feeds +{ + public class SubmitFeed + { + private Logic.Log.LogEvent logEvent = new Logic.Log.LogEvent(); + + public bool FeedSubmissionRecived { get; set; } = false; + + public SubmitFeed(Model.Export.AmazonFeedSubmission feedSubmission) + { + FeedSubmissionRecived = false; + + var cred = new CredentialMws(); + var config = new MarketplaceWebService.MarketplaceWebServiceConfig(); + config.ServiceURL = cred.ServiceURL; + + + var marketPlaceList = new MarketplaceWebService.Model.IdList(); + marketPlaceList.Id = new List { cred.MarketPlaceIdUK }; + + var request = new MarketplaceWebService.Model.SubmitFeedRequest(); + request.MarketplaceIdList = marketPlaceList; + request.Merchant = cred.MerchantId; + request.FeedContent = feedSubmission.File.FileData; + request.FeedType = feedSubmission.FeedType; + request.ContentMD5 = feedSubmission.File.FileMD5base64; + request.FeedContent.Position = 0; + + var service = new Data.AmazonMWS.Service().MarketPlaceWeb; + + bool repeat = true; + var response = new MarketplaceWebService.Model.SubmitFeedResponse(); + + // try for a response + while (repeat) + { + try + { + response = service.SubmitFeed(request); + repeat = false; + } + catch (MarketplaceWebServiceException ex) when (ex.ErrorCode == "RequestThrottled") + { + MiscFunction.MwsThrottleWait(150); // 15 inital requests, restore 1 every 2 minutes + } + catch (MarketplaceWebService.MarketplaceWebServiceException ex) + { + string errorLong = "Caught Exception: " + ex.Message + Environment.NewLine + + "Response Status Code: " + ex.StatusCode + Environment.NewLine + + "Error Code: " + ex.ErrorCode + Environment.NewLine + + "Error Type: " + ex.ErrorType + Environment.NewLine + + "Request ID: " + ex.RequestId + Environment.NewLine + + "XML: " + Environment.NewLine + ex.XML + Environment.NewLine + + "ResponseHeaderMetadata: " + ex.ResponseHeaderMetadata + Environment.NewLine; + + logEvent.LogError("Unhandled MarketplaceWebServiceException while running InvokeSubmitFeed", errorLong); + throw new Exception("Unhandled MarketplaceWebServiceException while running InvokeSubmitFeed"); + } + } + + // test the response + if (response.IsSetSubmitFeedResult()) + { + MarketplaceWebService.Model.SubmitFeedResult submitFeedResult = response.SubmitFeedResult; + + if (submitFeedResult.IsSetFeedSubmissionInfo()) + { + MarketplaceWebService.Model.FeedSubmissionInfo feedSubmissionInfo = submitFeedResult.FeedSubmissionInfo; + if (feedSubmissionInfo.IsSetFeedSubmissionId()) + { + feedSubmission.FeedSubmissionId = feedSubmissionInfo.FeedSubmissionId; + FeedSubmissionRecived = true; + } + else + { + logEvent.LogError("Response from MWS SubmitFeed did not contain a 'FeedSubmissionId'", submitFeedResult.ToString()); + return; + } + if (feedSubmissionInfo.IsSetFeedProcessingStatus()) + { + feedSubmission.FeedProcessingStatus = feedSubmissionInfo.FeedProcessingStatus; + } + if (feedSubmissionInfo.IsSetCompletedProcessingDate()) + { + feedSubmission.CompletedProcessingDate = DateTime.SpecifyKind(feedSubmissionInfo.CompletedProcessingDate, DateTimeKind.Utc); + } + if (feedSubmissionInfo.IsSetStartedProcessingDate()) + { + feedSubmission.StartedProcessingDate = DateTime.SpecifyKind(feedSubmissionInfo.StartedProcessingDate, DateTimeKind.Utc); + } + if (feedSubmissionInfo.IsSetSubmittedDate()) + { + if (feedSubmissionInfo.SubmittedDate != null) + { + feedSubmission.SubmittedDate = DateTime.SpecifyKind(DateTime.Parse(feedSubmissionInfo.SubmittedDate), DateTimeKind.Utc); + } + } + } + else + { + logEvent.LogError("Response from MWS SubmitFeed did not contain a 'FeedSubmissionInfo'", response.ToXML()); + throw new Exception("Request FeedSubmissionInfo not set."); // no idea what to do here, what happened, has it been submitted? + } + } + else + { + logEvent.LogError("Response from MWS SubmitFeed did not contain a 'SubmitFeedResult'", response.ToXML()); + throw new Exception("Request SubmitFeedResult not set."); // no idea what to do here, what happened, has it been submitted? + } + } + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/Service.cs b/src/bnhtrade.Core/Data/AmazonMWS/Service.cs index 7eb0773..9b3442a 100644 --- a/src/bnhtrade.Core/Data/AmazonMWS/Service.cs +++ b/src/bnhtrade.Core/Data/AmazonMWS/Service.cs @@ -25,17 +25,16 @@ namespace bnhtrade.Core.Data.AmazonMWS { var cred = new AmazonMWS.CredentialMws(); - this.merchantId = cred.merchantId; - this.marketplaceId = cred.marketPlaceId; - this.accessKeyId = cred.accessKeyId; - this.secretAccessKey = cred.secretAccessKey; - this.applicationName = cred.applicationName; - this.applicationVersion = cred.applicationVersion; - this.serviceURL = cred.serviceURL; + this.merchantId = cred.MerchantId; + this.marketplaceId = cred.MarketPlaceIdUK; + this.accessKeyId = cred.AccessKeyId; + this.secretAccessKey = cred.SecretAccessKey; + this.applicationName = cred.ApplicationName; + this.applicationVersion = cred.ApplicationVersion; + this.serviceURL = cred.ServiceURL; } public MarketplaceWebService.MarketplaceWebService MarketPlaceWeb - { get { diff --git a/src/bnhtrade.Core/Data/Database/Account/CreateInvoiceLineItem.cs b/src/bnhtrade.Core/Data/Database/Account/CreateInvoiceLineItem.cs new file mode 100644 index 0000000..df00bda --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Account/CreateInvoiceLineItem.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Account +{ + public class CreateInvoiceLineItem : Connection + { + public CreateInvoiceLineItem(string sqlConnectionString) : base(sqlConnectionString) + { + } + + public int CreateDefault(string itemCode) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAccountInvoiceLineItem ( ItemName, ItemCode ) + OUTPUT INSERTED.AccountInvoiceLineItemID + VALUES ( @itemName, @itemCode ) + ", conn)) + { + cmd.Parameters.AddWithValue("@itemName", itemCode); + cmd.Parameters.AddWithValue("@itemCode", itemCode); + + object obj = cmd.ExecuteScalar(); + + if (obj == null || obj == DBNull.Value) + { + throw new Exception("Error inserting new defalt invoice line item into database"); + } + + return (int)obj; + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Account/ReadAccountCode.cs b/src/bnhtrade.Core/Data/Database/Account/ReadAccountCode.cs index 1e5fb86..0887af7 100644 --- a/src/bnhtrade.Core/Data/Database/Account/ReadAccountCode.cs +++ b/src/bnhtrade.Core/Data/Database/Account/ReadAccountCode.cs @@ -9,62 +9,34 @@ namespace bnhtrade.Core.Data.Database.Account { public class ReadAccountCode : Connection { - private bool allRetrived; - private Dictionary cache; - protected ReadAccountCode(string sqlConnectionString) : base(sqlConnectionString) + private Data.Database.WhereBuilder sqlWhere = new WhereBuilder(); + private List resultList; + + public ReadAccountCode(string sqlConnectionString) : base(sqlConnectionString) { - allRetrived = false; - cache = new Dictionary(); } - protected void ClearCache() + + public List All() { - allRetrived = false; - cache.Clear(); + Innit(); + return Execute(null, null); } - public List GetAll() + + public List ByAccountCode(List accountCodeList) { - if (allRetrived == false) + Innit(); + + if (accountCodeList == null || !accountCodeList.Any()) { - UpdateCache(-1); - allRetrived = true; + return resultList; } - var returnList = new List(); - foreach (var item in cache) - { - returnList.Add(item.Value); - } - - return returnList; + sqlWhere.In("tblAccountChartOf.AccountCode", accountCodeList, " WHERE "); + return Execute(sqlWhere.SqlWhereString, sqlWhere.ParameterList); } - public Model.Account.AccountCode GetByAccountCode(int accountCode) - { - if (cache.ContainsKey(accountCode)) - { - return cache[accountCode]; - } - else if (allRetrived) - { - return null; - } - else - { - UpdateCache(accountCode); - if (cache.ContainsKey(accountCode)) - { - return cache[accountCode]; - } - else - { - return null; - } - } - } - protected void UpdateCache(int accountCode = -1) - { - var dicCache = new Dictionary(); - bool whereClause = false; + private List Execute(string sqlWhere, Dictionary parameters) + { //build sql query string sqlString = @" SELECT tblAccountChartOf.AccountChartOfID @@ -74,13 +46,8 @@ namespace bnhtrade.Core.Data.Database.Account ,tblAccountChartOfType.AccountChartOfType ,tblAccountChartOfType.BasicType FROM tblAccountChartOf - INNER JOIN tblAccountChartOfType ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID"; - if (accountCode > -1) - { - whereClause = true; - sqlString = sqlString + @" - WHERE (((tblAccountChartOf.AccountCode) = @accountCode))"; - } + INNER JOIN tblAccountChartOfType ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID + " + sqlWhere; using (SqlConnection conn = new SqlConnection(sqlConnectionString)) { @@ -88,9 +55,12 @@ namespace bnhtrade.Core.Data.Database.Account using (SqlCommand cmd = new SqlCommand(sqlString, conn)) { - if (whereClause) + if (parameters != null) { - cmd.Parameters.AddWithValue("@accountCode", accountCode); + foreach (var parameter in parameters) + { + cmd.Parameters.AddWithValue(parameter.Key, parameter.Value); + } } using (SqlDataReader reader = cmd.ExecuteReader()) @@ -108,30 +78,19 @@ namespace bnhtrade.Core.Data.Database.Account result.Type = reader.GetString(4); result.BasicType = reader.GetString(5); - if (whereClause) - { - if (cache.ContainsKey(result.AccountCodeId)) - { - cache.Remove(result.AccountCodeId); - } - cache.Add(result.AccountCodeId, result); - } - else - { - dicCache.Add(result.AccountCodeId, result); - } + resultList.Add(result); } } + + return resultList; } } } - // update cache - if (!whereClause) - { - cache.Clear(); - allRetrived = true; - cache = dicCache; - } + } + + private void Innit() + { + resultList = new List(); } } } diff --git a/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItem.cs b/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItem.cs new file mode 100644 index 0000000..ae85e11 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItem.cs @@ -0,0 +1,113 @@ +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.Account +{ + public class ReadInvoiceLineItem : Connection + { + public ReadInvoiceLineItem(string sqlConnectionString) : base(sqlConnectionString) + { + Innit(); + } + + public Dictionary AccountCodeList { get; private set; } + + public Dictionary TaxCodeList { get; private set; } + + private void Innit() + { + AccountCodeList = new Dictionary(); + TaxCodeList = new Dictionary(); + } + + public Model.Account.InvoiceLineItem ByItemCode(string itemCode) + { + if (string.IsNullOrWhiteSpace(itemCode)) { return null; } + + var result = ByItemCode(new List{ itemCode }); + + if (!result.Any()) + { + return null; + } + else + { + return result[itemCode]; + } + } + + public Dictionary ByItemCode(List itemCodeList) + { + Innit(); + var resultList = new Dictionary(); + + if (itemCodeList == null || !itemCodeList.Any()) + { return resultList; } + + string sql = @" + SELECT tblAccountInvoiceLineItem.ItemCode + ,tblAccountInvoiceLineItem.ItemName + ,tblAccountInvoiceLineItem.ItemDescription + ,tblAccountInvoiceLineItem.IsNewReviewRequired + ,tblAccountInvoiceLineItem.InvoiceLineEntryEnable + ,tblAccountChartOf.AccountCode + ,tblAccountTaxCode.TaxCode + FROM tblAccountInvoiceLineItem + LEFT OUTER JOIN tblAccountTaxCode ON tblAccountInvoiceLineItem.AccountTaxCodeID_Default = tblAccountTaxCode.AccountTaxCodeID + LEFT OUTER JOIN tblAccountChartOf ON tblAccountInvoiceLineItem.AccountChartOfID_Default = tblAccountChartOf.AccountChartOfID + WHERE "; + + var whereBuilder = new WhereBuilder(); + whereBuilder.In("tblAccountInvoiceLineItem.ItemCode", itemCodeList); + sql += whereBuilder.SqlWhereString; + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + foreach (var param in whereBuilder.ParameterList) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + while (reader.Read()) + { + var result = new Model.Account.InvoiceLineItem(); + + result.ItemCode = reader.GetString(0); + result.Name = reader.GetString(1); + if (!reader.IsDBNull(2)) { result.Description = reader.GetString(2); } + result.IsNewReviewRequired = reader.GetBoolean(3); + result.InvoiceLineEntryEnabled = reader.GetBoolean(4); + + if (!reader.IsDBNull(5)) + { + AccountCodeList.Add(result.ItemCode, reader.GetInt32(5)); + } + if (!reader.IsDBNull(6)) + { + TaxCodeList.Add(result.ItemCode, reader.GetString(6)); + } + + resultList.Add(result.ItemCode, result); + } + } + + return resultList; + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItemCode.cs b/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItemCode.cs deleted file mode 100644 index 94708ff..0000000 --- a/src/bnhtrade.Core/Data/Database/Account/ReadInvoiceLineItemCode.cs +++ /dev/null @@ -1,148 +0,0 @@ -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.Account -{ - public class ReadInvoiceLineItemCode : Connection - { - public ReadInvoiceLineItemCode(string sqlConnectionString) : base (sqlConnectionString) - { - cacheLineItemByTablePk = new Dictionary(); - cacheTablePkByItemCode = new Dictionary(); - } - - private Dictionary cacheLineItemByTablePk; - private Dictionary cacheTablePkByItemCode; - - public bool InsertNewOnNoMatch { get; set; } = false; - - public string NewTypeTitle { get; } = "NEW TYPE"; - - public void CacheClear() - { - cacheLineItemByTablePk.Clear(); - cacheTablePkByItemCode.Clear(); - } - - private void CacheRemove(int tablePk) - { - if (cacheLineItemByTablePk.ContainsKey(tablePk)) - { - string itemCode = cacheLineItemByTablePk[tablePk].ItemCode; - cacheLineItemByTablePk.Remove(tablePk); - cacheTablePkByItemCode.Remove(itemCode); - } - } - - public void CacheRemove(string itemCode) - { - if (cacheTablePkByItemCode.ContainsKey(itemCode)) - { - CacheRemove(cacheTablePkByItemCode[itemCode]); - } - } - - private void CacheUpdate(int tablePk, Model.Account.InvoiceLineItem lineItem) - { - if (cacheLineItemByTablePk.ContainsKey(tablePk)) - { - CacheRemove(tablePk); - } - cacheLineItemByTablePk.Add(tablePk, lineItem); - cacheTablePkByItemCode.Add(lineItem.ItemCode, tablePk); - } - - public Model.Account.InvoiceLineItem ByItemCode(string itemCode, bool forceCacheUpdate = false) - { - // check cache - if (!forceCacheUpdate && cacheTablePkByItemCode.ContainsKey(itemCode)) - { - return cacheLineItemByTablePk[cacheTablePkByItemCode[itemCode]]; - } - - var returnObject = new Model.Account.InvoiceLineItem(); - returnObject.ItemCode = itemCode; - - using (TransactionScope scopeSupress = new TransactionScope(TransactionScopeOption.Suppress)) - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - using (SqlCommand cmd = new SqlCommand(@" - SELECT tblExportAccountInvoiceLineType.ExportAccountInvoiceLineTypeID - ,tblExportAccountInvoiceLineType.TypeTitle - ,tblExportAccountInvoiceLineType.TypeDescription - ,tblExportAccountInvoiceLineType.IsNewReviewRequired - ,tblExportAccountInvoiceLineType.InvoiceLineEntryEnable - ,tblAccountChartOf.AccountCode - ,tblAccountTaxCode.TaxCode - FROM ( - tblExportAccountInvoiceLineType LEFT JOIN tblAccountChartOf ON tblExportAccountInvoiceLineType.AccountChartOfID_Default = tblAccountChartOf.AccountChartOfID - ) - LEFT JOIN tblAccountTaxCode ON tblExportAccountInvoiceLineType.AccountTaxCodeID_Default = tblAccountTaxCode.AccountTaxCodeID - WHERE (((tblExportAccountInvoiceLineType.MatchString) = @matchString)) - ", conn)) - { - cmd.Parameters.AddWithValue("@matchString", returnObject.ItemCode); - - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - int tablePk = reader.GetInt32(0); - returnObject.Title = reader.GetString(1); - if (!reader.IsDBNull(2)) { returnObject.Description = reader.GetString(2); } - returnObject.IsNewReviewRequired = reader.GetBoolean(3); - returnObject.InvoiceLineEntryEnabled = reader.GetBoolean(4); - if (!reader.IsDBNull(5)) { returnObject.DefaultAccountCode = reader.GetInt32(5); } - if (!reader.IsDBNull(6)) { returnObject.DefaultTaxCode = reader.GetString(6); } - - // add to cache - CacheUpdate(tablePk, returnObject); - - // return object - return returnObject; - } - } - } - - // insert new and retrive new value, if required - if (InsertNewOnNoMatch) - { - int tablePk = 0; - returnObject.Title = NewTypeTitle; - returnObject.ItemCode = itemCode; - returnObject.IsNewReviewRequired = true; - - using (SqlCommand insertCmd = new SqlCommand(@" - INSERT INTO tblExportAccountInvoiceLineType ( TypeTitle, MatchString ) - OUTPUT INSERTED.ExportAccountInvoiceLineTypeID - VALUES ( @typeTitle, @matchString ) - ", conn)) - { - insertCmd.Parameters.AddWithValue("@typeTitle", returnObject.Title); - insertCmd.Parameters.AddWithValue("@matchString", returnObject.ItemCode); - - tablePk = (int)insertCmd.ExecuteScalar(); - - scopeSupress.Complete(); - } - // add to cache - CacheUpdate(tablePk, returnObject); - - // return object - return returnObject; - } - else - { - return null; - } - } - } - } -} diff --git a/src/bnhtrade.Core/Data/Database/Account/ReadTaxCode.cs b/src/bnhtrade.Core/Data/Database/Account/ReadTaxCode.cs index 7332673..61a8275 100644 --- a/src/bnhtrade.Core/Data/Database/Account/ReadTaxCode.cs +++ b/src/bnhtrade.Core/Data/Database/Account/ReadTaxCode.cs @@ -9,165 +9,32 @@ namespace bnhtrade.Core.Data.Database.Account { public class ReadTaxCode : Connection { - private bool allRetrived; - private Dictionary cache; + private Data.Database.WhereBuilder whereBuilder; + public ReadTaxCode(string sqlConnectionString) : base(sqlConnectionString) { - allRetrived = false; - cache = new Dictionary(); + whereBuilder = new WhereBuilder(); } - private void ClearCache() + + private List Execute(string sqlWhere, Dictionary parameters) { - allRetrived = false; - cache.Clear(); - } - public List GetAll() - { - if (allRetrived == false) - { - UpdateCache(null); - allRetrived = true; - } + var resultList = new List(); - var returnList = new List(); - foreach (var item in cache) - { - returnList.Add(item.Value); - } - - return returnList; - } - public Dictionary BySkuNumber(List skuNumberList) - { - // check input list for items - if (skuNumberList == null || !skuNumberList.Any()) - { - return null; - } - - // build SQL string - string sqlString = @" - SELECT - tblSku.skuSkuNumber, tblAccountTaxCode.TaxCode - FROM - tblAccountTaxCode INNER JOIN tblSku ON tblAccountTaxCode.AccountTaxCodeID = tblSku.AccountTaxCodeID - WHERE - "; - - var parameterValueList = new List>(); - foreach (var item in skuNumberList) - { - if (!string.IsNullOrWhiteSpace(item)) - { - int count = parameterValueList.Count; - var parameterValue = new Tuple("@parameter" + count, item); - parameterValueList.Add(parameterValue); - if (count == 0) - { - sqlString = sqlString + @" - skuSkuNumber = " + parameterValue.Item1; - } - else - { - sqlString = sqlString + @" - OR skuSkuNumber = " + parameterValue.Item1; - } - } - } - - if (parameterValueList.Count == 0) - { - return null; - } - - // execute query and build result list - var skuTaxCodeList = new List>(); - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - using (SqlCommand cmd = new SqlCommand(sqlString, conn)) - { - foreach (var item in parameterValueList) - { - cmd.Parameters.AddWithValue(item.Item1, item.Item2); - } - - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (!reader.HasRows) - { - return null; - } - - while (reader.Read()) - { - var skuTaxCode = new Tuple( - reader.GetString(0), - reader.GetString(1) - ); - skuTaxCodeList.Add(skuTaxCode); - } - } - } - - // build dictionary of skuNumber to TaxCodeInfo - var returnDictionary = new Dictionary(); - foreach (var item in skuTaxCodeList) - { - returnDictionary.Add(item.Item1, GetByTaxCodeId(item.Item2)); - } - - return returnDictionary; - } - } - public Model.Account.TaxCode GetByTaxCodeId(string taxCode) - { - if (cache.ContainsKey(taxCode)) - { - return cache[taxCode]; - } - else if (allRetrived) - { - return null; - } - else - { - UpdateCache(taxCode); - if (cache.ContainsKey(taxCode)) - { - return cache[taxCode]; - } - else - { - return null; - } - } - } - private void UpdateCache(string taxCode) - { - var dicCache = new Dictionary(); - - bool whereClause = false; //build sql query string sqlString = @" SELECT TaxCode - ,TaxRateName - ,TaxRateMultiplierNet - ,TaxRateMultiplierGross + ,TaxCodeName + ,TaxCodeDescription + ,TaxRatePercent + ,IsMarginScheme ,IsValidOnExpense ,IsVailidOnIncome - ,Description ,IsActive ,TaxType FROM tblAccountTaxCode"; - if (!string.IsNullOrWhiteSpace(taxCode)) - { - whereClause = true; - sqlString = sqlString + @" - WHERE TaxCode = @taxCode"; - } + + sqlString += sqlWhere; using (SqlConnection conn = new SqlConnection(sqlConnectionString)) { @@ -175,9 +42,9 @@ namespace bnhtrade.Core.Data.Database.Account using (SqlCommand cmd = new SqlCommand(sqlString, conn)) { - if (whereClause) + foreach (var paramter in parameters) { - cmd.Parameters.AddWithValue("@taxCode", taxCode); + cmd.Parameters.AddWithValue(paramter.Key, paramter.Value); } using (SqlDataReader reader = cmd.ExecuteReader()) @@ -186,42 +53,160 @@ namespace bnhtrade.Core.Data.Database.Account { while (reader.Read()) { - var result = new Model.Account.TaxCode(); + string taxCodeId = reader.GetString(0); + string name = reader.GetString(1); + string description = null; + if (!reader.IsDBNull(2)) { description = reader.GetString(2); } + decimal rate = reader.GetDecimal(3); + bool isMargin = reader.GetBoolean(4); + bool isValidOnExpense = reader.GetBoolean(5); + bool isValidOnIncome = reader.GetBoolean(6); + bool isActive = reader.GetBoolean(7); + string taxType = reader.GetString(8); - result.TaxCodeId = reader.GetString(0); - result.TaxRateTitle = reader.GetString(1); - result.NetAmountMultiplier = reader.GetDecimal(2); - result.GrossAmountMultiplier = reader.GetDecimal(3); - result.IsValidOnExpense = reader.GetBoolean(4); - result.IsValidOnIncome = reader.GetBoolean(5); - if (!reader.IsDBNull(6)) { result.TaxRateDescription = reader.GetString(6); } - result.IsActive = reader.GetBoolean(7); - result.TaxType = reader.GetString(8); + var result = new Model.Account.TaxCodeInfo( + taxCodeId, + name, + description, + rate, + isMargin, + isValidOnExpense, + isValidOnIncome, + taxType, + isActive); - if (whereClause) - { - if (cache.ContainsKey(result.TaxCodeId)) - { - cache.Remove(result.TaxCodeId); - } - cache.Add(result.TaxCodeId, result); - } - else - { - dicCache.Add(result.TaxCodeId, result); - } + resultList.Add(result); } } } } } - // update cache - if (!whereClause) + return resultList; + } + + public List GetByTaxCode(List taxcodeList) + { + var resultList = new List(); + + if (taxcodeList == null || !taxcodeList.Any()) { - cache.Clear(); - allRetrived = true; - cache = dicCache; + return resultList; } + + whereBuilder.Innit(); + whereBuilder.In("TaxCode", taxcodeList, "WHERE"); + + return Execute(whereBuilder.SqlWhereString, whereBuilder.ParameterList); + } + + public List GetAllActive() + { + string sqlWhere = @" + WHERE IsActive=@isActive;"; + var parameters = new Dictionary(); + parameters.Add("@isActive", true); + + return Execute(sqlWhere, parameters); + } + + public Dictionary GetTaxCodeBySkuNumber(List skuNumberList) + { + var resultList = new Dictionary(); + + if (skuNumberList == null || !skuNumberList.Any()) + { + return resultList; + } + + string sql = @" + SELECT tblSku.skuSkuNumber + ,tblAccountTaxCode.TaxCode + FROM tblSku + INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID "; + + whereBuilder.Innit(); + whereBuilder.In("tblSku.skuSkuNumber", skuNumberList, "WHERE"); + + sql += whereBuilder.SqlWhereString; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(sql, conn)) + { + foreach (var param in whereBuilder.ParameterList) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + return resultList; + } + + while (reader.Read()) + { + resultList.Add(reader.GetString(0), reader.GetString(1)); + } + } + } + } + + return resultList; + } + + public Dictionary GetTaxCodeByInvoiceLineItemCode(List lineItemCode) + { + var resultList = new Dictionary(); + + if (lineItemCode == null || !lineItemCode.Any()) + { + return resultList; + } + + string sql = @" + SELECT tblAccountInvoiceLineItem.ItemCode + ,tblAccountTaxCode.TaxCode + FROM tblAccountInvoiceLineItem + LEFT OUTER JOIN tblAccountTaxCode ON tblAccountInvoiceLineItem.AccountTaxCodeID_Default = tblAccountTaxCode.AccountTaxCodeID + "; + + whereBuilder.Innit(); + whereBuilder.In("tblAccountInvoiceLineItem.ItemCode", lineItemCode, "WHERE"); + + sql += whereBuilder.SqlWhereString; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(sql, conn)) + { + foreach (var param in whereBuilder.ParameterList) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + return resultList; + } + + while (reader.Read()) + { + if (reader.IsDBNull(1)) { resultList.Add(reader.GetString(0), null); } + else { resultList.Add(reader.GetString(0), reader.GetString(1)); } + } + } + } + } + + return resultList; } } } diff --git a/src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentInfo.cs b/src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentInfo.cs new file mode 100644 index 0000000..403fb24 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentInfo.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.AmazonShipment +{ + public class ReadShipmentInfo : Connection + { + private List shipmentIdList; + + public ReadShipmentInfo(string sqlConnectionString) : base(sqlConnectionString) + { + } + + /// + /// Return active shipments only. Default is false. + /// + public bool ReturnOnlyActiveShipments { get; set; } = false; + + private bool IsSetFbaShipmentIdList + { + get + { + if (FbaShipmentIdList == null || !FbaShipmentIdList.Any()) { return false; } + else { return true; } + } + } + + /// + /// Filter results by Amazon's shipment Id. + /// + private List FbaShipmentIdList + { + get { return shipmentIdList; } + set + { + if (value != null) + { + // clean list + shipmentIdList = new List(); + foreach (string item in value) + { + if (item.Length > 0) + { + shipmentIdList.Add(item); + } + } + if (!FbaShipmentIdList.Any()) + { + shipmentIdList = null; + throw new Exception("Invalid shipment Id set"); + } + } + } + } + + public Model.AmazonFba.ShipmentInfo HeaderByFbaShipmentId(string fbaShipmentId) + { + if (string.IsNullOrWhiteSpace(fbaShipmentId)) + { + return null; + } + var list = new List { fbaShipmentId }; + var result = HeaderByFbaShipmentId(list); + if (result.Any()) + { + return result[0]; + } + else + { + return null; + } + } + + public List HeaderByFbaShipmentId(List fbaShipmentIdList) + { + FbaShipmentIdList = fbaShipmentIdList; + + if (IsSetFbaShipmentIdList) + { + string sql = @" + AND tblAmazonShipment.ShipmentId IN @shipmentId "; + + var parameters = new DynamicParameters(); + parameters.Add("@shipmentId", FbaShipmentIdList); + + return HeaderInfo(sql, parameters); + } + else + { + return new List(); + } + } + + /// + /// Retrives table primary key 'AmazonShipmentID' for tblAmazonShipment + /// + /// Amazon's inbound FBA shipment Id. + /// Primary key or -1 if match isn't found. + private List HeaderInfo(string sqlWhere, DynamicParameters parameters) + { + // build the sql string + string sql = @" + SELECT tblAmazonShipment.AmazonShipmentID + ,tblAmazonShipment.ShipmentName + ,tblAmazonShipment.ShipmentId AS FbaShipmentId + ,tblAmazonShipment.CenterId + ,tblAmazonShipment.ShipmentStatus + ,tblAmazonShipment.LastUpdated + ,tblAmazonShipment.IsClosed + ,tblStockStatus.StockStatusID AS ShipmentStockStatusId + ,tblStockStatus.StockStatus AS ShipmentStockStatus + FROM tblAmazonShipment + LEFT OUTER JOIN tblStockStatus ON tblAmazonShipment.ShipmentStockStatusID = tblStockStatus.StockStatusID + WHERE 1=1 "; + + sql += sqlWhere; + + if (ReturnOnlyActiveShipments) + { + sql = sql + @" + AND IsClosed = 0"; + } + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var result = conn.Query(sql, parameters).ToList(); + + // set datetime kind + for (int i = 0; i < result.Count; i++) + { + if (result[i].IsSetLastUpdated()) + { + result[i].LastUpdated = DateTime.SpecifyKind(result[i].LastUpdated, DateTimeKind.Utc); + } + } + + return result; + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs b/src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentPrimaryKey.cs similarity index 94% rename from src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs rename to src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentPrimaryKey.cs index 044d03b..7a3fbff 100644 --- a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs +++ b/src/bnhtrade.Core/Data/Database/AmazonFba/ReadShipmentPrimaryKey.cs @@ -5,14 +5,18 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Data.Database.FBAInbound +namespace bnhtrade.Core.Data.Database.AmazonShipment { - public class GetShipmentPrimaryKey : Connection + public class ReadShipmentPrimaryKey : Connection { private bool enableCache = false; private Dictionary shipmentPKByAmazonShipmentIdDic; private Dictionary amazonShipmentIdByShipmentPKDic; - public GetShipmentPrimaryKey(string sqlConnectionString) : base(sqlConnectionString) { } + + public ReadShipmentPrimaryKey(string sqlConnectionString) : base(sqlConnectionString) + { + } + public bool CacheEnabled { get { return enableCache; } @@ -30,6 +34,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } } } + private void ClearCache() { if (CacheEnabled) @@ -38,6 +43,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound amazonShipmentIdByShipmentPKDic.Clear(); } } + private void DeleteCachedShipmentPK(int shipmentPrimaryKey) { if (CacheEnabled) @@ -50,6 +56,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } } } + /// /// Retrives table primary key 'AmazonShipmentID' for tblAmazonShipment /// @@ -99,6 +106,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound UpdateCache(shipmentPK, amazonShipmentId); return shipmentPK; } + private void UpdateCache(int shipmentPK, string amazonShipmentId) { if (CacheEnabled) diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs b/src/bnhtrade.Core/Data/Database/AmazonFba/SetShipmentInfo.cs similarity index 88% rename from src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs rename to src/bnhtrade.Core/Data/Database/AmazonFba/SetShipmentInfo.cs index 049e77b..c83f3ce 100644 --- a/src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs +++ b/src/bnhtrade.Core/Data/Database/AmazonFba/SetShipmentInfo.cs @@ -6,20 +6,24 @@ using System.Text; using System.Threading.Tasks; using System.Transactions; -namespace bnhtrade.Core.Data.Database.FBAInbound +namespace bnhtrade.Core.Data.Database.AmazonShipment { public class SetShipmentInfo : Connection { - private GetShipmentPrimaryKey getPK; - private Data.Database.SKU.GetSkuId skuIdLoopkup; - public SetShipmentInfo(string sqlConnectionString) : base(sqlConnectionString) { } - private GetShipmentPrimaryKey GetPK + private ReadShipmentPrimaryKey getPK; + private Data.Database.Sku.GetSkuId skuIdLoopkup; + + public SetShipmentInfo(string sqlConnectionString) : base(sqlConnectionString) + { + } + + private ReadShipmentPrimaryKey GetPK { get { if (getPK == null) { - getPK = new GetShipmentPrimaryKey(sqlConnectionString); + getPK = new ReadShipmentPrimaryKey(sqlConnectionString); } return getPK; } @@ -28,18 +32,20 @@ namespace bnhtrade.Core.Data.Database.FBAInbound getPK = value; } } - private Data.Database.SKU.GetSkuId SkuIdLoopkup + + private Data.Database.Sku.GetSkuId SkuIdLoopkup { get { if (skuIdLoopkup == null) { - skuIdLoopkup = new SKU.GetSkuId(sqlConnectionString); + skuIdLoopkup = new Sku.GetSkuId(sqlConnectionString); } return skuIdLoopkup; } } - public void Excecute(Model.AmazonFBAInbound.ShipmentInfo info) + + public void Excecute(Model.AmazonFba.ShipmentInfo info) { using (var scope = new TransactionScope()) { @@ -54,7 +60,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } // get tablePK - int shipmentPK = GetPK.ByAmazonShipmentId(info.AmazonShipmentId); + int shipmentPK = GetPK.ByAmazonShipmentId(info.FbaShipmentId); // add or update shipment header info if (shipmentPK == -1) @@ -106,7 +112,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } } - public void ExcecuteByList(List infoList) + public void ExcecuteByList(List infoList) { using (var scope = new TransactionScope()) { @@ -138,7 +144,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } } - private int InsertShipmentHeaderInfo(Model.AmazonFBAInbound.ShipmentInfo info) + private int InsertShipmentHeaderInfo(Model.AmazonFba.ShipmentInfo info) { if (!info.IsSetAll()) { @@ -149,7 +155,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound { conn.Open(); - if (GetPK.ByAmazonShipmentId(info.AmazonShipmentId) != -1) + if (GetPK.ByAmazonShipmentId(info.FbaShipmentId) != -1) { throw new Exception("Shipment insert failed, shipment with same Amazon Id already exists."); } @@ -189,10 +195,10 @@ namespace bnhtrade.Core.Data.Database.FBAInbound { cmd.Parameters.AddWithValue("@amazonShipmentCount", sequenceNumber); cmd.Parameters.AddWithValue("@shipmentName", info.ShipmentName); - cmd.Parameters.AddWithValue("@shipmentId", info.AmazonShipmentId); + cmd.Parameters.AddWithValue("@shipmentId", info.FbaShipmentId); cmd.Parameters.AddWithValue("@centerId", info.DestinationFulfillmentCenterId); cmd.Parameters.AddWithValue("@shipmentStatus", info.ShipmentStatus); - cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdatedUtc); + cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdated.ToUniversalTime()); cmd.Parameters.AddWithValue("@isClosed", info.ShipmentIsClosed); int tablePk = (int)cmd.ExecuteScalar(); @@ -203,9 +209,9 @@ namespace bnhtrade.Core.Data.Database.FBAInbound } } - private void UpdateShipmentHeaderInfo(Model.AmazonFBAInbound.ShipmentInfo info) + private void UpdateShipmentHeaderInfo(Model.AmazonFba.ShipmentInfo info) { - int tablePK = GetPK.ByAmazonShipmentId(info.AmazonShipmentId); + int tablePK = GetPK.ByAmazonShipmentId(info.FbaShipmentId); if (tablePK == -1) { throw new Exception("Shipment insert failed, shipment with same Amazon Id already exists."); @@ -229,7 +235,7 @@ namespace bnhtrade.Core.Data.Database.FBAInbound { cmd.Parameters.AddWithValue("@shipmentName", info.ShipmentName); cmd.Parameters.AddWithValue("@shipmentStatus", info.ShipmentStatus); - cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdatedUtc); + cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdated.ToUniversalTime()); cmd.Parameters.AddWithValue("@isClosed", info.ShipmentIsClosed); cmd.Parameters.AddWithValue("@tablePK", tablePK); diff --git a/src/bnhtrade.Core/Data/Database/Connection.cs b/src/bnhtrade.Core/Data/Database/Connection.cs index ec28d19..35ed544 100644 --- a/src/bnhtrade.Core/Data/Database/Connection.cs +++ b/src/bnhtrade.Core/Data/Database/Connection.cs @@ -10,11 +10,14 @@ namespace bnhtrade.Core.Data.Database public class Connection { protected readonly string sqlConnectionString; + public Connection(string sqlConnectionString) { // setup sql parameters - if (sqlConnectionString.Length == 0) - { throw new Exception("Zero length sql connectionstring passed"); } + if (string.IsNullOrWhiteSpace(sqlConnectionString)) + { + throw new Exception("Zero length sql connection string passed"); + } this.sqlConnectionString = sqlConnectionString; } } diff --git a/src/bnhtrade.Core/Data/Database/Constants.cs b/src/bnhtrade.Core/Data/Database/Constants.cs new file mode 100644 index 0000000..4b989b5 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Constants.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database +{ + public static class Constants + { + public static int GetProductConditionIdNew() + { + return 10; + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Export/CreateAmazonFeedSubmission.cs b/src/bnhtrade.Core/Data/Database/Export/CreateAmazonFeedSubmission.cs new file mode 100644 index 0000000..3b8e5d9 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Export/CreateAmazonFeedSubmission.cs @@ -0,0 +1,74 @@ +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.Export +{ + public class CreateAmazonFeedSubmission : Connection + { + public CreateAmazonFeedSubmission (string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public int Execute(string feedType, Model.Data.DatabaseFileStream fileStreamData) + { + // write to db + int id = 0; + var result = new Model.Export.AmazonFeedSubmission(); + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(@" + INSERT INTO tblExportAmazonFeedSubmission ( + FileData + ,FileExtention + ,FileSize + ,FileMD5base64 + ,ExportAmazonFeedSubmissionTypeID + ,ExportAmazonFeedSubmissionStatusID ) + OUTPUT + INSERTED.ExportAmazonFeedSubmissionID + ,INSERTED.FileGUID + VALUES ( + @fileData + ,@fileExtention + ,@fileSize + ,@fileMD5base64 + ,(SELECT ExportAmazonFeedSubmissionTypeID + FROM tblExportAmazonFeedSubmissionType + WHERE FeedType = @feedType ) + ,(SELECT ExportAmazonFeedSubmissionStatusID + FROM tblExportAmazonFeedSubmissionStatus + WHERE FeedProcessingStatus = 'New' ) + ) + ", conn)) + { + fileStreamData.FileData.Position = 0; + cmd.Parameters.AddWithValue("@fileData", fileStreamData.FileData.ToArray()); + cmd.Parameters.AddWithValue("@fileExtention", fileStreamData.FileExtention); + cmd.Parameters.AddWithValue("@fileSize", fileStreamData.FileSize); + cmd.Parameters.AddWithValue("@fileMD5base64", fileStreamData.FileMD5base64); + cmd.Parameters.AddWithValue("@feedType", feedType); + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + throw new Exception("Insert returned no rows"); + + reader.Read(); + id = reader.GetInt32(0); + fileStreamData.FileGUID = reader.GetGuid(1); + } + + return id; + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Export/CreateSalesInvoice.cs b/src/bnhtrade.Core/Data/Database/Export/CreateSalesInvoice.cs index 88919ae..9fdf55a 100644 --- a/src/bnhtrade.Core/Data/Database/Export/CreateSalesInvoice.cs +++ b/src/bnhtrade.Core/Data/Database/Export/CreateSalesInvoice.cs @@ -10,88 +10,15 @@ namespace bnhtrade.Core.Data.Database.Export { public class CreateSalesInvoice : Connection { - private Logic.Log.LogEvent log = new Logic.Log.LogEvent(); - public CreateSalesInvoice(string sqlConnectionString) : base(sqlConnectionString) { } - public void SaveInvoice(List invoiceList) + public void Execute(List invoiceList) { using (TransactionScope scope = new TransactionScope()) { - // get table pks for invoice type line and fill in invoice line details - var readItemCode = new Data.Database.Account.ReadInvoiceLineItemCode(sqlConnectionString); - readItemCode.InsertNewOnNoMatch = true; - bool newTypeFound = false; - bool newTypeTitleFound = false; - for (int i = 0; i < invoiceList.Count(); i++) - { - for (int j = 0; j < invoiceList[i].InvoiceLineList.Count(); j++) - { - var itemCodeInfo = readItemCode.ByItemCode(invoiceList[i].InvoiceLineList[j].ItemCode); - if (itemCodeInfo.InvoiceLineEntryEnabled == false) - { - invoiceList[i].InvoiceAmount = invoiceList[i].InvoiceAmount - invoiceList[i].InvoiceLineList[j].GrossTotalAmount; - invoiceList[i].InvoiceLineList.RemoveAt(j); - j = j - 1; - continue; - } - else if (itemCodeInfo.IsNewReviewRequired) - { - newTypeFound = true; - } - else - { - if (itemCodeInfo.Title == readItemCode.NewTypeTitle) - { newTypeTitleFound = true; } - else - { - invoiceList[i].InvoiceLineList[j].AccountCode = itemCodeInfo.DefaultAccountCode; - invoiceList[i].InvoiceLineList[j].TaxCode = itemCodeInfo.DefaultTaxCode; - invoiceList[i].InvoiceLineList[j].Description = itemCodeInfo.Title; - } - } - } - } - if (newTypeFound || newTypeTitleFound) - { - if (newTypeFound) - { - log.LogError("New line ItemCode found. Add item code default values and then try again."); - } - if (newTypeTitleFound) - { - log.LogError("ItemCode found with the incomplete title '" + readItemCode.NewTypeTitle + "'. Update title and then try again."); - } - return; - } - - // add temp invoice numbers to invoices - var sequence = new Programmability.Sequence(sqlConnectionString); - for (int i = 0; i < invoiceList.Count(); i++) - { - if (invoiceList[i].InvoiceNumberIsSet) - { - var log = new Logic.Log.LogEvent(); - log.LogError("Unexpected invoice number found."); - return; - } - invoiceList[i].InvoiceNumber = "_tmp" + sequence.GetNext("ExportTempInvoiceNumber").ToString("00000000"); - } - - // validate the list of invoices - var validateInvoice = new Logic.Account.ValidateSalesInvoice(); - validateInvoice.InvoiceLineDescriptionIsRequired = false; - validateInvoice.IsValidInvoice(invoiceList); - if (validateInvoice.ErrorListIsSet) - { - log.LogError("Invalid Sales invoice(s) found during Amazon Settlement process. See extended info.", validateInvoice.ErrorListToString()); - return; - } - validateInvoice = null; - using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) { sqlConn.Open(); @@ -134,7 +61,7 @@ namespace bnhtrade.Core.Data.Database.Export cmd.Parameters.AddWithValue("@currencyCode", invoiceList[i].InvoiceCurrencyCode); cmd.Parameters.AddWithValue("@markComplete", false); cmd.Parameters.AddWithValue("@invoiceNumber", invoiceList[i].InvoiceNumber); - cmd.Parameters.AddWithValue("@invoiceAmount", invoiceList[i].InvoiceAmount); + cmd.Parameters.AddWithValue("@invoiceAmount", invoiceList[i].InvoiceTotalAmount); invoiceId = (int)cmd.ExecuteScalar(); } @@ -145,7 +72,7 @@ namespace bnhtrade.Core.Data.Database.Export using (SqlCommand cmd = new SqlCommand(@" INSERT INTO tblExportAccountInvoiceLine ( ExportAccountInvoiceID - ,ExportAccountInvoiceLineTypeID + ,AccountInvoiceLineItemID ,NetAmount ,AccountChartOfID ,TaxAmount @@ -155,9 +82,9 @@ namespace bnhtrade.Core.Data.Database.Export VALUES ( @invoiceId ,( - SELECT ExportAccountInvoiceLineTypeID - FROM tblExportAccountInvoiceLineType - WHERE MatchString = @itemCode + SELECT AccountInvoiceLineItemID + FROM tblAccountInvoiceLineItem + WHERE ItemCode = @itemCode ) ,@netAmount ,( @@ -176,10 +103,10 @@ namespace bnhtrade.Core.Data.Database.Export { cmd.Parameters.AddWithValue("@invoiceID", invoiceId); cmd.Parameters.AddWithValue("@itemCode", invoiceList[i].InvoiceLineList[j].ItemCode); - cmd.Parameters.AddWithValue("@netAmount", invoiceList[i].InvoiceLineList[j].TotalNetAmount); - cmd.Parameters.AddWithValue("@accountCode", invoiceList[i].InvoiceLineList[j].AccountCode); + cmd.Parameters.AddWithValue("@netAmount", invoiceList[i].InvoiceLineList[j].UnitAmount); + cmd.Parameters.AddWithValue("@accountCode", invoiceList[i].InvoiceLineList[j].AccountCode.AccountCodeId); cmd.Parameters.AddWithValue("@taxAmount", invoiceList[i].InvoiceLineList[j].TaxAmount); - cmd.Parameters.AddWithValue("@taxCode", invoiceList[i].InvoiceLineList[j].TaxCode); + cmd.Parameters.AddWithValue("@taxCode", invoiceList[i].InvoiceLineList[j].TaxCode.TaxCode); int lineId = (int)cmd.ExecuteScalar(); } @@ -190,4 +117,4 @@ namespace bnhtrade.Core.Data.Database.Export } } } -} +} \ No newline at end of file diff --git a/src/bnhtrade.Core/Data/Database/Export/ReadAmazonFeedSubmission.cs b/src/bnhtrade.Core/Data/Database/Export/ReadAmazonFeedSubmission.cs new file mode 100644 index 0000000..4471699 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Export/ReadAmazonFeedSubmission.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Export +{ + public class ReadAmazonFeedSubmission : Connection + { + public ReadAmazonFeedSubmission(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public bool RetriveFile { get; set; } = false; + + public List ByAmazonFeedSubmissionId(List submissionId) + { + throw new NotImplementedException(); + } + + public List GetOpenFeeds() + { + string sql = @" + WHERE tblExportAmazonFeedSubmissionStatus.FeedComplete = @feedComplete + AND FeedSubmissionId IS NOT NULL;"; + + var parameters = new Dictionary { { "@feedComplete", false } }; + + return Execute(sql, parameters); + } + + private List Execute(string sqlWhereClause, Dictionary parameters) + { + var returnList = new List(); + + // build the sql string + string sql = @" + SELECT tblExportAmazonFeedSubmissionType.FeedType + ,tblExportAmazonFeedSubmission.FeedSubmissionId + ,tblExportAmazonFeedSubmissionStatus.FeedProcessingStatus + ,tblExportAmazonFeedSubmission.SubmittedDate + ,tblExportAmazonFeedSubmission.StartedProcessingDate + ,tblExportAmazonFeedSubmission.CompletedProcessingDate"; + + if (RetriveFile) + sql += @" + ,tblExportAmazonFeedSubmission.FileGUID + ,tblExportAmazonFeedSubmission.FileData + ,tblExportAmazonFeedSubmission.FileExtention + ,tblExportAmazonFeedSubmission.FileSize + ,tblExportAmazonFeedSubmission.FileMD5base64"; + + sql += @" + FROM tblExportAmazonFeedSubmission + INNER JOIN tblExportAmazonFeedSubmissionStatus + ON tblExportAmazonFeedSubmission.ExportAmazonFeedSubmissionStatusID + = tblExportAmazonFeedSubmissionStatus.ExportAmazonFeedSubmissionStatusID + INNER JOIN tblExportAmazonFeedSubmissionType + ON tblExportAmazonFeedSubmission.ExportAmazonFeedSubmissionTypeID + = tblExportAmazonFeedSubmissionType.ExportAmazonFeedSubmissionTypeID"; + + sql += sqlWhereClause; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(sql, conn)) + { + if (parameters != null || !parameters.Any()) + { + foreach(var parameter in parameters) + { + cmd.Parameters.AddWithValue(parameter.Key, parameter.Value); + } + } + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + return returnList; + + while (reader.Read()) + { + var submission = new Model.Export.AmazonFeedSubmission(); + + if (!reader.IsDBNull(0)) + submission.FeedType = reader.GetString(0); + if (!reader.IsDBNull(1)) + submission.FeedSubmissionId = reader.GetString(1); + if (!reader.IsDBNull(2)) + submission.FeedProcessingStatus = reader.GetString(2); + if (!reader.IsDBNull(3)) + submission.SubmittedDate = DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc); + if (!reader.IsDBNull(4)) + submission.StartedProcessingDate = DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc); + if (!reader.IsDBNull(5)) + submission.CompletedProcessingDate = DateTime.SpecifyKind(reader.GetDateTime(5), DateTimeKind.Utc); + + if (RetriveFile) + { + var file = new Model.Data.DatabaseFileStream(); + + file.FileGUID = reader.GetGuid(6); + byte[] fileData = (byte[])reader[7]; + file.FileData = new System.IO.MemoryStream(fileData); + file.FileExtention = reader.GetString(8); + file.FileSize = reader.GetInt32(9); + file.FileMD5base64 = reader.GetString(10); + + submission.File = file; + } + returnList.Add(submission); + } + } + } + } + return returnList; + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Export/UpdateAmazonFeedSubmission.cs b/src/bnhtrade.Core/Data/Database/Export/UpdateAmazonFeedSubmission.cs new file mode 100644 index 0000000..e7ed797 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Export/UpdateAmazonFeedSubmission.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Export +{ + public class UpdateAmazonFeedSubmission : Connection + { + public UpdateAmazonFeedSubmission(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public void AddAmazonFeedId(int exportAmazonFeedSubmissionID, string amazonFeedId) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(@" + SELECT COUNT (ExportAmazonFeedSubmissionID) + FROM tblExportAmazonFeedSubmission + WHERE FeedSubmissionId = @amazonFeedId", conn)) + { + cmd.Parameters.AddWithValue("@amazonFeedId", amazonFeedId); + + int i = (int)cmd.ExecuteScalar(); + + if (i > 0) + throw new Exception("Amazon submission Id already exists in table"); + } + + using (var cmd = new SqlCommand(@" + UPDATE tblExportAmazonFeedSubmission + SET FeedSubmissionId = @amazonFeedId + WHERE ExportAmazonFeedSubmissionID=@exportAmazonFeedSubmissionID", conn)) + { + cmd.Parameters.AddWithValue("@amazonFeedId", amazonFeedId); + cmd.Parameters.AddWithValue("@exportAmazonFeedSubmissionID", exportAmazonFeedSubmissionID); + + int i = cmd.ExecuteNonQuery(); + + if (i == 0) + throw new Exception("Error updating table."); + } + } + } + + public void UpdateStatusInfo(Model.Export.AmazonFeedSubmission feedSubmission) + { + UpdateStatusInfo(new List { feedSubmission }); + } + + public void UpdateStatusInfo(List feedSubmissionList) + { + if (feedSubmissionList == null || !feedSubmissionList.Any()) + return; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + for (int i = 0; i < feedSubmissionList.Count; i++) + { + if (!feedSubmissionList[i].IsSetFeedSubmissionId) + throw new Exception("Amazon Feed Submission Id required"); + + if (!feedSubmissionList[i].IsSetFeedProcessingStatus) + throw new Exception("Amazon Feed stauts required"); + + string sql = @" + UPDATE tblExportAmazonFeedSubmission + SET ExportAmazonFeedSubmissionStatusID = + (SELECT ExportAmazonFeedSubmissionStatusID + FROM tblExportAmazonFeedSubmissionStatus + WHERE FeedProcessingStatus = @feedProcessingStatus ) + ,SubmittedDate = @submittedDate + ,StartedProcessingDate = @startedProcessingDate + ,CompletedProcessingDate = @completedProcessingDate + WHERE FeedSubmissionId = @feedSubmissionId;"; + + using (var cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("@feedSubmissionId", feedSubmissionList[i].FeedSubmissionId); + cmd.Parameters.AddWithValue("@feedProcessingStatus", feedSubmissionList[i].FeedProcessingStatus); + + if (!feedSubmissionList[i].IsSetSubmittedDate) { cmd.Parameters.AddWithValue("@submittedDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@submittedDate", feedSubmissionList[i].SubmittedDate.ToUniversalTime()); } + + if (!feedSubmissionList[i].IsSetStartedProcessingDate) { cmd.Parameters.AddWithValue("@startedProcessingDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@startedProcessingDate", feedSubmissionList[i].StartedProcessingDate.ToUniversalTime()); } + + if (!feedSubmissionList[i].IsSetCompletedProcessingDate) { cmd.Parameters.AddWithValue("@completedProcessingDate", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@completedProcessingDate", feedSubmissionList[i].CompletedProcessingDate.ToUniversalTime()); } + + int j = cmd.ExecuteNonQuery(); + + if (j == 0) + throw new Exception("Error updating table."); + } + + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs b/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs deleted file mode 100644 index 9dd3ca6..0000000 --- a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Data.Database.FBAInbound -{ - public class GetShipmentHeaderInfo : Connection - { - private List shipmentIdList; - public GetShipmentHeaderInfo(string sqlConnectionString) : base(sqlConnectionString) { } - /// - /// Return active shipments only. Default is false. - /// - public bool ActiveShipments { get; set; } = false; - public bool IsSetActiveShipments { get { return true; } } - public bool IsSetShipmentIdList - { - get - { - if (ShipmentIdList == null || !ShipmentIdList.Any()) { return false; } - else { return true; } - } - } - /// - /// Filter results by Amazon's shipment Id. - /// - public List ShipmentIdList - { - get { return shipmentIdList; } - set - { - if (value != null) - { - // clean list - shipmentIdList = new List(); - foreach (string item in value) - { - if (item.Length > 0) - { - shipmentIdList.Add(item); - } - } - if (!ShipmentIdList.Any()) - { - shipmentIdList = null; - throw new Exception("Invalid shipment Id set"); - } - } - } - } - /// - /// Retrives table primary key 'AmazonShipmentID' for tblAmazonShipment - /// - /// Amazon's inbound FBA shipment Id. - /// Primary key or -1 if match isn't found. - public List Execute() - { - // build the sql string - int countShipId = 0; - string sqlString = @" - SELECT - AmazonShipmentID - ,ShipmentName - ,ShipmentId - ,CenterId - ,ShipmentStatus - ,LastUpdated - ,IsClosed - FROM - tblAmazonShipment - WHERE - 1 = 1"; - if (ActiveShipments) - { - sqlString = sqlString + @" - AND IsClosed = 0"; - } - var dicShipIdByParameterString = new Dictionary(); - if (IsSetShipmentIdList) - { - foreach (string item in ShipmentIdList) - { - countShipId = countShipId + 1; - string parameterString = "@shipmentId" + countShipId; - dicShipIdByParameterString.Add(parameterString, item); - if (countShipId == 1) - { - sqlString = sqlString + @" - AND ( ShipmentId = " + parameterString; - } - else - { - sqlString = sqlString + @" - OR ShipmentId = " + parameterString; - } - } - if (countShipId > 0) - { - sqlString = sqlString + " )"; - } - } - - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - using (SqlCommand cmd = new SqlCommand(sqlString, conn)) - { - // add shipId parameters - if (ShipmentIdList.Any()) - { - foreach (var item in dicShipIdByParameterString) - { - cmd.Parameters.AddWithValue(item.Key, item.Value); - } - } - - using (var reader = cmd.ExecuteReader()) - { - if (!reader.HasRows) - { - // no records - return null; - } - - var infoList = new List(); - while (reader.Read()) - { - var info = new Model.AmazonFBAInbound.ShipmentInfo(); - - int tablePK = reader.GetInt32(0); - info.ShipmentName = reader.GetString(1); - info.AmazonShipmentId = reader.GetString(2); - info.DestinationFulfillmentCenterId = reader.GetString(3); - info.ShipmentStatus = reader.GetString(4); - info.LastUpdatedUtc = reader.GetDateTime(5); - bool dbIsClosed = reader.GetBoolean(6); - - // db consistancy check - if (dbIsClosed != info.ShipmentIsClosed) - { - throw new Exception("Data inconstitancy in database: check shipment IsClosed where AmazonShipmentID=" + tablePK); - } - - // update cache - infoList.Add(info); - } - return infoList; - } - } - } - } - } -} diff --git a/src/bnhtrade.Core/Data/Database/Import/ReadFbaInventoryAge.cs b/src/bnhtrade.Core/Data/Database/Import/ReadFbaInventoryAge.cs new file mode 100644 index 0000000..d48d07f --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Import/ReadFbaInventoryAge.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Import +{ + public class ReadFbaInventoryAge : Connection + { + public ReadFbaInventoryAge(string sqlConnectionString): base(sqlConnectionString) + { + + } + + public (int MinAge, int MaxAge)? BySkuNumber(string skuNumber, string orderChannel) + { + int minAge = 0; + int maxAge = 0; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd03 = new SqlCommand(@" + SELECT [snapshot-date] + ,[inv-age-0-to-90-days] + ,[inv-age-91-to-180-days] + ,[inv-age-181-to-270-days] + ,[inv-age-271-to-365-days] + ,[inv-age-365-plus-days] + FROM tblImportFbaInventoryAgeReport + WHERE sku = @skuNumber AND marketplace = @orderChannel + ", conn)) + { + cmd03.Parameters.AddWithValue("@skuNumber", skuNumber); + cmd03.Parameters.AddWithValue("@orderChannel", orderChannel); + + using (var reader03 = cmd03.ExecuteReader()) + { + if (reader03.Read()) + { + // final min age + if (reader03.GetInt32(1) > 0) { minAge = 1; } + else + { + if (reader03.GetInt32(2) > 0) { minAge = 91; } + else + { + if (reader03.GetInt32(3) > 0) { minAge = 181; } + else + { + if (reader03.GetInt32(4) > 0) { minAge = 271; } + else + { + if (reader03.GetInt32(5) > 0) { minAge = 366; } + } + } + } + } + + //find max age + if (reader03.GetInt32(5) > 0) { maxAge = 2147483647; } + else + { + if (reader03.GetInt32(4) > 0) { maxAge = 365; } + else + { + if (reader03.GetInt32(3) > 0) { maxAge = 270; } + else + { + if (reader03.GetInt32(2) > 0) { maxAge = 180; } + else + { + if (reader03.GetInt32(1) > 0) { maxAge = 90; } + } + } + } + } + } + else + { + return null; + } + } + } + } + return (minAge, maxAge); + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Import/ReadFbaSaleShipment.cs b/src/bnhtrade.Core/Data/Database/Import/ReadFbaSaleShipment.cs new file mode 100644 index 0000000..4b8d91b --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Import/ReadFbaSaleShipment.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Import +{ + public class ReadFbaSaleShipment : Connection + { + public ReadFbaSaleShipment(string sqlConnectionString): base(sqlConnectionString) + { + + } + + public Dictionary GetMaxSalePrice(List skuNumber, int timePeriodDay) + { + var returnList = new Dictionary(); + + if (skuNumber == null || !skuNumber.Any()) + { + return returnList; + } + + string sql = @" + SELECT sku + ,Max(ISNULL([tblImportFbaSaleShipment].[item-price], 0) + ISNULL([tblImportFbaSaleShipment].[item-tax], 0)) AS Expr1 + FROM tblImportFbaSaleShipment + WHERE ( + (sku IN ("; + + for (int i = 0; i < skuNumber.Count; i++) + { + if (!(i + 1 == skuNumber.Count)) + { + sql += "@skuNumber" + i + ", "; + } + else + { + sql += "@skuNumber" + i + "))"; + } + } + + sql += @" + AND ((tblImportFbaSaleShipment.[shipment-date]) >= @shipDateFilter) + ) + GROUP BY sku;"; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + using (var cmd = new SqlCommand(sql, conn)) + { + for (int i = 0; i < skuNumber.Count; i++) + { + cmd.Parameters.AddWithValue("@skuNumber" + i, skuNumber[i]); + } + cmd.Parameters.AddWithValue("@shipDateFilter", DateTime.Today.AddDays(timePeriodDay * -1)); + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + return returnList; + } + + while (reader.Read()) + { + decimal price = reader.GetDecimal(1); + if (price > 0) + { + returnList.Add(reader.GetString(0), price); + } + } + } + } + } + return returnList; + } + + public Dictionary GetSaleCount(List skuNumber, DateTime periodStart, DateTime periodEnd) + { + var returnList = new Dictionary(); + + if (skuNumber == null || !skuNumber.Any()) + { + return returnList; + } + + string sql = @" + SELECT sku + ,Count(1) AS CountOfSku + FROM tblImportFbaSaleShipment + WHERE ( + (sku IN @skuNumber) + AND ( + (tblImportFbaSaleShipment.[shipment-date] >= @periodStart) + AND tblImportFbaSaleShipment.[shipment-date] <= @periodEnd + ) + ) + GROUP BY sku;"; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + var param = new DynamicParameters(); + param.Add("@skuNumber", skuNumber); + param.Add("@periodStart", periodStart.ToUniversalTime()); + param.Add("@periodEnd", periodEnd.ToUniversalTime()); + + return conn.Query(sql, param).ToDictionary( + row => (string)row.sku, + row => (int)row.CountOfSku); + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Product/CreateCompetitivePrice.cs b/src/bnhtrade.Core/Data/Database/Product/CreateCompetitivePrice.cs new file mode 100644 index 0000000..ad1a5fb --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Product/CreateCompetitivePrice.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Product +{ + public class CreateCompetitivePrice : Connection + { + public CreateCompetitivePrice(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public int ProductCompetitivePriceSet(int productId, int conditionId, decimal price, bool isBuyBoxPrice, DateTime? priceDate = null) + { + DateTime dt = new DateTime(); + if (priceDate == null || priceDate == default(DateTime)) + { + dt = DateTime.Now; + } + else + { + dt = (DateTime)priceDate; + } + + if (priceDate.Value.Kind == DateTimeKind.Unspecified) + { + throw new Exception("Unspecified DateTimeKind"); + } + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + UPDATE Table1 + SET ( + CompetitivePrice = @price + ,IsBuyBoxPrice = @isBuyBoxPrice + ) + OUTPUT INSERTED.ProductPriceCompetitiveID + WHERE ProductID = @productId + AND SkuConditionID = @conditionId + AND PriceDate = @priceDate + + IF @@ROWCOUNT = 0 + INSERT INTO tblProductPriceCompetitive ( + ProductID + ,SkuConditionID + ,CompetitivePrice + ,PriceDate + ,IsBuyBoxPrice + ) + OUTPUT INSERTED.ProductPriceCompetitiveID + VALUES ( + @productId + ,@conditionId + ,@price + ,@priceDate + ,@isBuyBoxPrice + );" + , sqlConn)) + { + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@price", price); + cmd.Parameters.AddWithValue("@priceDate", dt.ToUniversalTime()); + cmd.Parameters.AddWithValue("@isBuyBoxPrice", isBuyBoxPrice); + + return (int)cmd.ExecuteScalar(); + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Product/ReadCompetitivePrice.cs b/src/bnhtrade.Core/Data/Database/Product/ReadCompetitivePrice.cs new file mode 100644 index 0000000..21c24c8 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Product/ReadCompetitivePrice.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Product +{ + public class ReadCompetitivePrice : Connection + { + public ReadCompetitivePrice(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public List Execute(List<(int productId, int conditionId)> productIdAndConditionId) + { + int maxParameterCount = 2100; + int parameterPerPrice = 2; + int maxQuery = (int)decimal.Round(maxParameterCount / parameterPerPrice) - 1; + + var resultList = new List(); + + if (productIdAndConditionId == null) + { + return resultList; + } + + if (productIdAndConditionId.Count == 0) + { + return resultList; + } + + if (productIdAndConditionId.Count <= maxQuery) + { + return ExecuteSub(productIdAndConditionId); + } + else + { + var partialList = new List<(int productId, int conditionId)>(); + int queryCount = 0; + + for (int i= 0; i < productIdAndConditionId.Count; i++) + { + queryCount++; + partialList.Add(productIdAndConditionId[i]); + if (queryCount == maxQuery) + { + resultList.AddRange(ExecuteSub(partialList)); + partialList = new List<(int productId, int conditionId)>(); + queryCount = 0; + } + } + if (queryCount > 0) + { + resultList.AddRange(ExecuteSub(partialList)); + } + return resultList; + } + } + + private List ExecuteSub(List<(int productId, int conditionId)> productIdAndConditionId) + { + var resultList = new List(); + + // build the sql string + string sql = @" + SELECT t.CompetitivePrice, t.PriceDate, t.ProductID, t.SkuConditionID + FROM tblProductPriceCompetitive AS t INNER JOIN (SELECT ProductID, SkuConditionID, Max(PriceDate) AS MaxOfPriceDate + FROM tblProductPriceCompetitive "; + + for(int i = 0; i < productIdAndConditionId.Count; i++) + { + if (i == 0) + { + sql += @" + WHERE (ProductID=@productId" + i + " AND SkuConditionID=@conditionId" + i + ")"; + } + else + { + sql += @" + OR (ProductID=@productId" + i + " AND SkuConditionID=@conditionId" + i + ")"; + } + } + sql += @" + GROUP BY ProductID , SkuConditionID) AS a + ON (t.PriceDate = a.MaxOfPriceDate) + AND (t.ProductID = a.ProductID) + AND (t.SkuConditionID = a.SkuConditionID)"; + + + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + + using (SqlCommand cmd = new SqlCommand(sql, sqlConn)) + { + for (int i = 0; i < productIdAndConditionId.Count; i++) + { + cmd.Parameters.AddWithValue("@productId" + i, productIdAndConditionId[i].productId); + cmd.Parameters.AddWithValue("@conditionId" + i, productIdAndConditionId[i].conditionId); + } + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + return resultList; + } + + while (reader.Read()) + { + var result = new Model.Product.CompetitivePrice(); + + result.ConditionId = reader.GetInt32(3); + result.Price = reader.GetDecimal(0); + result.PriceDatetime = DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc); + result.ProductId = reader.GetInt32(2); + result.PriceIsEstimated = false; + + resultList.Add(result); + } + return resultList; + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs b/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs index 4662e03..60e4155 100644 --- a/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs +++ b/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Data.SqlClient; -namespace bnhtrade.Core.Data.Database.SKU +namespace bnhtrade.Core.Data.Database.Sku { public class GetSkuId { diff --git a/src/bnhtrade.Core/Data/Database/SKU/GetSku.cs b/src/bnhtrade.Core/Data/Database/SKU/GetSku.cs index 835b7fe..e610cbd 100644 --- a/src/bnhtrade.Core/Data/Database/SKU/GetSku.cs +++ b/src/bnhtrade.Core/Data/Database/SKU/GetSku.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Data.Database.SKU +namespace bnhtrade.Core.Data.Database.Sku { class GetSku : Connection { diff --git a/src/bnhtrade.Core/Data/Database/SKU/Price/CreatePricingDetail.cs b/src/bnhtrade.Core/Data/Database/SKU/Price/CreatePricingDetail.cs new file mode 100644 index 0000000..bed9aa4 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/SKU/Price/CreatePricingDetail.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Data.SqlClient; +using System.Transactions; + +namespace bnhtrade.Core.Data.Database.Sku.Price +{ + public class CreatePricingDetail : Connection + { + public CreatePricingDetail(string sqlConnectionString) : base(sqlConnectionString) + { + } + + public void Executue(List newInfo) + { + if (newInfo == null || !newInfo.Any()) + { return; } + + using (var scope = new TransactionScope()) + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // write new item to table + for (int i = 0; i < newInfo.Count(); i++) + { + string sql = @" + INSERT INTO tblSkuPriceType ( + SkuID + ,[OrderChannelID] + ,[PriceInfoTimeStamp] + ,[OrderChannelQuantity] + ,[UnitPurchaseCost] + ,[UnitMinPriceProfit] + ,[UnitMinPriceCost] + ,[UnitMinPriceDestory] + ,[InventoryAgeMin] + ,[InventoryAgeMax] + ,[SkuPriceTypeID] + ,[CompetitivePrice] + ,[MinPrice] + ,[MaxPrice] + ,[RepriceIncrement] + ,[ReviewRequired] + ) + VALUES ( + (SELECT skuSkuID FROM tblSku WHERE skuSkuNumber=@skuNumber) + ,(SELECT OrderChannelID FROM tblOrderChannel WHERE OrderChannel=@orderChannel) + ,@priceInfoTimeStamp + ,@orderChannelQuantity + ,@unitPurchaseCost + ,@unitMinPriceProfit + ,@unitMinPriceCost + ,@unitMinPriceDestory + ,@inventoryAgeMin + ,@inventoryAgeMax + ,@skuPriceTypeID + ,@competitivePrice + ,@minPrice + ,@maxPrice + ,@repriceIncrement + ,@reviewRequired + );"; + + using (var cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("@skuNumber", newInfo[i].SkuNumber); + cmd.Parameters.AddWithValue("@orderChannel", newInfo[i].OrderChannel); + cmd.Parameters.AddWithValue("@priceInfoTimeStamp", newInfo[i].PriceInfoTimeStamp); + cmd.Parameters.AddWithValue("@orderChannelQuantity", newInfo[i].OrderChannelQuantity); + cmd.Parameters.AddWithValue("@unitPurchaseCost", newInfo[i].UnitPurchaseCost); + cmd.Parameters.AddWithValue("@unitMinPriceProfit", newInfo[i].UnitMinPriceProfit); + cmd.Parameters.AddWithValue("@unitMinPriceCost", newInfo[i].UnitMinPriceCost); + cmd.Parameters.AddWithValue("@unitMinPriceDestory", newInfo[i].UnitMinPriceDestory); + cmd.Parameters.AddWithValue("@inventoryAgeMin", newInfo[i].InventoryAgeMin); + cmd.Parameters.AddWithValue("@inventoryAgeMax", newInfo[i].InventoryAgeMax); + cmd.Parameters.AddWithValue("@skuPriceTypeID", newInfo[i].PriceTypeId); + cmd.Parameters.AddWithValue("@competitivePrice", newInfo[i].CompetitivePrice); + cmd.Parameters.AddWithValue("@minPrice", newInfo[i].MinPrice); + cmd.Parameters.AddWithValue("@maxPrice", newInfo[i].MaxPrice); + cmd.Parameters.AddWithValue("@repriceIncrement", newInfo[i].RepriceIncrement); + cmd.Parameters.AddWithValue("@reviewRequired", newInfo[i].ReviewRequired); + + int j = cmd.ExecuteNonQuery(); + + if (j < 1) + { + throw new Exception("Failed database insert statement"); + } + } + } + scope.Complete(); + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/SKU/Price/ReadParameter.cs b/src/bnhtrade.Core/Data/Database/SKU/Price/ReadParameter.cs new file mode 100644 index 0000000..eb97d20 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/SKU/Price/ReadParameter.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Sku.Price +{ + public class ReadParameter : Connection + { + public ReadParameter(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public List Execute() + { + string stringSql = @" + SELECT + b.SkuID AS SkuId + ,b.SkuTotalQuantity AS TotalQuantity + ,b.SkuTotalCost AS TotalCost + ,b.SkuAvgUnitCost AS UnitCostAverage + ,tblSku.skuSkuNumber AS SkuNumber + ,tblSku.skuProductID AS ProductId + ,tblSku.skuSkuConditionID AS ConditionId + ,tblSku.AccountTaxCodeID AS TaxCodeId + ,tblProductCategory.ProfitMinPercent AS ProfitMargin + ,tblProductCategory.ProfitMinAmount AS PriceMinProfit + ,(tblAmazonFeeEstimate.ReferralFee / tblAmazonFeeEstimate.PriceToEstimateFeeListingPrice) As AgentFeeMargin + ,(tblAmazonFeeEstimate.VariableClosingFee + tblAmazonFeeEstimate.PerItemFee + tblAmazonFeeEstimate.FBAFee + tblAmazonFeeEstimate.OtherFee_Exception) AS AgentFeeFixed + ,tblAccountTaxCode.TaxRateMultiplierGross AS VatMargin + ,tblAccountTaxCode.TaxRateName AS TaxRateName + ,tblSkuCondition.IsFixedPrice AS IsFixedPrice + ,tblSkuCondition.CompetitivePriceMultiplierNew + FROM + ((((( + SELECT + a.SkuID, + Sum(a.SumOfQuantity) AS SkuTotalQuantity, + Sum(a.QuanityTimesUnitCost) AS SkuTotalCost, + Sum(a.QuanityTimesUnitCost)/Sum(a.SumOfQuantity) AS SkuAvgUnitCost + FROM + ( + SELECT + tblStock.SkuID, + Sum(tblStockJournalPost.Quantity) AS SumOfQuantity, + tblStockJournal.StockID, tblAccountStockCost.AmountUnit, + Sum([tblStockJournalPost].[Quantity])*[tblAccountStockCost].[AmountUnit] AS QuanityTimesUnitCost + FROM + (((tblStockJournalPost + INNER JOIN tblStockStatus + ON tblStockJournalPost.StockStatusID = tblStockStatus.StockStatusID) + INNER JOIN tblStockJournal ON tblStockJournalPost.StockJournalID = tblStockJournal.StockJournalID) + INNER JOIN tblAccountStockCost ON tblStockJournal.StockID = tblAccountStockCost.StockID) + INNER JOIN tblStock ON tblAccountStockCost.StockID = tblStock.StockID + WHERE + tblStockStatus.StockStatusTypeID=3 + OR tblStockStatus.StockStatusTypeID=4 + GROUP BY + tblStockJournal.StockID, + tblAccountStockCost.AmountUnit, + tblStock.SkuID + HAVING + Sum(tblStockJournalPost.Quantity)>0 + ) a + GROUP BY + a.SkuID + ) b + INNER JOIN tblSku ON b.SkuID = tblSku.skuSkuID) + INNER JOIN tblProduct ON tblSku.skuProductID = tblProduct.prdProductID) + LEFT JOIN tblAmazonFeeEstimate ON tblProduct.prdProductID = tblAmazonFeeEstimate.ProductIdentifier ) + INNER JOIN tblProductCategory ON tblProduct.ProductCategoryID = tblProductCategory.ProductCategoryID) + INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID + INNER JOIN tblSkuCondition ON tblSku.skuSkuConditionID = tblSkuCondition.scnSkuConditionID + "; + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var invPricing = conn.Query(stringSql).ToList(); + + if (invPricing != null || invPricing.Any()) + { + return invPricing; + } + else + { + return null; + } + } + } + } +} + diff --git a/src/bnhtrade.Core/Data/Database/SKU/Price/ReadPricingDetail.cs b/src/bnhtrade.Core/Data/Database/SKU/Price/ReadPricingDetail.cs new file mode 100644 index 0000000..3419127 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/SKU/Price/ReadPricingDetail.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Sku.Price +{ + public class ReadPricingDetail : Connection + { + public ReadPricingDetail(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public Dictionary ReadDictionary(List skuNumberList, string orderChannel) + { + var dic = new Dictionary(); + var list = Read(skuNumberList, orderChannel); + + for (int i = 0; i < list.Count; i++) + { + dic.Add(list[i].SkuNumber, list[i]); + } + return dic; + } + + public List Read(List skuNumberList, string orderChannel) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + string sql = @" + SELECT tblSku.skuSkuNumber AS SkuNumber + ,tblOrderChannel.OrderChannel + ,tblSkuPrice.PriceInfoTimeStamp + ,tblSkuPrice.OrderChannelQuantity + ,tblSkuPrice.UnitPurchaseCost + ,tblSkuPrice.UnitMinPriceProfit + ,tblSkuPrice.UnitMinPriceCost + ,tblSkuPrice.UnitMinPriceDestory + ,tblSkuPrice.InventoryAgeMin + ,tblSkuPrice.InventoryAgeMax + ,tblSkuPrice.CompetitivePrice + ,tblSkuPrice.MinPrice + ,tblSkuPrice.MaxPrice + ,tblSkuPrice.RepriceIncrement + ,tblSkuPrice.ReviewRequired + ,tblSkuPriceType.SkuPriceTypeID + ,tblSkuPriceType.TypeTitle + FROM tblSkuPrice + INNER JOIN tblSkuPriceType ON tblSkuPrice.SkuPriceTypeID = tblSkuPriceType.SkuPriceTypeID + INNER JOIN tblSku ON tblSkuPrice.SkuID = tblSku.skuSkuID + INNER JOIN tblOrderChannel ON tblSkuPrice.OrderChannelID = tblOrderChannel.OrderChannelID + WHERE tblSku.skuSkuNumber IN @skuNumber + AND (tblOrderChannel.OrderChannel = @orderChannel);"; + + var parameters = new DynamicParameters(); + parameters.Add("@skuNumber", skuNumberList); + parameters.Add("@orderChannel", orderChannel); + + return conn.Query(sql, parameters).ToList(); + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/SKU/ReadSkuConditionInfo.cs b/src/bnhtrade.Core/Data/Database/SKU/ReadSkuConditionInfo.cs new file mode 100644 index 0000000..e0e2ad3 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/SKU/ReadSkuConditionInfo.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Sku +{ + public class ReadSkuConditionInfo : Connection + { + public ReadSkuConditionInfo(string sqlConnectionString): base(sqlConnectionString) + { + + } + + public List Read(List conditionIdList) + { + string sql = @" + SELECT scnSkuConditionID AS SkuConditionId + ,scnTitleShort AS TitleShort + ,scnSkuNumberSuffix AS SkuConditionNumber + ,BaseType AS AmazonBaseType + ,IsFixedPrice + ,CompetitivePriceMultiplierNew AS CompetitivePriceMultiplier + ,scnRepricerStrategy AS RepricerStrategy + ,scnAmazonIdentifier AS AmazonIdentifier + ,scnConditionNoteDefault AS ConditionNoteDefault + ,scnDescription AS Description + FROM tblSkuCondition"; + + if (conditionIdList != null || !conditionIdList.Any()) + { + sql += @" + WHERE scnSkuConditionID IN @conditionIdList + "; + } + + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var paramter = new DynamicParameters(); + paramter.Add("@conditionIdList", conditionIdList); + + return conn.Query(sql, paramter).ToList(); + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Stock/CreateSkuTransaction.cs b/src/bnhtrade.Core/Data/Database/Stock/CreateSkuTransaction.cs new file mode 100644 index 0000000..2a7b9e0 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Stock/CreateSkuTransaction.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Stock +{ + public class CreateSkuTransaction : Connection + { + public CreateSkuTransaction(string sqlConnectionString) : base(sqlConnectionString) + { + } + + public void Create(Model.Stock.SkuTransaction skuTransaction) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblStockSkuTransaction ( + TransactionDate + ,StockSkuTransactionTypeID + ,ForeignKey + ,Reference + ,Detail + ,SkuID + ,Quantity + ,IsProcessed + ,StockJournalID + ) + OUTPUT INSERTED.StockSkuTransactionID + VALUES ( + @transactionDate + ,@stockSkuTransactionTypeID + ,@foreignKey + ,@reference + ,@Detail + ,( + SELECT skuSkuID + FROM tblSku + WHERE skuSkuNumber = @skuNumber + ) + ,@quantity + ,@isProcessed + ,@stockJournalID + ) + ", conn)) + { + cmd.Parameters.AddWithValue("@transactionDate", skuTransaction.TransactionDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@stockSkuTransactionTypeID", skuTransaction.SkuTransactionTypeId); + if (!skuTransaction.IsSetForeignKey) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@foreignKey", skuTransaction.ForeignKey); } + if (!skuTransaction.IsSetReference) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reference", skuTransaction.Reference); } + if (!skuTransaction.IsSetDetail) { 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); } + + object obj = cmd.ExecuteScalar(); + + if (obj == null || obj == DBNull.Value) + { + throw new Exception("Sku Reconcile Transaction insert failed"); + } + + skuTransaction.SkuTransactionId = (int)obj; + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Stock/DeleteSkuTransaction.cs b/src/bnhtrade.Core/Data/Database/Stock/DeleteSkuTransaction.cs new file mode 100644 index 0000000..fb2fa37 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Stock/DeleteSkuTransaction.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Stock +{ + public class DeleteSkuTransaction : Connection + { + public DeleteSkuTransaction (string sqlConnectionString): base(sqlConnectionString) + { + } + + public void ByTransactionId(int skuReconcileId) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM tblStockSkuTransaction WHERE StockSkuTransactionID = @transactionId + ", conn)) + { + cmd.Parameters.AddWithValue("@transactionId", skuReconcileId); + + if (cmd.ExecuteNonQuery() < 1) + { + throw new Exception("Delete sku transaction effected no records"); + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransaction.cs b/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransaction.cs new file mode 100644 index 0000000..189f776 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransaction.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Stock +{ + public class ReadSkuTransaction : Connection + { + public ReadSkuTransaction(string sqlConnectionString) : base(sqlConnectionString) + { + + } + + public int? GetJournalId(int skuTransactionId) + { + using (var conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (var cmd = new SqlCommand(@" + SELECT StockJournalID FROM tblStockSkuTransaction WHERE StockSkuTransactionID=@transactionId + ", conn)) + { + cmd.Parameters.AddWithValue("@transactionId", skuTransactionId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null || obj == DBNull.Value) + { + return null; + } + else + { + return (int)obj; + } + } + } + } + + public List GetUnreconciled() + { + // order by stocktransId desc = Amazon reports are listed in datetime ASC order, some reports have date only, + // however I have reason to believe these are in time order. + // Adding this means they at least get processed in the correct order (maybe)! + string sqlWhere = @" + WHERE tblStockSkuTransaction.IsProcessed = 0 + AND ( + tblStockSkuTransactionType.StockJournalEntryEnabled = 1 + OR tblStockSkuTransactionType.IsNewReviewRequired = 1 + ) "; + + return Read(sqlWhere, new DynamicParameters()); + } + + private List Read(string sqlWhere, DynamicParameters parameters) + { + var resultList = new List(); + + string sql = @" + SELECT tblStockSkuTransaction.StockSkuTransactionID AS SkuTransactionId + ,tblStockSkuTransaction.TransactionDate + ,tblStockSkuTransaction.StockSkuTransactionTypeID AS SkuTransactionTypeId + ,tblStockSkuTransaction.ForeignKey + ,tblStockSkuTransaction.Reference + ,tblStockSkuTransaction.Detail + ,tblStockSkuTransaction.Quantity + ,tblStockSkuTransaction.IsProcessed + ,tblStockSkuTransaction.StockJournalID AS StockJournalId + ,tblStockSkuTransactionType.TypeTitle AS SkuTransactionTypeName + ,tblSku.skuSkuNumber AS SkuNumber + ,tblStockSkuTransaction.SkuID + FROM tblStockSkuTransaction + INNER JOIN tblStockSkuTransactionType ON tblStockSkuTransaction.StockSkuTransactionTypeID = tblStockSkuTransactionType.StockSkuTransactionTypeID + INNER JOIN tblSku ON tblStockSkuTransaction.SkuID = tblSku.skuSkuID "; + + sql += sqlWhere; + + sql += @" + ORDER BY tblStockSkuTransaction.TransactionDate ASC, tblStockSkuTransaction.StockSkuTransactionID DESC;"; + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + resultList = conn.Query(sql, parameters).ToList(); + } + + // set datetime kind + for (int i = 0; i < resultList.Count; i++) + { + if (resultList[i].IsSetTransactionDate) + { + resultList[i].TransactionDate = DateTime.SpecifyKind(resultList[i].TransactionDate, DateTimeKind.Utc); + } + } + + return resultList; + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransactionType.cs b/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransactionType.cs new file mode 100644 index 0000000..58d0f43 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Stock/ReadSkuTransactionType.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; + +namespace bnhtrade.Core.Data.Database.Stock +{ + public class ReadSkuTransactionType : Connection + { + public ReadSkuTransactionType(string sqlConnectionString) : base(sqlConnectionString) + { + } + + /// + /// Depriciated, delete when not required by other code + /// + /// + /// + /// + public int GetTypeId(string typeCode) + { + /* GetStockTransactionTypeId return meanings + * >0 use the as the TypeId when inserting transaction + * 0 Skip transpose, type doesn't exist or is new (not reviewed yet) + * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ + + // old optional parameters + // , bool onNewReturnId = false, bool onNewDisableInsert = false + + if (typeCode.Length == 0) + { + throw new Exception("Empty match string passed to method"); + } + using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) + { + sqlConn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT + StockSkuTransactionTypeID, + IsNewReviewRequired, + TransactionImportEnabled + FROM + tblStockSkuTransactionType + WHERE + TypeCode=@typeCode; + ", sqlConn)) + { + cmd.Parameters.AddWithValue("@typeCode", typeCode); + + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + int index01 = reader.GetOrdinal("StockSkuTransactionTypeID"); + int index02 = reader.GetOrdinal("IsNewReviewRequired"); + int index03 = reader.GetOrdinal("TransactionImportEnabled"); + + int transactionTypeId = reader.GetInt32(index01); + bool isNew = reader.GetBoolean(index02); + bool? importEnabled = reader[index03] as bool? ?? null; // column can be null + + if (isNew == true || importEnabled == null) + { + // return 0 and 'skip' item + return 0; + } + else if (importEnabled == false) + { + // mark IsProcessed=true and leave transactionId=null + return -1; + } + else if (transactionTypeId > 0) + { + + return transactionTypeId; + } + else + { + throw new Exception("Sku TransactionTypeId lookup method failed, is one of the 'enabled' boolean on table set to null?"); + } + } + else + { + return 0; + } + } + } + } + } + + private List Execute(string sqlWhere, DynamicParameters param) + { + string sql = @" + SELECT tblStockSkuTransactionType.StockSkuTransactionTypeID AS TypeId + ,tblStockSkuTransactionType.TypeName + ,tblStockSkuTransactionType.TypeCode + ,tblStockSkuTransactionType.TypeDescription + ,tblStockSkuTransactionType.StockJournalTypeID + ,tblStockSkuTransactionType.TransactionForeignKeyName + ,tblStockSkuTransactionType.TransactionReferenceType + ,tblStockSkuTransactionType.IsNewReviewRequired + ,tblStockSkuTransactionType.TransactionImportEnabled + ,tblStockSkuTransactionType.StockJournalEntryEnabled + ,tblStockSkuTransactionType.DebitStockStatusID + ,tblStockSkuTransactionType.CreditStockStatusID + ,tblStockSkuTransactionType.StatusBalanceCheckRequired + ,tblStockSkuTransactionType.FilterStockOnDateTime + ,tblStockSkuTransactionType.FirstInFirstOut + ,tblStockSkuTransactionType.RecordCreated + ,CreditStatus.StockStatus AS CreditStockStatus + ,DebitStatus.StockStatus AS DebitStockStatus + FROM tblStockStatus AS DebitStatus + RIGHT OUTER JOIN tblStockSkuTransactionType ON DebitStatus.StockStatusID = tblStockSkuTransactionType.DebitStockStatusID + LEFT OUTER JOIN tblStockStatus AS CreditStatus ON tblStockSkuTransactionType.CreditStockStatusID = CreditStatus.StockStatusID + "; + + sql += sqlWhere; + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + return conn.Query(sql, param).ToList(); + } + } + + public List ByTypeCode(List typeCode) + { + string sqlWhere = @" + WHERE TypeCode IN @typeCode "; + + var param = new DynamicParameters(); + param.Add("@typeCode", typeCode); + + return Execute(sqlWhere, param); + } + + public List ByTypeName(List typeName) + { + string sqlWhere = @" + WHERE TypeName IN @typeName "; + + var param = new DynamicParameters(); + param.Add("@typeName", typeName); + + return Execute(sqlWhere, param); + } + + } +} diff --git a/src/bnhtrade.Core/Data/Database/Stock/UpdateSkuTransaction.cs b/src/bnhtrade.Core/Data/Database/Stock/UpdateSkuTransaction.cs new file mode 100644 index 0000000..ffcade3 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Stock/UpdateSkuTransaction.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.Stock +{ + public class UpdateSkuTransaction : Connection + { + private string err = "Database UpdateSkuTransaction: "; + + public UpdateSkuTransaction(string sqlConnectionString) : base(sqlConnectionString) + { + } + + 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"); + } + } + } + } + + /// + /// Update the StockJournalID field. Will also set the IsProcessed value base on input. + /// + /// Sku Transaction Id + /// Stock Journal Id or null to unset + 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"); + } + } + } + } + + /// + /// Update the StockJournalID field. Will also set the IsProcessed value base on input. + /// + /// Sku Transaction Id + /// Sku Transaction quantity. Set to null to leave database value unchanged. + /// Stock Journal Id + 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) + { + using (var conn = new SqlConnection()) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblStockSkuTransaction + SET TransactionDate = @transactionDate + ,StockSkuTransactionTypeID = @stockSkuTransactionTypeID + ,ForeignKey = @foreignKey + ,Reference = @reference + ,Detail = @Detail + ,SkuID = ( + SELECT skuSkuID + FROM tblSku + WHERE skuSkuNumber = @skuNumber + ) + ,Quantity = @quantity + ,IsProcessed = @isProcessed + ,StockJournalID = @stockJournalID + WHERE StockSkuTransactionID = @transactionId + ", conn)) + { + cmd.Parameters.AddWithValue("@transactionDate", skuTransaction.TransactionDate.ToUniversalTime()); + cmd.Parameters.AddWithValue("@stockSkuTransactionTypeID", skuTransaction.SkuTransactionTypeId); + if (!skuTransaction.IsSetForeignKey) { cmd.Parameters.AddWithValue("@foreignKey", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@foreignKey", skuTransaction.ForeignKey); } + if (!skuTransaction.IsSetReference) { cmd.Parameters.AddWithValue("@reference", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@reference", skuTransaction.Reference); } + if (!skuTransaction.IsSetDetail) { 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("@transactionId", skuTransaction.SkuTransactionId); + + int effected = cmd.ExecuteNonQuery(); + + if (effected < 1) + { + throw new Exception(err += "stockSkuTransaction IsProcessed update failed"); + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/WhereBuilder.cs b/src/bnhtrade.Core/Data/Database/WhereBuilder.cs new file mode 100644 index 0000000..9a05760 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/WhereBuilder.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database +{ + public class WhereBuilder + { + private int parameterCount; + + public WhereBuilder() + { + Innit(); + } + + public string SqlWhereString { get; private set; } + + public Dictionary ParameterList { get; private set; } + + public void Innit() + { + SqlWhereString = null; + ParameterList = new Dictionary(); + parameterCount = 0; + } + + /// + /// Used to create a string for an SQL where condition 'In' statement + /// + /// Name of the column to used to for the condition statement + /// List of values to test in condition statement + /// Optional string to prefix to the returned result + public void In(string columnReference, List orValueList, string wherePrefix = null) + { + Innit(); + + if (orValueList == null || !orValueList.Any()) + { + return; + } + + string sqlWhere = @" + "; + + if (wherePrefix != null) + { + sqlWhere += wherePrefix; + } + + sqlWhere += " " + columnReference + " IN ( "; + + var paramters = new Dictionary(); + int listCount = orValueList.Count(); + for (int i = 0; i < listCount; i++, parameterCount++) + { + if (i > 0) + { + sqlWhere += ", "; + } + + string param = "@parameter" + parameterCount; + sqlWhere += param; + paramters.Add(param, orValueList[i]); + } + sqlWhere += " )"; + + SqlWhereString = sqlWhere; + ParameterList = paramters; + } + + /// + /// Used to create a string for an SQL where condition 'In' statement + /// + /// Name of the column to used to for the condition statement + /// List of values to test in condition statement + /// Optional string to prefix to the returned result + public void In(string columnReference, List orValueList, string wherePrefix = null) + { + var stringList = new List(); + + if (orValueList != null || !orValueList.Any()) + { + foreach (int value in orValueList) + { + stringList.Add(value.ToString()); + } + } + + In(columnReference, stringList, wherePrefix); + } + } +} diff --git a/src/bnhtrade.Core/Extensions.cs b/src/bnhtrade.Core/Extensions.cs new file mode 100644 index 0000000..d7f479e --- /dev/null +++ b/src/bnhtrade.Core/Extensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core +{ + static class Extensions + { + public static bool In(this T item, params T[] items) + { + if (items == null) + throw new ArgumentNullException("items"); + + return items.Equals(item); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Account/GetAccountCodeInfo.cs b/src/bnhtrade.Core/Logic/Account/GetAccountCodeInfo.cs new file mode 100644 index 0000000..7c4663a --- /dev/null +++ b/src/bnhtrade.Core/Logic/Account/GetAccountCodeInfo.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Account +{ + public class GetAccountCodeInfo + { + private string sqlConnectionString; + private Data.Database.Account.ReadAccountCode readAccountCode; + private Dictionary cache; + + public GetAccountCodeInfo(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + readAccountCode = new Data.Database.Account.ReadAccountCode(sqlConnectionString); + cache = new Dictionary(); + } + + public void CacheClear() + { + cache.Clear(); + } + + public void CacheFill() + { + CacheClear(); + + var resultList = readAccountCode.All(); + foreach (var result in resultList) + { + cache.Add(result.AccountCodeId, result); + } + } + + public void CacheFill(List accountCodeList, bool forceDbRead = false) + { + if (accountCodeList == null || !accountCodeList.Any()) + { + return; + } + + var accountCodeQueryList = new List(); + foreach (var code in accountCodeList.Distinct().ToList()) + { + if (forceDbRead) + { + cache.Remove(code); + accountCodeQueryList.Add(code); + } + else if (!cache.ContainsKey(code)) + { + accountCodeQueryList.Add(code); + } + } + + // get db list + var dbList = readAccountCode.ByAccountCode(accountCodeQueryList); + + // add to cache + foreach (var item in dbList) + { + cache.Add(item.AccountCodeId, item); + } + } + + public Model.Account.AccountCode ByAccountCode(int accountCode, bool forceDbRead = false) + { + CacheFill(new List { accountCode }, forceDbRead); + + if (cache.ContainsKey(accountCode)) + { + return cache[accountCode]; + } + else + { + return null; + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Account/GetInvoiceLineItem.cs b/src/bnhtrade.Core/Logic/Account/GetInvoiceLineItem.cs new file mode 100644 index 0000000..fa7aceb --- /dev/null +++ b/src/bnhtrade.Core/Logic/Account/GetInvoiceLineItem.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Account +{ + public class GetInvoiceLineItem + { + string sqlConnectionString; + private Dictionary cache; + private Data.Database.Account.ReadInvoiceLineItem dbRead; + private Logic.Log.LogEvent log = new Logic.Log.LogEvent(); + private Logic.Account.GetTaxCodeInfo getTaxCode; + private Logic.Account.GetAccountCodeInfo getAccountCode; + + public GetInvoiceLineItem(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + CacheInnit(); + dbRead = new Data.Database.Account.ReadInvoiceLineItem(sqlConnectionString); + getAccountCode = new GetAccountCodeInfo(sqlConnectionString); + getTaxCode = new GetTaxCodeInfo(sqlConnectionString); + } + + /// + /// Create new 'default' line item code when a requested item code is not found. + /// + public bool InsertNewOnNoMatch { get; set; } = false; + + public void CacheInnit() + { + cache = new Dictionary(); + } + + /// + /// Prefill cache in one SQL call, saves multiple SQL calls. + /// + /// List of item codes to lookup from database + /// Forces a database read (does not read cache) + public void CacheFill(List itemCodeList, bool forceDbRead = false) + { + if (itemCodeList == null || !itemCodeList.Any()) + { + return; + } + + var itemCodeQueryList = new List(); + foreach (var itemCode in itemCodeList) + { + if (forceDbRead) + { + cache.Remove(itemCode); + itemCodeQueryList.Add(itemCode); + } + else if (!cache.ContainsKey(itemCode)) + { + itemCodeQueryList.Add(itemCode); + } + } + + // query database + var resultList = dbRead.ByItemCode(itemCodeQueryList); + + // fill account & tax codes cache + getAccountCode.CacheFill(dbRead.AccountCodeList.Values.ToList(), forceDbRead); + getTaxCode.CacheFill(dbRead.TaxCodeList.Values.ToList(), forceDbRead); + + // build final itemcode object and add to cache + foreach (var result in resultList.Values) + { + if (dbRead.AccountCodeList.ContainsKey(result.ItemCode)) + { + result.DefaultAccountCode = getAccountCode.ByAccountCode(dbRead.AccountCodeList[result.ItemCode]); + } + + if (dbRead.TaxCodeList.ContainsKey(result.ItemCode)) + { + result.DefaultTaxCode = getTaxCode.GetByTaxCode(dbRead.TaxCodeList[result.ItemCode]); + } + + cache.Add(result.ItemCode, result); + } + } + + /// + /// Creates new 'default' item code entry. The item code and title are set the same and will require updating. + /// + /// Item code string + /// + public Model.Account.InvoiceLineItem CreateDefault(string itemCode) + { + new Data.Database.Account.CreateInvoiceLineItem(sqlConnectionString).CreateDefault(itemCode); + var item = dbRead.ByItemCode(itemCode); + cache.Add(item.ItemCode, item); + return item; + } + + public Model.Account.InvoiceLineItem ByItemCode(string itemCode, bool forceDbRead = false) + { + if (string.IsNullOrWhiteSpace(itemCode)) + { + return null; + } + + CacheFill(new List { itemCode }, forceDbRead); + + Model.Account.InvoiceLineItem item = null; + if (cache.ContainsKey(itemCode)) + { + item = cache[itemCode]; + + // check title + if (!item.IsNewReviewRequired && item.Name == item.ItemCode) + { + throw new Exception + ("ItemCode found with the incomplete title. Update title and then try again."); + } + + return item; + } + + if (!InsertNewOnNoMatch) + { + return null; + } + else + { + return CreateDefault(itemCode); + } + } + + /// + /// Tests if ItemCode has Invoice line entry enabled + /// + /// Item code + /// Forces a database read (does not read cache) + /// + public bool InvoiceLineEntryEnabled(string itemCode, bool forceDbRead = false) + { + var item = ByItemCode(itemCode, forceDbRead); + if (item == null) + throw new Exception("Invalid item code"); + return item.InvoiceLineEntryEnabled; + } + + /// + /// Tests if ItemCode is new (default) and a review id required + /// + /// Item code + /// Forces a database read (does not read cache) + /// + public bool IsNewReviewRequired(string itemCode, bool forceDbRead = false) + { + var item = ByItemCode(itemCode, forceDbRead); + if (item == null) + { + throw new Exception("Invalid item code"); + } + return item.IsNewReviewRequired; + } + } +} \ No newline at end of file diff --git a/src/bnhtrade.Core/Logic/Account/GetTaxCodeInfo.cs b/src/bnhtrade.Core/Logic/Account/GetTaxCodeInfo.cs new file mode 100644 index 0000000..a50342e --- /dev/null +++ b/src/bnhtrade.Core/Logic/Account/GetTaxCodeInfo.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Account +{ + public class GetTaxCodeInfo + { + string sqlConnectionString; + private bool allRetrived; + private Dictionary cache; + private Dictionary cacheInvoiceItem; + private Data.Database.Account.ReadTaxCode dbRead; + + public GetTaxCodeInfo(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + allRetrived = false; + CacheClear(); + dbRead = new Data.Database.Account.ReadTaxCode(sqlConnectionString); + } + + private void CacheClear() + { + cache = new Dictionary(); + cacheInvoiceItem = new Dictionary(); + } + + public void CacheFill() + { + CacheClear(); + + var list = dbRead.GetAllActive(); + foreach (var item in list) + { + cache.Add(item.TaxCode, item); + } + } + + public void CacheFill(List taxCodeList, bool forceDbRead = false) + { + if (taxCodeList == null || !taxCodeList.Any()) + { + return; + } + + var taxCodeQueryList = new List(); + foreach (var code in taxCodeList.Distinct().ToList()) + { + if (forceDbRead) + { + cache.Remove(code); + taxCodeQueryList.Add(code); + } + else if (!cache.ContainsKey(code)) + { + taxCodeQueryList.Add(code); + } + } + + // get db list + var dbList = dbRead.GetByTaxCode(taxCodeQueryList); + + // add to cache + foreach (var item in dbList) + { + cache.Add(item.TaxCode, item); + } + } + + public List GetAllActive() + { + CacheFill(); + return cache.Values.ToList(); + } + + public Model.Account.TaxCodeInfo GetByTaxCode(string taxCode, bool forceDbRead = false) + { + if (string.IsNullOrWhiteSpace(taxCode)) + { + return null; + } + + CacheFill(new List { taxCode }, forceDbRead); + + if (cache.ContainsKey(taxCode)) + { + return cache[taxCode]; + } + else + { + return null; + } + } + + /// + /// Gets list of Tax Code Info for a given list of Sku Numbers + /// + /// List of SKU numbers + /// Dictionary, key is SkuNumber and value is Tax Code Info + public Dictionary GetBySkuNumber(List skuNumberList) + { + var returnList = new Dictionary(); + + if (skuNumberList == null || !skuNumberList.Any()) + { + return returnList; + } + + // remove any duplicates + var cleanSkuList = skuNumberList.Distinct().ToList(); + + // get db list + var dbList = dbRead.GetTaxCodeBySkuNumber(skuNumberList); + + if (!dbList.Any()) { return returnList; } + + // charge the cache + dbRead.GetAllActive(); + + // build dictionary + foreach (var item in dbList) + { + var taxInfo = GetByTaxCode(item.Value); + if (taxInfo != null) + { + returnList.Add(item.Key, taxInfo); + } + } + + return returnList; + } + + public Dictionary Get(List invoiceLineList) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Account/TaxCalculation.cs b/src/bnhtrade.Core/Logic/Account/TaxCalculation.cs new file mode 100644 index 0000000..73c9b5d --- /dev/null +++ b/src/bnhtrade.Core/Logic/Account/TaxCalculation.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Account +{ + public class TaxCalculation + { + public decimal GetGrossAmount(decimal netAmount, decimal taxPercent) + { + return netAmount * (1 + (taxPercent / 100)); + } + + public decimal GetGrossAmount(decimal netAmount, Model.Account.TaxCodeInfo taxCodeInfo) + { + return GetGrossAmount(netAmount, taxCodeInfo.TaxRate); + } + + public decimal GetNetAmount(decimal grossAmount, decimal taxPercent) + { + return grossAmount / (1 + (taxPercent / 100)); + } + + public decimal GetNetAmount(decimal grossAmount, Model.Account.TaxCodeInfo taxCodeInfo) + { + return GetNetAmount(grossAmount, taxCodeInfo.TaxRate); + } + + public decimal GetTaxAmount(decimal amount, bool amountIsTaxInclusive, decimal taxPercent) + { + if (amountIsTaxInclusive) + { + return amount - GetNetAmount(amount, taxPercent); + } + else + { + return amount * (taxPercent / 100); + } + } + + public decimal GetTaxAmount(decimal amount, bool amountIsTaxInclusive, Model.Account.TaxCodeInfo taxCodeInfo) + { + return GetTaxAmount(amount, amountIsTaxInclusive, taxCodeInfo.TaxRate); + } + + public decimal GetMarginTaxRate(DateTime transactionDate) + { + decimal vatRate = 0; + if (transactionDate >= new DateTime(2011, 01, 04)) + { + vatRate = 20; + } + else + { + // more coding required + throw new Exception("Transaction is outside the current margin scheme date scope"); + } + return vatRate; + } + + public decimal GetMarginTaxAmount(decimal marginAmount, DateTime transactionDate) + { + decimal vatRate = GetMarginTaxRate(transactionDate); + + return GetTaxAmount(marginAmount, true, vatRate); + } + + public decimal GetMarginTaxAmount(decimal purchasePrice, decimal salePrice, DateTime transactionDate) + { + return GetMarginTaxAmount(salePrice - purchasePrice, transactionDate); + } + + /// + /// Returns a value to multiply margin (sale - purchase price) by to find margin scheme tax amount + /// + /// Date of transaction + /// Value between 0 and 1 + public decimal GetMarginMultiplier(DateTime transactionDate) + { + decimal vatRate = GetMarginTaxRate(transactionDate); + return vatRate / (vatRate + 100); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Account/ValidateInvoice.cs b/src/bnhtrade.Core/Logic/Account/ValidateInvoice.cs deleted file mode 100644 index 69fd9ad..0000000 --- a/src/bnhtrade.Core/Logic/Account/ValidateInvoice.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Logic.Account -{ - public abstract class ValidateInvoice : Validate - { - protected Account.ValidateAccountCode validateAccountCode = new Account.ValidateAccountCode(); - protected Account.ValidateCurrencyCode validateCurrencyCode = new Account.ValidateCurrencyCode(); - protected Account.ValidateTaxCode validateTaxCode = new ValidateTaxCode(); - protected Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck(); - - public bool InvoiceNumberIsRequired { get; set; } = true; - public bool InvoiceLineDescriptionIsRequired { get; set; } = true; - - public new void Innit() - { - base.Innit(); - validateAccountCode.Innit(); - validateCurrencyCode.Innit(); - validateTaxCode.Innit(); - stringCheck.Innit(); - } - - protected bool IsValidInvoice(Model.Account.IInvoice invoice) - { - return IsValidInvoice(new List { invoice }); - } - - protected bool IsValidInvoice(List invoiceList) - { - Innit(); - - if (invoiceList == null || !invoiceList.Any()) - { - ErrorListAdd("Invoice list is null or empty."); - return false; - } - - var tempErrorList = new List(); - for (int i = 0; i < invoiceList.Count(); i++) - { - Innit(); - - // check header info - if (invoiceList[i].ContactNameIsSet) { IsValidInvoiceContact(invoiceList[i].ContactName); } - else { ErrorListAdd("'Contact Name' is a required value"); } - - if (invoiceList[i].InvoiceAmountIsSet) - { - if (!invoiceList[i].IsCreditNoteIsSet) - { ErrorListAdd("'Is Credit Note' is a required value"); } - else - { - if (invoiceList[i].IsCreditNote && invoiceList[i].InvoiceAmount > 0) - { ErrorListAdd("Credit Note amount cannot be greater than zero"); } - else if (!invoiceList[i].IsCreditNote && invoiceList[i].InvoiceAmount < 0) - { ErrorListAdd("Invoice amount cannot be less than zero"); } - } - } - else { ErrorListAdd("'Invoice Amount' is a required value"); } - - if (invoiceList[i].InvoiceCurrencyCodeIsSet) { IsValidInvoiceCurrency(invoiceList[i].InvoiceCurrencyCode); } - else { ErrorListAdd("'Invoice Currency Code' is a required value"); } - - if (invoiceList[i].InvoiceDateIsSet) { IsValidInvoiceDate(invoiceList[i].InvoiceDate); } - else { ErrorListAdd("'Invoice Date' is a required value"); } - - if (!invoiceList[i].InvoiceDateKindIsSet) { ErrorListAdd("'Invoice Date Kind' is a required value"); } - - if (invoiceList[i].InvoiceDueDateIsSet) { IsValidInvoiceDueDate(invoiceList[i].InvoiceDueDate); } - - if (invoiceList[i].InvoiceNumberIsSet) - { IsValidInvoiceNumber(invoiceList[i].InvoiceNumber); } - else - { - if (InvoiceNumberIsRequired) { ErrorListAdd("'Invoice Number' is a required value"); } - } - - if (invoiceList[i].InvoiceReferenceIsSet) { IsValidInvoiceReference(invoiceList[i].InvoiceReference); } - else { ErrorListAdd("'Invoice Reference' is a required value"); } - - if (!invoiceList[i].IsCreditNoteIsSet) { ErrorListAdd("'Invoice Reference' is a required value"); } - - - // loop though lines and check and sum totals - if (!invoiceList[i].InvoiceLineListIsSet) - { ErrorListAdd("Invoice is required to have lines."); } - else - { - decimal lineTotal = 0; - for (int j = 0; j < invoiceList[i].InvoiceLineList.Count(); j++) - { - if (!invoiceList[i].InvoiceLineList[j].AccountCodeIsSet) { ErrorListAdd("Line 'Account Code' is a required value"); } - else { IsValidInvoiceLineAccount(invoiceList[i].InvoiceLineList[j].AccountCode); } - - if (!invoiceList[i].InvoiceLineList[j].DescriptionIsSet) - { - if (InvoiceLineDescriptionIsRequired) { ErrorListAdd("Line 'Description' is a required value"); } - } - else { IsValidInvoiceLineDescription(invoiceList[i].InvoiceLineList[j].Description); } - - if (!invoiceList[i].InvoiceLineList[j].GrossTotalAmountIsSet) { ErrorListAdd("Line 'Gross Total Amount' is a required value"); } - - if (!invoiceList[i].InvoiceLineList[j].ItemCodeIsSet) { ErrorListAdd("Line 'Item Code' is a required value"); } - else { IsValidLineItemCode(invoiceList[i].InvoiceLineList[j].ItemCode); } - - if (!invoiceList[i].InvoiceLineList[j].QuantityIsSet) { ErrorListAdd("Line 'Quantity' is a required value"); } - - if (!invoiceList[i].InvoiceLineList[j].TaxAmountIsSet) { ErrorListAdd("Line 'Tax Amount' is a required value"); } - - if (!invoiceList[i].InvoiceLineList[j].TaxCodeIsSet) { ErrorListAdd("Line 'Tax Code' is a required value"); } - else { IsValidLineTaxCode(invoiceList[i].InvoiceLineList[j].TaxCode); } - - if (!invoiceList[i].InvoiceLineList[j].TotalNetAmountIsSet) { ErrorListAdd("Line 'Total Net Amount' is a required value"); } - - if ((invoiceList[i].InvoiceLineList[j].TaxAmount - + invoiceList[i].InvoiceLineList[j].TaxAmountAdjust - + invoiceList[i].InvoiceLineList[j].TotalNetAmount) != invoiceList[i].InvoiceLineList[j].GrossTotalAmount) - { ErrorListAdd("Incorrect invoice line total (gross) amount."); } - - lineTotal = lineTotal + invoiceList[i].InvoiceLineList[j].GrossTotalAmount; - } - - // check totals - if (invoiceList[i].InvoiceAmountIsSet && (invoiceList[i].InvoiceAmount != lineTotal)) - { ErrorListAdd("Invoice line total does not match invoice total amount."); } - } - tempErrorList.AddRange(ErrorList.Select(x => "[Inv" + i + "] " + x).ToList()); - } - - Innit(); - ErrorListAdd(tempErrorList); - - if (ErrorListIsSet) { return false; } - else { return true; } - } - - protected bool IsValidInvoiceLineAccount(int accountCode) - { - validateAccountCode.Innit(); - if (!validateAccountCode.IsValidAccountCodeId(accountCode)) - { - ErrorListAdd(validateAccountCode.ErrorList.Select(x => "Invalid invoice line account code: " + x).ToList()); - return false; - } - else - { return true; } - } - - protected bool IsValidInvoiceLineDescription(string lineDescription) - { - int maxLength = 150; - stringCheck.Innit(); - if (!stringCheck.MaxLength(lineDescription, maxLength)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid invoice line description: " + x).ToList()); - return false; - } - return true; - } - - protected bool IsValidInvoiceContact(string contactName) - { - int maxlength = 150; - stringCheck.Innit(); - if (!stringCheck.MaxLength(contactName, maxlength)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid invoice nontact name: " + x).ToList()); - return false; - } - return true; - } - - protected bool IsValidInvoiceDate(DateTime invoiceDate) - { - if (invoiceDate.Kind != DateTimeKind.Utc) - { - ErrorListAdd(@"Invalid date/time, UTC kind required."); - return false; - } - else if (invoiceDate == default(DateTime)) - { - ErrorListAdd("Date and time is default value."); - return false; - } - return true; - } - - protected bool IsValidInvoiceDueDate(DateTime invoiceDueDate) - { - if (invoiceDueDate.Kind != DateTimeKind.Utc) - { - ErrorListAdd(@"Invalid date/time, UTC kind required."); - return false; - } - else if (invoiceDueDate == default(DateTime)) - { - ErrorListAdd("Date and time is default value."); - return false; - } - return true; - } - - protected bool IsValidInvoiceCurrency(string currencyCode) - { - validateCurrencyCode.Innit(); - if (!validateCurrencyCode.IsValidCurrencyCode(currencyCode)) - { - ErrorListAdd(validateCurrencyCode.ErrorList.Select(x => "Invalid invoice currency code: " + x).ToList()); - return false; - } - else { return true; } - } - - protected bool IsValidInvoiceNumber(string invoiceNumber) - { - int maxlength = 64; - stringCheck.Innit(); - if (!stringCheck.MaxLength(invoiceNumber, maxlength)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid invoice number: " + x).ToList()); - return false; - } - return true; - } - - protected bool IsValidInvoiceReference(string invoiceReference) - { - int maxlength = 50; - stringCheck.Innit(); - if (!stringCheck.MaxLength(invoiceReference, maxlength)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid invoice reference: " + x).ToList()); - return false; - } - return true; - } - - protected bool IsValidLineItemCode(string itemCode) - { - int maxlength = 250; - stringCheck.Innit(); - if (!stringCheck.MaxLength(itemCode, maxlength)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid invoice line item code: " + x).ToList()); - return false; - } - return true; - } - - protected bool IsValidLineTaxCode(string taxCode) - { - validateTaxCode.Innit(); - if (validateTaxCode.IsValidTaxCodeId(taxCode)) - { return true; } - else - { - ErrorListAdd(validateTaxCode.ErrorList.Select(x => "Invalid invoice line " + x).ToList()); - return false; - } - } - } -} diff --git a/src/bnhtrade.Core/Logic/Account/ValidateSalesInvoice.cs b/src/bnhtrade.Core/Logic/Account/ValidateSalesInvoice.cs deleted file mode 100644 index ef6a103..0000000 --- a/src/bnhtrade.Core/Logic/Account/ValidateSalesInvoice.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Logic.Account -{ - public class ValidateSalesInvoice : ValidateInvoice - { - public ValidateSalesInvoice() - { - int propertyCount = new Model.Account.SalesInvoice().GetType().GetProperties().Count(); - if (propertyCount != 20) - { throw new Exception("Model.Account.SalesInvoice property count has altered. Validate class requires an update."); } - - propertyCount = new Model.Account.SalesInvoice.InvoiceLine().GetType().GetProperties().Count(); - if (propertyCount != 18) - { throw new Exception("Model.Account.SalesInvoice property count has altered. Validate class requires an update."); } - } - - public bool IsValidInvoice(Model.Account.SalesInvoice invoice) - { - return IsValidInvoice(new List { invoice }); - } - - public bool IsValidInvoice(List invoiceList) - { - var interfaceList = invoiceList.Cast().ToList(); - - return IsValidInvoice(interfaceList); - } - } -} diff --git a/src/bnhtrade.Core/Logic/Account/ValidateTaxCode.cs b/src/bnhtrade.Core/Logic/Account/ValidateTaxCode.cs deleted file mode 100644 index ccf72e8..0000000 --- a/src/bnhtrade.Core/Logic/Account/ValidateTaxCode.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Logic.Account -{ - public class ValidateTaxCode : Validate - { - private Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck(); - - public new void Innit() - { - base.Innit(); - stringCheck.Innit(); - } - public bool IsValidGrossAmountMultiplier(decimal multiplier) - { - if (multiplier >= 0 && multiplier <= 1) - { - return true; - } - else - { - ErrorListAdd( "Gross multiplier must be equal to, or between, 0 and 1."); - return false; - } - } - public bool IsValidNetAmountMultiplier(decimal multiplier) - { - if (multiplier >= 0 && multiplier <= 1) - { - return true; - } - else - { - ErrorListAdd("Net multiplier must not be less than 0 or greater than 1."); - return false; - } - } - public bool IsValidOnExpense(Model.Account.TaxCode taxInfo) - { - if (taxInfo.IsValidOnExpense || taxInfo.IsSetIsValidOnIncome) - { - if (taxInfo.IsSetIsValidOnExpense) - { - return true; - } - else - { - ErrorListAdd("Is Valid On Expense has not been set."); - return false; - } - } - else - { - ErrorListAdd("Either 'IsValidOnExpense' or 'IsSetIsValidOnSale' must be set to true."); - return false; - } - } - public bool IsValidOnIncome(Model.Account.TaxCode taxInfo) - { - if (taxInfo.IsValidOnExpense || taxInfo.IsSetIsValidOnIncome) - { - if (taxInfo.IsSetIsValidOnIncome) - { - return true; - } - else - { - ErrorListAdd("Is Valid On Income has not been set."); - return false; - } - } - else - { - ErrorListAdd("Either 'IsValidOnPurchase' or 'IsSetIsValidOnSale' must be set to true."); - return false; - } - } - public bool IsValidTaxCodeId(string taxCodeId) - { - if (!stringCheck.IsAlphaNumeric(taxCodeId, true)) - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid Tax Code: " + x).ToList()); - return false; - } - if (taxCodeId.Length != 4) - { - ErrorListAdd("Invalid Tax Code: Length does not equal 4 charaters."); - return false; - } - return true; - } - public bool IsValidTaxRateDescription(string description) - { - if (stringCheck.MaxLength(description, 250, true)) - { - return true; - } - else - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid Tax Rate Description: " + x).ToList()); - return false; - } - } - public bool IsValidTaxRateTitle(string title) - { - if (stringCheck.MaxLength(title, 50, false)) - { - return true; - } - else - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid Tax Rate Title: " + x).ToList()); - return false; - } - } - public bool IsValidTaxRateTitleShort(string title) - { - if (stringCheck.MaxLength(title, 50, false)) - { - return true; - } - else - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid Tax Rate Title Short: " + x).ToList()); - return false; - } - } - public bool IsValidTaxType(string taxType) - { - if (stringCheck.MaxLength(taxType, 50, false)) - { - return true; - } - else - { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid Tax Rate Type: " + x).ToList()); - return false; - } - } - } -} diff --git a/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs b/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs index c80adad..b353629 100644 --- a/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs +++ b/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs @@ -36,33 +36,32 @@ namespace bnhtrade.Core.Logic.AmazonFBAInbound shipmentRequest.LastUpdatedAfter = dateTimeAfter.AddDays(-14); shipmentRequest.LastUpdatedBefore = dateTimeBefore; - List shipmentInfoList = shipmentRequest.GetShipmentInfo(); + List shipmentInfoList = shipmentRequest.GetShipmentInfo(); // build list of shipments returned from mws var dicShipExistsInDb = new Dictionary(); foreach (var item in shipmentInfoList) { - dicShipExistsInDb.Add(item.AmazonShipmentId, false); + dicShipExistsInDb.Add(item.FbaShipmentId, false); } // build list of shipmentId that do not exist in database int complete = 0; using (TransactionScope scope = new TransactionScope()) { - List newShipmentInfoList = null; + List newShipmentInfoList = null; if (dicShipExistsInDb.Any()) { var newShipmentId = new List(); // query db for shipment header info - var requestHeader = new Data.Database.FBAInbound.GetShipmentHeaderInfo(sqlConnectionString); - requestHeader.ShipmentIdList = dicShipExistsInDb.Keys.ToList(); - var resultHeader = requestHeader.Execute(); + var resultHeader = new Data.Database.AmazonShipment.ReadShipmentInfo(sqlConnectionString) + .HeaderByFbaShipmentId(dicShipExistsInDb.Keys.ToList()); // compare db and mws result foreach (var item in resultHeader) { - dicShipExistsInDb[item.AmazonShipmentId] = true; + dicShipExistsInDb[item.FbaShipmentId] = true; } foreach (var item in dicShipExistsInDb) { @@ -81,7 +80,7 @@ namespace bnhtrade.Core.Logic.AmazonFBAInbound foreach (var item in newShipmentInfoList) { var shipmentItemInfoRequest = new Data.AmazonMWS.FBAInbound.ListInboundShipmentItems(); - item.ShipmentItemInfoList = shipmentItemInfoRequest.GetByAmazonShipmentId(item.AmazonShipmentId); + item.ShipmentItemInfoList = shipmentItemInfoRequest.GetByAmazonShipmentId(item.FbaShipmentId); } } @@ -91,10 +90,10 @@ namespace bnhtrade.Core.Logic.AmazonFBAInbound foreach (var item in newShipmentInfoList) { // add the update date - item.LastUpdatedUtc = dateTimeBefore; + item.LastUpdated = dateTimeBefore; // write to db - var dbWrite = new Data.Database.FBAInbound.SetShipmentInfo(sqlConnectionString); + var dbWrite = new Data.Database.AmazonShipment.SetShipmentInfo(sqlConnectionString); dbWrite.Excecute(item); complete = complete + 1; } diff --git a/src/bnhtrade.Core/Logic/Export/AmazonSettlement.cs b/src/bnhtrade.Core/Logic/Export/AmazonSettlement.cs index e853c2b..3fbae60 100644 --- a/src/bnhtrade.Core/Logic/Export/AmazonSettlement.cs +++ b/src/bnhtrade.Core/Logic/Export/AmazonSettlement.cs @@ -11,7 +11,8 @@ namespace bnhtrade.Core.Logic.Export public class AmazonSettlement { private string sqlConnectionString; - private Dictionary taxCodeBySkuNumer; + private Logic.Log.LogEvent log = new Logic.Log.LogEvent(); + private List lineItemCodeList = new List(); public AmazonSettlement(string sqlConnectionString) { @@ -21,12 +22,11 @@ namespace bnhtrade.Core.Logic.Export public void ToInvoice() { var console = new UI.Console.Update(); - var log = new Logic.Log.LogEvent(); log.LogInformation("Starting processing of Amazon settlement data into export invoice table..."); // check settlement reports consistancy var consistencyCheck = new Data.Database.Consistency.ImportAmazonSettlement(sqlConnectionString).PeriodDateGaps(); - if (consistencyCheck == false ) + if (consistencyCheck == false) { return; } // get list of unprocssed settlement reports to export @@ -65,38 +65,34 @@ namespace bnhtrade.Core.Logic.Export } // validate settlelments - var validate = new Logic.Import.ValidateAmazonSettlement(); + var validate = new Logic.Validate.AmazonSettlement(); for (int i = 0; i < settlementList.Count(); i++) { if (!validate.IsValid(settlementList[i])) { - log.LogError("Error procesing Amazon Settlement data for export.", validate.ErrorListToString()); + log.LogError("Error procesing Amazon Settlement data for export.", validate.ValidationResultListToString()); } } - if (validate.ErrorListIsSet) { return; } + if (validate.IsValidResult == false) { return; } // get dictionary of sku-number to taxcodeId Console.Write("\rBuilding SKU list... "); - var dicSkuNumberToTaxCodeId = new Dictionary(); - for (int i = 0; i < settlementList.Count(); i++) + var skuList = new List(); + foreach (var settlement in settlementList) { - if (settlementList[i].SettlementLineListIsSet) + if (settlement.SettlementLineListIsSet) { - for (int j = 0; j < settlementList[i].SettlementLineList.Count(); j++) + foreach (var line in settlement.SettlementLineList) { - if (settlementList[i].SettlementLineList[j].SkuIsSet - && !string.IsNullOrWhiteSpace(settlementList[i].SettlementLineList[j].Sku)) + if (line.SkuIsSet + && !string.IsNullOrWhiteSpace(line.Sku)) { - if (!dicSkuNumberToTaxCodeId.ContainsKey(settlementList[i].SettlementLineList[j].Sku)) - { - dicSkuNumberToTaxCodeId.Add(settlementList[i].SettlementLineList[j].Sku, null); - } + skuList.Add(line.Sku); } } } } - var readTaxCode = new Data.Database.Account.ReadTaxCode(sqlConnectionString); - taxCodeBySkuNumer = readTaxCode.BySkuNumber(dicSkuNumberToTaxCodeId.Keys.ToList()); + var taxCodeBySkuNumer = new Logic.Account.GetTaxCodeInfo(sqlConnectionString).GetBySkuNumber(skuList); // loop through each settlement and build list of invoices to export Console.Write("\rBuilding invoices to export... "); @@ -117,7 +113,7 @@ namespace bnhtrade.Core.Logic.Export var itemCodeTotal = new Dictionary(); foreach (var line in month) { - string itemCode = BuildLineItemCode(line.Sku, line.TransactionType, line.AmountType, line.AmountDescription); + string itemCode = BuildLineItemCode(taxCodeBySkuNumer, line.Sku, line.TransactionType, line.AmountType, line.AmountDescription); if (itemCodeTotal.ContainsKey(itemCode)) { itemCodeTotal[itemCode] += line.Amount; @@ -137,13 +133,12 @@ namespace bnhtrade.Core.Logic.Export decimal lineTaxTotal = 0m; foreach (var item in itemCodeTotal) { - var line = new Model.Account.SalesInvoice.InvoiceLine(); + var line = new Model.Account.SalesInvoice.InvoiceLine(invoice.UnitAmountIsTaxExclusive); line.ItemCode = item.Key; - line.TotalNetAmount = item.Value; - lineNetTotal += item.Value; - line.TaxAmount = 0; - lineTaxTotal += 0; line.Quantity = 1; + line.UnitAmount = item.Value; + lineNetTotal += item.Value; + lineTaxTotal += 0; invoice.InvoiceLineList.Add(line); } @@ -153,11 +148,10 @@ namespace bnhtrade.Core.Logic.Export { invoice.InvoiceDate = settlementList[i].EndDate; } else { invoice.InvoiceDate = new DateTime(month.Key.Year, month.Key.Month, 1, 0, 0, 0, DateTimeKind.Utc).AddMonths(1).AddDays(-1); } - invoice.InvoiceDateKind = DateTimeKind.Utc; invoice.InvoiceDueDate = settlementList[i].DepositDate; invoice.InvoiceReference = settlementList[i].SettlementId; - invoice.InvoiceAmount = lineNetTotal + lineTaxTotal; - if (invoice.InvoiceAmount < 0) { invoice.IsCreditNote = true; } + invoice.InvoiceTotalAmount = lineNetTotal + lineTaxTotal; + if (invoice.InvoiceTotalAmount < 0) { invoice.IsCreditNote = true; } else { invoice.IsCreditNote = false; } // invoice complete, add to list @@ -174,11 +168,11 @@ namespace bnhtrade.Core.Logic.Export { if (invoiceTotal.ContainsKey(invoiceList[i].InvoiceReference)) { - invoiceTotal[invoiceList[i].InvoiceReference] += invoiceList[i].InvoiceAmount; + invoiceTotal[invoiceList[i].InvoiceReference] += invoiceList[i].InvoiceTotalAmount.GetValueOrDefault(); } else { - invoiceTotal.Add(invoiceList[i].InvoiceReference, invoiceList[i].InvoiceAmount); + invoiceTotal.Add(invoiceList[i].InvoiceReference, invoiceList[i].InvoiceTotalAmount.GetValueOrDefault()); } } for (int i = 0; i < settlementList.Count(); i++) @@ -194,8 +188,65 @@ namespace bnhtrade.Core.Logic.Export return; } - // postfix invoices spanning multiple months with -n - if (invoiceList.Count() > 1) + // add invoice item code data to lines + // also clean invoices of any disabled lines (remove lines and possibly invoices) + var getLineItemInfo = new Logic.Account.GetInvoiceLineItem(sqlConnectionString); + getLineItemInfo.InsertNewOnNoMatch = true; + getLineItemInfo.CacheFill(lineItemCodeList); + bool newTypeFound = false; + + for (int i = 0; i < invoiceList.Count(); i++) + { + for (int j = 0; j < invoiceList[i].InvoiceLineList.Count(); j++) + { + var itemCode = getLineItemInfo.ByItemCode(invoiceList[i].InvoiceLineList[j].ItemCode); + // error! itemCode should never be null + if (itemCode == null) + { + throw new Exception("Item code is null"); + } + // flag new type and throw exception further on + else if (itemCode.IsNewReviewRequired) + { + newTypeFound = true; + } + // clean invoices of any disabled lines (remove lines and possibly invoices) + else if (itemCode.InvoiceLineEntryEnabled == false) + { + // remove line + invoiceList[i].InvoiceTotalAmount = invoiceList[i].InvoiceTotalAmount - invoiceList[i].InvoiceLineList[j].LineTotalAmount; + invoiceList[i].InvoiceLineList.RemoveAt(j); + j = j - 1; + + // remove invoice? + if (invoiceList[i].InvoiceLineList.Count == 0) + { + invoiceList.RemoveAt(i); + i = i - 1; + } + } + // get here add info to lines + else + { + invoiceList[i].InvoiceLineList[j].AccountCode = itemCode.DefaultAccountCode; + invoiceList[i].InvoiceLineList[j].Description = itemCode.Name; + invoiceList[i].InvoiceLineList[j].ItemCode = itemCode.ItemCode; + invoiceList[i].InvoiceLineList[j].TaxCode = itemCode.DefaultTaxCode; + } + } + } + + if (newTypeFound) + { + if (newTypeFound) + { + throw new Exception("New line ItemCode found. Add item code default values and then try again."); + } + return; + } + + // postfix invoices references that span multiple months with -n + if (invoiceList.Count > 1) { string lastRef = invoiceList[0].InvoiceReference; int countRef = 1; @@ -215,7 +266,7 @@ namespace bnhtrade.Core.Logic.Export if (countRef > 2) { log.LogError( - countRef + " total numner of export invoices created from Amazon Settlement Id" + lastRef + "." + countRef + " invoices where created from Amazon Settlement Id" + lastRef + "." , "Settlement period appears to span more 3 months or more. Whilst this is possible, it is unsual. Confirm his is correct."); } @@ -230,8 +281,12 @@ namespace bnhtrade.Core.Logic.Export { try { + var saveInv = new Logic.Export.SalesInvoice(sqlConnectionString); + // add temp invoice numbers + saveInv.AddTempInvoiceNumber(invoiceList, true); + // write to the database (gets validated there) - new Data.Database.Export.CreateSalesInvoice(sqlConnectionString).SaveInvoice(invoiceList); + saveInv.SaveSalesInvoice(invoiceList); // set settlements to isprocessed new Data.Database.Import.UpdateAmazonSettlement(sqlConnectionString).SetIsProcessedTrue(settlementIdList); @@ -241,15 +296,16 @@ namespace bnhtrade.Core.Logic.Export catch (Exception ex) { scope.Dispose(); - log.LogError(ex.Message); + log.LogError("Exeception caught while writing Amazon settlement invoices to DB. Changes were rolled back." + , ex.Message); return; } } Console.Write("\r"); - log.LogInformation("\rFinished processing of Amazon settlement data. " + invoiceList.Count() + " invoices created from "+ settlementIdList.Count() + " Amazon settlement reports."); + log.LogInformation("\rFinished processing of Amazon settlement data. " + invoiceList.Count() + " invoices created from " + settlementIdList.Count() + " Amazon settlement reports."); } - private string BuildLineItemCode(string skuNumber, string transactionType, string amountType, string amountDescription) + private string BuildLineItemCode(Dictionary taxCodeBySkuNumer, string skuNumber, string transactionType, string amountType, string amountDescription) { // build the match string // NB special case for global accounting sale and refunds (also note Goodlwill is included) and sku's where tax is included @@ -264,13 +320,18 @@ namespace bnhtrade.Core.Logic.Export { if (taxCodeBySkuNumer.ContainsKey(skuNumber)) { - matchString = matchString + ""; + matchString = matchString + ""; } else { throw new Exception("Sku#" + skuNumber + " tax info not found in dictionary list."); } } + + // add to list of generated line item codes + lineItemCodeList.Add(matchString); + + // return value return matchString; } } diff --git a/src/bnhtrade.Core/Logic/Export/AmazonSubmitFile.cs b/src/bnhtrade.Core/Logic/Export/AmazonSubmitFile.cs new file mode 100644 index 0000000..70ba709 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Export/AmazonSubmitFile.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Export +{ + public class AmazonSubmitFile + { + private string sqlConnectionString; + private Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck(); + private Log.LogEvent log = new Log.LogEvent(); + + public AmazonSubmitFile(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + + public void SubmitInventoryLoader(MemoryStream stream) + { + Model.Export.AmazonFeedSubmission result; + int queueId = QueueInventoryLoader(stream, out result); + SubmitQueuedFeedSubmission(queueId, result); + } + + public void SubmitInventoryLoader(MemoryStream stream, out Model.Export.AmazonFeedSubmission result) + { + int queueId = QueueInventoryLoader(stream, out result); + SubmitQueuedFeedSubmission(queueId, result); + } + + public int QueueInventoryLoader(MemoryStream stream) + { + Model.Export.AmazonFeedSubmission result; + return QueueFeedSubbmission("_POST_FLAT_FILE_INVLOADER_DATA_", "txt", stream, out result); + } + + public int QueueInventoryLoader(MemoryStream stream, out Model.Export.AmazonFeedSubmission result) + { + // write file database + return QueueFeedSubbmission("_POST_FLAT_FILE_INVLOADER_DATA_", "txt", stream, out result); + } + + private int QueueFeedSubbmission(string feedType, string fileExtention, MemoryStream stream, out Model.Export.AmazonFeedSubmission result) + { + // construct file object + var fileInfo = new Model.Data.DatabaseFileStream(); + fileInfo.FileExtention = fileExtention; + fileInfo.FileData = stream; + fileInfo.FileMD5base64 = new Logic.Utilities.CalculateMD5().Base64(stream); + + long longSize = stream.Length; + if (longSize > 2147483647) + throw new Exception("File size over 2.15 GB"); + fileInfo.FileSize = (int)longSize; + + // save to database + int queueId = 0; + using (var scope = new TransactionScope()) + { + queueId = new Data.Database.Export.CreateAmazonFeedSubmission(sqlConnectionString).Execute(feedType, fileInfo); + + // validate the result + var validateResults = new List(); + + bool isValid = Validator.TryValidateObject( + fileInfo, + new ValidationContext(fileInfo, null, null), + validateResults); + + if (isValid == false) + { + string error = "Create Database Amazon Feed Submission cancelled. Object validation failed."; + new Log.LogEvent().LogError(error, string.Join(Environment.NewLine, validateResults)); + scope.Dispose(); + throw new Exception(error); + } + scope.Complete(); + } + + // create feed object + result = new Model.Export.AmazonFeedSubmission(); + result.FeedType = feedType; + result.File = fileInfo; + + return queueId; + } + + // private, only to be used where you're sure feedSubmission matches DB and you don't want to call info from DB (large file) + private void SubmitQueuedFeedSubmission(int queueId, Model.Export.AmazonFeedSubmission feedSubmission) + { + // upload to mws + var feedSubmitt = new Data.AmazonMWS.Feeds.SubmitFeed(feedSubmission); + + if (!feedSubmitt.FeedSubmissionRecived) + { + // failed do something here + throw new NotImplementedException(); + } + + // set the amazon feed Id + var dbUpdate = new Data.Database.Export.UpdateAmazonFeedSubmission(sqlConnectionString); + dbUpdate.AddAmazonFeedId(queueId, feedSubmission.FeedSubmissionId); + + // update progress info + dbUpdate.UpdateStatusInfo(feedSubmission); + } + + private void SubmitQueuedFeedSubmission(int queueId) + { + throw new NotImplementedException(); + } + + private void SubmitQueuedFeedSubmission() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Export/AmazonSubmitFileStatus.cs b/src/bnhtrade.Core/Logic/Export/AmazonSubmitFileStatus.cs new file mode 100644 index 0000000..b2ac14c --- /dev/null +++ b/src/bnhtrade.Core/Logic/Export/AmazonSubmitFileStatus.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Export +{ + public class AmazonSubmitFileStatus + { + private string sqlConnectionString; + private bnhtrade.Core.Logic.Log.LogEvent log = new Log.LogEvent(); + + public AmazonSubmitFileStatus(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + + public void UpdateStatusInfo() + { + var openList = new Data.Database.Export.ReadAmazonFeedSubmission(sqlConnectionString).GetOpenFeeds(); + if (openList.Count == 0) + return; + + var getStatus = new Data.AmazonMWS.Feeds.GetFeedSubmissions(); + getStatus.FeedSubmissionIdList = openList.Select(x => x.FeedSubmissionId).ToList(); + var currentStatus = getStatus.Invoke(); + + for (int i = 0; i < openList.Count; i++) + { + bool found = false; + for (int j = 0; j < currentStatus.Count; j++) + { + if (openList[i].FeedSubmissionId == currentStatus[j].FeedSubmissionId) + { + found = true; + + openList[i].FeedProcessingStatus = currentStatus[j].FeedProcessingStatus; + if (currentStatus[j].IsSetCompletedProcessingDate()) + openList[i].CompletedProcessingDate = currentStatus[j].CompletedProcessingDate; + if (currentStatus[j].IsSetStartedProcessingDate()) + openList[i].StartedProcessingDate = currentStatus[j].StartedProcessingDate; + if (currentStatus[j].IsSetSubmittedDate()) + openList[i].SubmittedDate = DateTime.Parse(currentStatus[j].SubmittedDate); + } + } + if (found == false) + { + log.LogError("FeedSubmissionId '" + openList[i].FeedSubmissionId + "' exists in database but was not returned by Amazon MWS when queried."); + openList.RemoveAt(i); + i = i - 1; + } + } + + // update the database + new Data.Database.Export.UpdateAmazonFeedSubmission(sqlConnectionString).UpdateStatusInfo(openList); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Export/SalesInvoice.cs b/src/bnhtrade.Core/Logic/Export/SalesInvoice.cs new file mode 100644 index 0000000..8ade92b --- /dev/null +++ b/src/bnhtrade.Core/Logic/Export/SalesInvoice.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Export +{ + public class SalesInvoice + { + private string sqlConnectionString; + private Logic.Log.LogEvent log = new Log.LogEvent(); + + public SalesInvoice(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + + public string GetNextTempInvoiceNumber() + { + var sequence = new Data.Database.Programmability.Sequence(sqlConnectionString); + return "_tmp" + sequence.GetNext("ExportTempInvoiceNumber").ToString("00000000"); + } + + public void AddTempInvoiceNumber(IEnumerable invoiceList, bool overwriteExisting) + { + for (int i = 0; i < invoiceList.Count(); i++) + { + if (invoiceList.ElementAt(i).InvoiceNumber != null && overwriteExisting == false) + { + continue; + } + invoiceList.ElementAt(i).InvoiceNumber = GetNextTempInvoiceNumber(); + } + } + + public void SaveSalesInvoice(List invoiceList) + { + // validate the list of invoices + var validateInvoice = new Logic.Validate.SalesInvoice(); + validateInvoice.IsValidExportInvoice(invoiceList); + if (validateInvoice.IsValidResult == false) + { + log.LogError("Invalid Sales invoice(s) found. See extended info.", validateInvoice.ValidationResultListToString()); + return; + } + validateInvoice = null; + + // save to database + new Data.Database.Export.CreateSalesInvoice(sqlConnectionString).Execute(invoiceList); + } + } +} \ No newline at end of file diff --git a/src/bnhtrade.Core/Logic/Export/ValidateSalesInvoice.cs b/src/bnhtrade.Core/Logic/Export/ValidateSalesInvoice.cs deleted file mode 100644 index f07e20b..0000000 --- a/src/bnhtrade.Core/Logic/Export/ValidateSalesInvoice.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Logic.Export -{ - class ValidateSalesInvoice : Logic.Account.ValidateInvoice - { - //public bool IsValidInvoice(Model.Export.SetSalesInvoice invoice) - //{ - // ErrorMessage = null; - - // var baseInvoice = CopyInvoiceToBase(invoice); - // if (!base.IsValidInvoice(baseInvoice)) - // { - // return false; - // } - - // // check each match string only appears once - // var dicLookup = new Dictionary(); - // foreach (var line in invoice.InvoiceLineList) - // { - // if (dicLookup.ContainsKey(line.LineTypeMatchString)) - // { - // ErrorMessage = "'Line type match string' duplication."; - // return false; - // } - // else - // { - // dicLookup.Add(line.LineTypeMatchString, null); - // } - // } - - // return true; - //} - //public bool IsValidInvoiceHeader(Model.Export.SetSalesInvoice invoice) - //{ - // ErrorMessage = null; - - // var baseInvoice = CopyInvoiceHeaderToBase(invoice); - // if (base.IsValidInvoiceHeader(baseInvoice)) - // { - // return true; - // } - // else - // { - // return false; - // } - //} - //public bool IsValidInvoiceLine(Model.Export.SetSalesInvoiceLine invoiceLine) - //{ - // ErrorMessage = null; - - // var baseLine = CopyInvoiceLineToBase(invoiceLine); - // if (!IsValidLineTypeMatchString(invoiceLine.LineTypeMatchString) - // || !base.IsValidInvoiceLine(baseLine)) - // { - // return false; - // } - - // return true; - //} - //public bool IsValidLineTypeMatchString(string matchString) - //{ - // ErrorMessage = null; - // var stringCheck = new Logic.Utilities.StringCheck(); - // if (!stringCheck.MaxLength(matchString, 250)) - // { - // ErrorMessage = "Invalid Line Type Match String: " + stringCheck.ErrorMessage; - // return false; - // } - // return true; - //} - //private Model.Account.SalesInvoice CopyInvoiceToBase(Model.Export.SetSalesInvoice invoice) - //{ - // var baseInvoice = CopyInvoiceHeaderToBase(invoice); - // if (invoice.IsSetInvoiceLineList) - // { - // var baseLineList = new List(); - // foreach (var line in invoice.InvoiceLineList) - // { - // baseLineList.Add(CopyInvoiceLineToBase(line)); - // } - // baseInvoice.InvoiceLineList = baseLineList; - // } - // return baseInvoice; - //} - - //private Model.Account.SalesInvoice CopyInvoiceHeaderToBase(Model.Export.SetSalesInvoice invoice) - //{ - // var baseInvoice = new Model.Account.SalesInvoice(); - - // if (invoice.IsSetContactName) - // { baseInvoice.ContactName = invoice.ContactName; } - // if (invoice.IsSetInvoiceAmount) - // { baseInvoice.InvoiceAmount = invoice.InvoiceAmount; } - // if (invoice.IsSetInvoiceCurrencyCode) - // { baseInvoice.InvoiceCurrencyCode = invoice.InvoiceCurrencyCode; } - // if (invoice.IsSetInvoiceDate) - // { baseInvoice.InvoiceDate = invoice.InvoiceDate; } - // if (invoice.IsSetInvoiceNumber) - // { baseInvoice.InvoiceNumber = invoice.InvoiceNumber; } - // if (invoice.IsSetInvoiceReference) - // { baseInvoice.InvoiceReference = invoice.InvoiceReference; } - // if (invoice.IsSetIsComplete) - // { baseInvoice.IsComplete = invoice.IsComplete; } - - // return baseInvoice; - //} - //private Model.Account.SalesInvoiceLine CopyInvoiceLineToBase(Model.Export.SetSalesInvoiceLine invoiceLine) - //{ - // var baseLine = new Model.Account.SalesInvoiceLine(); - - // if (invoiceLine.IsSetAccountCode) - // { baseLine.AccountCode = invoiceLine.AccountCode; } - - // // something missing here ?????? - - // if (invoiceLine.IsSetDescription) - // { baseLine.Description = invoiceLine.Description; } - // if (invoiceLine.IsSetNetAmount) - // { baseLine.TotalNetAmount = invoiceLine.NetAmount; } - - // // tax adjustment to set ?????????? - - // if (invoiceLine.IsSetTaxCode) - // { baseLine.TaxCode = invoiceLine.TaxCode; } - - // return baseLine; - //} - } -} diff --git a/src/bnhtrade.Core/Logic/Product/GetCompetitivePrice.cs b/src/bnhtrade.Core/Logic/Product/GetCompetitivePrice.cs new file mode 100644 index 0000000..4733759 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Product/GetCompetitivePrice.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Product +{ + public class GetCompetitivePrice + { + private Dictionary competitivePrices; + private int newConditionId = Data.Database.Constants.GetProductConditionIdNew(); + private string sqlConnectionString; + private Data.Database.Product.ReadCompetitivePrice read; + private List productIdList; + private List conditionIdList; + private Data.Database.Product.ReadCompetitivePrice dbRead; + private Dictionary newConditionMultipier; + + public GetCompetitivePrice(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + dbRead = new Data.Database.Product.ReadCompetitivePrice(sqlConnectionString); + newConditionMultipier = new Dictionary(); + } + + /// + /// If a competitive price for a used condition is not found, return an estimated figure. + /// + public bool EstimatePrice { get; set; } = false; + + public int DistinctRequestCount { get; private set; } = 0; + + public int DistinctResponceCount { get; private set; } = 0; + + public void Innit() + { + DistinctRequestCount = 0; + DistinctResponceCount = 0; + } + + public Dictionary Execute(List skuParamList) + { + var requestList = new List<(int ProductId, int ConditionId)>(); + for (int i = 0; i < skuParamList.Count; i++) + { + requestList.Add((skuParamList[i].ProductId, skuParamList[i].ConditionId)); + } + var result = Execute(requestList); + + // build return list + var returnList = new Dictionary(); + for (int i = 0; i < skuParamList.Count; i++) + { + // skip? + if (returnList.ContainsKey(skuParamList[i].SkuNumber)) + { + continue; + } + // make a match + for (int j = 0; j < result.Count; j++) + { + if (skuParamList[i].ProductId == result[j].ProductId && skuParamList[i].ConditionId == result[j].ConditionId) + { + returnList.Add(skuParamList[i].SkuNumber, result[j].Clone()); + break; + } + } + } + return returnList; + } + + public List Execute(List<(int ProductId, int ConditionId)> requestList) + { + Innit(); + + var result = new List(); + + if (requestList == null || !requestList.Any()) + { + return result; + } + + // build distinct list + var distinctRequestList = new List<(int productId, int conditionId)>(); + for (int i = 0; i < requestList.Count; i++) + { + // filter values already requested + bool distinct = true; + for (int j = 0; j < distinctRequestList.Count; j++) + { + if (requestList[i].ProductId == distinctRequestList[j].productId + && requestList[i].ConditionId == distinctRequestList[j].conditionId) + { + distinct = false; + break; + } + } + if (distinct) + { distinctRequestList.Add((requestList[i].ProductId, requestList[i].ConditionId)); } + } + + DistinctRequestCount = distinctRequestList.Count(); + var dbResult = dbRead.Execute(distinctRequestList); + + // only contiue if estimated values are retured + if (DistinctRequestCount == dbResult.Count || !EstimatePrice) + { + DistinctResponceCount = dbResult.Count; + return result; + } + + // build estimated list + var estimatedRequestList = new List<(int productId, int conditionId)>(); + //var conditionMultipier = new Dictionary(); + for (int i = 0; i < distinctRequestList.Count; i++) + { + bool request = true; + // check if db returned record + for (int j = 0; j < dbResult.Count; j++) + { + if (distinctRequestList[i].productId == dbResult[j].ProductId + && distinctRequestList[i].conditionId == dbResult[j].ConditionId) + { + request = false; + break; + } + } + // check if 'new' condition price has already been retrived + if (request) + { + for (int j = 0; j < dbResult.Count; j++) + { + if (distinctRequestList[i].productId == dbResult[j].ProductId + && dbResult[j].ConditionId == newConditionId) + { + request = false; + break; + } + } + } + // add to request lists + if (request) + { + estimatedRequestList.Add((distinctRequestList[i].productId, newConditionId)); + if (!newConditionMultipier.ContainsKey(distinctRequestList[i].conditionId)) + { + newConditionMultipier.Add(distinctRequestList[i].conditionId, -1); + } + } + } + + dbResult.AddRange(dbRead.Execute(estimatedRequestList)); + UpdateConditionMultipers(); + + // build a new return list + var newResult = new List(); + var noMatchList = new List<(int productId, int conditionId)>(); + for (int i = 0; i < distinctRequestList.Count; i++) + { + // add exact matches + bool noMatch = true; + for (int j = 0; j < dbResult.Count; j++) + { + if (distinctRequestList[i].productId == dbResult[j].ProductId + && distinctRequestList[i].conditionId == dbResult[j].ConditionId) + { + noMatch = false; + newResult.Add(dbResult[j]); + break; + } + } + // add estimated matches + if (noMatch) + { + for (int j = 0; j < dbResult.Count; j++) + { + if (distinctRequestList[i].productId == dbResult[j].ProductId + && dbResult[j].ConditionId == newConditionId) + { + if (!newConditionMultipier.ContainsKey(distinctRequestList[i].conditionId)) + { + break; + } + + var clone = dbResult[j].Clone(); + clone.ConditionId = distinctRequestList[i].conditionId; + clone.Price = decimal.Round(clone.Price * newConditionMultipier[distinctRequestList[i].conditionId], 2); + clone.PriceIsEstimated = true; + + newResult.Add(clone); + noMatch = false; + break; + } + } + } + if (noMatch) + { + noMatchList.Add(distinctRequestList[i]); + } + } + + DistinctResponceCount = newResult.Count; + return newResult; + } + + public Model.Product.CompetitivePrice Execute(int productId, int conditionId) + { + Innit(); + DistinctRequestCount = 1; + var result = dbRead.Execute(new List<(int, int)> { (productId, conditionId) }); + + if (!result.Any()) + { + DistinctResponceCount = 0; + return null; + } + else + { + DistinctResponceCount = 1; + return result.First(); + } + } + + private void UpdateConditionMultipers() + { + var conditionInfo = new List(); + + if (newConditionMultipier.Any()) + { + conditionInfo = new Logic.Sku.GetSkuConditionInfo(sqlConnectionString) + .GetByConditionId(newConditionMultipier.Keys.ToList()); + } + else + { + conditionInfo = new Logic.Sku.GetSkuConditionInfo(sqlConnectionString).GetAll(); + } + + for(int i = 0; i < conditionInfo.Count; i++) + { + if (newConditionMultipier.ContainsKey(conditionInfo[i].SkuConditionId)) + { + newConditionMultipier[conditionInfo[i].SkuConditionId] = conditionInfo[i].CompetitivePriceMultiplier; + } + else + { + throw new Exception("Condition Id mismatch"); + } + } + + // check all multipilers have been set + for (int i = 0; i < newConditionMultipier.Count; i++) + { + if (newConditionMultipier.ElementAt(i).Value <= 0) + { + throw new Exception("Invalid price multiplier"); + } + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Sku/GetSkuConditionInfo.cs b/src/bnhtrade.Core/Logic/Sku/GetSkuConditionInfo.cs new file mode 100644 index 0000000..c4142ee --- /dev/null +++ b/src/bnhtrade.Core/Logic/Sku/GetSkuConditionInfo.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Sku +{ + public class GetSkuConditionInfo + { + private string sqlConnectionString; + private Data.Database.Sku.ReadSkuConditionInfo dbRead; + + public GetSkuConditionInfo(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + dbRead = new Data.Database.Sku.ReadSkuConditionInfo(sqlConnectionString); + } + + public List GetAll() + { + return dbRead.Read(new List()); + } + + public List GetByConditionId(List conditionIdList) + { + return dbRead.Read(conditionIdList); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Sku/Price/FbaPricing.cs b/src/bnhtrade.Core/Logic/Sku/Price/FbaPricing.cs new file mode 100644 index 0000000..3dc41ce --- /dev/null +++ b/src/bnhtrade.Core/Logic/Sku/Price/FbaPricing.cs @@ -0,0 +1,386 @@ +using CsvHelper; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Sku.Price +{ + public class FbaPricing + { + private string sqlConnectionString; + private bnhtrade.Core.Logic.Log.LogEvent log = new Log.LogEvent(); + string err = "FbaPricing Error: "; + private string marginSchemeTaxCode = "T190"; + int repriceHoldOnSalePeriod = 14; // days + private int newConditionId = Data.Database.Constants.GetProductConditionIdNew(); + private List skuInfo; + private Dictionary competitivePrices; + DateTime crTimeStamp = DateTime.UtcNow; + private int repriceIncrementDivisor = 60; + private Dictionary saleCountInPeriod = new Dictionary(); + private Logic.Account.TaxCalculation taxCalc; + private decimal marginSchemeMargin; + + public FbaPricing(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + taxCalc = new Account.TaxCalculation(); + crTimeStamp = DateTime.UtcNow; + marginSchemeMargin = taxCalc.GetMarginMultiplier(crTimeStamp); + } + + public void Update(bool overrideDayCheck = false) + { + using (var scope = new TransactionScope()) + { + string orderChannel = "Amazon.co.uk"; // may in future enable other order channels + + // need to add some cheks up here for last stock reconcilliation + + + + + + + // get current sku base pricing details (stock quantity, competative price, VAT info, etc.) + skuInfo = new Data.Database.Sku.Price.ReadParameter(sqlConnectionString).Execute(); + if (skuInfo == null || !skuInfo.Any()) + { + throw new Exception("Querying the database returned no records."); + } + + // create lists that we'll add to during lopp + var loader = new List(); + var crDictionary = new Dictionary(); + + // open needed classes + var readAge = new Data.Database.Import.ReadFbaInventoryAge(sqlConnectionString); + + // get current db pricing + var dbDictionary = new Data.Database.Sku.Price.ReadPricingDetail(sqlConnectionString).ReadDictionary(skuInfo.Select(o => o.SkuNumber).ToList(), orderChannel); + + // get required competivie prices + var readComp = new Logic.Product.GetCompetitivePrice(sqlConnectionString); + readComp.EstimatePrice = true; + var compPrices = readComp.Execute(skuInfo); + + // loop through skus returnd from stock query + for (int i = 0; i < skuInfo.Count(); i++) + { + string skuNumber = skuInfo[i].SkuNumber; + + var cr = new Model.Sku.Price.PriceInfo(); + + if (!overrideDayCheck && dbDictionary.Count > 0 && !OkayToReprice(dbDictionary[skuNumber].PriceInfoTimeStamp)) + { continue; } + + // load in values from skuInfo + cr.PriceTypeId = 1; + cr.ReviewRequired = false; + cr.OrderChannel = orderChannel; + cr.OrderChannelQuantity = skuInfo[i].TotalQuantity; + cr.PriceInfoTimeStamp = crTimeStamp; + cr.SkuNumber = skuInfo[i].SkuNumber; + + // get inventory age range + var invAge = readAge.BySkuNumber(skuInfo[i].SkuNumber, orderChannel); + if (invAge == null) + { + // this means lost stock, or unreconciled inventory... need to pause these skus else the price could decrease without it being on sale + err += "No records returned from tblImportFbaInventoryAgeReport for skuID=" + skuInfo[i].SkuId; + log.LogError(err); + throw new Exception(err); + } + cr.InventoryAgeMin = invAge.Value.MinAge; + cr.InventoryAgeMax = invAge.Value.MaxAge; + + // get minimum prices + cr.UnitMinPriceCost = GetMinPriceCost(i); + cr.UnitMinPriceProfit = GetMinPriceProfit(i); + cr.UnitPurchaseCost = skuInfo[i].UnitCostAverage; + + // set competitive price + if (compPrices.ContainsKey(skuInfo[i].SkuNumber)) + { + cr.CompetitivePrice = compPrices[skuInfo[i].SkuNumber].Price; + cr.CompetitivePriceIsEstimated = compPrices[skuInfo[i].SkuNumber].PriceIsEstimated; + } + else + { + cr.CompetitivePrice = cr.UnitMinPriceProfit + (cr.UnitMinPriceProfit / 2); + cr.CompetitivePriceIsEstimated = true; + } + + // set min max price + cr.RepriceIncrement = cr.CompetitivePrice / repriceIncrementDivisor; + + if (dbDictionary.ContainsKey(skuNumber)) + { + // sales wihtin period, therefore hold price + if (GetSaleCountInPeriod(i) > 0) + { + cr.MaxPrice = dbDictionary[skuNumber].MaxPrice; + cr.MinPrice = dbDictionary[skuNumber].MinPrice; + cr.RepriceIncrement = dbDictionary[skuNumber].RepriceIncrement; + } + // else reduce + else + { + if (dbDictionary[skuNumber].MaxPrice < dbDictionary[skuNumber].MinPrice) + { + err += "Max price lower than min price"; + log.LogError(err); + throw new Exception(err); + } + // redue both prices together + else if (dbDictionary[skuNumber].MaxPrice == dbDictionary[skuNumber].MinPrice) + { + cr.MaxPrice = dbDictionary[skuNumber].MaxPrice - cr.RepriceIncrement; + cr.MinPrice = cr.MaxPrice; + } + // reduce only max until it hits the min + else + { + cr.MaxPrice = dbDictionary[skuNumber].MaxPrice - cr.RepriceIncrement; + if (cr.MaxPrice < dbDictionary[skuNumber].MinPrice) + { + cr.MinPrice = cr.MaxPrice; + } + else + { + cr.MinPrice = dbDictionary[skuNumber].MinPrice; + } + } + } + } + else + { + // new value + cr.MaxPrice = cr.CompetitivePrice * 1.2m; + cr.MinPrice = cr.CompetitivePrice * 1m; + } + + // check on min price + cr.UnitMinPriceDestory = GetMinPriceDestroy(i); + if (cr.MaxPrice < cr.UnitMinPriceDestory) { cr.MaxPrice = cr.UnitMinPriceDestory; } + if (cr.MinPrice < cr.UnitMinPriceDestory) { cr.MinPrice = cr.UnitMinPriceDestory; } + + // add values to inventory loader list + var item = new Model.Export.AmazonIventoryLoaderFile(); + item.Sku = skuInfo[i].SkuNumber; + item.Price = cr.MaxPrice; + item.MinimumAllowedPrice = cr.MinPrice; + item.MaximumAllowedPrice = cr.MaxPrice; + item.SetFulfillmentCenterId(true); + loader.Add(item); + + // save current prices to dictionary + if (crDictionary.ContainsKey(skuNumber)) + { + err += "Multiple SkuId found in data"; + log.LogError(err); + throw new Exception(err); + } + crDictionary.Add(skuNumber, cr); + } + // finish loop + + // validate and save values to database + var validate = new Core.Logic.Validate.SkuPriceInfo(); + if (!validate.IsValidDatabaseCreate(crDictionary.Values.ToList())) + { + err += "Database object create validation failed"; + log.LogError(err, validate.ValidationResultListToString()); + throw new Exception(err); + } + + new Data.Database.Sku.Price.CreatePricingDetail(sqlConnectionString).Executue(crDictionary.Values.ToList()); + + // create and upload inventory loader file to amazon + var exportList = new List(); + foreach (var item in crDictionary.Values) + { + var listItem = new Model.Export.AmazonIventoryLoaderFile(); + listItem.Sku = item.SkuNumber; + listItem.MinimumAllowedPrice = item.MinPrice; + listItem.MaximumAllowedPrice = item.MaxPrice; + listItem.Price = item.MaxPrice; + listItem.SetFulfillmentCenterId(true); + exportList.Add(listItem); + } + + // validate + var vaildateInvLoader = new Validate.AmazonIventoryLoaderFile(); + if (!vaildateInvLoader.IsValidFbaPricing(exportList)) + { + err += "Inventory loader object validation failed"; + log.LogError(err, vaildateInvLoader.ValidationResultListToString()); + throw new Exception(err); + } + + // create file stream + var config = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.CurrentCulture); + config.Delimiter = "\t"; + config.Encoding = Encoding.UTF8; + + var stream = new MemoryStream(); + using (var writer = new StreamWriter(stream, Encoding.UTF8)) + using (var csv = new CsvWriter(writer, config)) + { + csv.WriteRecords(exportList); + } + + // submit file to database and amazon mws + var submit = new Logic.Export.AmazonSubmitFile(sqlConnectionString); + + return; + + submit.SubmitInventoryLoader(stream); + + scope.Complete(); + } + } + + private bool OkayToReprice(DateTime lastPriceUpdate) + { + if (lastPriceUpdate == default(DateTime)) + { + err += "Invalid, datetime is default."; + log.LogError(err); + throw new Exception(err); + } + + bool update = false; + lastPriceUpdate = new DateTime(lastPriceUpdate.Year, lastPriceUpdate.Month, lastPriceUpdate.Day); + DateTime today = new DateTime(crTimeStamp.Year, crTimeStamp.Month, crTimeStamp.Day); + + // will only update once on tue, wed or thurs each week. + if (today.DayOfWeek == DayOfWeek.Tuesday || today.DayOfWeek == DayOfWeek.Wednesday || today.DayOfWeek == DayOfWeek.Thursday) + { + if (today > lastPriceUpdate.AddDays(3)) + { + update = true; + } + } + + return update; + } + + /// + /// Get the minimum sale price to break even. + /// + /// + /// + private decimal GetMinPriceCost(int i) + { + decimal costPrice = skuInfo[i].UnitCostAverage; + decimal agentFeeFixed = skuInfo[i].AgentFeeFixed; + decimal agentFeeMargin = skuInfo[i].AgentFeeMargin; + decimal vatMargin = skuInfo[i].VatMargin; + + decimal price = 0; + + if (skuInfo[i].TaxCode == marginSchemeTaxCode) + { + price = (costPrice + agentFeeFixed - (costPrice * marginSchemeMargin)) + / (1 - agentFeeMargin - marginSchemeMargin); + } + else + { + price = (costPrice + agentFeeFixed) + / (1 - agentFeeMargin - vatMargin); + } + price = decimal.Round(price, 2); + return price; + } + + /// + /// Get the minimum sale price to achieve required profit margin. + /// + /// + /// Minimum price in decimal + private decimal GetMinPriceProfit(int i) + { + decimal costPrice = skuInfo[i].UnitCostAverage; + decimal minProfit = skuInfo[i].PriceMinProfit; + decimal profitMargin = skuInfo[i].ProfitMargin; + decimal agentFeeFixed = skuInfo[i].AgentFeeFixed; + decimal agentFeeMargin = skuInfo[i].AgentFeeMargin; + decimal vatMargin = skuInfo[i].VatMargin; + + decimal price = 0; + + if (skuInfo[i].TaxCode == marginSchemeTaxCode) // taxcodeinfo now has ismarginscheme boolean + { + price = (costPrice + agentFeeFixed - (costPrice * marginSchemeMargin)) + / (1 - profitMargin - agentFeeMargin - marginSchemeMargin); + } + else + { + price = (costPrice + agentFeeFixed) + / (1 - profitMargin - agentFeeMargin - vatMargin); + } + price = decimal.Round(price, 2); + + // if profit margin is less than min required, redo using min value (not percent) + if (price < minProfit) + { + if (skuInfo[i].TaxCode == marginSchemeTaxCode) + { + price = (minProfit + costPrice + agentFeeFixed - (costPrice * marginSchemeMargin)) + / (1 - agentFeeMargin - marginSchemeMargin); + } + else + { + price = (minProfit + costPrice + agentFeeFixed) + / (1 - agentFeeMargin - vatMargin); + } + } + price = decimal.Round(price, 2); + return price; + } + + private decimal GetMinPriceDestroy(int i) + { + decimal agentFeeFixed = skuInfo[i].AgentFeeFixed; + decimal agentFeeMargin = skuInfo[i].AgentFeeMargin; + decimal vatMargin = skuInfo[i].VatMargin; + + decimal price = 0; + + if (skuInfo[i].TaxCode == marginSchemeTaxCode) + { + price = (agentFeeFixed) / (1 - agentFeeMargin); + } + else + { + price = (agentFeeFixed) / (1 - agentFeeMargin - vatMargin); + } + price = decimal.Round(price, 2); + return price; + } + + private int GetSaleCountInPeriod(int i) + { + if (!saleCountInPeriod.Any()) + { + saleCountInPeriod = new Data.Database.Import.ReadFbaSaleShipment(sqlConnectionString) + .GetSaleCount(skuInfo.Select(x => x.SkuNumber).ToList(), DateTime.Now.AddDays(repriceHoldOnSalePeriod * -1), DateTime.Now); + } + if (saleCountInPeriod.ContainsKey(skuInfo[i].SkuNumber)) + { + return saleCountInPeriod[skuInfo[i].SkuNumber]; + } + else + { + return 0; + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Sku/Price/UpdateRepricingValues.cs b/src/bnhtrade.Core/Logic/Sku/Price/UpdateRepricingValues.cs new file mode 100644 index 0000000..5ea3010 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Sku/Price/UpdateRepricingValues.cs @@ -0,0 +1,787 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Data.SqlClient; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Sku.Price +{ + public class UpdateRepricingValues + { + //public void Update(string sqlConnectionString, bool skipReportUpdate = false) + //{ + // // need to add some cheks up here for last amazon reports import dates + + + + // /* + // * Quite complex this one, order of business + // * + // * Stage 1 - Stock Ledger Query reporting FBA stock (loop through this table) + // * Stage 1 - Read current values from SkuPrice tabel into variables + // * Stage 2 - Get/Set current MIN Price type 'crPriceMin_SkuPriceType' + // * Stage 3 - Set MIN Price, based off type + // * Stage 4 - Get/Set current MAX Price type 'crPriceMin_SkuPriceType' + // * Stage 5 - Set MAX Price, based off type + // * Stage 6 - Final check before db update + // * Stage 7 - Update main/history table + // */ + + // DateTime crTimeStamp = DateTime.UtcNow; + // int orderChannelId = 2; // may in future enable other order channels + + // // refers to max price movements + // decimal repriceDecreaseIncrement = 0.03m; // 3% each week + // int repriceDecreasePeriod = 7; // days + // int repriceHoldOnSalePeriod = 14; // days + // decimal repriceIncreaseIncrement = repriceDecreaseIncrement; // increases price if max sale price is within % of max price + // decimal repriceIncreaseOnStockSold = 0.3m; // percent of total qty sold over sale hold period + + // // add a check up here to test for any ASINs that do not have an estimated fee + + + + + + // // maybe add a constistancy check here (double entries in table (sku and order channel combination) + + + // using (var conn = new SqlConnection(sqlConnectionString)) + // { + // // loop through table + // using (var cmd01 = new SqlCommand("needs deleteing", conn)) + // { + // using (var reader01 = cmd01.ExecuteReader()) + // { + // var skuPricing = new Data.Database.Sku.Price.ReadParameter(sqlConnectionString).Execute(); + + // if (skuPricing == null) + // { + // throw new Exception("Querying the database returned no records."); + // } + // else + // { + // new Data.Database.Sku.Price.UpdateSkuPriceIsProcessed(sqlConnectionString).Update(); + // } + + // using (var scope = new TransactionScope()) + // using (var scopeConn = new SqlConnection(sqlConnectionString)) + // { + // scopeConn.Open(); + + // foreach (var sku in skuPricing) + // { + // // switches + // bool insertRequired = false; // skuId does not already exist in table + // bool updateRequired = false; // skuId exists and an edit is required + // bool resetMaxBaseAndMultiplier = false; // Quantity is moving from 0 to >0, lookup/update some values is required + + // // current (cr) variables + // var cr = new Model.Sku.Price.DetailResponce(); + + // cr.OrderChannelQuantity = sku.TotalQuantity; + // cr.UnitAvgCost = sku.UnitCostAverage; + + + // // Stage 1 + // // get db values from inventory table + // var db = new Data.Database.Sku.Price.ReadPricingDetail(sqlConnectionString).Read(sku.SkuId, orderChannelId); + // if (db == null) + // { + // insertRequired = true; + // db = new Model.Sku.Price.DetailResponce(); + + // // if this is null alot of the following code can be skipped, wip + + + + + + + + + + + + + + // } + + // // STAGE 2 + // // SKU current stock details (i.e. quantity, cost per unit, inventory age, etc.) + + // // get inventory age range + // var invAge = new Data.Database.Import.ReadFbaInventoryAge(sqlConnectionString).BySkuId(sku.SkuId, db.OrderChannelId); + + // if (invAge == null) + // { + // throw new Exception("No records returned from tblImportFbaInventoryAgeReport for skuID=" + sku.SkuId); + // } + // cr.InventoryAgeMin = invAge.Value.MinAge; + // cr.InventoryAgeMax = invAge.Value.MaxAge; + + + // // STAGE 3 + // // Get/Set Min Price SkukPriceTypeID + // // Do not change the 'crPriceMin_SkuPriceType' value after this stage + + // // + // //bool setMinToAuto = true; + // cr.PriceMin_SkuPriceType = 0; + // switch (db.PriceMin_SkuPriceType) + // { + // // Out of Stock + // case 0: + // if (cr.OrderChannelQuantity > 0) + // { cr.PriceMin_SkuPriceType = 1; } + // break; + + // //Auto + // case 1: + // cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; + // break; + + // // Fixed SKU price + // case 2: + // cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; + // break; + + // // Manual Price, Permanent + // case 100: + // cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; + // break; + + // // Manual Price, Inv Age Range Includes + // case 110: + // if (db.PriceMinStoredInt >= cr.InventoryAgeMin && db.PriceMinStoredInt <= cr.InventoryAgeMax) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Age Range Less Than + // case 111: + // if (cr.InventoryAgeMax < db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Age Range Greater Than + // case 112: + // if (cr.InventoryAgeMin > db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Less than + // case 120: + // if (cr.OrderChannelQuantity < db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Greater than + // case 121: + // if (cr.OrderChannelQuantity > db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Equal to + // case 122: + // if (cr.OrderChannelQuantity == db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Equal to + // case 123: + // if (cr.OrderChannelQuantity != db.PriceMinStoredInt) + // { cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; } + // else { cr.PriceMin_SkuPriceType = 1; } + // break; + + // default: + // // review of some sort required + // if (db.PriceMin_SkuPriceType >= 200 && db.PriceMin_SkuPriceType < 225) + // { + // cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; + // cr.ReviewRequired = true; + // } + // // error type + // else if (db.PriceMin_SkuPriceType >= 225 && db.PriceMin_SkuPriceType < 256) + // { + // cr.PriceMin_SkuPriceType = db.PriceMin_SkuPriceType; + // } + // // unhandled id type + // else + // { + // cr.PriceMin_SkuPriceType = 255; + // cr.ReviewRequired = true; + // } + // break; + // } + + // // Check manual enteries are present, if they are required + // if ((db.RequireAmountManual && db.PriceMinAmountManual == null) || (db.RequireStordedInt && db.PriceMinStoredInt == null)) + // { + // cr.PriceMin_SkuPriceType = 253; + // cr.ReviewRequired = true; + // } + + // // Stage 4 + // // Set MIN Price + + // // calculate the min 'auto' sku price & tax + // decimal crProfitMinAmount; + // decimal crPriceMinCalculatedTax; + + // if (sku.TaxRateName == "MS" || sku.TaxRateName == "GA") + // { + // cr.PriceMinAmountAuto = (5m * cr.UnitAvgCost + 6m * sku.AgentFeeFixed) / (-6m * sku.ProfitMargin - 6m * sku.AmazonMargin + 5m); + // crPriceMinCalculatedTax = (cr.PriceMinAmountAuto - cr.UnitAvgCost) * (1 / 6); + // crProfitMinAmount = cr.PriceMinAmountAuto * sku.ProfitMargin; + // } + // else + // { + // cr.PriceMinAmountAuto = (cr.UnitAvgCost + sku.AgentFeeFixed) / (1 - (sku.ProfitMargin + sku.AmazonMargin + sku.VatMargin)); + // crPriceMinCalculatedTax = cr.PriceMinAmountAuto * sku.VatMargin; + // crProfitMinAmount = cr.PriceMinAmountAuto * sku.ProfitMargin; + // } + + // // if profit margin is less than min required, redo + // if (crProfitMinAmount < sku.PriceMinProfit) + // { + // if (sku.TaxRateName == "MS" || sku.TaxRateName == "GA") + // { + // cr.PriceMinAmountAuto = (6m * sku.PriceMinProfit + 5m * cr.UnitAvgCost + 6m * sku.AgentFeeFixed) / (-6m * sku.AmazonMargin + 5m); + // crPriceMinCalculatedTax = (cr.PriceMinAmountAuto - cr.UnitAvgCost) * (1 / 6); + // crProfitMinAmount = cr.PriceMinAmountAuto * sku.ProfitMargin; + // } + // else + // { + // cr.PriceMinAmountAuto = (cr.UnitAvgCost + sku.AgentFeeFixed + sku.PriceMinProfit) / (1 - (sku.AgentFeeMargin + sku.VatMargin)); + // crPriceMinCalculatedTax = cr.PriceMinAmountAuto * sku.VatMargin; + // crProfitMinAmount = cr.PriceMinAmountAuto * sku.ProfitMargin; + // } + // } + + // // Calculate current final MIN price values + // if (cr.PriceMin_SkuPriceType == 1) + // { + // cr.PriceMinAmountFinal = cr.PriceMinAmountAuto; + // cr.PriceMinAmountFinalFee = (cr.PriceMinAmountFinal * sku.AgentFeeMargin) + sku.AgentFeeFixed; + // cr.PriceMinAmountFinalTax = crPriceMinCalculatedTax; + // } + // else + // { + // cr.PriceMinAmountFinal = (decimal)db.PriceMinAmountManual; + // cr.PriceMinAmountFinalFee = ((decimal)db.PriceMinAmountManual * sku.AgentFeeMargin) + sku.AgentFeeFixed; + // if (sku.TaxRateName == "MS" || sku.TaxRateName == "GA") + // { + // cr.PriceMinAmountFinalTax = ((decimal)db.PriceMinAmountManual - cr.UnitAvgCost) * (1 / 6); + // } + // else + // { + // cr.PriceMinAmountFinalTax = cr.PriceMinAmountAuto * sku.VatMargin; + // } + // } + + // // STAGE 5 + // // Get/Set MAX Price SkukPriceTypeID + // // Do not change the 'cr.PriceMax_SkuPriceType' value after this stage + + // cr.PriceMax_SkuPriceType = 0; + // switch (db.PriceMax_SkuPriceType) + // { + // // Out of Stock + // case 0: + // if (cr.OrderChannelQuantity > 0) + // { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Auto + // case 1: + // cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; + // break; + + // // Fixed SKU price + // case 2: + // cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; + // break; + + // // Manual Price, Permanent + // case 100: + // cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; + // break; + + // // Manual Price, Inv Age Range Includes + // case 110: + // if (db.PriceMaxStoredInt >= cr.InventoryAgeMin && db.PriceMaxStoredInt <= cr.InventoryAgeMax) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Age Range Less Than + // case 111: + // if (cr.InventoryAgeMax < db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Age Range Greater Than + // case 112: + // if (cr.InventoryAgeMin > db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Less than + // case 120: + // if (cr.OrderChannelQuantity < db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Greater than + // case 121: + // if (cr.OrderChannelQuantity > db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Equal to + // case 122: + // if (cr.OrderChannelQuantity == db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // // Manual Price, Inv Quanity is Not Equal to + // case 123: + // if (cr.OrderChannelQuantity == db.PriceMaxStoredInt) + // { cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; } + // else { cr.PriceMax_SkuPriceType = 1; } + // break; + + // default: + // // review of some sort required + // if (db.PriceMax_SkuPriceType >= 200 && db.PriceMax_SkuPriceType < 225) + // { + // cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; + // cr.ReviewRequired = true; + // } + // // error type + // else if (db.PriceMax_SkuPriceType >= 225 && db.PriceMax_SkuPriceType < 256) + // { + // cr.PriceMax_SkuPriceType = db.PriceMax_SkuPriceType; + // } + // // unhandled id type + // else + // { + // cr.PriceMax_SkuPriceType = 255; + // cr.ReviewRequired = true; + // } + // break; + // } + + // // Check manual enteried are present, if they are required + // if ((db.RequireAmountManualMax && db.PriceMaxAmountManual == null) || (db.RequireStordedIntMax && db.PriceMaxStoredInt == null)) + // { + // cr.PriceMax_SkuPriceType = 253; + // cr.ReviewRequired = true; + // } + + // // STAGE 6 + // // Set MAX Price + + // // CASE: Reset MAX-Price base & multiplier values (new record or switching back to auto) + // if (insertRequired || (cr.PriceMax_SkuPriceType == 1 && db.PriceMax_SkuPriceType != 1)) + // { + // // get competative price and apply multiplier + // bool usedForceNew = false; + // var request = new bnhtrade.Core.Product.ProductQuery(); + // var compPrice = request.ProductCompetitivePriceGet(sqlConnectionString, sku.ProductId, sku.ConditionId); + // if (compPrice.price == null || compPrice.priceDate == null) + // { + // if (sku.ConditionId != 10) + // { + // usedForceNew = true; + // compPrice = request.ProductCompetitivePriceGet(sqlConnectionString, sku.ProductId, 10); + // } + // if (compPrice.price == null || compPrice.priceDate == null) + // { + // cr.PriceMax_SkuPriceType = 254; + // cr.ReviewRequired = true; + // } + // } + + // cr.PriceMaxAmountAutoBase = compPrice.price ?? 0; + // if (usedForceNew) + // { + // cr.PriceMaxAmountAutoMultiplier = sku.CompetitivePriceMultiplierNew; + // } + // else + // { + // cr.PriceMaxAmountAutoMultiplier = sku.CompetitivePriceMultiplierMatch; + // } + + // // transfer manual values, if required + // if (insertRequired == false) + // { + // cr.PriceMaxAmountManual = db.PriceMaxAmountManual; + // cr.PriceMaxStoredInt = db.PriceMaxStoredInt; + // } + + // // set final max value + // cr.PriceMaxAmountFinal = cr.PriceMaxAmountAutoBase * cr.PriceMaxAmountAutoMultiplier; + // } + + // // already on auto, adjust existing value, if required + // else if (db.PriceMax_SkuPriceType == 1) + // { + // // get last sale date + // int shipmentsInSaleHoldPeriod = 0; + // // works from last unit ship-date, not the preferred order-date + // // TODO: this could be better when other parts of application get more info + // DateTime shipDateFilter = crTimeStamp.AddDays(repriceHoldOnSalePeriod * -1); + // shipDateFilter = new DateTime(shipDateFilter.Year, shipDateFilter.Month, shipDateFilter.Day); + // using (var cmd04 = new SqlCommand(@" + // SELECT COUNT(tblImportFbaSaleShipment.ImportFbaSaleShipmentID) AS RecordCount + // FROM tblImportFbaSaleShipment + // INNER JOIN tblSku ON tblImportFbaSaleShipment.sku = tblSku.skuSkuNumber + // WHERE (tblSku.skuSkuID = @skuID) + // AND (tblImportFbaSaleShipment.[shipment-date] >= @shipDateFilter) + // ", conn)) + // { + // cmd04.Parameters.AddWithValue("@skuID", sku.SkuId); + // cmd04.Parameters.AddWithValue("@shipDateFilter", shipDateFilter); + + // shipmentsInSaleHoldPeriod = (int)cmd04.ExecuteScalar(); + // } + // // get max item sale price during period + // decimal maxSalePrice = 0; + // if (shipmentsInSaleHoldPeriod > 0) + // { + // using (var cmd05 = new SqlCommand(@" + // SELECT Max(ISNULL([tblImportFbaSaleShipment].[item-price], 0) + ISNULL([tblImportFbaSaleShipment].[item-tax], 0)) AS Expr1 + // FROM tblImportFbaSaleShipment + // INNER JOIN tblSku ON tblImportFbaSaleShipment.sku = tblSku.skuSkuNumber + // WHERE ( + // ((tblSku.skuSkuID) = @skuID) + // AND ((tblImportFbaSaleShipment.[shipment-date]) >= @shipDateFilter) + // ) + // ", conn)) + // { + // cmd05.Parameters.AddWithValue("@skuID", sku.SkuId); + // cmd05.Parameters.AddWithValue("@shipDateFilter", shipDateFilter); + + // maxSalePrice = (decimal)cmd05.ExecuteScalar(); + // } + // } + + // DateTime updateDate = new DateTime(db.PriceCreated.Year, db.PriceCreated.Month, db.PriceCreated.Day); + // updateDate = updateDate.AddDays(repriceDecreasePeriod); + + // // decrease maxx price + // if (crTimeStamp >= updateDate && shipmentsInSaleHoldPeriod == 0) + // { + // cr.PriceMaxAmountAutoBase = db.PriceMaxAmountAutoBase; + // cr.PriceMaxAmountAutoMultiplier = db.PriceMaxAmountAutoMultiplier - repriceDecreaseIncrement; + // cr.PriceMaxAmountManual = db.PriceMaxAmountManual; + // cr.PriceMaxStoredInt = db.PriceMaxStoredInt; + // cr.PriceMaxAmountFinal = cr.PriceMaxAmountAutoBase * cr.PriceMaxAmountAutoMultiplier; + // } + // else + // { + // // increase price + // if (maxSalePrice >= (db.PriceMaxAmountAutoBase * (db.PriceMaxAmountAutoMultiplier - repriceIncreaseIncrement))) + // { + // cr.PriceMaxAmountAutoBase = db.PriceMaxAmountAutoBase; + // cr.PriceMaxAmountAutoMultiplier = db.PriceMaxAmountAutoMultiplier + repriceIncreaseIncrement; + // cr.PriceMaxAmountManual = db.PriceMaxAmountManual; + // cr.PriceMaxStoredInt = db.PriceMaxStoredInt; + // cr.PriceMaxAmountFinal = cr.PriceMaxAmountAutoBase * cr.PriceMaxAmountAutoMultiplier; + // } + // // remain same + // else + // { + // cr.PriceMaxAmountAutoBase = db.PriceMaxAmountAutoBase; + // cr.PriceMaxAmountAutoMultiplier = db.PriceMaxAmountAutoMultiplier; + // cr.PriceMaxAmountManual = db.PriceMaxAmountManual; + // cr.PriceMaxStoredInt = db.PriceMaxStoredInt; + // cr.PriceMaxAmountFinal = cr.PriceMaxAmountAutoBase * cr.PriceMaxAmountAutoMultiplier; + // } + // } + // } + + // // STAGE 7 + // // Checks before update + + // // max < min + // if (cr.PriceMaxAmountFinal < cr.PriceMinAmountFinal) + // { + // // on auto, set max to min value and update base multipier to reflect new value + // if (cr.PriceMax_SkuPriceType == 1) + // { + // cr.PriceMaxAmountFinal = cr.PriceMinAmountFinal; + // cr.PriceMaxAmountAutoMultiplier = cr.PriceMinAmountFinal / cr.PriceMaxAmountAutoBase; + // } + // else if (cr.PriceMax_SkuPriceType > 0 && cr.PriceMax_SkuPriceType < 200) + // { + // cr.PriceMax_SkuPriceType = 252; + // cr.ReviewRequired = true; + // } + // } + + // // this should be last check + // // check for zero values (where there should not be any) -- this could be a life saver i.e. selling item for £0.00 + // if (cr.PriceMinAmountFinal * cr.PriceMaxAmountFinal == 0) + // { + // cr.PriceMax_SkuPriceType = 251; + // cr.ReviewRequired = true; + // } + + // // STAGE 8 + // // Update main/history tables, if required + // // round decimals for db comarison + // cr.UnitAvgCost = decimal.Round(cr.UnitAvgCost, 2); + // cr.PriceMinAmountAuto = decimal.Round(cr.PriceMinAmountAuto, 2); + // cr.PriceMinAmountFinalFee = decimal.Round(cr.PriceMinAmountFinalFee, 2); + // cr.PriceMinAmountFinalTax = decimal.Round(cr.PriceMinAmountFinalTax, 2); + // cr.PriceMinAmountFinal = decimal.Round(cr.PriceMinAmountFinal, 2); + // cr.PriceMaxAmountAutoMultiplier = decimal.Round(cr.PriceMaxAmountAutoMultiplier, 8); + // cr.PriceMaxAmountFinal = decimal.Round(cr.PriceMaxAmountFinal, 2); + + // if (insertRequired == false && + // ( + // db.OrderChannelQuantity != cr.OrderChannelQuantity || + // db.UnitAvgCost != cr.UnitAvgCost || + // db.InventoryAgeMin != cr.InventoryAgeMin || + // db.InventoryAgeMax != cr.InventoryAgeMax || + // db.PriceMin_SkuPriceType != cr.PriceMin_SkuPriceType || + // db.PriceMinAmountAuto != cr.PriceMinAmountAuto || + // db.PriceMinAmountFinalFee != cr.PriceMinAmountFinalFee || + // db.PriceMinAmountFinalTax != cr.PriceMinAmountFinalTax || + // db.PriceMinAmountFinal != cr.PriceMinAmountFinal || + // db.PriceMax_SkuPriceType != cr.PriceMax_SkuPriceType || + // db.PriceMaxAmountAutoBase != cr.PriceMaxAmountAutoBase || + // db.PriceMaxAmountAutoMultiplier != cr.PriceMaxAmountAutoMultiplier || + // db.PriceMaxAmountFinal != cr.PriceMaxAmountFinal || + // db.ReviewRequired != cr.ReviewRequired + // ) + // ) + // { + // updateRequired = true; + // } + + + + + + + + + + + + + + // // insert old data to history table + // if (updateRequired) + // { + // using (var cmd06 = new SqlCommand(@" + // INSERT INTO tblSkuPriceHistory ( + // SkuID + // ,OrderChannelID + // ,OrderChannelQuantity + // ,UnitAvgCost + // ,InventoryAgeMin + // ,InventoryAgeMax + // ,PriceMin_SkuPriceType + // ,PriceMinAmountAuto + // ,PriceMinAmountManual + // ,PriceMinStoredInt + // ,PriceMinAmountFinalFee + // ,PriceMinAmountFinalTax + // ,PriceMinAmountFinal + // ,PriceMax_SkuPriceType + // ,PriceMaxAmountAutoBase + // ,PriceMaxAmountAutoMultiplier + // ,PriceMaxAmountManual + // ,PriceMaxStoredInt + // ,PriceMaxAmountFinal + // ,RecordModified + // ,ReviewRequired + // ) + // VALUES ( + // @skuID + // ,@dbOrderChannelID + // ,@dbOrderChannelQuantity + // ,@dbUnitAvgCost + // ,@dbInventoryAgeMin + // ,@dbInventoryAgeMax + // ,@dbPriceMin_SkuPriceType + // ,@dbPriceMinAmountAuto + // ,@dbPriceMinAmountManual + // ,@dbPriceMinStoredInt + // ,@dbPriceMinAmountFinalFee + // ,@dbPriceMinAmountFinalTax + // ,@dbPriceMinAmountFinal + // ,@dbPriceMax_SkuPriceType + // ,@dbPriceMaxAmountAutoBase + // ,@dbPriceMaxAmountAutoMultiplier + // ,@dbPriceMaxAmountManual + // ,@dbPriceMaxStoredInt + // ,@dbPriceMaxAmountFinal + // ,@dbRecordModified + // ,@dbReviewRequired + // ) + // ", scopeConn)) + // { + // cmd06.Parameters.AddWithValue("@skuID", sku.SkuId); + // cmd06.Parameters.AddWithValue("@dbOrderChannelID", db.OrderChannelId); + // cmd06.Parameters.AddWithValue("@dbOrderChannelQuantity", db.OrderChannelQuantity); + // cmd06.Parameters.AddWithValue("@dbUnitAvgCost", db.UnitAvgCost); + // cmd06.Parameters.AddWithValue("@dbInventoryAgeMin", db.InventoryAgeMin); + // cmd06.Parameters.AddWithValue("@dbInventoryAgeMax", db.InventoryAgeMax); + // cmd06.Parameters.AddWithValue("@dbPriceMin_SkuPriceType", db.PriceMin_SkuPriceType); + // cmd06.Parameters.AddWithValue("@dbPriceMinAmountAuto", db.PriceMinAmountAuto); + // cmd06.Parameters.AddWithValue("@dbPriceMinAmountManual", db.PriceMinAmountManual); + // cmd06.Parameters.AddWithValue("@dbPriceMinStoredInt", db.PriceMinStoredInt); + // cmd06.Parameters.AddWithValue("@dbPriceMinAmountFinalFee", db.PriceMinAmountFinalFee); + // cmd06.Parameters.AddWithValue("@dbPriceMinAmountFinalTax", db.PriceMinAmountFinalTax); + // cmd06.Parameters.AddWithValue("@dbPriceMinAmountFinal", db.PriceMinAmountFinal); + // cmd06.Parameters.AddWithValue("@dbPriceMax_SkuPriceType", db.PriceMax_SkuPriceType); + // cmd06.Parameters.AddWithValue("@dbPriceMaxAmountAutoBase", db.PriceMaxAmountAutoBase); + // cmd06.Parameters.AddWithValue("@dbPriceMaxAmountAutoMultiplier", db.PriceMaxAmountAutoMultiplier); + // cmd06.Parameters.AddWithValue("@dbPriceMaxAmountManual", db.PriceMaxAmountManual); + // cmd06.Parameters.AddWithValue("@dbPriceMaxStoredInt", db.PriceMaxStoredInt); + // cmd06.Parameters.AddWithValue("@dbPriceMaxAmountFinal", db.PriceMaxAmountFinal); + // cmd06.Parameters.AddWithValue("@dbRecordModified", db.PriceCreated); + // cmd06.Parameters.AddWithValue("@dbReviewRequired", db.ReviewRequired); + + // int count = cmd06.ExecuteNonQuery(); + // } + // } + + // // delete existing data in current table + // if (updateRequired) + // { + // using (var cmd07 = new SqlCommand(@" + // DELETE FROM tblSkuPriceHistory + // WHERE SkuID = @skuID AND OrderChannelID = @dbOrderChannelID + // ", scopeConn)) + // { + // cmd07.Parameters.AddWithValue("@skuID", sku.SkuId); + // cmd07.Parameters.AddWithValue("@dbOrderChannelID", db.OrderChannelId); + + // int count = cmd07.ExecuteNonQuery(); + // } + // } + + // // insert new data into current table + // if (updateRequired || insertRequired) + // { + // using (var cmd06 = new SqlCommand(@" + // INSERT INTO tblSkuPrice ( + // SkuID + // ,OrderChannelID + // ,OrderChannelQuantity + // ,UnitAvgCost + // ,InventoryAgeMin + // ,InventoryAgeMax + // ,PriceMin_SkuPriceType + // ,PriceMinAmountAuto + // ,PriceMinAmountManual + // ,PriceMinStoredInt + // ,PriceMinAmountFinalFee + // ,PriceMinAmountFinalTax + // ,PriceMinAmountFinal + // ,PriceMax_SkuPriceType + // ,PriceMaxAmountAutoBase + // ,PriceMaxAmountAutoMultiplier + // ,PriceMaxAmountManual + // ,PriceMaxStoredInt + // ,PriceMaxAmountFinal + // ,RecordModified + // ,ReviewRequired + // ) + // VALUES ( + // @skuID + // ,@crOrderChannelID + // ,@crOrderChannelQuantity + // ,@crUnitAvgCost + // ,@crInventoryAgeMin + // ,@crInventoryAgeMax + // ,@crPriceMin_SkuPriceType + // ,@crPriceMinAmountAuto + // ,@crPriceMinAmountManual + // ,@crPriceMinStoredInt + // ,@crPriceMinAmountFinalFee + // ,@crPriceMinAmountFinalTax + // ,@crPriceMinAmountFinal + // ,@crPriceMax_SkuPriceType + // ,@crPriceMaxAmountAutoBase + // ,@crPriceMaxAmountAutoMultiplier + // ,@crPriceMaxAmountManual + // ,@crPriceMaxStoredInt + // ,@crPriceMaxAmountFinal + // ,@crRecordModified + // ,@crReviewRequired + // ) + // ", scopeConn)) + // { + // cmd06.Parameters.AddWithValue("@skuID", sku.SkuId); + // cmd06.Parameters.AddWithValue("@crOrderChannelID", db.OrderChannelId); + // cmd06.Parameters.AddWithValue("@crOrderChannelQuantity", cr.OrderChannelQuantity); + // cmd06.Parameters.AddWithValue("@crUnitAvgCost", cr.UnitAvgCost); + // cmd06.Parameters.AddWithValue("@crInventoryAgeMin", cr.InventoryAgeMin); + // cmd06.Parameters.AddWithValue("@crInventoryAgeMax", cr.InventoryAgeMax); + // cmd06.Parameters.AddWithValue("@crPriceMin_SkuPriceType", cr.PriceMin_SkuPriceType); + // cmd06.Parameters.AddWithValue("@crPriceMinAmountAuto", cr.PriceMinAmountAuto); + // cmd06.Parameters.AddWithValue("@crPriceMinAmountManual", cr.PriceMinAmountManual); + // cmd06.Parameters.AddWithValue("@crPriceMinStoredInt", cr.PriceMinStoredInt); + // cmd06.Parameters.AddWithValue("@crPriceMinAmountFinalFee", cr.PriceMinAmountFinalFee); + // cmd06.Parameters.AddWithValue("@crPriceMinAmountFinalTax", cr.PriceMinAmountFinalTax); + // cmd06.Parameters.AddWithValue("@crPriceMinAmountFinal", cr.PriceMinAmountFinal); + // cmd06.Parameters.AddWithValue("@crPriceMax_SkuPriceType", cr.PriceMax_SkuPriceType); + // cmd06.Parameters.AddWithValue("@crPriceMaxAmountAutoBase", cr.PriceMaxAmountAutoBase); + // cmd06.Parameters.AddWithValue("@crPriceMaxAmountAutoMultiplier", cr.PriceMaxAmountAutoMultiplier); + // cmd06.Parameters.AddWithValue("@crPriceMaxAmountManual", cr.PriceMaxAmountManual); + // cmd06.Parameters.AddWithValue("@crPriceMaxStoredInt", cr.PriceMaxStoredInt); + // cmd06.Parameters.AddWithValue("@crPriceMaxAmountFinal", cr.PriceMaxAmountFinal); + // cmd06.Parameters.AddWithValue("@crRecordModified", cr.PriceCreated); + // cmd06.Parameters.AddWithValue("@crReviewRequired", cr.ReviewRequired); + + // int count = cmd06.ExecuteNonQuery(); + // } + // } + + + + + + + + + + // } // drop out of query while loop here + + // // set any records that are not IsProcessed=TRUE to no quantity (i.e. by type) and quantity + // // or... do I copy record to history and delete <------- THIS + + + // // also, should add check, cross reference inventory age table against stock ledger results to highlight sku where I reckon + // // qty is zero and amazon is >0 + + + // scope.Complete(); + // } + // } + // } + // } + //} + } +} \ No newline at end of file diff --git a/src/bnhtrade.Core/Logic/Stock/Reallocate.cs b/src/bnhtrade.Core/Logic/Stock/Reallocate.cs new file mode 100644 index 0000000..350735e --- /dev/null +++ b/src/bnhtrade.Core/Logic/Stock/Reallocate.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Stock +{ + public class Reallocate + { + private string sqlConnectionString; + + public Reallocate(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + + public int StockReallocateByStockId(int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId, + DateTime entryDate = default(DateTime)) + { + if (entryDate == default(DateTime)) + { + entryDate = DateTime.Now; + } + + // create the list + var posts = new List<(int statusId, int quantity)>(); + posts.Add((debitStatusId, quantity)); + posts.Add((creditStatusId, (quantity * -1))); + + // execute + return Core.Stock.StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false); + } + + + /// + /// Feed an skuId and quantity into function and the stock will be reallocated + /// + public List<(int StockJournalId, int Quantity)> StockReallocateBySkuNumber(int journalTypeId, string skuNumber, int quantity, int debitStatusId, int creditStatusId, + bool firstInFirstOut = true, DateTime entryDate = default(DateTime), bool reallocatePartialQuantity = false) + { + var returnList = new List<(int StockJournalId, int Quantity)>(); + + List> list = Core.Stock.StockJournal.GetStockStatusBalanceBySkuNumber(sqlConnectionString, skuNumber, creditStatusId, entryDate, firstInFirstOut); + + if (list == null || !list.Any()) + { + return returnList; + } + + // quantity check + int avaiableQuantity = 0; + foreach (Tuple item in list) + { + avaiableQuantity = avaiableQuantity + item.Item3; + } + if (avaiableQuantity < quantity && reallocatePartialQuantity == false) + { + return null; + } + + // make the changes + using (TransactionScope scope = new TransactionScope()) + { + foreach (Tuple item in list) + { + if (quantity > item.Item3) + { + int tempInt = StockReallocateByStockId(journalTypeId, item.Item1, item.Item3, debitStatusId, creditStatusId, entryDate); + quantity = quantity - item.Item3; + returnList.Add((tempInt, item.Item3)); + } + else + { + int tempInt = StockReallocateByStockId(journalTypeId, item.Item1, quantity, debitStatusId, creditStatusId, entryDate); + returnList.Add((tempInt, quantity)); + break; + } + } + scope.Complete(); + return returnList; + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Stock/SkuTransactionPersistance.cs b/src/bnhtrade.Core/Logic/Stock/SkuTransactionPersistance.cs new file mode 100644 index 0000000..010f596 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Stock/SkuTransactionPersistance.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Stock +{ + public class SkuTransactionPersistance + { + 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.ReadSkuTransaction dbSkuTransRead; + private Data.Database.Stock.UpdateSkuTransaction dbSkuTransUpdate; + private Logic.Validate.SkuTransaction validateSkuTrans; + private Logic.Log.LogEvent log; + + public SkuTransactionPersistance(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + log = new Log.LogEvent(); + } + + private Data.Database.Stock.DeleteSkuTransaction DatabaseSkuTransDelete(bool forceNew = false) + { + if (dbSkuTransDelete == null || forceNew) + { + dbSkuTransDelete = new Data.Database.Stock.DeleteSkuTransaction(sqlConnectionString); + } + return dbSkuTransDelete; + } + + private Data.Database.Stock.CreateSkuTransaction DatabaseSkuTransInsert(bool forceNew = false) + { + if (dbSkuTransCreate == null || forceNew) + { + dbSkuTransCreate = new Data.Database.Stock.CreateSkuTransaction(sqlConnectionString); + } + return dbSkuTransCreate; + } + + private Data.Database.Stock.ReadSkuTransaction DatabaseSkuTransRead(bool forceNew = false) + { + if (dbSkuTransRead == null || forceNew) + { + dbSkuTransRead = new Data.Database.Stock.ReadSkuTransaction(sqlConnectionString); + } + return dbSkuTransRead; + } + + private Data.Database.Stock.UpdateSkuTransaction DatabaseSkuTransUpdate(bool forceNew = false) + { + if (dbSkuTransUpdate == null || forceNew) + { + dbSkuTransUpdate = new Data.Database.Stock.UpdateSkuTransaction(sqlConnectionString); + } + return dbSkuTransUpdate; + } + + private Logic.Validate.SkuTransaction Validate() + { + if (validateSkuTrans == null) + { + validateSkuTrans = new Validate.SkuTransaction(); + } + return validateSkuTrans; + } + + public void Delete(int skuTransactionId) + { + using (var scope = new TransactionScope()) + { + try + { + // is there a journal entry attached? + int? journalId = DatabaseSkuTransRead().GetJournalId(skuTransactionId); + if (journalId != null) + { + Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, (int)journalId); + } + + DatabaseSkuTransDelete().ByTransactionId(skuTransactionId); + scope.Complete(); + } + catch (Exception ex) + { + scope.Dispose(); + throw ex; + } + } + } + + public void DeleteJournalEntry(int skuTransactionId) + { + using (var scope = new TransactionScope()) + { + try + { + // is there a journal entry attached? + int? journalId = DatabaseSkuTransRead().GetJournalId(skuTransactionId); + if (journalId != null) + { + DatabaseSkuTransUpdate().Update(skuTransactionId, null); + Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, (int)journalId); + } + scope.Complete(); + } + catch (Exception ex) + { + scope.Dispose(); + throw ex; + } + } + } + + 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); + } + + public void Update(Model.Stock.SkuTransaction skuTransaction) + { + if (skuTransaction == null) + { + throw new Exception(err + "Object was null"); + } + + Validate().Innit(); + 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); + } + } + dbSkuTransUpdate.Update(skuTransaction); + scope.Complete(); + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Stock/SkuTransactionReconcile.cs b/src/bnhtrade.Core/Logic/Stock/SkuTransactionReconcile.cs new file mode 100644 index 0000000..350dc80 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Stock/SkuTransactionReconcile.cs @@ -0,0 +1,398 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +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.Validate.SkuTransaction validateSkuTrans; + private Logic.Stock.Reallocate stockReallocate; + private Logic.Log.LogEvent logEvent; + private string err = "Reconcile Sku Transaction Exception: "; + + public SkuTransactionReconcile(string sqlConnectionString) + { + Innit(); + this.sqlConnectionString = sqlConnectionString; + dbSkuTransaction = new SkuTransactionPersistance(sqlConnectionString); + dbSkuTransactionType = new SkuTransactionTypePersistance(sqlConnectionString); + readShipmentInfo = new Data.Database.AmazonShipment.ReadShipmentInfo(sqlConnectionString); + validateSkuTrans = new Validate.SkuTransaction(); + stockReallocate = new Logic.Stock.Reallocate(sqlConnectionString); + logEvent = new Log.LogEvent(); + } + + public int ItemsCompleted { get; private set; } + + public int ItemsRemaining { get; private set; } + + public DateTime LastItemDateTime { get; private set; } + + public string ProgressMessage { get; private set; } + + public bool ReconciliationComplete { get; private set; } + + public int CurrentTransactionId { get; private set; } + + public int CurrentTransactionTypeId { get; private set; } + + public Model.Stock.SkuTransaction CurrentSkuTransaction { get; private set; } + + private void Innit() + { + ItemsCompleted = 0; + ItemsRemaining = 0; + LastItemDateTime = default(DateTime); + ProgressMessage = null; + ReconciliationComplete = false; + CurrentTransactionId = 0; + CurrentTransactionTypeId = 0; + } + + /// + /// 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) + /// + /// Download and process Amazon reports before starting process + /// + public void ReconcileStockTransactions(bool updateTransactions) + { + Innit(); + string currentMethodName = nameof(ReconcileStockTransactions); + + // ensure import table have been processed into transaction table without exception + if (updateTransactions == true) + { + try + { + var preCheck = new bnhtrade.Core.Stock.StockReconciliation(); + preCheck.ProcessFbaStockImportData(sqlConnectionString); + } + catch (Exception ex) + { + ProgressMessage = "Precheck failed: " + ex.Message; + return; + } + } + + logEvent.LogInformation("Starting ReconcileStockTransactions()"); + int recordSkip = 0; + + ProcessLostAndFound(); + + // get list of sku transactions to reconcile + var transList = new Data.Database.Stock.ReadSkuTransaction(sqlConnectionString).GetUnreconciled(); + ItemsRemaining = transList.Count; + ItemsCompleted = 0; + + try + { + // loop through transaction list + for (int i = 0; i < transList.Count; i++) + { + using (var scope = new TransactionScope()) + { + + Console.Write("\rProcessing record: {0} ({1} skipped)", (i + 1 + recordSkip), recordSkip); + + // setup return values + CurrentSkuTransaction = transList[i]; + CurrentTransactionId = transList[i].SkuTransactionId; + CurrentTransactionTypeId = transList[i].SkuTransactionTypeId; + LastItemDateTime = transList[i].TransactionDate; + + // load type into variable + var transType = dbSkuTransactionType.GetByTypeName(transList[i].SkuTransactionTypeName); + + // stop if a new transactiontype is encountered + if (transType.IsNewReviewRequired) + { + ProgressMessage = "New 'Transaction-Type' encountered"; + //Console.Write("\r"); + //MiscFunction.EventLogInsert(errMessage, 1); + goto Stop; + } + + // set debit/credit status' for special cases (i.e. NULL or 0 debit/credit ids in stockTransactionType table) + if (transType.StockJournalEntryEnabled == true && (transType.DebitStockStatusId == 0 || transType.CreditStockStatusId == 0)) + { + // FBA Shipment Receipt +ve + if (transType.TypeCode == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>" + || transType.TypeCode == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><-ve>") + { + var shipmentInfo = readShipmentInfo.HeaderByFbaShipmentId(transList[i].Reference); + + if (shipmentInfo.IsSetShipmentStockStatusId()) + { + // +ve shipment receipt + if (transType.CreditStockStatusId == 0 && transType.DebitStockStatusId > 0) + { transType.CreditStockStatusId = shipmentInfo.ShipmentStockStatusId; } + + // -ve shipment receipt + else if (transType.DebitStockStatusId == 0 && transType.CreditStockStatusId > 0) + { transType.DebitStockStatusId = shipmentInfo.ShipmentStockStatusId; } + + // something went wrong, raise error + else + { + ProgressMessage = "Unable to retrive FBA shipment location/status from tblAmazonShipment for Amazon shipment '" + shipmentInfo.FbaShipmentId + "'."; + recordSkip = recordSkip + 1; + goto Stop; + } + } + } + // something went wrong, raise error + else + { + ProgressMessage = "Coding required. Unhandled special case Transaction-Type encountered (Transaction-Type debit or credit is set to 0)."; + recordSkip = recordSkip + 1; + goto Stop; + } + } + + // make the changes + if (transType.StockJournalEntryEnabled == false) + { + transList[i].IsProcessed = true; + dbSkuTransaction.Update(transList[i]); + } + else + { + var list = new List<(int StockJournalId, int Quantity)>(); + if (transType.FilterStockOnDateTime) + { + list = stockReallocate.StockReallocateBySkuNumber( + transType.StockJournalTypeId, + transList[i].SkuNumber, + transList[i].Quantity, + transType.DebitStockStatusId, + transType.CreditStockStatusId, + transType.FirstInFirstOut, + transList[i].TransactionDate, + false); + } + else + { + list = stockReallocate.StockReallocateBySkuNumber( + transType.StockJournalTypeId, + transList[i].SkuNumber, + transList[i].Quantity, + transType.DebitStockStatusId, + transType.CreditStockStatusId, + transType.FirstInFirstOut, + DateTime.UtcNow, + false); + } + + // insufficient balance available + if (list == null || !list.Any()) + { + // in special case (found inventory), continue + if (transType.TypeCode.Contains("<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_>")) + { + continue;// <--------------------------------------------------------------------------------------------------- is this the soruce of the bug? + } + else + { + ProgressMessage = "Insurficent status/location balance to relocate stock"; + recordSkip = recordSkip + 1; + goto Stop; + } + } + + // fail safe + int qtyAllocated = list.Sum(c => c.Quantity); + if (qtyAllocated > transList[i].Quantity) + { + throw new Exception( + currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function" + + transList[i].SkuTransactionId); + } + + // update sku transaction table + int qtyRemain = qtyAllocated; + var newRecordList = new List(); + for (int j = 0; j <= list.Count; j++) + { + // update existing record + if (j == 0) + { + transList[i].Quantity = (short)list[j].Quantity; + transList[i].StockJournalId = list[j].StockJournalId; + transList[i].IsProcessed = true; + + dbSkuTransaction.Update(transList[i]); + } + // new record + else if (j < list.Count) + { + var newRecord = transList[i].Clone(); + newRecord.Quantity = (short)list[j].Quantity; + newRecord.IsProcessed = true; + newRecord.StockJournalId = list[j].StockJournalId; + newRecordList.Add(newRecord); + } + // new record, unallocated quantity + else if (qtyRemain > 0) + { + var newRecord = transList[i].Clone(); + newRecord.Quantity = (short)qtyRemain; + newRecord.IsProcessed = false; + newRecordList.Add(newRecord); + } + + if (j < list.Count) + { + qtyRemain = qtyRemain - list[j].Quantity; + } + } + // add new transactions to table + for (int j = 0; j < newRecordList.Count; j++) + { + dbSkuTransaction.Create(newRecordList[j]); + } + } + ItemsCompleted++; + ItemsRemaining++; + scope.Complete(); + } + // end of scope + } + // end of loop + } + catch (Exception ex) + { + Console.Write("\r"); + ProgressMessage = ex.Message; + return; + } + + Stop: + Console.Write("\r"); + + MiscFunction.EventLogInsert("ProcessStockTransactions() compete. " + ItemsCompleted + " total records processed, " + recordSkip + " rows uncompllete due to insurficent stock."); + MiscFunction.EventLogInsert("ProcessStockTransactions(), " + recordSkip + " rows skipped due to insurficent stock.", 2); + + ReconciliationComplete = true; + ProgressMessage = "Operation complete."; + return; + } + + + /// + /// + /// + public void ProcessLostAndFound() + { + using (var scope = new TransactionScope()) + { + + // get list of sku transactions to reconcile + var transList = new Data.Database.Stock.ReadSkuTransaction(sqlConnectionString).GetUnreconciled(); + ItemsRemaining = transList.Count; + ItemsCompleted = 0; + + // 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 = "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><-ve>"; + string found = "<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><+ve>"; + + for (int i = 0; i < transList.Count; i++) + { + var transType = dbSkuTransactionType.GetByTypeName(transList[i].SkuTransactionTypeName); + + if (transType.TypeCode == found && !transList[i].IsProcessed) + { + 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++) + { + // we have a match + if (transList[j].SkuNumber == sku && !transList[j].IsProcessed && transType.TypeCode == lost) + { + // split transaction and break + if (foundQtyUnAllocated - transList[j].Quantity < 0) + { + // create and validate clone + var clone = transList[j].Clone(); + clone.Quantity = (short)foundQtyUnAllocated; + clone.IsProcessed = true; + + // modifiy and validate existing record + transList[j].IsProcessed = false; + transList[j].Quantity = (short)(transList[j].Quantity - foundQtyUnAllocated); + foundQtyUnAllocated = 0; + + // 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) + { + break; + } + } + } + + // 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) + { + throw new NotImplementedException(); + + // create clone + var clone = transList[i].Clone(); + clone.Quantity -= (short)foundQtyUnAllocated; + clone.IsProcessed = true; + + // modifiy and validate existing record + transList[i].IsProcessed = false; + transList[i].Quantity -= (short)foundQtyUnAllocated; + foundQtyUnAllocated = 0; + + // submitt to database + dbSkuTransaction.Create(clone); + dbSkuTransaction.Update(transList[i]); + } + // this shouldn't happen + else + { + throw new Exception("Quantity unallocated is negative number"); + } + } + } + } + scope.Complete(); + } + } + } +} diff --git a/src/bnhtrade.Core/Logic/Stock/SkuTransactionTypePersistance.cs b/src/bnhtrade.Core/Logic/Stock/SkuTransactionTypePersistance.cs new file mode 100644 index 0000000..e93bc41 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Stock/SkuTransactionTypePersistance.cs @@ -0,0 +1,98 @@ +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 cache; + private Data.Database.Stock.ReadSkuTransactionType dbRead; + + public SkuTransactionTypePersistance(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + dbRead = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString); + InnitCache(); + } + + public void InnitCache() + { + cache = new List(); + } + + public Model.Stock.SkuTransactionType GetByTypeCode(string typeCode, bool clearCache = false) + { + if (string.IsNullOrWhiteSpace(typeCode)) + { + return null; + } + + if (clearCache) + { + InnitCache(); + } + else + { + for (int i = 0; i < cache.Count; i++) + { + if (cache[i].TypeCode == typeCode) + { + return cache[i]; + } + } + } + + var result = dbRead.ByTypeCode(new List { 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) + { + InnitCache(); + } + else + { + for (int i = 0; i < cache.Count; i++) + { + if (cache[i].TypeName == typeName) + { + return cache[i]; + } + } + } + + var result = dbRead.ByTypeName(new List { typeName }); + + if (result.Any()) + { + cache.Add(result[0]); + return result[0]; + } + else + { + return null; + } + } + + } +} diff --git a/src/bnhtrade.Core/Logic/Utilities/CalculateMD5.cs b/src/bnhtrade.Core/Logic/Utilities/CalculateMD5.cs new file mode 100644 index 0000000..ae1af28 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Utilities/CalculateMD5.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Utilities +{ + public class CalculateMD5 + { + public string Base64(Stream stream) + { + stream.Position = 0; + + MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); + byte[] hash = provider.ComputeHash(stream); + string returnvalue = Convert.ToBase64String(hash); + return returnvalue; + } + + public string Base64(byte[] byteArray) + { + MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); + byte[] hash = provider.ComputeHash(byteArray); + string returnvalue = Convert.ToBase64String(hash); + return returnvalue; + } + } +} diff --git a/src/bnhtrade.Core/Logic/Utilities/DateTimeCheck.cs b/src/bnhtrade.Core/Logic/Utilities/DateTimeCheck.cs index e5d63ac..dacc3fe 100644 --- a/src/bnhtrade.Core/Logic/Utilities/DateTimeCheck.cs +++ b/src/bnhtrade.Core/Logic/Utilities/DateTimeCheck.cs @@ -6,18 +6,18 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Logic.Utilities { - public class DateTimeCheck : Validate + public class DateTimeCheck : Validate.Validate { public bool IsUtc(DateTime dateTimeToCheck) { if (dateTimeToCheck == default(DateTime)) { - ErrorListAdd( "DateTime value set to default."); + ValidationResultAdd( "DateTime value set to default."); return false; } if (dateTimeToCheck.Kind != DateTimeKind.Utc) { - ErrorListAdd("DateTime not set to UTC kind."); + ValidationResultAdd("DateTime not set to UTC kind."); return false; } return true; @@ -26,12 +26,12 @@ namespace bnhtrade.Core.Logic.Utilities { if (dateTimeToCheck == default(DateTime)) { - ErrorListAdd("DateTime value set to default."); + ValidationResultAdd("DateTime value set to default."); return false; } if (dateTimeToCheck.Kind != DateTimeKind.Local) { - ErrorListAdd("DateTime not set to Local kind."); + ValidationResultAdd("DateTime not set to Local kind."); return false; } return true; diff --git a/src/bnhtrade.Core/Logic/Utilities/DateTimeParse.cs b/src/bnhtrade.Core/Logic/Utilities/DateTimeParse.cs new file mode 100644 index 0000000..970a387 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Utilities/DateTimeParse.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Utilities +{ + public class DateTimeParse + { + public DateTime ParseMwsReportDateTime(string reportDateTime) + { + string isoDateTime = + reportDateTime.Substring(6, 4) + "-" + + reportDateTime.Substring(3, 2) + "-" + + reportDateTime.Substring(0, 2) + "T" + + reportDateTime.Substring(11, 2) + ":" + + reportDateTime.Substring(14, 2) + ":" + + reportDateTime.Substring(17, 2) + "Z"; + return DateTime.Parse(isoDateTime); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Utilities/DecimalCheck.cs b/src/bnhtrade.Core/Logic/Utilities/DecimalCheck.cs index eed1d1a..1448e67 100644 --- a/src/bnhtrade.Core/Logic/Utilities/DecimalCheck.cs +++ b/src/bnhtrade.Core/Logic/Utilities/DecimalCheck.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Logic.Utilities { - public class DecimalCheck : Validate + public class DecimalCheck : Validate.Validate { /// /// Finds total number of digits in a decimal number, does not include decimal point. @@ -36,13 +36,13 @@ namespace bnhtrade.Core.Logic.Utilities int precision = GetPrecision(decimalToCheck); if (precision > 2) { - ErrorListAdd("Decimal precision overload"); + ValidationResultAdd("Decimal precision overload"); return false; } int length = GetLength(decimalToCheck); if (length > 9) { - ErrorListAdd("Decimal length overload"); + ValidationResultAdd("Decimal length overload"); return false; } return true; diff --git a/src/bnhtrade.Core/Logic/Utilities/StringCheck.cs b/src/bnhtrade.Core/Logic/Utilities/StringCheck.cs index b75429e..79f51a3 100644 --- a/src/bnhtrade.Core/Logic/Utilities/StringCheck.cs +++ b/src/bnhtrade.Core/Logic/Utilities/StringCheck.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Logic.Utilities { - public class StringCheck : Validate + public class StringCheck : Validate.Validate { public bool AllowEmpty { get; set; } = false; public bool AllowWhiteSpace { get; set; } = false; @@ -22,7 +22,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (!allowNull) { - ErrorListAdd("String is null"); + ValidationResultAdd("String is null"); return false; } } @@ -35,12 +35,12 @@ namespace bnhtrade.Core.Logic.Utilities { if ((c >= 'a' && c <= 'z') && upperCaseOnly) { - ErrorListAdd("String contains lower case numerical charater(s)."); + ValidationResultAdd("String contains lower case numerical charater(s)."); return false; } else { - ErrorListAdd("String contains non-alpha charater(s)."); + ValidationResultAdd("String contains non-alpha charater(s)."); return false; } } @@ -54,7 +54,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (!allowNull) { - ErrorListAdd("String is null"); + ValidationResultAdd("String is null"); return false; } } @@ -68,12 +68,12 @@ namespace bnhtrade.Core.Logic.Utilities { if ((c >= 'a' && c <= 'z') && upperCaseOnly) { - ErrorListAdd("String contains lower case numerical charater(s)."); + ValidationResultAdd("String contains lower case numerical charater(s)."); return false; } else { - ErrorListAdd("String contains non-alphanumeric charater(s)."); + ValidationResultAdd("String contains non-alphanumeric charater(s)."); return false; } } @@ -87,7 +87,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (allowNull == false) { - ErrorListAdd("String is null"); + ValidationResultAdd("String is null"); return false; } } @@ -97,7 +97,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (c < '0' || c > '9') { - ErrorListAdd("String contains non-numeric charater(s)."); + ValidationResultAdd("String contains non-numeric charater(s)."); return false; } } @@ -114,7 +114,7 @@ namespace bnhtrade.Core.Logic.Utilities int length = stringToCheck.Length; if (length != stringLength) { - ErrorListAdd("String length (" + length + ") does not equal " + stringLength + " charaters."); + ValidationResultAdd("String length (" + length + ") does not equal " + stringLength + " charaters."); return false; } return true; @@ -131,7 +131,7 @@ namespace bnhtrade.Core.Logic.Utilities int length = stringToCheck.Length; if (length > maxLength) { - ErrorListAdd("String length (" + length + ") is greater than " + maxLength + " charaters."); + ValidationResultAdd("String length (" + length + ") is greater than " + maxLength + " charaters."); return false; } } @@ -147,7 +147,7 @@ namespace bnhtrade.Core.Logic.Utilities int length = stringToCheck.Length; if (length <= minLength) { - ErrorListAdd("String length (" + length + ") is less than " + minLength + " charaters."); + ValidationResultAdd("String length (" + length + ") is less than " + minLength + " charaters."); return false; } return true; @@ -161,7 +161,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (!allowNull) { - ErrorListAdd("String is null, empty or white space."); + ValidationResultAdd("String is null, empty or white space."); return false; } } @@ -169,7 +169,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (!AllowEmpty) { - ErrorListAdd("String is empty."); + ValidationResultAdd("String is empty."); return false; } } @@ -177,7 +177,7 @@ namespace bnhtrade.Core.Logic.Utilities { if (!AllowWhiteSpace) { - ErrorListAdd("String is white space."); + ValidationResultAdd("String is white space."); return false; } } diff --git a/src/bnhtrade.Core/Logic/Validate.cs b/src/bnhtrade.Core/Logic/Validate.cs deleted file mode 100644 index 6c56590..0000000 --- a/src/bnhtrade.Core/Logic/Validate.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Logic -{ - public abstract class Validate - { - private List errorList = new List(); - - public List ErrorList - { - get { return errorList; } - } - - public bool ErrorListIsSet - { - get - { - if (errorList == null || !errorList.Any()) { return false; } - else { return true; } - } - } - - protected void ErrorListAdd(string errorString) - { - this.errorList.Add(errorString); - } - - protected void ErrorListAdd(List errorList) - { - this.errorList.AddRange(errorList); - } - - public string ErrorListToString() - { - if (ErrorListIsSet) - { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < ErrorList.Count; i++) - { - result.AppendLine(ErrorList[i]); - } - return result.ToString(); - } - else { return null; } - } - - public void Innit() - { - this.errorList = new List(); - } - } -} diff --git a/src/bnhtrade.Core/Logic/Account/ValidateAccountCode.cs b/src/bnhtrade.Core/Logic/Validate/AccountCode.cs similarity index 79% rename from src/bnhtrade.Core/Logic/Account/ValidateAccountCode.cs rename to src/bnhtrade.Core/Logic/Validate/AccountCode.cs index 0d3980f..e252f42 100644 --- a/src/bnhtrade.Core/Logic/Account/ValidateAccountCode.cs +++ b/src/bnhtrade.Core/Logic/Validate/AccountCode.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Logic.Account +namespace bnhtrade.Core.Logic.Validate { - public class ValidateAccountCode : Validate + public class AccountCode : Validate { private Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck(); @@ -21,7 +21,7 @@ namespace bnhtrade.Core.Logic.Account { return true; } else { - ErrorListAdd("Invalid account code."); + ValidationResultAdd("Invalid account code."); return false; } } @@ -33,7 +33,7 @@ namespace bnhtrade.Core.Logic.Account } else { - ErrorListAdd(stringCheck.ErrorList); + ValidationResultAdd(stringCheck.ValidationResult); return false; } } @@ -45,7 +45,7 @@ namespace bnhtrade.Core.Logic.Account } else { - ErrorListAdd(stringCheck.ErrorList); + ValidationResultAdd(stringCheck.ValidationResult); return false; } } @@ -57,7 +57,7 @@ namespace bnhtrade.Core.Logic.Account } else { - ErrorListAdd(stringCheck.ErrorList); + ValidationResultAdd(stringCheck.ValidationResult); return false; } } @@ -69,7 +69,7 @@ namespace bnhtrade.Core.Logic.Account } else { - ErrorListAdd(stringCheck.ErrorList); + ValidationResultAdd(stringCheck.ValidationResult); return false; } } diff --git a/src/bnhtrade.Core/Logic/Validate/AmazonIventoryLoaderFile.cs b/src/bnhtrade.Core/Logic/Validate/AmazonIventoryLoaderFile.cs new file mode 100644 index 0000000..28d5e8a --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/AmazonIventoryLoaderFile.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Validate +{ + public class AmazonIventoryLoaderFile : Validate + { + public bool IsValidFbaPricing(IEnumerable exportList) + { + if (!IsValid(exportList)) + { + return false; + } + + return IsValidResult; + } + } +} diff --git a/src/bnhtrade.Core/Logic/Import/ValidateAmazonSettlement.cs b/src/bnhtrade.Core/Logic/Validate/AmazonSettlement.cs similarity index 71% rename from src/bnhtrade.Core/Logic/Import/ValidateAmazonSettlement.cs rename to src/bnhtrade.Core/Logic/Validate/AmazonSettlement.cs index 63a1c21..eb98720 100644 --- a/src/bnhtrade.Core/Logic/Import/ValidateAmazonSettlement.cs +++ b/src/bnhtrade.Core/Logic/Validate/AmazonSettlement.cs @@ -4,16 +4,16 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Logic.Import +namespace bnhtrade.Core.Logic.Validate { - public class ValidateAmazonSettlement : Validate + public class AmazonSettlement : Validate { protected Utilities.StringCheck stringCheck = new Utilities.StringCheck(); protected Utilities.DateTimeCheck timeCheck = new Utilities.DateTimeCheck(); - protected Account.ValidateCurrencyCode currencyCheck = new Account.ValidateCurrencyCode(); + protected Logic.Validate.CurrencyCode currencyCheck = new Logic.Validate.CurrencyCode(); protected Utilities.DecimalCheck decimalCheck = new Utilities.DecimalCheck(); - public ValidateAmazonSettlement() : base() + public AmazonSettlement() : base() { } @@ -40,38 +40,38 @@ namespace bnhtrade.Core.Logic.Import for (int i = 0; i < settlementList.Count; i++) { - if (!settlementList[i].CurrencyCodeIsSet) { ErrorListAdd("CurrencyCode is a required value."); } + if (!settlementList[i].CurrencyCodeIsSet) { ValidationResultAdd("CurrencyCode is a required value."); } else { IsValidCurrencyCode(settlementList[i].CurrencyCode); } - if (!settlementList[i].DepositDateIsSet) { ErrorListAdd("DepositDate is a required value."); } + if (!settlementList[i].DepositDateIsSet) { ValidationResultAdd("DepositDate is a required value."); } else { IsValidDepositDate(settlementList[i].DepositDate); } - if (!settlementList[i].EndDateIsSet) { ErrorListAdd("EndDate is a required value."); } + if (!settlementList[i].EndDateIsSet) { ValidationResultAdd("EndDate is a required value."); } else { IsValidEndDate(settlementList[i].EndDate); } - if (!settlementList[i].IsProcessedIsSet) { ErrorListAdd("IsProcessed is a required value."); } + if (!settlementList[i].IsProcessedIsSet) { ValidationResultAdd("IsProcessed is a required value."); } else { IsValidIsProcessed(settlementList[i].IsProcessed); } if (!settlementList[i].MarketPlaceNameIsSet) { - if (ValidateMarketPlaceName) { ErrorListAdd("MarketPlaceName is a required value."); } + if (ValidateMarketPlaceName) { ValidationResultAdd("MarketPlaceName is a required value."); } } else { IsValidMarketPlaceName(settlementList[i].MarketPlaceName); } - if (!settlementList[i].SettlementIdIsSet) { ErrorListAdd("SettlementId is a required value."); } + if (!settlementList[i].SettlementIdIsSet) { ValidationResultAdd("SettlementId is a required value."); } else { IsValidSettlementId(settlementList[i].SettlementId); } - if (!settlementList[i].StartDateIsSet) { ErrorListAdd("StartDate is a required value."); } + if (!settlementList[i].StartDateIsSet) { ValidationResultAdd("StartDate is a required value."); } else { IsValidStartDate(settlementList[i].StartDate); } - if (!settlementList[i].TotalAmountIsSet) { ErrorListAdd("TotalAmount is a required value."); } + if (!settlementList[i].TotalAmountIsSet) { ValidationResultAdd("TotalAmount is a required value."); } else { IsValidTotalAmount(settlementList[i].TotalAmount); } // check line list if (!settlementList[i].SettlementLineListIsSet) { - ErrorListAdd("Settlement line list is null or empty"); + ValidationResultAdd("Settlement line list is null or empty"); continue; } else @@ -88,14 +88,13 @@ namespace bnhtrade.Core.Logic.Import // check totals if (lineSum != settlementList[i].TotalAmount) { - ErrorListAdd("Settlement header total (" + settlementList[i].TotalAmount + + ValidationResultAdd("Settlement header total (" + settlementList[i].TotalAmount + ") does not match line total (" + lineSum + ")"); } } } - if (ErrorListIsSet) { return false; } - else { return true; } + return IsValidResult; } public bool IsValid(Model.Import.AmazonSettlement.SettlementLine settlementLine) @@ -111,7 +110,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Amount is a required value."); + ValidationResultAdd("Amount is a required value."); } @@ -121,7 +120,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Amount Description is a required value."); + ValidationResultAdd("Amount Description is a required value."); } @@ -131,7 +130,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Amount Type is a required value."); + ValidationResultAdd("Amount Type is a required value."); } @@ -141,7 +140,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Currency Code is a required value."); + ValidationResultAdd("Currency Code is a required value."); } @@ -161,7 +160,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Is Processed is a required value."); + ValidationResultAdd("Is Processed is a required value."); } @@ -201,7 +200,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Posted DateTime is a required value."); + ValidationResultAdd("Posted DateTime is a required value."); } if (settlementLine.PromotionIdIsSet) @@ -230,23 +229,22 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Transaction Type is a required value."); + ValidationResultAdd("Transaction Type is a required value."); } - if (ErrorListIsSet) { return false; } - else { return true; } + return IsValidResult; } public bool IsValidSettlementId(string settlementId) { if (!stringCheck.IsNumeric(settlementId)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid settlement Id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid settlement Id: " + x).ToList()); return false; } if (!stringCheck.MaxLength(settlementId, 50)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid settlement Id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid settlement Id: " + x).ToList()); return false; } return true; @@ -261,7 +259,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(marketPlaceName, 50, true)) { - ErrorListAdd("Invalid market place name."); + ValidationResultAdd("Invalid market place name."); return false; } return true; @@ -271,7 +269,7 @@ namespace bnhtrade.Core.Logic.Import { if (!timeCheck.IsUtc(startDate)) { - ErrorListAdd(timeCheck.ErrorList.Select(x => "Invalid StartDate: " + x).ToList()); + ValidationResultAdd(timeCheck.ValidationResult.Select(x => "Invalid StartDate: " + x).ToList()); return false; } return true; @@ -281,7 +279,7 @@ namespace bnhtrade.Core.Logic.Import { if (!timeCheck.IsUtc(endDate)) { - ErrorListAdd(timeCheck.ErrorList.Select(x => "Invalid EndDate: " + x).ToList()); + ValidationResultAdd(timeCheck.ValidationResult.Select(x => "Invalid EndDate: " + x).ToList()); return false; } return true; @@ -291,7 +289,7 @@ namespace bnhtrade.Core.Logic.Import { if (!timeCheck.IsUtc(depositDate)) { - ErrorListAdd(timeCheck.ErrorList.Select(x => "Invalid DepositDate: " + x).ToList()); + ValidationResultAdd(timeCheck.ValidationResult.Select(x => "Invalid DepositDate: " + x).ToList()); return false; } return true; @@ -301,7 +299,7 @@ namespace bnhtrade.Core.Logic.Import { if (!decimalCheck.SqlLength92(totalAmount)) { - ErrorListAdd(decimalCheck.ErrorList.Select(x => "Total Amount Invalid: " + x).ToList()); + ValidationResultAdd(decimalCheck.ValidationResult.Select(x => "Total Amount Invalid: " + x).ToList()); return false; } return true; @@ -311,7 +309,7 @@ namespace bnhtrade.Core.Logic.Import { if (!currencyCheck.IsValidCurrencyCode(currencyCode)) { - ErrorListAdd(currencyCheck.ErrorList.Select(x => "Total Amount CurrencyCode: " + x).ToList()); + ValidationResultAdd(currencyCheck.ValidationResult.Select(x => "Total Amount CurrencyCode: " + x).ToList()); return false; } return true; @@ -338,7 +336,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(transactionType, 50)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid transaction type: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid transaction type: " + x).ToList()); return false; } return true; @@ -347,7 +345,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(orderId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid order id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid order id: " + x).ToList()); return false; } return true; @@ -356,7 +354,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(merchantOrderId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid merchant order id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid merchant order id: " + x).ToList()); return false; } return true; @@ -365,7 +363,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(adjustmentId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid adjustment id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid adjustment id: " + x).ToList()); return false; } return true; @@ -374,7 +372,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(shipmentId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid shipment id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid shipment id: " + x).ToList()); return false; } return true; @@ -383,7 +381,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(amountType, 50)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid amount type: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid amount type: " + x).ToList()); return false; } return true; @@ -392,7 +390,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(amountDescription, 100)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid amount description: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid amount description: " + x).ToList()); return false; } return true; @@ -401,7 +399,7 @@ namespace bnhtrade.Core.Logic.Import { if (!decimalCheck.SqlLength92(amount)) { - ErrorListAdd(decimalCheck.ErrorList.Select(x => "Invalid amount: " + x).ToList()); + ValidationResultAdd(decimalCheck.ValidationResult.Select(x => "Invalid amount: " + x).ToList()); return false; } return true; @@ -410,7 +408,7 @@ namespace bnhtrade.Core.Logic.Import { if (!currencyCheck.IsValidCurrencyCode(currenyCode)) { - ErrorListAdd(currencyCheck.ErrorList.Select(x => "Invalid curreny code: " + x).ToList()); + ValidationResultAdd(currencyCheck.ValidationResult.Select(x => "Invalid curreny code: " + x).ToList()); return false; } return true; @@ -419,7 +417,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(fulfillmentId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid fulfillment Id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid fulfillment Id: " + x).ToList()); return false; } return true; @@ -429,7 +427,7 @@ namespace bnhtrade.Core.Logic.Import var timeCheck = new Logic.Utilities.DateTimeCheck(); if (!timeCheck.IsUtc(postDateTime)) { - ErrorListAdd(@"Invalid post date/time, not set to UTC kind."); + ValidationResultAdd(@"Invalid post date/time, not set to UTC kind."); return false; } return true; @@ -438,7 +436,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(orderItemCode, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid order item code: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid order item code: " + x).ToList()); return false; } return true; @@ -447,7 +445,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(merchantOrderItemId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid merchant order item id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid merchant order item id: " + x).ToList()); return false; } return true; @@ -456,7 +454,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(merchantAdjustmentItemId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid merchant adjustment item id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid merchant adjustment item id: " + x).ToList()); return false; } return true; @@ -465,7 +463,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(skuNumber, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid sku number: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid sku number: " + x).ToList()); return false; } return true; @@ -478,7 +476,7 @@ namespace bnhtrade.Core.Logic.Import { if (!stringCheck.MaxLength(promotionId, 50, true)) { - ErrorListAdd(stringCheck.ErrorList.Select(x => "Invalid promotion id: " + x).ToList()); + ValidationResultAdd(stringCheck.ValidationResult.Select(x => "Invalid promotion id: " + x).ToList()); return false; } return true; @@ -491,7 +489,7 @@ namespace bnhtrade.Core.Logic.Import } else { - ErrorListAdd("Export account invoice line id cannot be less than 1"); + ValidationResultAdd("Export account invoice line id cannot be less than 1"); return false; } } diff --git a/src/bnhtrade.Core/Logic/Account/ValidateCurrencyCode.cs b/src/bnhtrade.Core/Logic/Validate/CurrencyCode.cs similarity index 82% rename from src/bnhtrade.Core/Logic/Account/ValidateCurrencyCode.cs rename to src/bnhtrade.Core/Logic/Validate/CurrencyCode.cs index 478f842..e2acf9f 100644 --- a/src/bnhtrade.Core/Logic/Account/ValidateCurrencyCode.cs +++ b/src/bnhtrade.Core/Logic/Validate/CurrencyCode.cs @@ -5,9 +5,9 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace bnhtrade.Core.Logic.Account +namespace bnhtrade.Core.Logic.Validate { - public class ValidateCurrencyCode : Validate + public class CurrencyCode : Validate { private Logic.Utilities.StringCheck stringCheck = new Logic.Utilities.StringCheck(); public new void Innit() @@ -23,7 +23,7 @@ namespace bnhtrade.Core.Logic.Account } else { - ErrorListAdd(stringCheck.ErrorList); + ValidationResultAdd(stringCheck.ValidationResult); return false; } } diff --git a/src/bnhtrade.Core/Logic/Validate/SalesInvoice.cs b/src/bnhtrade.Core/Logic/Validate/SalesInvoice.cs new file mode 100644 index 0000000..74570c1 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/SalesInvoice.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Validate +{ + public class SalesInvoice : Logic.Validate.Validate + { + public SalesInvoice() + { + } + + public bool IsValidExportInvoice(IEnumerable invoiceList) + { + if (!IsValid(invoiceList)) + { + return false; + } + + foreach (var invoice in invoiceList) + { + if (invoice.UnitAmountIsTaxExclusive == false) + { + ValidationResultAdd("Tax inclusive line unit amounts are not supported"); + return false; + } + + foreach (var invoiceLine in invoice.InvoiceLineList) + { + if (invoiceLine.Quantity != 1) + { + ValidationResultAdd("Quantities greater than 1 are not supported"); + return false; + } + } + } + + return IsValidResult; + } + } +} diff --git a/src/bnhtrade.Core/Logic/Validate/SkuPriceInfo.cs b/src/bnhtrade.Core/Logic/Validate/SkuPriceInfo.cs new file mode 100644 index 0000000..ca739b7 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/SkuPriceInfo.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Validate +{ + public class SkuPriceInfo : Validate + { + public SkuPriceInfo() + { + Innit(); + } + + public bool IsValidDatabaseCreate(List priceInfoList) + { + Innit(); + + if (!IsValid(priceInfoList)) + { + return false; + } + + return IsValidResult; + } + } +} diff --git a/src/bnhtrade.Core/Logic/Validate/SkuTransaction.cs b/src/bnhtrade.Core/Logic/Validate/SkuTransaction.cs new file mode 100644 index 0000000..1a7db22 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/SkuTransaction.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Validate +{ + public class SkuTransaction : Validate + { + public bool DatabaseUpdate(Model.Stock.SkuTransaction skuTransaction) + { + return IsValid(new List { skuTransaction }); + } + + public bool DatabaseUpdate(List skuTransactionList) + { + if (!IsValid(skuTransactionList)) + { + 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) + { + return IsValid(new List { skuTransaction }); + } + + public bool DatabaseInsert(List skuTransactionList) + { + return IsValid(skuTransactionList); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Validate/TaxCodeInfo.cs b/src/bnhtrade.Core/Logic/Validate/TaxCodeInfo.cs new file mode 100644 index 0000000..d4f1dff --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/TaxCodeInfo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.Validate +{ + public class TaxCodeInfo : Validate + { + public bool IsValidPresistanceGet(Model.Account.TaxCodeInfo taxCodeInfo) + { + return IsValid(taxCodeInfo); + } + } +} diff --git a/src/bnhtrade.Core/Logic/Validate/Validate.cs b/src/bnhtrade.Core/Logic/Validate/Validate.cs new file mode 100644 index 0000000..589f948 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Validate/Validate.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; + +namespace bnhtrade.Core.Logic.Validate +{ + public abstract class Validate + { + public List ValidationResult { get; set; } = new List(); + + public bool IsValidResult + { + get + { + if (ValidationResult.Any()) { return false; } + else { return true; } + } + } + + public void Innit() + { + ValidationResult = new List(); + } + + protected bool IsValid(IValidatableObject validatableObject) + { + if (validatableObject == null) + { + ValidationResult.Add(new ValidationResult("Validatable object is null")); + return false; + } + + var validationContext = new ValidationContext(validatableObject); + ValidationResult.AddRange(validatableObject.Validate(validationContext)); + return IsValidResult; + } + + protected bool IsValid(IEnumerable validatableObjectList) + { + if (validatableObjectList == null || !validatableObjectList.Any()) + { + ValidationResult.Add(new ValidationResult("Validatable object list is empty or null")); + return false; + } + + foreach (var validatableObject in validatableObjectList) + { + if (!IsValid(validatableObject)) { return false; } + } + + return IsValidResult; + } + + protected void ValidationResultAdd(string result) + { + ValidationResult.Add(new ValidationResult(result)); + } + + protected void ValidationResultAdd(List result) + { + foreach (var item in result) + { + ValidationResultAdd(item); + } + } + + protected void ValidationResultAdd(ValidationResult result) + { + ValidationResult.Add(result); + } + + protected void ValidationResultAdd(List result) + { + ValidationResult.AddRange(result); + } + + public string ValidationResultListToString() + { + if (IsValidResult == false) + { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < ValidationResult.Count; i++) + { + result.AppendLine(ValidationResult[i].ErrorMessage); + } + return result.ToString(); + } + else { return null; } + } + } +} diff --git a/src/bnhtrade.Core/Model/Account/AccountCode.cs b/src/bnhtrade.Core/Model/Account/AccountCode.cs index 054a14e..861ea3c 100644 --- a/src/bnhtrade.Core/Model/Account/AccountCode.cs +++ b/src/bnhtrade.Core/Model/Account/AccountCode.cs @@ -1,58 +1,86 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bnhtrade.Core.Model.Account { - public class AccountCode + public class AccountCode : IValidatableObject { private int? accountCodeId; + + [Required(), Range(1, int.MaxValue)] public int AccountCodeId { get { return (int)accountCodeId; } set { accountCodeId = value; } } + + [Required(), MaxLength(150)] public string Title { get; set; } + + [MaxLength(500)] public string Description { get; set; } + + [Required(), MaxLength(50)] public string Type { get; set; } + + [Required(), MaxLength(50)] public string BasicType { get; set; } + public bool IsSetAccountCodeId { get { return accountCodeId != null; } } + public bool IsSetTitle { get { return Title != null; } } + public bool IsSetDescription { get { return Description != null; } } + public bool IsSetType { get { return Type != null; } } + public bool IsSetBasicType { get { return BasicType != null; } } + + public IEnumerable Validate(ValidationContext validationContext) + { + var resultList = new List(); + + if (!IsSetAccountCodeId) + { + resultList.Add(new ValidationResult("Account Code is not set")); + } + + return resultList; + } } } diff --git a/src/bnhtrade.Core/Model/Account/Invoice.cs b/src/bnhtrade.Core/Model/Account/Invoice.cs index e00265f..2667f7a 100644 --- a/src/bnhtrade.Core/Model/Account/Invoice.cs +++ b/src/bnhtrade.Core/Model/Account/Invoice.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -8,6 +9,10 @@ namespace bnhtrade.Core.Model.Account { public interface IInvoice : IInvoiceHeader { + decimal InvoiceNetAmount { get; } + + decimal InvoiceTaxAmount { get; } + List InvoiceLineList { get; set; } bool InvoiceLineListIsSet { get; } @@ -17,163 +22,231 @@ namespace bnhtrade.Core.Model.Account { string ItemCode { get; set; } - bool ItemCodeIsSet { get; } - - bool DescriptionIsSet { get; } - string Description { get; set; } - int Quantity { get; set; } + decimal? Quantity { get; set; } - bool QuantityIsSet { get; } + decimal? UnitAmount { get; set; } - decimal TotalNetAmount { get; set; } + Model.Account.AccountCode AccountCode { get; set; } - bool TotalNetAmountIsSet { get; } + Model.Account.TaxCodeInfo TaxCode { get; set; } - bool AccountCodeIsSet { get; } + decimal? TaxAmountAdjust { get; set; } - int AccountCode { get; set; } + decimal? TaxAmount { get; } - bool TaxCodeIsSet { get; } - - string TaxCode { get; set; } - - decimal TaxAmountAdjust { get; set; } - - bool TaxAmountAdjustIsSet { get; } - - decimal TaxAmount { get; } - - bool TaxAmountIsSet { get; } - - decimal GrossTotalAmount { get; } - - bool GrossTotalAmountIsSet { get; } + decimal LineTotalAmount { get; } } public abstract class Invoice : InvoiceHeader, IInvoice { + private bool unitAmountIsTaxExclusive = true; + + public decimal InvoiceNetAmount { get; } + + public decimal InvoiceTaxAmount { get; } + + public bool UnitAmountIsTaxExclusive + { + get { return unitAmountIsTaxExclusive; } + set + { + unitAmountIsTaxExclusive = value; + if (InvoiceLineList != null) + { + for (int i = 0; i < InvoiceLineList.Count; i++) + { + InvoiceLineList[i].UnitAmountIsTaxExclusive = unitAmountIsTaxExclusive; + } + } + } + } + public List InvoiceLineList { get; set; } = new List(); public bool InvoiceLineListIsSet { get { - if (InvoiceLineList == null || !InvoiceLineList.Any()) - { return false; } - else - { return true; } + if (InvoiceLineList == null || !InvoiceLineList.Any()) { return false; } + else { return true; } } } - public class InvoiceLine : IInvoiceLine + public class InvoiceLine : IInvoiceLine, IValidatableObject { - private int? accountCode; - private decimal? netAmount; - private decimal? taxAmount; + private decimal? unitAmount; + private Model.Account.TaxCodeInfo taxCode; private decimal? taxAmountAdjust; - private int? quantity; - private decimal? discount; + private decimal? quantity; - public string ItemCode + public InvoiceLine(bool unitAmountIsTaxExclusive) { - get; - set; + UnitAmountIsTaxExclusive = unitAmountIsTaxExclusive; } - public bool ItemCodeIsSet + public string ItemCode { get; set; } + + public string Description { get; set; } + + [Required(), Range(0, 9999999.99)] + public decimal? Quantity { - get { return ItemCode != null; } + get { return quantity; } + set + { + if (value == null) { quantity = null; } + else { quantity = decimal.Round((decimal)value, 4, MidpointRounding.AwayFromZero); } + } } - public string Description - { - get; - set; + [Required()] + public decimal? UnitAmount + { + get { return unitAmount; } + set + { + if (value == null) { unitAmount = null; } + else { unitAmount = decimal.Round(value.GetValueOrDefault(), 4, MidpointRounding.AwayFromZero); } + } } - public bool DescriptionIsSet - { - get { return Description != null; } + public bool UnitAmountIsTaxExclusive { get; set; } + + [Required()] + public Model.Account.AccountCode AccountCode + { + get; + set; } - public int Quantity - { - get { return (int)quantity.GetValueOrDefault(); } - set { quantity = value; } + [Required()] + public Model.Account.TaxCodeInfo TaxCode + { + get { return taxCode; } + set + { + if (value == null || TaxCode == null || value.TaxCode != taxCode.TaxCode) + { + TaxAmountAdjust = 0; + } + + taxCode = value; + } } - public bool QuantityIsSet + [Required()] + public decimal? TaxAmount { - get { return quantity != null; } + get + { + return TaxAmountAdjust + GetCalculatedTax(); + } } - public decimal TotalNetAmount + public decimal? TaxAmountAdjust { - get { return (decimal)netAmount.GetValueOrDefault(); } - set { netAmount = value; } + get { return taxAmountAdjust; } + set + { + if (value == null) { taxAmountAdjust = null; } + else { taxAmountAdjust = decimal.Round((decimal)value, 2, MidpointRounding.AwayFromZero); } + } } - public bool TotalNetAmountIsSet + public decimal LineTotalAmount { - get { return netAmount != null; } + get + { + if (CanCalculateLine()) + { + return ((decimal)Quantity * (decimal)UnitAmount) + (decimal)TaxAmount; + } + else { return 0; } + } } - public int AccountCode + private bool CanCalculateLine() { - get { return (int)accountCode.GetValueOrDefault(); } - set { accountCode = value; } + if (Quantity == null || UnitAmount == null || TaxCode == null) { return false; } + else { return true; } } - public bool AccountCodeIsSet + private decimal GetCalculatedTax() { - get { return accountCode != null; } + decimal calculatedTax = 0; + if (CanCalculateLine()) + { + if (UnitAmountIsTaxExclusive) + { + calculatedTax = ((decimal)Quantity * (decimal)UnitAmount) * (TaxCode.TaxRate / 100); + } + else + { + calculatedTax = ((decimal)Quantity * (decimal)UnitAmount) * (TaxCode.TaxRate / (100 + TaxCode.TaxRate)); + } + return decimal.Round(calculatedTax, 2, MidpointRounding.AwayFromZero); + } + else + { + return 0; + } } - public string TaxCode + public void SetTaxAmountAdjust(decimal lineTaxAmount) { - get; - set; + decimal adjustedAmount = lineTaxAmount - GetCalculatedTax(); + if (adjustedAmount == 0) { TaxAmountAdjust = null; } + else { TaxAmountAdjust = adjustedAmount; } } - public bool TaxCodeIsSet + public IEnumerable Validate(ValidationContext validationContext) { - get { return TaxCode != null; } + throw new NotImplementedException(); + + var resultList = new List(); + + if (TaxAmount > LineTotalAmount / 2) + { + resultList.Add(new ValidationResult("Line tax amount is greater than net amount")); + } + + } + } + + public new IEnumerable Validate(ValidationContext validationContext) + { + var subResult = base.Validate(validationContext); + var resultList = new List(); + resultList.AddRange(subResult); + + + // loop though lines and check sum totals + if (!InvoiceLineListIsSet) + { + resultList.Add(new ValidationResult("No lines set on Invoice")); + } + else + { + decimal lineTotal = 0; + foreach (var line in InvoiceLineList) + { + lineTotal += line.LineTotalAmount; + + if (UnitAmountIsTaxExclusive != line.UnitAmountIsTaxExclusive) + { + resultList.Add(new ValidationResult("Invalid UnitAmountIsTaxExclusive")); + } + } + + // check totals + if (InvoiceTotalAmount != lineTotal) + { resultList.Add(new ValidationResult("Invoice line total does not equal invoice total")); } } - public decimal TaxAmount - { - get { return (decimal)taxAmount.GetValueOrDefault(); } - set { taxAmount = decimal.Round(value, 2); } - } - - public bool TaxAmountIsSet - { - get { return taxAmount != null; } - } - - public decimal TaxAmountAdjust - { - get { return (decimal)taxAmountAdjust.GetValueOrDefault(); } - set { taxAmountAdjust = decimal.Round(value, 2); } - } - - public bool TaxAmountAdjustIsSet - { - get { return taxAmountAdjust != null; } - } - - public decimal GrossTotalAmount - { - get { return (decimal)netAmount.GetValueOrDefault() + TaxAmount; } - } - - public bool GrossTotalAmountIsSet - { - get { return (TotalNetAmountIsSet && TaxAmountIsSet); } - } + return resultList; } } } diff --git a/src/bnhtrade.Core/Model/Account/InvoiceHeader.cs b/src/bnhtrade.Core/Model/Account/InvoiceHeader.cs index 895b1b6..e6e92b8 100644 --- a/src/bnhtrade.Core/Model/Account/InvoiceHeader.cs +++ b/src/bnhtrade.Core/Model/Account/InvoiceHeader.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,31 +10,24 @@ namespace bnhtrade.Core.Model.Account public interface IInvoiceHeader { string ContactName { get; set; } - bool ContactNameIsSet { get; } - decimal InvoiceAmount { get; set; } - bool InvoiceAmountIsSet { get; } + + decimal? InvoiceTotalAmount { get; set; } + string InvoiceCurrencyCode { get; set; } - bool InvoiceCurrencyCodeIsSet { get; } - DateTime InvoiceDate { get; set; } - bool InvoiceDateIsSet { get; } - DateTime InvoiceDueDate { get; set; } - bool InvoiceDueDateIsSet { get; } - DateTimeKind InvoiceDateKind { get; set; } - bool InvoiceDateKindIsSet { get; } + + DateTime? InvoiceDate { get; set; } + + DateTime? InvoiceDueDate { get; set; } + string InvoiceNumber { get; set; } - bool InvoiceNumberIsSet { get; } + string InvoiceReference { get; set; } - bool InvoiceReferenceIsSet { get; } + bool IsCreditNote { get; set; } - bool IsCreditNoteIsSet { get; } } - public abstract class InvoiceHeader : IInvoiceHeader + public abstract class InvoiceHeader :IInvoiceHeader, IValidatableObject { - private string invoiceCurrencyCode; - private DateTime? invoiceDate; - private DateTime? invoiceDueDate; - private DateTimeKind? invoiceDateKind = DateTimeKind.Utc; private decimal? invoiceAmount; public InvoiceHeader() @@ -41,95 +35,51 @@ namespace bnhtrade.Core.Model.Account IsCreditNote = false; } + [Required()] public string ContactName { get; set; } - public bool ContactNameIsSet - { - get { return ContactName != null; } - } + [Required()] + public DateTime? InvoiceDate { get; set; } - public DateTime InvoiceDate - { - get { return (DateTime)invoiceDate.GetValueOrDefault(); } - set { invoiceDate = value; } - } + [Required()] + public DateTime? InvoiceDueDate { get; set; } - public bool InvoiceDateIsSet - { - get { return invoiceDate != null; } - } - - public DateTime InvoiceDueDate - { - get { return (DateTime)invoiceDueDate.GetValueOrDefault(); } - set { invoiceDueDate = value; } - } - - public bool InvoiceDueDateIsSet - { - get { return invoiceDueDate != null; } - } - - public DateTimeKind InvoiceDateKind - { - get { return (DateTimeKind)invoiceDateKind; } - set { invoiceDateKind = value; } - } - - public bool InvoiceDateKindIsSet - { - get { return invoiceDateKind != null; } - } - - public string InvoiceCurrencyCode - { - get { return invoiceCurrencyCode; } - set - { - if (!string.IsNullOrWhiteSpace(value)) - { - invoiceCurrencyCode = value.ToUpper(); - } - } - } - - public bool InvoiceCurrencyCodeIsSet - { - get { return InvoiceCurrencyCode != null; } - } + [Required(), MinLength(3), MaxLength(3)] + public string InvoiceCurrencyCode { get; set; } + [Required()] public string InvoiceNumber { get; set; } - public bool InvoiceNumberIsSet - { - get { return InvoiceNumber != null; } - } - public string InvoiceReference { get; set; } - public bool InvoiceReferenceIsSet - { - get { return InvoiceReference != null; } - } - - public decimal InvoiceAmount + [Required()] + public decimal? InvoiceTotalAmount { get { return (decimal)invoiceAmount; } - set { invoiceAmount = value; } + set + { + if (value == null) { invoiceAmount = null; } + else { invoiceAmount = decimal.Round((decimal)value, 2, MidpointRounding.AwayFromZero); } + } } - public bool InvoiceAmountIsSet + [Required()] + public bool IsCreditNote { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) { - get { return invoiceAmount != null; } - } - public bool IsCreditNote - { - get; - set; - } - public bool IsCreditNoteIsSet - { - get { return true; } + var resultList = new List(); + + if (IsCreditNote && InvoiceTotalAmount > 0) + { + resultList.Add(new ValidationResult("Credit Note amount cannot be greater than zero")); + } + else if (!IsCreditNote && InvoiceTotalAmount < 0) + { + resultList.Add(new ValidationResult("Invoice amount cannot be less than zero")); + } + + return resultList; } } } diff --git a/src/bnhtrade.Core/Model/Account/InvoiceLineItem.cs b/src/bnhtrade.Core/Model/Account/InvoiceLineItem.cs index 83dd0df..ce3c9de 100644 --- a/src/bnhtrade.Core/Model/Account/InvoiceLineItem.cs +++ b/src/bnhtrade.Core/Model/Account/InvoiceLineItem.cs @@ -1,47 +1,70 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bnhtrade.Core.Model.Account { - public class InvoiceLineItem + public class InvoiceLineItem : IValidatableObject { + [Required()] public string ItemCode { get; set; } - public string Title + + [Required()] + public string Name { get; set; } + public string Description { get; set; } + + [Required()] public bool IsNewReviewRequired { get; set; } + + [Required()] public bool InvoiceLineEntryEnabled { get; set; } - public int DefaultAccountCode + + [Required()] + public Model.Account.AccountCode DefaultAccountCode { get; set; } - public string DefaultTaxCode + + [Required()] + public Model.Account.TaxCodeInfo DefaultTaxCode { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + var resultList = new List(); + + resultList.AddRange(DefaultAccountCode.Validate(validationContext)); + resultList.AddRange(DefaultTaxCode.Validate(validationContext)); + + return resultList; + } } } diff --git a/src/bnhtrade.Core/Model/Account/TaxCode.cs b/src/bnhtrade.Core/Model/Account/TaxCode.cs deleted file mode 100644 index bbd4588..0000000 --- a/src/bnhtrade.Core/Model/Account/TaxCode.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace bnhtrade.Core.Model.Account -{ - public class TaxCode - { - private decimal? netAmountMultiplier = null; - private decimal? grossAmountMultiplier = null; - private bool? isActive = null; - private bool? isValidOnExpense = null; - private bool? isValidOnIncome = null; - - public string TaxCodeId { get; set; } - public string TaxRateDescription { get; set; } - public string TaxRateTitle { get; set; } - public string TaxType { get; set; } - public decimal NetAmountMultiplier - { - get { return (decimal)netAmountMultiplier; } - set { netAmountMultiplier = value; } - } - public decimal GrossAmountMultiplier - { - get { return (decimal)grossAmountMultiplier; } - set { grossAmountMultiplier = value; } - } - public bool IsActive - { - get { return (bool)isActive; } - set { isActive = value; } - } - public bool IsSetAll - { - get - { - if (IsSetGrossAmountMultiplier - && IsSetIsActive - && IsSetIsValidOnExpense - && IsSetIsValidOnIncome - && IsSetNetAmountMultiplier - && IsSetTaxCodeId - && IsSetTaxRateTitle - && IsSetTaxRateDescription - ) - { - return true; - } - else { return false; } - } - } - public bool IsSetGrossAmountMultiplier - { - get { return grossAmountMultiplier != null; } - } - public bool IsSetIsActive - { - get { return isActive != null; } - } - public bool IsSetIsValidOnExpense - { - get { return isValidOnExpense != null; } - } - public bool IsSetIsValidOnIncome - { - get { return isValidOnIncome != null; } - } - public bool IsSetNetAmountMultiplier - { - get { return netAmountMultiplier != null; } - } - public bool IsSetTaxCodeId - { - get { return TaxCodeId != null; } - } - public bool IsSetTaxRateTitle - { - get { return TaxRateTitle != null; } - } - public bool IsSetTaxRateDescription - { - get { return TaxRateDescription != null; } - } - public bool IsSetTaxType - { - get { return TaxType != null; } - } - public bool IsValidOnExpense - { - get { return (bool)isValidOnExpense; } - set { isValidOnExpense = value; } - } - public bool IsValidOnIncome - { - get { return (bool)isValidOnIncome; } - set { isValidOnIncome = value; } - } - } -} diff --git a/src/bnhtrade.Core/Model/Account/TaxCodeInfo.cs b/src/bnhtrade.Core/Model/Account/TaxCodeInfo.cs new file mode 100644 index 0000000..fe57a95 --- /dev/null +++ b/src/bnhtrade.Core/Model/Account/TaxCodeInfo.cs @@ -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.Account +{ + public class TaxCodeInfo : IValidatableObject + { + public TaxCodeInfo(string taxCodeId, string title, string description, decimal taxRatePercent, bool isMarginSchemeRate, + bool isValidOnExpense, bool isValidOnIncome, string taxType, bool isActive) + { + if (TaxRate < 0) + { + throw new Exception("Tax rate is less than zero"); + } + + if (TaxRate >= 100) + { + // 100% rate has been used where the line total is all tax + // you need to do somemore coding when this facility is required + throw new Exception("Tax rate is >= 100%"); + } + + TaxCode = taxCodeId; + TaxCodeDescription = description; + TaxRate = taxRatePercent; + IsMarginScheme = isMarginSchemeRate; + TaxCodeName = title; + TaxType = taxType; + IsActive = isActive; + IsValidOnExpense = isValidOnExpense; + IsValidOnIncome = isValidOnIncome; + } + + /// + /// Unique identifier + /// + [Required()] + public string TaxCode { get; private set; } + + [Required()] + public string TaxCodeName { get; private set; } + + public string TaxCodeDescription { get; private set; } + + /// + /// Tax rate as a percentage + /// + [Required(), Range(0, 100)] + public decimal TaxRate { get; private set; } + + public bool IsMarginScheme { get; private set; } + + [Required()] + public string TaxType { get; private set; } + + public bool IsValidOnExpense { get; private set; } + + public bool IsValidOnIncome { get; private set; } + + public bool IsActive { get; private set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + var resultList = new List(); + return resultList; + } + } +} diff --git a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs b/src/bnhtrade.Core/Model/AmazonFba/ShipmentInfo.cs similarity index 86% rename from src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs rename to src/bnhtrade.Core/Model/AmazonFba/ShipmentInfo.cs index 67d3bb2..476c71e 100644 --- a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs +++ b/src/bnhtrade.Core/Model/AmazonFba/ShipmentInfo.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Model.AmazonFBAInbound +namespace bnhtrade.Core.Model.AmazonFba { public class ShipmentInfo { @@ -13,9 +13,12 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound private string shipmentStatus; private DateTime lastUpdatedUtc; private Dictionary shipmentStatusToIsClosed; + private int? shipmentStockStatusId = null; + + public string FbaShipmentId { get; set; } - public string AmazonShipmentId { get; set; } public string ShipmentName { get; set; } + public string DestinationFulfillmentCenterId { get { return destinationFulfillmentCenterId; } @@ -31,6 +34,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound } } } + public string ShipmentStatus { get @@ -47,7 +51,16 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound shipmentStatus = status; } } - public DateTime LastUpdatedUtc + + public string ShipmentStockStatus { get; set; } + + public int ShipmentStockStatusId + { + get { return shipmentStockStatusId.GetValueOrDefault(); } + set { shipmentStockStatusId = value; } + } + + public DateTime LastUpdated { get { @@ -58,6 +71,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound lastUpdatedUtc = DateTime.SpecifyKind(value, DateTimeKind.Utc); } } + public bool ShipmentIsClosed { get @@ -72,6 +86,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound } } } + public List ShipmentItemInfoList { get { return shipmentItemInfoList; } @@ -84,7 +99,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound if (!item.IsSetAll()) { throw new Exception("Infomation missing from Shipment Item list"); } - if (item.AmazonShipmentId != AmazonShipmentId) + if (item.AmazonShipmentId != FbaShipmentId) { throw new Exception("Amazon shipment id in item list does not match header information."); } if (skuCheck.ContainsKey(item.SKUNumber)) @@ -104,6 +119,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound shipmentItemInfoList = value; } } + public bool IsSetAll() { if (IsSetAllHeaderInfo() && IsSetListShipmentItemInfo()) @@ -115,6 +131,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound return false; } } + public bool IsSetAllHeaderInfo() { if (IsSetAmazonShipmentId() @@ -131,35 +148,52 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound return false; } } + public bool IsSetAmazonShipmentId() { - return AmazonShipmentId != null; + return FbaShipmentId != null; } + public bool IsSetShipmentName() { return ShipmentName != null; } + public bool IsSetDestinationFulfillmentCenterId() { return DestinationFulfillmentCenterId != null; } + public bool IsSetLastUpdated() { - return LastUpdatedUtc != default(DateTime); + return LastUpdated != default(DateTime); } + public bool IsSetListShipmentItemInfo() { return ShipmentItemInfoList != null; } + public bool IsSetShipmentIsClosed() { return ShipmentStatus != null; } + public bool IsSetShipmentStatus() { return ShipmentStatus != null; } + public bool IsSetShipmentStockStatus() + { + return ShipmentStockStatus != null; + } + + public bool IsSetShipmentStockStatusId() + { + return shipmentStockStatusId != null; + } + public ShipmentInfo() { shipmentStatusToIsClosed = new Dictionary(); diff --git a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs b/src/bnhtrade.Core/Model/AmazonFba/ShipmentItemInfo.cs similarity index 97% rename from src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs rename to src/bnhtrade.Core/Model/AmazonFba/ShipmentItemInfo.cs index 1173a98..2332979 100644 --- a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs +++ b/src/bnhtrade.Core/Model/AmazonFba/ShipmentItemInfo.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace bnhtrade.Core.Model.AmazonFBAInbound +namespace bnhtrade.Core.Model.AmazonFba { public class ShipmentItemInfo { @@ -18,14 +18,17 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound /// Gets and sets the AmazonShipmentId property. /// public string AmazonShipmentId { get; set; } + /// /// Gets and sets the SKUNumber property. /// public string SKUNumber { get; set; } + /// /// Gets and sets the FulfillmentNetworkSKU property. /// public string AmazonFNSKU { get; set; } + /// /// Gets and sets the QuantityAllocated property. /// @@ -34,6 +37,7 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound get { return quantityAllocated; } set { quantityAllocated = value; isSetQuantityAllocated = true; } } + /// /// Gets and sets the QuantityReceived property. /// @@ -59,22 +63,27 @@ namespace bnhtrade.Core.Model.AmazonFBAInbound return false; } } + public bool IsSetAmazonShipmentId() { return AmazonShipmentId != null; } + public bool IsSetSKUNumber() { return SKUNumber != null; } + public bool IsSetFulfillmentNetworkSKU() { return AmazonFNSKU != null; } + public bool IsSetQuantityAllocated() { return isSetQuantityAllocated; } + public bool IsSetQuantityReceived() { return isSetQuantityReceived; diff --git a/src/bnhtrade.Core/Model/Data/DatabaseFileStream.cs b/src/bnhtrade.Core/Model/Data/DatabaseFileStream.cs new file mode 100644 index 0000000..51919f3 --- /dev/null +++ b/src/bnhtrade.Core/Model/Data/DatabaseFileStream.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Data +{ + public class DatabaseFileStream : IDisposable, IValidatableObject + { + [Required()] + public Guid FileGUID { get; set; } + + [Required()] + public MemoryStream FileData { get; set; } + + public bool IsSetFileData + { + get { return FileData != null; } + } + + [Required(), StringLength(3, MinimumLength = 3)] + public string FileExtention { get; set; } + + [Required(), Range(1, 2147483647)] + public int FileSize { get; set; } + + [Required(), StringLength(24, MinimumLength = 24)] + public string FileMD5base64 { get; set; } + + public string CalculateContentMD5(MemoryStream stream) + { + MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); + byte[] hash = provider.ComputeHash(stream); + return Convert.ToBase64String(hash); + } + + public IEnumerable Validate(ValidationContext validationContext) + { + var resultList = new List(); + + if (IsSetFileData && FileData.Length == 0) + { + var validate = new ValidationResult("Stream is empty"); + resultList.Add(validate); + } + if (IsSetFileData && FileMD5base64 != new Logic.Utilities.CalculateMD5().Base64(FileData)) + { + var validate = new ValidationResult("Calculated file MD5 hash does not match."); + resultList.Add(validate); + } + + return resultList; + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects). + if (FileData != null) + FileData.Dispose(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + //~AmazonFeedSubmission() + //{ + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + //} + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion + } +} + diff --git a/src/bnhtrade.Core/Model/Export/AmazonFeedSubmission.cs b/src/bnhtrade.Core/Model/Export/AmazonFeedSubmission.cs new file mode 100644 index 0000000..44d86f2 --- /dev/null +++ b/src/bnhtrade.Core/Model/Export/AmazonFeedSubmission.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Export +{ + public class AmazonFeedSubmission : IValidatableObject + { + //private int? exportAmazonFeedSubmissionId; + private DateTime? submittedDate; + private DateTime? startedProcessingDate; + private DateTime? completedProcessingDate; + + //public int ExportAmazonFeedSubmissionID + //{ + // get { return exportAmazonFeedSubmissionId.GetValueOrDefault(); } + // set { exportAmazonFeedSubmissionId = value; } + //} + + //public bool IsSetExportAmazonFeedSubmissionID + //{ + // get { return exportAmazonFeedSubmissionId != null; } + //} + + [Required()] + public string FeedType { get; set; } + + public bool IsSetFeedType + { + get { return !string.IsNullOrWhiteSpace(FeedType); } + } + + [Required()] + public string FeedSubmissionId { get; set; } + + public bool IsSetFeedSubmissionId + { + get { return !string.IsNullOrWhiteSpace(FeedSubmissionId); } + } + + public DateTime SubmittedDate + { + get { return submittedDate.GetValueOrDefault(); } + set { submittedDate = value; } + } + + public bool IsSetSubmittedDate + { + get { return submittedDate != null; } + } + + public string FeedProcessingStatus { get; set; } + + public bool IsSetFeedProcessingStatus + { + get { return !string.IsNullOrWhiteSpace(FeedProcessingStatus); } + } + + public DateTime StartedProcessingDate + { + get { return startedProcessingDate.GetValueOrDefault(); } + set { startedProcessingDate = value; } + } + + public bool IsSetStartedProcessingDate + { + get { return startedProcessingDate != null; } + } + + public DateTime CompletedProcessingDate + { + get { return completedProcessingDate.GetValueOrDefault(); } + set { completedProcessingDate = value; } + } + + public bool IsSetCompletedProcessingDate + { + get { return completedProcessingDate != null; } + } + + public Model.Data.DatabaseFileStream File { get; set; } + + public bool FileIsSet + { + get { return File != null; } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + var results = new List(); + + if (IsSetSubmittedDate && SubmittedDate == default(DateTime)) + results.Add(new ValidationResult("Submitted Date is systen default")); + if (IsSetStartedProcessingDate && StartedProcessingDate == default(DateTime)) + results.Add(new ValidationResult("Started Processing Date is systen default")); + if (IsSetCompletedProcessingDate && CompletedProcessingDate == default(DateTime)) + results.Add(new ValidationResult("Completed Processing Date is systen default")); + + if (IsSetFeedProcessingStatus) + { + if (FeedProcessingStatus != "_DONE_" || FeedProcessingStatus != "_SUBMITTED_" || FeedProcessingStatus != "_IN_PROGRESS_" || + FeedProcessingStatus != "_UNCONFIRMED_" || FeedProcessingStatus != "_CANCELLED_" || FeedProcessingStatus != "_IN_SAFETY_NET_" || + FeedProcessingStatus != "_AWAITING_ASYNCHRONOUS_REPLY_") + { + results.Add(new ValidationResult("Invalid Feed Processing Status '" + FeedProcessingStatus + "'")); + } + } + + if (FileIsSet) + { + Validator.TryValidateObject( + File, + new ValidationContext(File, null, null), + results); + } + + return results; + } + } +} diff --git a/src/bnhtrade.Core/Model/Export/AmazonIventoryLoaderFile.cs b/src/bnhtrade.Core/Model/Export/AmazonIventoryLoaderFile.cs new file mode 100644 index 0000000..0e96ba4 --- /dev/null +++ b/src/bnhtrade.Core/Model/Export/AmazonIventoryLoaderFile.cs @@ -0,0 +1,136 @@ +using CsvHelper.Configuration.Attributes; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Export +{ + public class AmazonIventoryLoaderFile : IValidatableObject + { + private bool isSetSetFulfillmentCenterId = false; + + [Required()] + [Name("sku")] + public string Sku { get; set; } + + [Name("product-id")] + public string ProductId { get; set; } + + /// + /// One of the following: 1=ASIN, 2=ISBN, 3=UPC, 4=EAN + /// + [Name("product-id-type")] + [Range(1,4)] + public int? ProductIdType { get; set; } + + [Name("price")] + [Range(0, double.MaxValue)] + public decimal? Price { get; set; } + + [Name("minimum-seller-allowed-price")] + [Range(0, double.MaxValue)] + public decimal? MinimumAllowedPrice { get; set; } + + [Name("maximum-seller-allowed-price")] + [Range(0, double.MaxValue)] + public decimal? MaximumAllowedPrice { get; set; } + + /// + /// 11=New, 1=Used Like New, 2=Used Very Good, 3=Used Good, 4=Used Acceptable, + /// 5=Collectible Like New, 6=Collectible Very Good, 7=Collectible Good, 8=Collectible Acceptable, 9=Not used + /// + [Name("item-condition")] + [Range(1,11)] + public int? ItemCondition { get; set; } + + [Name("quantity")] + public int? Quantity { get; set; } + + /// + /// a = update/add, d = delete, x = delete completely from system + /// + [MaxLength(1)] + [Name("add-delete")] + public string AddDelete { get; set; } + + [Name("will-ship-internationally")] + [BooleanTrueValues("y")] + [BooleanFalseValues("n")] + public bool? WillShipInternationally { get; set; } + + [Name("expedited-shipping")] + public string ExpeditedShipping { get; set; } + + [Name("standard-plus")] + public string StandardPlus { get; set; } + + [MaxLength(2000)] + [Name("item-note")] + public string ItemNote { get; set; } + + [Name("fulfillment-center-id")] + public string FulfillmentCenterId { get; private set; } + + [Name("merchant-shipping-group-name")] + public string MerchantShippingGroupName { get; set; } + + public void SetFulfillmentCenterId(bool IsFba) + { + isSetSetFulfillmentCenterId = true; + if (IsFba) + { + FulfillmentCenterId = "AMAZON_EU"; + } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + var results = new List(); + + if (isSetSetFulfillmentCenterId == false) + { + results.Add(new ValidationResult("FulfillmentCenterId is not set.")); + } + + if (ItemCondition.GetValueOrDefault() == 9 || ItemCondition.GetValueOrDefault() == 10) + { + results.Add(new ValidationResult("Invalid Item Condition id")); + } + + if (AddDelete != null && (AddDelete != "a" || AddDelete != "d" || AddDelete != "x")) + { + results.Add(new ValidationResult("Invalid AddDelete")); + } + + if (MaximumAllowedPrice != null || MinimumAllowedPrice != null) + { + if (MaximumAllowedPrice == null) + { + results.Add(new ValidationResult("If setting MinimumAllowedPrice, the MaximumAllowedPrice must also be set.")); + } + + if (MinimumAllowedPrice == null) + { + results.Add(new ValidationResult("If setting MaximumAllowedPrice, the MinimumAllowedPrice must also be set.")); + } + + if (Price == null) + { + results.Add(new ValidationResult("If setting MaximumAllowedPrice or MinimumAllowedPrice the Price must also be set.")); + } + else if (MaximumAllowedPrice != null && MinimumAllowedPrice != null) + { + if (Price < MinimumAllowedPrice || Price > MaximumAllowedPrice) + { + results.Add(new ValidationResult("Price is ouside the bounds set by the MaximumAllowedPrice and MinimumAllowedPrice.")); + } + } + } + + return results; + } + } +} diff --git a/src/bnhtrade.Core/Model/Product/CompetitivePrice.cs b/src/bnhtrade.Core/Model/Product/CompetitivePrice.cs new file mode 100644 index 0000000..2e98f77 --- /dev/null +++ b/src/bnhtrade.Core/Model/Product/CompetitivePrice.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Product +{ + public class CompetitivePrice + { + private bool? priceIsEstimated; + private decimal? price = null; + + public int ProductId { get; set; } + + public int ConditionId { get; set; } + + public decimal Price + { + get { return price.GetValueOrDefault(); } + set { price = value; } + } + + public bool PriceIsSet + { + get { return price != null; } + } + + public DateTime PriceDatetime { get; set; } + + public bool PriceIsEstimated + { + get { return priceIsEstimated.GetValueOrDefault(); } + set { priceIsEstimated = value; } + } + + public bool PriceIsEstimatedIsSet + { + get { return priceIsEstimated != null; } + } + + public CompetitivePrice Clone() + { + var clone = new CompetitivePrice(); + clone.ConditionId = ConditionId; + if (PriceIsSet) { clone.Price = Price; } + clone.PriceDatetime = PriceDatetime; + if (PriceIsEstimatedIsSet) { clone.priceIsEstimated = PriceIsEstimated; } + clone.ProductId = ProductId; + return clone; + } + } +} diff --git a/src/bnhtrade.Core/Model/SKU/Sku.cs b/src/bnhtrade.Core/Model/SKU/Sku.cs index d87eabb..eb31d88 100644 --- a/src/bnhtrade.Core/Model/SKU/Sku.cs +++ b/src/bnhtrade.Core/Model/SKU/Sku.cs @@ -9,60 +9,95 @@ namespace bnhtrade.Core.Model.Sku public class Sku { private bool? isActive; - public string ConditionModelPlaceholder + private int? conditionId; + private int? productId; + + public int ConditionId + { + get { return conditionId.GetValueOrDefault(); } + set { conditionId = value; } + } + + public bool ConditionIdIsSet + { + get { return conditionId != null; } + } + + public string ConditionTitle { get; set; } - public string ProductModelPlaceholder + + public bool ConditionTitleIsSet + { + get { return ConditionTitle != null; } + } + + public int ProductId + { + get { return productId.GetValueOrDefault(); } + set { productId = value; } + } + + public bool ProductIdIsSet + { + get { return productId != null; } + } + + public string ProductTitle { get; set; } + + public bool ProductTitleIsSet + { + get { return ProductTitle != null; } + } + public string SkuNumber { get; set; } - public Account.TaxCode TaxCode + + public bool SkuNumberIsSet + { + get { return SkuNumber != null; } + } + + public string TaxCode { get; set; } + + public bool TaxCodeIsSet + { + get { return TaxCode != null; } + } + public string AmazonFNSKU { get; set; } + + public bool AmazonFNSKUIsSet + { + get { return AmazonFNSKU != null; } + } + public bool IsActive { get { return (bool)isActive; } set { isActive = value; } } - public bool IsSetConditionModelPlaceholder - { - get { return ConditionModelPlaceholder != null; } - } - public bool IsSetProductModelPlaceholder - { - get { return ProductModelPlaceholder != null; } - } - public bool IsSetSkuNumber - { - get { return SkuNumber != null; } - } - public bool IsSetTaxCode - { - get { return TaxCode != null; } - } - public bool IsSetAmazonFNSKU - { - get { return AmazonFNSKU != null; } - } - public bool IsSetIsActive + + public bool IsActiveIsSet { get { return isActive != null; } } - } } diff --git a/src/bnhtrade.Core/Model/SKU/SkuConditionInfo.cs b/src/bnhtrade.Core/Model/SKU/SkuConditionInfo.cs new file mode 100644 index 0000000..2ba5a29 --- /dev/null +++ b/src/bnhtrade.Core/Model/SKU/SkuConditionInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Sku +{ + public class SkuConditionInfo + { + public int SkuConditionId { get; set; } + + public string SkuConditionNumber { get; set; } + + public string TitleShort { get; set; } + + public string Description { get; set; } + + public bool IsFixedPrice { get; set; } + + + /// + /// Can be used to estimate a competitve price from 'New' condition competitive price + /// + public decimal CompetitivePriceMultiplier { get; set; } + + public string AmazonBaseType { get; set; } + + public int AmazonIdentifier { get; set; } + + public string ConditionNoteDefault { get; set; } + + public string RepricerStrategy { get; set; } + } +} diff --git a/src/bnhtrade.Core/Model/Sku/Price/DetailRequest.cs b/src/bnhtrade.Core/Model/Sku/Price/DetailRequest.cs new file mode 100644 index 0000000..aadefdd --- /dev/null +++ b/src/bnhtrade.Core/Model/Sku/Price/DetailRequest.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Sku.Price +{ + public class DetailRequest + { + public int SkuId { get; set; } + + public int OrderChannelId { get; set; } + + public int OrderChannelQuantity { get; set; } + + public decimal OrderChannelFeeFixed { get; set; } + + public decimal OrderChannelFeeMargin { get; set; } + + public decimal UnitAvgCost { get; set; } + + public int InventoryAgeMin { get; set; } + + public int InventoryAgeMax { get; set; } + + public int PriceMin_SkuPriceType { get; set; } + + public decimal? PriceMinAmountManual { get; set; } + + public int? PriceMinStoredInt { get; set; } + + public int PriceMax_SkuPriceType { get; set; } + + public bool PriceMaxBaseMultipilerReset { get; set; } = false; + + public decimal? PriceMaxAmountManual { get; set; } + + public int? PriceMaxStoredInt { get; set; } + } +} diff --git a/src/bnhtrade.Core/Model/Sku/Price/DetailResponce.cs b/src/bnhtrade.Core/Model/Sku/Price/DetailResponce.cs new file mode 100644 index 0000000..72b6c2c --- /dev/null +++ b/src/bnhtrade.Core/Model/Sku/Price/DetailResponce.cs @@ -0,0 +1,71 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Sku.Price +{ + public class DetailResponce + { + public int SkuId { get; set; } + + public int OrderChannelId { get; set; } + + public int OrderChannelQuantity { get; set; } + + public decimal UnitAvgCost { get; set; } + + public int InventoryAgeMin { get; set; } + + public int InventoryAgeMax { get; set; } + + public int PriceMin_SkuPriceType { get; set; } + + public decimal PriceMinAmountAuto { get; set; } + + public decimal? PriceMinAmountManual { get; set; } + + public int? PriceMinStoredInt { get; set; } + + public decimal PriceMinAmountFinalFee { get; set; } + + public decimal PriceMinAmountFinalTax { get; set; } + + public decimal PriceMinAmountFinal { get; set; } + + public int PriceMax_SkuPriceType { get; set; } + + public decimal PriceMaxAmountAutoBase { get; set; } + + public decimal PriceMaxAmountAutoMultiplier { get; set; } + + public DateTime PriceMaxAmountAutoModified { get; set; } + + public decimal? PriceMaxAmountManual { get; set; } + + public int? PriceMaxStoredInt { get; set; } + + public decimal PriceMaxAmountFinal { get; set; } + + public DateTime PriceCreated { get; set; } + + public string TypeTitle { get; set; } + + public bool ReviewRequired + { + get + { + if (TypeTitle.Substring(0, 15) == "Review Required") + { return true; } + else + { return false; } + } + } + + public bool RequireAmountManual { get; set; } + + public bool RequireStordedInt { get; set; } + } +} diff --git a/src/bnhtrade.Core/Model/Sku/Price/PriceInfo.cs b/src/bnhtrade.Core/Model/Sku/Price/PriceInfo.cs new file mode 100644 index 0000000..c4c2f86 --- /dev/null +++ b/src/bnhtrade.Core/Model/Sku/Price/PriceInfo.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Sku.Price +{ + public class PriceInfo : IValidatableObject + { + private bool? reviewRequired; + + [Required()] + public string SkuNumber { get; set; } + + [Required()] + public string OrderChannel { get; set; } + + [Required()] + public DateTime PriceInfoTimeStamp { get; set; } + + [Required(), Range(0, 32767)] + public int OrderChannelQuantity { get; set; } + + /// + /// The average purchase cost of each unit + /// + [Required(), Range(0, 9999999.99)] + public decimal UnitPurchaseCost { get; set; } + + /// + /// The average minimun sale price to achieve set minumum profit + /// + [Required(), Range(0, 9999999.99)] + public decimal UnitMinPriceProfit { get; set; } + + /// + /// The average minimun sale price to cover costs + /// + [Required(), Range(0, 9999999.99)] + public decimal UnitMinPriceCost { get; set; } + + /// + /// The minimun price at which it is more ecomoical to destory item + /// + [Required(), Range(0, 9999999.99)] + public decimal UnitMinPriceDestory { get; set; } + + [Required(), Range(0, 32767)] + public int InventoryAgeMin { get; set; } + + [Required(), Range(0, 32767)] + public int InventoryAgeMax { get; set; } + + [Range(0, 255)] + public int PriceTypeId { get; set; } + + public string PriceTypeTitle { get; set; } + + [Required(), Range(0, 9999999.99)] + public decimal CompetitivePrice { get; set; } + + public bool CompetitivePriceIsEstimated { get; set; } + + [Required(), Range(0, 9999999.99)] + public decimal MinPrice { get; set; } + + [Required(), Range(0, 9999999.99)] + public decimal MaxPrice { get; set; } + + [Required(), Range(0, 9999999.99)] + public decimal RepriceIncrement { get; set; } + + [Required()] + public bool ReviewRequired + { + get { return reviewRequired.GetValueOrDefault(); } + set { reviewRequired = value; } + } + + public bool IsSetReviewRequired + { + get { return reviewRequired != null; } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + var resultList = new List(); + if (MaxPrice < MinPrice) + { + resultList.Add(new ValidationResult("Max price is less than min price")); + } + + return resultList; + } + } +} diff --git a/src/bnhtrade.Core/Model/Sku/Price/SkuPriceParameter.cs b/src/bnhtrade.Core/Model/Sku/Price/SkuPriceParameter.cs new file mode 100644 index 0000000..987feea --- /dev/null +++ b/src/bnhtrade.Core/Model/Sku/Price/SkuPriceParameter.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.Sku.Price +{ + public class SkuPriceParameter + { + public int SkuId { get; set; } + + public string SkuNumber { get; set; } + + public int TotalQuantity { get; set; } + + public decimal UnitCostAverage { get; set; } + + public int ProductId { get; set; } + + public int ConditionId { get; set; } + + public string TaxCode { get; set; } + + public decimal ProfitMargin { get; set; } + + + /// + /// Agent fee as ratio of selling price (i.e. 0.25) + /// + public decimal AgentFeeMargin { get; set; } + + /// + /// Total of agent fixed fees + /// + public decimal AgentFeeFixed { get; set; } + + /// + /// Amazon margin as a ratio of 1 (i.e. 0.2) + /// + public decimal VatMargin { get; set; } + + public string TaxRateName { get; set; } + + public bool IsFixedPrice { get; set; } + + public decimal CompetitivePriceMultiplierNew { get; set; } + + public decimal TotalCost { get; set; } + + public decimal PriceMinProfit { get; set; } + } +} diff --git a/src/bnhtrade.Core/Model/Stock/SkuTransaction.cs b/src/bnhtrade.Core/Model/Stock/SkuTransaction.cs new file mode 100644 index 0000000..483d163 --- /dev/null +++ b/src/bnhtrade.Core/Model/Stock/SkuTransaction.cs @@ -0,0 +1,189 @@ +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 SkuTransaction : IValidatableObject + { + private DateTime? transactionDate = null; + private bool? isProcessed = null; + private short? quantity = null; + private int? stockjournalId = null; + private int? skuTransactionId = null; + private int? skuTransactionTypeId = null; + private int? foreignKey = null; + + 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 int SkuTransactionTypeId + { + get { return skuTransactionTypeId.GetValueOrDefault(); } + private set { skuTransactionTypeId = value; } + } + + public bool IsSetSkuTransactionTypeId + { + get { return skuTransactionTypeId != null; } + } + + public string SkuTransactionTypeName { get; private set; } + + public bool IsSetReconcileSkuTypeName + { + get { return SkuTransactionTypeName != 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 void SetReconcileSkuType(int reconcileSkuTypeId, string reconcileSkuTypeName) + { + if (!string.IsNullOrWhiteSpace(reconcileSkuTypeName) || reconcileSkuTypeId == 0) + { + SkuTransactionTypeId = reconcileSkuTypeId; + SkuTransactionTypeName = reconcileSkuTypeName; + } + } + + public SkuTransaction Clone() + { + var clone = new SkuTransaction(); + + 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 (IsSetReconcileSkuTypeName) { clone.SkuTransactionTypeName = string.Copy(this.SkuTransactionTypeName); } + if (IsSetStockJournalId) { clone.StockJournalId = this.StockJournalId; } + if (IsSetSkuTransactionId) { clone.SkuTransactionId = this.SkuTransactionId; } + if (IsSetSkuTransactionTypeId) { clone.SkuTransactionTypeId = this.SkuTransactionTypeId; } + if (IsSetTransactionDate) { clone.TransactionDate = this.TransactionDate; } + + return clone; + } + + public IEnumerable Validate(ValidationContext validationContext) + { + var result = new List(); + + if (!IsSetTransactionDate) + { + 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 (!IsSetSkuTransactionTypeId) + { + result.Add(new ValidationResult("Stock Transaction TypeId 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; + } + } +} diff --git a/src/bnhtrade.Core/Model/Stock/SkuTransactionType.cs b/src/bnhtrade.Core/Model/Stock/SkuTransactionType.cs new file mode 100644 index 0000000..b9eac33 --- /dev/null +++ b/src/bnhtrade.Core/Model/Stock/SkuTransactionType.cs @@ -0,0 +1,63 @@ +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 SkuTransactionType + { + private int? typeId = null; + + [Required()] + public int TypeId + { + get { return typeId.GetValueOrDefault(); } + set { typeId = value; } + } + + public bool IsSetTypeId + { + get { return typeId != null; } + } + + public string TypeName { get; set; } + + public bool IsSetTypeName + { + get { return TypeName != null; } + } + + public string TypeCode { get; set; } + + public string TypeDescription { get; set; } + + public int StockJournalTypeId { get; set; } + + public string TransactionForeignKeyName { get; set; } + + public string TransactionReferenceType { get; set; } + + public bool IsNewReviewRequired { get; set; } + + public bool TransactionImportEnabled { get; set; } + + public bool StockJournalEntryEnabled { get; set; } + + public int DebitStockStatusId { get; set; } + + public string DebitStockStatus { get; set; } + + public int CreditStockStatusId { get; set; } + + public string CreditStockStatus { get; set; } + + public bool StatusBalanceCheckRequired { get; set; } + + public bool FilterStockOnDateTime { get; set; } + + public bool FirstInFirstOut { get; set; } + } +} diff --git a/src/bnhtrade.Core/Program.cs b/src/bnhtrade.Core/Program.cs index 5a4c79a..82321dd 100644 --- a/src/bnhtrade.Core/Program.cs +++ b/src/bnhtrade.Core/Program.cs @@ -1657,95 +1657,9 @@ namespace bnhtrade.Core } } } - - public (decimal? price, DateTime? priceDate) ProductCompetitivePriceGet(string sqlConnectionString, int productId, int conditionId) - { - using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) - { - sqlConn.Open(); - - using (SqlCommand cmd = new SqlCommand( - "SELECT t.CompetitivePrice, t.PriceDate " + - "FROM tblProductPriceCompetitive AS t INNER JOIN (SELECT ProductID, Max(PriceDate) AS MaxOfPriceDate " + - "FROM tblProductPriceCompetitive " + - "WHERE ProductID=" + productId + " AND SkuConditionID=" + conditionId + - "GROUP BY ProductID) AS a ON (t.PriceDate = a.MaxOfPriceDate) AND (t.ProductID = a.ProductID)" - , sqlConn)) - { - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - DateTime dt = reader.GetDateTime(1); - dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); - return (reader.GetDecimal(0), dt); - } - else - { - return (null, null); - } - } - } - } - } - - public int ProductCompetitivePriceSet(string sqlConnectionString, int productId, int conditionId, decimal price, bool isBuyBoxPrice, DateTime? priceDate = null) - { - if (priceDate == null) - { - priceDate = DateTime.UtcNow; - } - DateTime dt = DateTime.SpecifyKind(priceDate.Value, DateTimeKind.Utc); - - try - { - using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) - { - sqlConn.Open(); - - using (SqlCommand cmd = new SqlCommand( - "INSERT INTO tblProductPriceCompetitive (ProductID, SkuConditionID, CompetitivePrice, PriceDate, IsBuyBoxPrice) " + - "OUTPUT INSERTED.ProductPriceCompetitiveID " + - "VALUES (@productId, @conditionId, @price, @priceDate, @isBuyBoxPrice)" - , sqlConn)) - { - cmd.Parameters.AddWithValue("@productId", productId); - cmd.Parameters.AddWithValue("@conditionId", conditionId); - cmd.Parameters.AddWithValue("@price", price); - cmd.Parameters.AddWithValue("@priceDate", dt.ToUniversalTime()); - cmd.Parameters.AddWithValue("@isBuyBoxPrice", isBuyBoxPrice); - - return (int)cmd.ExecuteScalar(); - } - } - } - catch (Exception e) - { - throw e; - } - } - - public int testing(string sqlConnectionString) - { - int id = 0; - using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) - { - sqlConn.Open(); - - using (SqlCommand sqlCommand = new SqlCommand( - "SELECT skuSkuID " + - "FROM tblSku " + - "WHERE skuSkuNumber='006449-10'" - , sqlConn)) - { - //execute sql - id = (int)sqlCommand.ExecuteScalar(); - } - } - return id; - } } } + namespace Stock { public class StockCreate @@ -2189,10 +2103,20 @@ namespace bnhtrade.Core public static int StockJournalInsert(string sqlConnectionString, int journalTypeId, int stockId, List<(int statusId, int quantity)> journalPosts, DateTime entryDate, bool isNewStock = false) { - // balance and status IsCredit checks made by post insert function + /* + * 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 ome slight performance benefits. + * + * Once you've done this, fix the SkuTransactionReconcile class: Currently it's transactionscope onyl covers updates. + * Need to set the scope to cover the intial table read (to lock the records). The issue above restricts this. + */ - // make entrydate utc - entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); + + // balance and status IsCredit checks made by post insert function // create the journal entry int stockJournalId; @@ -2278,6 +2202,7 @@ namespace bnhtrade.Core bool consistencyResult = true; if (consistencyRequired) { + consistencyResult = false; // build list of effected status' var statusIdEffected = new List(); foreach (var item in journalPosts) @@ -2451,7 +2376,6 @@ namespace bnhtrade.Core } } - private static void StockJournalPostInsert(SqlConnection conn, int stockId, int stockJournalId, List<(int statusId, int quantity)> journalPosts, bool isNewStock = false) { @@ -2805,23 +2729,28 @@ namespace bnhtrade.Core // Function returns a list with balance of stock avaiable by individual stockId ordered by earliest added to status (stock journal entrydate) // beforeDate - used to filter results, useful when reallocating stock retrospectivly (i.e. avoid case were stock is // moved out of status, ahead of it being moved into that status) -- really this should be the calling function that does this!! - public static List> GetStockStatusBalanceBySkuId - (string sqlConnectionString, int skuId, int stockStatusId, DateTime? maxDateUtc = null, bool sortAgeAscending = true) + public static List> GetStockStatusBalanceBySkuNumber + (string sqlConnectionString, string skuNumber, int stockStatusId, DateTime? maxDateUtc = null, bool sortAgeAscending = true) { //build sql statement string strSQL = @" - SELECT a.JournalDate, a.balance, a.stockID - FROM ( - SELECT MIN(tblStockJournal.EntryDate) AS JournalDate, SUM(tblStockJournalPost.Quantity) AS Balance, tblStock.StockID - FROM tblStockJournal INNER JOIN - tblStock ON tblStockJournal.StockID = tblStock.StockID INNER JOIN - tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID - WHERE (tblStock.SkuID = @skuId ) AND (tblStockJournalPost.StockStatusID = @stockStatusId ) - GROUP BY tblStock.StockID - HAVING (SUM(tblStockJournalPost.Quantity)) > 0 - ) a - "; + SELECT a.JournalDate + ,a.balance + ,a.stockID + FROM ( + SELECT MIN(tblStockJournal.EntryDate) AS JournalDate + ,SUM(tblStockJournalPost.Quantity) AS Balance + ,tblStock.StockID + FROM tblStockJournal + INNER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID + INNER JOIN tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID + INNER JOIN tblSku ON tblStock.SkuID = tblSku.skuSkuID + WHERE (tblStockJournalPost.StockStatusID = @stockStatusId) + AND (tblSku.skuSkuNumber = @skuNumber) + GROUP BY tblStock.StockID + HAVING (SUM(tblStockJournalPost.Quantity) > 0) + ) a "; if (maxDateUtc != null) { strSQL = strSQL + @" @@ -2840,7 +2769,7 @@ namespace bnhtrade.Core using (SqlCommand cmd = new SqlCommand(strSQL, sqlConn)) { // add parameters - cmd.Parameters.AddWithValue("@skuId", skuId); + cmd.Parameters.AddWithValue("@skuNumber", skuNumber); cmd.Parameters.AddWithValue("@stockStatusId", stockStatusId); if (maxDateUtc != null) { cmd.Parameters.AddWithValue("@beforeDateUtc", maxDateUtc.Value.ToUniversalTime()); } @@ -2885,80 +2814,6 @@ namespace bnhtrade.Core } } - public static int StockReallocateByStockId(string sqlConnectionString, int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId, - DateTime entryDate = default(DateTime)) - { - if (entryDate == default(DateTime)) - { - entryDate = DateTime.UtcNow; - } - entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc); - - // create the list - var posts = new List<(int statusId, int quantity)>(); - posts.Add((debitStatusId, quantity)); - posts.Add((creditStatusId, (quantity * -1))); - - // execute - return StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false); - } - - public static List> StockReallocateBySkuId(string sqlConnectionString, int journalTypeId, int skuId, int quantity, int debitStatusId, int creditStatusId, - bool moveOldestFirst = true, DateTime entryDate = default(DateTime), bool reallocatePartialQuantity = false) - { - // feed an skuId and quantity into function and the stock will be reallocated - // return tuple list - // Item1 = StockJournalId - // Item2 = Quantity - - List> list = GetStockStatusBalanceBySkuId(sqlConnectionString, skuId, creditStatusId, entryDate, moveOldestFirst); - if (list == null) - { - return null; - } - - List> returnList = new List>(); - - // quantity check - int avaiableQuantity = 0; - foreach (Tuple item in list) - { - avaiableQuantity = avaiableQuantity + item.Item3; - } - if (avaiableQuantity < quantity && reallocatePartialQuantity == false) - { - return null; - } - - // make the changes - try - { - using (TransactionScope scope = new TransactionScope()) - { - foreach (Tuple item in list) - { - if (quantity > item.Item3) - { - int tempInt = StockReallocateByStockId(sqlConnectionString, journalTypeId, item.Item1, item.Item3, debitStatusId, creditStatusId, entryDate); - quantity = quantity - item.Item3; - returnList.Add(new Tuple(tempInt, item.Item3)); - } - else - { - int tempInt = StockReallocateByStockId(sqlConnectionString, journalTypeId, item.Item1, quantity, debitStatusId, creditStatusId, entryDate); - returnList.Add(new Tuple(tempInt, quantity)); - break; - } - } - scope.Complete(); - return returnList; - } - } - catch (Exception) - { - throw; - } - } public static int GetStockIdByStockJournalId(string sqlConnectionString, int stockJournalId) { try @@ -2991,84 +2846,6 @@ namespace bnhtrade.Core } } - public static int StockTransactionTypeIdSelect(string sqlConnectionString, string matchString) - { - /* GetStockTransactionTypeId return meanings - * >0 use the as the TypeId when inserting transaction - * 0 Skip transpose, type doesn't exist or is new (not reviewed yet) - * -1 Type import/transpose is disabled, IsProcessed=TRUE StockTransactionID=NULL */ - - // old optional parameters - // , bool onNewReturnId = false, bool onNewDisableInsert = false - - if (matchString.Length == 0) - { - throw new Exception("Empty match string passed to method"); - } - try - { - using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString)) - { - sqlConn.Open(); - using (SqlCommand cmd = new SqlCommand(@" - SELECT - StockTransactionTypeID, - IsNewReviewRequired, - TransactionImportEnabled - FROM - tblStockTransactionType - WHERE - MatchString=@matchString; - ", sqlConn)) - { - cmd.Parameters.AddWithValue("@matchString", matchString); - - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - int index01 = reader.GetOrdinal("StockTransactionTypeID"); - int index02 = reader.GetOrdinal("IsNewReviewRequired"); - int index03 = reader.GetOrdinal("TransactionImportEnabled"); - - int transactionTypeId = reader.GetInt32(index01); - bool isNew = reader.GetBoolean(index02); - bool? importEnabled = reader[index03] as bool? ?? null; // column can be null - - if (isNew == true || importEnabled == null) - { - // return 0 and 'skip' item - return 0; - } - else if (importEnabled == false) - { - // mark IsProcessed=true and leave transactionId=null - return -1; - } - else if (transactionTypeId > 0) - { - - return transactionTypeId; - } - else - { - throw new Exception("Stock TransactionTypeId lookup method went wrong, is one of the 'enabled' boolean on table set to null?"); - } - } - else - { - return 0; - } - } - } - } - } - catch (Exception ex) - { - throw ex; - } - } - public static int StockTransactionTypeIdInsert(string sqlConnectionString, int stockJournalTypeId, string matchString, bool transScopeSuppress = true) { int transactionTypeId; @@ -3089,12 +2866,12 @@ namespace bnhtrade.Core //check to see if type already exists, return id of that if it does using (SqlCommand cmd = new SqlCommand(@" SELECT - tblStockTransactionType.StockTransactionTypeID + tblStockSkuTransactionType.StockSkuTransactionTypeID FROM - tblStockTransactionType + tblStockSkuTransactionType WHERE - tblStockTransactionType.StockJournalTypeID=@stockJournalTypeId - AND tblStockTransactionType.MatchString=@matchString; + tblStockSkuTransactionType.StockJournalTypeID=@stockJournalTypeId + AND tblStockSkuTransactionType.MatchString=@matchString; ", conn)) { cmd.Parameters.AddWithValue("@matchString", matchString); @@ -3110,10 +2887,10 @@ namespace bnhtrade.Core // insert new and retrive new value using (SqlCommand cmd = new SqlCommand(@" - INSERT INTO tblStockTransactionType + INSERT INTO tblStockSkuTransactionType ( StockJournalTypeID, MatchString ) OUTPUT - INSERTED.StockTransactionTypeID + INSERTED.StockSkuTransactionTypeID VALUES ( @stockJournalTypeId, @matchString ); ", conn)) @@ -3317,19 +3094,6 @@ namespace bnhtrade.Core public class StockReconciliation { - public class ReconcileStockTransactionsResult - { - public bool ReconciliationComplete { get; set; } = false; - public int StockTransactionId { get; set; } - public int StockTransactionTypeId { get; set; } - public string ProgressMessage { get; set; } - public int ItemsCompleted { get; set; } - public int ItemsRemaining { get; set; } - public DateTime LastItemDateTime { get; set; } - } - - - // downloads new inventory data from mws and updates stock import tables public void UpdateFbaStockImportData(string sqlConnectionString) { @@ -3423,8 +3187,8 @@ namespace bnhtrade.Core try { - transactionTypeIdPos = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringPos); - transactionTypeIdNeg = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + transactionTypeIdPos = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchStringPos); + transactionTypeIdNeg = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchStringNeg); } catch (Exception ex) { @@ -3471,7 +3235,7 @@ namespace bnhtrade.Core transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); int importTableId = reader.GetInt32(index01); string sku = reader.GetString(index03); - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { @@ -3495,11 +3259,11 @@ namespace bnhtrade.Core { // attempt to update/correct earlier incorrect +ve StockTransaction entry using (SqlCommand cmd2 = new SqlCommand(@" - SELECT StockTransactionID, Quantity FROM tblStockTransaction - WHERE StockTransactionTypeID=@stockTransactionTypeId AND Reference=@reference AND SkuID=@skuId AND Quantity>=@quantity AND IsProcessed=0 + SELECT StockSkuTransactionID, Quantity FROM tblStockSkuTransaction + WHERE StockSkuTransactionTypeID=@stockSkuTransactionTypeId AND Reference=@reference AND SkuID=@skuId AND Quantity>=@quantity AND IsProcessed=0 ", transConn)) { - cmd2.Parameters.AddWithValue("stockTransactionTypeId", transactionTypeIdPos); + cmd2.Parameters.AddWithValue("stockSkuTransactionTypeId", transactionTypeIdPos); cmd2.Parameters.AddWithValue("reference", reference); cmd2.Parameters.AddWithValue("skuId", skuId); cmd2.Parameters.AddWithValue("quantity", (quantity * -1)); @@ -3516,16 +3280,16 @@ namespace bnhtrade.Core { using (SqlCommand cmd3 = new SqlCommand(@" UPDATE tblImportFbaInventoryReceiptReport - SET StockTransactionID=NULL - WHERE StockTransactionID=@transactionId + SET StockSkuTransactionID=NULL + WHERE StockSkuTransactionID=@transactionId ", transConn)) { cmd3.Parameters.AddWithValue("transactionId", transactionId); cmd3.ExecuteNonQuery(); } using (SqlCommand cmd3 = new SqlCommand(@" - DELETE FROM tblStockTransaction - WHERE StockTransactionID=@transactionId + DELETE FROM tblStockSkuTransaction + WHERE StockSkuTransactionID=@transactionId ", transConn)) { cmd3.Parameters.AddWithValue("transactionId", transactionId); @@ -3537,9 +3301,9 @@ namespace bnhtrade.Core else { using (SqlCommand cmd3 = new SqlCommand(@" - UPDATE tblStockTransaction + UPDATE tblStockSkuTransaction SET Quantity=@quantity - WHERE StockTransactionID=@transactionId + WHERE StockSkuTransactionID=@transactionId ", transConn)) { cmd3.Parameters.AddWithValue("transactionId", transactionId); @@ -3570,7 +3334,7 @@ namespace bnhtrade.Core // update isprocessed and transactionId on import table using (SqlCommand updateCmd = new SqlCommand( "UPDATE tblImportFbaInventoryReceiptReport " + - "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "SET StockSkuTransactionID=@transactionId, IsProcessed=1 " + "WHERE ImportFbaInventoryReceiptReportID=@importTableId;", transConn)) { @@ -3599,6 +3363,7 @@ namespace bnhtrade.Core + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); } } + public void ProcessFbaSaleShipmentData(string sqlConnectionString) { // hack time, method requires uptodate fba order information in db order tables @@ -3622,7 +3387,7 @@ namespace bnhtrade.Core try { - transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + transactionTypeId = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchString); } catch (Exception ex) { @@ -3639,9 +3404,11 @@ namespace bnhtrade.Core try { + using (TransactionScope scope = new TransactionScope()) using (SqlConnection conn = new SqlConnection(sqlConnectionString)) { conn.Open(); + using (SqlCommand cmd = new SqlCommand( "SELECT * FROM tblImportFbaSaleShipment WHERE IsProcessed=0 " + "ORDER BY [payments-date];" @@ -3668,7 +3435,7 @@ namespace bnhtrade.Core transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); int importTableId = reader.GetInt32(index01); string sku = reader.GetString(index03); - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } @@ -3682,11 +3449,12 @@ namespace bnhtrade.Core if (quantity > 0 && transactionTypeId == 0) { transposeSkip = transposeSkip + 1; continue; } - using (TransactionScope scope = new TransactionScope()) - { + //using (TransactionScope scope = new TransactionScope()) + //{ using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) { transConn.Open(); + int transactionId; if (quantity > 0 & transactionTypeId > 0) { transactionId = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, transactionDate, transactionTypeId, skuId, quantity, orderItemId, amazonOrderId, "", false, 0); } @@ -3697,7 +3465,7 @@ namespace bnhtrade.Core using (SqlCommand updateCmd = new SqlCommand( "UPDATE tblImportFbaSaleShipment " + - "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "SET StockSkuTransactionID=@transactionId, IsProcessed=1 " + "WHERE ImportFbaSaleShipmentID=@importTableId;", transConn)) { @@ -3709,13 +3477,14 @@ namespace bnhtrade.Core } } transposeCount = transposeCount + 1; - scope.Complete(); - } + // scope.Complete(); + //} } Console.Write("\r"); } } } + scope.Complete(); } MiscFunction.EventLogInsert("TransposeFbaSaleShipmentReport() complete, " + transposeCount + " total records transposed, " + transposeSkip + " records skipped."); if (transposeSkip > 0) { MiscFunction.EventLogInsert(transposeSkip + " number records skipped during TransposeFbaSaleShipmentReport() operation.", 2); } @@ -3726,6 +3495,7 @@ namespace bnhtrade.Core + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); } } + public void WIP_GetSetFbaOrderRefs(string sqlConnectionString) { // currently a hack, gets info from FBA sale shipment import table and has to run before the inforation is transposed to transaction table @@ -3776,6 +3546,7 @@ namespace bnhtrade.Core } } } + public void ProcessFbaReturnsData(string sqlConnectionString) { MiscFunction.EventLogInsert("Starting TransposeFbaReturnsReport()"); @@ -3834,7 +3605,7 @@ namespace bnhtrade.Core } } - int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + int transactionTypeId = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchString); /* GetStockTransactionTypeId return meanings * >0 use the as the TypeId when inserting transaction * 0 Skip transpose, yype is new or has not been reviewed yet @@ -3861,7 +3632,7 @@ namespace bnhtrade.Core if (!reader.IsDBNull(index09)) { detail = detail + Environment.NewLine + "Customer Comments: " + reader.GetString(index09); } - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } @@ -3880,7 +3651,7 @@ namespace bnhtrade.Core using (SqlCommand updateCmd = new SqlCommand( "UPDATE tblImportFbaCustomerReturn " + - "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "SET StockSkuTransactionID=@transactionId, IsProcessed=1 " + "WHERE ImportFbaCustomerReturnID=@importTableId;", transConn)) { @@ -3909,6 +3680,7 @@ namespace bnhtrade.Core + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); } } + public void ProcessFbaAdustmentData(string sqlConnectionString) { MiscFunction.EventLogInsert("Starting TransposeFbaAdustmentReport()"); @@ -3989,7 +3761,7 @@ namespace bnhtrade.Core return; } - int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + int transactionTypeId = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchString); /* GetStockTransactionTypeId return meanings * >0 use the as the TypeId when inserting transaction * 0 By default, new unreviewed type will return 0 to skip transpose. @@ -4018,7 +3790,7 @@ namespace bnhtrade.Core if (quantity < 0) { quantity = quantity * -1; } string reference = reader.GetString(index05); - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } @@ -4254,7 +4026,7 @@ namespace bnhtrade.Core using (SqlCommand updateCmd = new SqlCommand( "UPDATE tblImportFbaInventoryAdjustmentReport " + - "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "SET StockSkuTransactionID=@transactionId, IsProcessed=1 " + "WHERE ImportFbaInventoryAdjustmentReportID=@importTableId;", transConn)) { @@ -4286,6 +4058,7 @@ namespace bnhtrade.Core return; } + public void WIP_ProcessFbaReimbursementData(string sqlConnectionString) { /* @@ -4336,11 +4109,11 @@ namespace bnhtrade.Core // get transtypeIds for qty transaferred to amazon ownership string matchStringNeg = "<_GET_FBA_REIMBURSEMENTS_DATA_><-ve><" + reader.GetString(index04) + ">"; - int transactionTypeIdNeg = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + int transactionTypeIdNeg = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchStringNeg); if (invRecived > 0) { matchStringPos = "<_GET_FBA_REIMBURSEMENTS_DATA_><+ve><" + reader.GetString(index04) + ">"; - transactionTypeIdPos = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchStringNeg); + transactionTypeIdPos = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchStringPos); } /* GetStockTransactionTypeId return meanings * >0 use the as the TypeId when inserting transaction @@ -4363,7 +4136,7 @@ namespace bnhtrade.Core string reference = reader.GetString(index03); int quantityTotal = reader.GetInt32(index06); - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { @@ -4393,7 +4166,7 @@ namespace bnhtrade.Core UPDATE tblImportFbaReimbursementReport SET - StockTransactionID=@transactionId, + StockSkuTransactionID=@transactionId, IsProcessed=1 WHERE ImportFbaReimbursementReportID=@importTableId; @@ -4424,6 +4197,7 @@ namespace bnhtrade.Core + transposeCount + " total records completed, " + transposeSkip + " records skipped.", 1, ex.ToString()); } } + public void ProcessReportFbaRemovalOrder(string sqlConnectionString) { MiscFunction.EventLogInsert("Starting TransposeFbaRemovalOrderReport()"); @@ -4468,7 +4242,7 @@ namespace bnhtrade.Core string matchString = "<_GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA_><" + reader.GetString(index06) + "><" + reader.GetString(index08) + ">"; - int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, matchString); + int transactionTypeId = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchString); /* GetStockTransactionTypeId return meanings * >0 use the as the TypeId when inserting transaction * 0 Skip transpose, type is new or has not been reviewed yet @@ -4496,7 +4270,7 @@ namespace bnhtrade.Core { transactionTypeId = -1; } else { - var skuData = new Data.Database.SKU.GetSkuId(sqlConnectionString); + var skuData = new Data.Database.Sku.GetSkuId(sqlConnectionString); skuId = skuData.BySKUNumber(sku, true); } if (skuId < 1) @@ -4514,7 +4288,7 @@ namespace bnhtrade.Core using (SqlCommand updateCmd = new SqlCommand( "UPDATE tblImportFbaRemovalOrderReport " + - "SET StockTransactionID=@transactionId, IsProcessed=1 " + + "SET StockSkuTransactionID=@transactionId, IsProcessed=1 " + "WHERE ImportFbaRemovalOrderReportID=@importTableId;", transConn)) { @@ -4554,8 +4328,8 @@ namespace bnhtrade.Core sqlConn.Open(); using (SqlCommand cmd = new SqlCommand( - "INSERT INTO tblStockTransaction ( TransactionDate, StockTransactionTypeID, ForeignKey, SkuID, Quantity, Reference, Detail, IsProcessed, StockJournalID ) " + - "OUTPUT INSERTED.StockTransactionID " + + "INSERT INTO tblStockSkuTransaction ( TransactionDate, StockSkuTransactionTypeID, ForeignKey, SkuID, Quantity, Reference, Detail, IsProcessed, StockJournalID ) " + + "OUTPUT INSERTED.StockSkuTransactionID " + "VALUES (@transactionDate, @transactionTypeId, @foreignKey, @skuId, @Quantity, @reference, @detail, @isProcessed, @StockJournalId );", sqlConn)) { @@ -4580,663 +4354,9 @@ namespace bnhtrade.Core } } } - - // iterates through the stock transaction table and inserts stock journal entries, where applicable - // N.B. This function does not make allowances for status' that can create stock (i.e. if a status does not have stock available, this function will halt processing rows) - public ReconcileStockTransactionsResult ReconcileStockTransactions(string sqlConnectionString, bool updateTransactions) - { - // create the return object - ReconcileStockTransactionsResult returnResult = new ReconcileStockTransactionsResult(); - - string currentMethodName = nameof(ReconcileStockTransactions); - //bool returnComplete = false; - //string returnMessage = ""; - //string returnDetails = ""; - - // ensure import table have been processed into transaction table without exception - if (updateTransactions == true) - { - try - { - var preCheck = new StockReconciliation(); - preCheck.ProcessFbaStockImportData(sqlConnectionString); - } - catch (Exception ex) - { - returnResult.ProgressMessage = "Precheck failed: " + ex.Message; - return returnResult; - } - } - - MiscFunction.EventLogInsert("Starting ReconcileStockTransactions()"); - int record = 0; - int recordSkip = 0; - - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - string sqlPartString = @" - FROM tblStockTransaction INNER JOIN - tblStockTransactionType ON tblStockTransaction.StockTransactionTypeID = tblStockTransactionType.StockTransactionTypeID - WHERE tblStockTransaction.IsProcessed = 0 AND tblStockTransaction.SkuID IS NOT NULL AND tblStockTransaction.Quantity IS NOT NULL - AND ( tblStockTransactionType.StockJournalEntryEnabled = 1 OR tblStockTransactionType.IsNewReviewRequired = 1 ) "; - - - // get row count of record set - using (SqlCommand cmd = new SqlCommand("SELECT COUNT (tblStockTransaction.StockTransactionID) " + sqlPartString, conn)) - { - returnResult.ItemsRemaining = (int)cmd.ExecuteScalar(); - returnResult.ItemsCompleted = 0; - } - - // order by stocktransId desc = Amazon reports are listed in datetime ASC order, some reports have date only, however I have reason to believe these are in time order - // also. adding this means they at least get processed in the correct order (maybe)! - using (SqlCommand cmd = new SqlCommand(@" - SELECT tblStockTransaction.StockTransactionID, tblStockTransaction.TransactionDate, tblStockTransaction.StockTransactionTypeID, tblStockTransaction.ForeignKey, - tblStockTransaction.Reference, tblStockTransaction.Detail, tblStockTransaction.SkuID, tblStockTransaction.Quantity, - tblStockTransactionType.StockJournalEntryEnabled, tblStockTransactionType.DebitStockStatusID, tblStockTransactionType.CreditStockStatusID, - tblStockTransactionType.StatusBalanceCheckRequired, tblStockTransactionType.CreditStatusFirstInFirstOut, tblStockTransactionType.IsNewReviewRequired, - tblStockTransactionType.FilterStockOnDateTime, tblStockTransactionType.MatchString, StockJournalTypeID " + - sqlPartString + @" - ORDER BY tblStockTransaction.TransactionDate ASC, tblStockTransaction.StockTransactionID DESC; - ", conn)) - { - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.HasRows) - { - int index01 = reader.GetOrdinal("StockTransactionID"); - int index02 = reader.GetOrdinal("TransactionDate"); - int index03 = reader.GetOrdinal("StockTransactionTypeID"); - int index04 = reader.GetOrdinal("SkuID"); - int index05 = reader.GetOrdinal("Quantity"); - int index06 = reader.GetOrdinal("StockJournalEntryEnabled"); - int index07 = reader.GetOrdinal("ForeignKey"); - int index08 = reader.GetOrdinal("Reference"); - int index09 = reader.GetOrdinal("Detail"); - int index10 = reader.GetOrdinal("CreditStatusFirstInFirstOut"); - int index11 = reader.GetOrdinal("DebitStockStatusID"); - int index12 = reader.GetOrdinal("CreditStockStatusID"); - int index13 = reader.GetOrdinal("IsNewReviewRequired"); - int index14 = reader.GetOrdinal("FilterStockOnDateTime"); - int index15 = reader.GetOrdinal("MatchString"); - int index16 = reader.GetOrdinal("StockJournalTypeID"); - - while (reader.Read()) - { - record = record + 1; - Console.Write("\rProcessing record: {0} ({1} skipped)", (record + recordSkip), recordSkip); - - // read values into variables - int stockTransactionId = reader.GetInt32(index01); - DateTime transactionDate = reader.GetDateTime(index02); - transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); - int transactionTypeID = reader.GetInt32(index03); - int skuId = reader.GetInt32(index04); - int quantity = reader.GetInt32(index05); - bool entryEnabled = reader.GetBoolean(index06); - int foreignKey = 0; - if (reader[index07] != DBNull.Value) - { foreignKey = reader.GetInt32(index07); } - string reference = ""; - if (reader[index08] != DBNull.Value) - { reference = reader.GetString(index08); } - string detail = ""; - if (reader[index09] != DBNull.Value) - { detail = reader.GetString(index09); } - bool orderAsc = reader.GetBoolean(index10); - // check/set debit/credit staus to 0 for special cases - int debitStatus = 0; - if (!reader.IsDBNull(index11)) - { debitStatus = reader.GetInt32(index11); } - int creditStatus = 0; - if (!reader.IsDBNull(index12)) - { creditStatus = reader.GetInt32(index12); } - bool filterStockOnDateTime = reader.GetBoolean(index14); - string matchString = ""; - if (!reader.IsDBNull(index15)) - { - matchString = reader.GetString(index15); - } - int journalTypeId = reader.GetInt32(index16); - - // setup return values - returnResult.StockTransactionId = stockTransactionId; - returnResult.StockTransactionTypeId = transactionTypeID; - returnResult.LastItemDateTime = transactionDate; - - - // stop if a new transactiontype is encountered - if (reader.GetBoolean(index13) == true) - { - returnResult.ProgressMessage = "New 'Transaction-Type' encountered"; - //Console.Write("\r"); - //MiscFunction.EventLogInsert(errMessage, 1); - goto Finish; - } - - // set debit/credit status' for special cases (i.e. NULL or 0 debit/credit ids in stockTransactionType table) - if (entryEnabled == true && (debitStatus == 0 || creditStatus == 0)) - { - // FBA Shipment Receipt +ve - if (matchString == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><+ve>" - || matchString == "<_GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA_><-ve>") - { - using (SqlCommand cmd2 = new SqlCommand("" + - "SELECT ShipmentStockStatusID FROM tblAmazonShipment WHERE ShipmentId=@reference", conn)) - { - cmd2.Parameters.Add(new SqlParameter("reference", reference)); - - object temp = cmd2.ExecuteScalar(); - if (temp != DBNull.Value) - { - // +ve shipment receipt - if (creditStatus == 0 && debitStatus > 0) - { creditStatus = Convert.ToInt32(temp); } - - // -ve shipment receipt - else if (debitStatus == 0 && creditStatus > 0) - { debitStatus = Convert.ToInt32(temp); } - - // something went wrong, raise error - else - { - returnResult.ProgressMessage = "Unable to retrive FBA shipment location/status from tblAmazonShipment for Amazon shipment '" + reference + "'."; - recordSkip = recordSkip + 1; - //Console.Write("\r"); - //MiscFunction.EventLogInsert("Debit or credit id value missing for shipment receipt WHERE StockTransactionTypeId=" - // + transactionTypeID, 1, "", default(DateTime), true, conn); - goto Finish; - } - } - } - } - // something went wrong, raise error - else - { - returnResult.ProgressMessage = "Coding required. Unhandled special case Transaction-Type encountered (Transaction-Type debit or credit is set to 0)."; - recordSkip = recordSkip + 1; - goto Finish; - } - } - - // make the changes - if (entryEnabled == false) - { - using (SqlCommand cmdIsProcessed = new SqlCommand(@" - UPDATE tblStockTransaction - SET IsProcessed=1 - WHERE StockTransactionID=@stockTransactionId - ", conn)) - { - cmdIsProcessed.Parameters.AddWithValue("@stockTransactionId", stockTransactionId); - - cmdIsProcessed.ExecuteNonQuery(); - } - } - else - { - using (TransactionScope scope = new TransactionScope()) - { - using (SqlConnection transConn = new SqlConnection(sqlConnectionString)) - { - transConn.Open(); - List> list = new List>(); - if (filterStockOnDateTime == true) - { - list = Stock.StockJournal.StockReallocateBySkuId(sqlConnectionString, journalTypeId, skuId, quantity, debitStatus, creditStatus, orderAsc, - transactionDate.ToUniversalTime(), false); - } - else - { - list = Stock.StockJournal.StockReallocateBySkuId(sqlConnectionString, journalTypeId, skuId, quantity, debitStatus, creditStatus, orderAsc, - DateTime.UtcNow, false); - } - - // insufficient balance available - if (list == null) - { - // in special case (found inventory), continue - if (matchString.Contains("<_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_>")) - { - continue; - } - else - { - returnResult.ProgressMessage = "Insurficent status/location balance to relocate stock"; - recordSkip = recordSkip + 1; - //Console.Write("\r"); - //MiscFunction.EventLogInsert("StockReallocateBySkuId() returned null (i.e. no avaiable stock to relocate), WHERE StockTransactionId=" - // + stockTransactionId, 2, "", default(DateTime), true, conn); - goto Finish; - } - } - - // fail safe - if ((list.Sum(c => c.Item2) > quantity)) - { - throw new Exception( - currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function" - + stockTransactionId); - //recordSkip = recordSkip + 1; - //Console.Write("\r"); - //MiscFunction.EventLogInsert("StockReallocateBySkuId() returned retuned a greater quantity than passed to function, WHERE StockTransactionId=" - // + stockTransactionId, 1, "", default(DateTime), true, conn); - //goto Finish; - } - - - using (SqlCommand cmdUpdate = new SqlCommand(@" - UPDATE tblStockTransaction - SET Quantity=@quantity, StockJournalID=@StockJournalId, IsProcessed=1 - WHERE StockTransactionID=@stockTransactionId - ", transConn)) - { - cmdUpdate.Parameters.AddWithValue("@StockJournalId", list[0].Item1); - cmdUpdate.Parameters.AddWithValue("@quantity", list[0].Item2); - cmdUpdate.Parameters.AddWithValue("@stockTransactionId", stockTransactionId); - - cmdUpdate.ExecuteNonQuery(); - } - quantity = quantity - list[0].Item2; - - // only nessecary when there is more than one StockJournal entry - stockTransction row will be copied and quantities split accordingly - if (list.Count > 1) - { - for (int i = 1; i < list.Count; i++) - { - int tempInt = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, - transactionDate.ToUniversalTime(), transactionTypeID, skuId, list[i].Item2, foreignKey, reference, detail, true, list[i].Item1); - quantity = quantity - list[i].Item2; - - //fail safe - if (quantity < 0) - { - throw new Exception( - currentMethodName + ": StockReallocateBySkuId() returned greater quantity than passed to function" - + stockTransactionId); - //MiscFunction.EventLogInsert("StockReallocateBySkuId() function assigned/returned more quantity than was passed to function", - // 1, "", default(DateTime), true, conn); - //goto Finish; - } - } - } - - // any remaining quantity not reallocated is added back to transaction table with no corresponding stock journal entry - if (quantity > 0) - { - int tempInt = Stock.StockReconciliation.StockTransactionInsert(sqlConnectionString, - transactionDate.ToUniversalTime(), transactionTypeID, skuId, quantity, foreignKey, reference, detail, false, 0); - } - - scope.Complete(); - //} - } - } - } - returnResult.ItemsCompleted = returnResult.ItemsCompleted + 1; - returnResult.ItemsRemaining = returnResult.ItemsRemaining - 1; - } - } - // no records returned - else - { - returnResult.ReconciliationComplete = true; - returnResult.ProgressMessage = "No new transactions to process"; - goto Finish; - } - } - } - Console.Write("\r"); - } - - returnResult.ReconciliationComplete = true; - returnResult.ProgressMessage = "Stock transactions fully reconciled!"; - - Finish: - - MiscFunction.EventLogInsert("ProcessStockTransactions() compete. " + (record - recordSkip) + " total records processed, " + recordSkip + " rows uncompllete due to insurficent stock."); - MiscFunction.EventLogInsert("ProcessStockTransactions(), " + recordSkip + " rows skipped due to insurficent stock.", 2); - return returnResult; - } - } } - namespace Inventory - { - public class InventoryPricing - { - - public static void AmazonMinMaxTemp(string sqlConnectionString) - { - MiscFunction.ConsoleUpdate("Operation started."); - - // first command line git commit and push - - DateTime crTimeStamp = DateTime.SpecifyKind( DateTime.UtcNow, DateTimeKind.Utc); - int count = 0; - int exceptionSku = 0; - - string stringSql = @" - SELECT - b.SkuID - ,b.SkuTotalQuantity - ,b.SkuTotalCost - ,b.SkuAvgUnitCost - ,tblSku.skuProductID - ,tblSku.skuSkuConditionID - ,tblSku.AccountTaxCodeID - ,tblProductCategory.ProfitMinPercent - ,tblProductCategory.ProfitMinAmount - ,(tblAmazonFeeEstimate.ReferralFee / tblAmazonFeeEstimate.PriceToEstimateFeeListingPrice) As AmazonMargin - ,(tblAmazonFeeEstimate.VariableClosingFee + tblAmazonFeeEstimate.PerItemFee + tblAmazonFeeEstimate.FBAFee + tblAmazonFeeEstimate.OtherFee_Exception) AS AmazonFees - ,tblAccountTaxCode.TaxRateMultiplierNet - ,tblAccountTaxCode.TaxRateNameShort - ,tblSkuCondition.IsFixedPrice - ,tblSkuCondition.CompetitivePriceMultiplierNew - ,tblSkuCondition.CompetitivePriceMultiplierMatch - ,tblSkuCondition.scnSkuNumberSuffix - FROM - ((((( - SELECT - a.SkuID, - Sum(a.SumOfQuantity) AS SkuTotalQuantity, - Sum(a.QuanityTimesUnitCost) AS SkuTotalCost, - Sum(a.QuanityTimesUnitCost)/Sum(a.SumOfQuantity) AS SkuAvgUnitCost - FROM - ( - SELECT - tblStock.SkuID, - Sum(tblStockJournalPost.Quantity) AS SumOfQuantity, - tblStockJournal.StockID, tblAccountStockCost.AmountUnit, - Sum([tblStockJournalPost].[Quantity])*[tblAccountStockCost].[AmountUnit] AS QuanityTimesUnitCost - FROM - (((tblStockJournalPost - INNER JOIN tblStockStatus - ON tblStockJournalPost.StockStatusID = tblStockStatus.StockStatusID) - INNER JOIN tblStockJournal ON tblStockJournalPost.StockJournalID = tblStockJournal.StockJournalID) - INNER JOIN tblAccountStockCost ON tblStockJournal.StockID = tblAccountStockCost.StockID) - INNER JOIN tblStock ON tblAccountStockCost.StockID = tblStock.StockID - WHERE - tblStockStatus.StockStatusTypeID=3 - OR tblStockStatus.StockStatusTypeID=4 - GROUP BY - tblStockJournal.StockID, - tblAccountStockCost.AmountUnit, - tblStock.SkuID - HAVING - Sum(tblStockJournalPost.Quantity)>0 - ) a - GROUP BY - a.SkuID - ) b - INNER JOIN tblSku ON b.SkuID = tblSku.skuSkuID) - INNER JOIN tblProduct ON tblSku.skuProductID = tblProduct.prdProductID) - LEFT JOIN tblAmazonFeeEstimate ON tblProduct.prdProductID = tblAmazonFeeEstimate.ProductIdentifier ) - INNER JOIN tblProductCategory ON tblProduct.ProductCategoryID = tblProductCategory.ProductCategoryID) - INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID - INNER JOIN tblSkuCondition ON tblSku.skuSkuConditionID = tblSkuCondition.scnSkuConditionID - "; - try - { - using (var conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - // loop through table - using (var cmd01 = new SqlCommand(stringSql, conn)) - { - using (var reader01 = cmd01.ExecuteReader()) - { - if (reader01.HasRows) - { - - } - else - { - throw new Exception("Querying the database returned no records."); - } - - // get ordinlals - int ordinalSkuID = reader01.GetOrdinal("SkuID"); - int ordinalSkuTotalQuantity = reader01.GetOrdinal("SkuTotalQuantity"); - int ordinalSkuTotalCost = reader01.GetOrdinal("SkuTotalCost"); - int ordinalSkuAvgUnitCost = reader01.GetOrdinal("SkuAvgUnitCost"); - int ordinalProductId = reader01.GetOrdinal("skuProductID"); - int ordinalSkuConditionId = reader01.GetOrdinal("skuSkuConditionID"); - int ordinalAccountTaxCodeID = reader01.GetOrdinal("AccountTaxCodeID"); - int ordinalProfitMinPercent = reader01.GetOrdinal("ProfitMinPercent"); - int ordinalProfitMinAmount = reader01.GetOrdinal("ProfitMinAmount"); - int ordinalAmazonMargin = reader01.GetOrdinal("AmazonMargin"); - int ordinalAmazonFees = reader01.GetOrdinal("AmazonFees"); - int ordinalTaxRateMultiplierNet = reader01.GetOrdinal("TaxRateMultiplierNet"); - int ordinalTaxRateNameShort = reader01.GetOrdinal("TaxRateNameShort"); - int ordinalIsFixedPrice = reader01.GetOrdinal("IsFixedPrice"); - int ordinalCompetitivePriceMultiplierNew = reader01.GetOrdinal("CompetitivePriceMultiplierNew"); - int ordinalCompetitivePriceMultiplierMatch = reader01.GetOrdinal("CompetitivePriceMultiplierMatch"); - int ordinalSkuNumberSuffix = reader01.GetOrdinal("scnSkuNumberSuffix"); - - - while (reader01.Read()) - { - // other required variables - int skuId = reader01.GetInt32(ordinalSkuID); - exceptionSku = skuId; - int skuProductId = reader01.GetInt32(ordinalProductId); - int skuConditionId = reader01.GetInt32(ordinalSkuConditionId); - int skuTaxCodeId = reader01.GetByte(ordinalAccountTaxCodeID); - decimal skuProfitMargin = reader01.GetDecimal(ordinalProfitMinPercent) / 100; - decimal skuAmazonMargin = decimal.Round(reader01.GetDecimal(ordinalAmazonMargin), 3); - decimal skuVatMargin = reader01.GetDecimal(ordinalTaxRateMultiplierNet); - string skuTaxRateName = reader01.GetString(ordinalTaxRateNameShort); - bool skuIsFixedPrice = reader01.GetBoolean(ordinalIsFixedPrice); - decimal skuCompetitivePriceMultiplierNew = reader01.GetDecimal(ordinalCompetitivePriceMultiplierNew); - decimal skuCompetitivePriceMultiplierMatch = reader01.GetDecimal(ordinalCompetitivePriceMultiplierMatch); - decimal skuTotalCost = reader01.GetDecimal(ordinalSkuTotalCost); - decimal skuPriceMinProfit = reader01.GetDecimal(ordinalProfitMinAmount); - decimal skuOrderChannelFee = reader01.GetDecimal(ordinalAmazonFees); - decimal crUnitAvgCost = reader01.GetDecimal(ordinalSkuAvgUnitCost); - int skuNumberSuffix = reader01.GetInt32(ordinalSkuNumberSuffix); - - - // STAGE 2 - // SKU current stock details (i.e. quantity, cost per unit, inventory age, etc.) - - - - // Stage 4 - // Set MIN Price - decimal crUnitAvgCostActual = crUnitAvgCost; - decimal crPriceMinAmountAuto; - decimal crPriceMinAmountFinal; - decimal crProfitMinAmount; - - // used loss, sells just to cover fees - if (skuNumberSuffix >= 11 && skuNumberSuffix <= 14) - { - if (crUnitAvgCost == 0) - { - skuVatMargin = 0m; - } - crUnitAvgCost = 0m; - skuProfitMargin = 0m; - crProfitMinAmount = 0m; - skuPriceMinProfit = 0m; - } - - if (skuTaxRateName == "MS" || skuTaxRateName == "GA") - { - crPriceMinAmountAuto = (5m * crUnitAvgCost + 6m * skuOrderChannelFee) / (-6m * skuProfitMargin - 6m * skuAmazonMargin + 5m); - //crPriceMinCalculatedTax = (crPriceMinAmountAuto - crUnitAvgCost) * (1 / 6); - crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; - } - else - { - crPriceMinAmountAuto = (crUnitAvgCost + skuOrderChannelFee) / (1 - (skuProfitMargin + skuAmazonMargin + skuVatMargin)); - //crPriceMinCalculatedTax = crPriceMinAmountAuto * skuVatMargin; - crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; - } - - // if profit margin is less than min required, redo - if (crProfitMinAmount < skuPriceMinProfit) - { - if (skuTaxRateName == "MS" || skuTaxRateName == "GA") - { - crPriceMinAmountAuto = (6m * skuPriceMinProfit + 5m * crUnitAvgCost + 6m * skuOrderChannelFee) / (-6m * skuAmazonMargin + 5m); - //crPriceMinCalculatedTax = (crPriceMinAmountAuto - crUnitAvgCost) * (1 / 6); - crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; - } - else - { - crPriceMinAmountAuto = (crUnitAvgCost + skuOrderChannelFee + skuPriceMinProfit) / (1 - (skuAmazonMargin + skuVatMargin)); - //crPriceMinCalculatedTax = crPriceMinAmountAuto * skuVatMargin; - crProfitMinAmount = crPriceMinAmountAuto * skuProfitMargin; - } - } - - crPriceMinAmountFinal = crPriceMinAmountAuto; - - - // STAGE 6 - // Set MAX Price - decimal crPriceMaxAmountFinal; - - // CASE: Reset MAX-Price base & multiplier values (new record or switching back to auto) - // get competative price and apply multiplier - var request = new Core.Product.ProductQuery(); - var compPrice = request.ProductCompetitivePriceGet(sqlConnectionString, skuProductId, 10); - if (compPrice.price == null || compPrice.priceDate == null) - { - using (var cmd02 = new SqlCommand(@" - SELECT tblProduct.prdMaxPrice - FROM tblSku INNER JOIN tblProduct ON tblSku.skuProductID = tblProduct.prdProductID - WHERE (((tblSku.skuSkuID)=@skuId)); - ", conn)) - { - cmd02.Parameters.AddWithValue("@skuId", skuId); - - crPriceMaxAmountFinal = (decimal)cmd02.ExecuteNonQuery(); - } - } - else - { - crPriceMaxAmountFinal = (int)(compPrice.price * skuCompetitivePriceMultiplierNew); - } - - - // for fixed price items - if (skuIsFixedPrice == true) - { - using (var cmd02 = new SqlCommand(@" - SELECT tblSku.skuPriceMin, tblSku.skuPriceMax - FROM tblSku - WHERE (((tblSku.skuSkuID)=@skuId)); - ", conn)) - { - cmd02.Parameters.AddWithValue("@skuId", skuId); - - using (var reader02 = cmd02.ExecuteReader()) - { - decimal? max = null; - decimal? min = null; - reader02.Read(); - - if (!reader02.IsDBNull(0)) { min = reader02.GetDecimal(0); } - if (!reader02.IsDBNull(1)) { max = reader02.GetDecimal(1); } - - if (max == min && max != null) - { - crPriceMinAmountFinal = (decimal)min; - crPriceMaxAmountFinal = (decimal)max; - } - } - } - } - - // STAGE 7 - // Checks before update - - // max < min - if (crPriceMaxAmountFinal < crPriceMinAmountFinal) - { - crPriceMaxAmountFinal = crPriceMinAmountFinal; - } - - // this should be last check - // check for zero values (where there should not be any) -- this could be a life saver i.e. selling item for £0.00 - if (crPriceMinAmountFinal * crPriceMaxAmountFinal == 0) - { - throw new Exception("Min and/or Max value has comouted to 0 for SkuId=" + skuId); - } - - - // STAGE 8 - // Update sku table min/max values - - // round decimals for db comarison - crUnitAvgCost = decimal.Round(crUnitAvgCost, 2); - crUnitAvgCostActual = decimal.Round(crUnitAvgCostActual, 2); - crPriceMinAmountAuto = decimal.Round(crPriceMinAmountAuto, 2); - crPriceMinAmountFinal = decimal.Round(crPriceMinAmountFinal, 2); - crPriceMaxAmountFinal = decimal.Round(crPriceMaxAmountFinal, 2); - - // update sku table - using (var cmd03 = new SqlCommand(@" - UPDATE - tblSku - SET - tblSku.skuPriceMin = @priceMinAmountFinal - , tblSku.skuPriceMax = @priceMaxAmountFinal - ,tblSku.skuMinMaxExpire = Null - ,tblSku.skuSkuAvgCost = @unitAvgCost - ,tblSku.skuSkuAvgCostDate = @unitAvgCostDate - ,tblSku.skuPriceCompetitive = @compPrice - , tblSku.skuPriceCompetitiveDate = @compPriceDate - WHERE (((tblSku.skuSkuID)=@skuId)); - ", conn)) - { - cmd03.Parameters.AddWithValue("@priceMinAmountFinal", crPriceMinAmountFinal); - cmd03.Parameters.AddWithValue("@priceMaxAmountFinal", crPriceMaxAmountFinal); - cmd03.Parameters.AddWithValue("@unitAvgCost", crUnitAvgCostActual); - cmd03.Parameters.AddWithValue("@unitAvgCostDate", crTimeStamp.ToUniversalTime()); - if (compPrice.price == null) - { - cmd03.Parameters.AddWithValue("@compPrice", DBNull.Value); - cmd03.Parameters.AddWithValue("@compPriceDate", DBNull.Value); - } - else - { - cmd03.Parameters.AddWithValue("@compPrice", compPrice.price); - cmd03.Parameters.AddWithValue("@compPriceDate", DateTime.SpecifyKind((DateTime)compPrice.priceDate, DateTimeKind.Utc).ToUniversalTime()); - } - cmd03.Parameters.AddWithValue("@skuId", skuId); - - int updated = cmd03.ExecuteNonQuery(); - - if (!(updated > 0)) - { - throw new Exception("record not updated, for some reasonq"); - } - } - - count = count + 1; - } // drop out of query while loop here - } - } - } - MiscFunction.ConsoleUpdate("Complete. " + count + "SKUs updated."); - } - catch (Exception ex) - { - MiscFunction.ConsoleUpdate("Operation incomplete, stopped at SkuId=" + exceptionSku +". " + count + "SKUs updated."); - MiscFunction.ConsoleUpdate("Exception: " + ex.Message); - throw ex; - } - } - } - } namespace Order { public class OrderQuery @@ -5442,13 +4562,14 @@ namespace bnhtrade.Core { sqlConn.Open(); // retrive info for FbaOrders - transactionTypeId and it's debit statusId - int transactionTypeId = Stock.StockJournal.StockTransactionTypeIdSelect(sqlConnectionString, "<_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_>"); + string matchString = "<_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_>"; + int transactionTypeId = new Data.Database.Stock.ReadSkuTransactionType(sqlConnectionString).GetTypeId(matchString); if (transactionTypeId < 1) { - throw new Exception("Could not retirve stockTransactionId for amazon shipped orders"); + throw new Exception("Could not retirve StockSkuTransactionId for amazon shipped orders"); } using (SqlCommand sqlCommand = new SqlCommand(@" - SELECT DebitStockStatusID FROM tblStockTransactionType WHERE StockTransactionTypeID=@transactionTypeId + SELECT DebitStockStatusID FROM tblStockSkuTransactionType WHERE StockSkuTransactionTypeID=@transactionTypeId ", sqlConn)) { sqlCommand.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); @@ -5467,8 +4588,8 @@ namespace bnhtrade.Core // retrive orderItemId(s) List stockIdList = new List(); using (SqlCommand sqlCommand = new SqlCommand(@" - SELECT StockJournalID FROM tblStockTransaction - WHERE StockTransactionTypeID=@transactionTypeId AND ForeignKey=@orderId AND SkuID=@skuId + SELECT StockJournalID FROM tblStockSkuTransaction + WHERE StockSkuTransactionTypeID=@transactionTypeId AND ForeignKey=@orderId AND SkuID=@skuId ", sqlConn)) { sqlCommand.Parameters.AddWithValue("@transactionTypeId", transactionTypeId); @@ -5506,25 +4627,6 @@ namespace bnhtrade.Core } namespace AmazonAPI { - public class AmazonMwsService - { - public MarketplaceWebService.MarketplaceWebService GetAmazonMwsService() - { - CredentialMws cred = new CredentialMws(); - MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); - - MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient( - cred.accessKeyId, - cred.secretAccessKey, - cred.applicationName, - cred.applicationVersion, - config); - - config.ServiceURL = cred.serviceURL; - return service; - } - } - public class AmazonMwsProduct { public MarketplaceWebServiceProducts.MarketplaceWebServiceProducts GetAmazonMwsServiceProduct() @@ -5532,13 +4634,13 @@ namespace bnhtrade.Core CredentialMws cred = new CredentialMws(); MarketplaceWebServiceProductsConfig config = new MarketplaceWebServiceProductsConfig(); - config.ServiceURL = cred.serviceURL; + config.ServiceURL = cred.ServiceURL; MarketplaceWebServiceProducts.MarketplaceWebServiceProducts service = new MarketplaceWebServiceProductsClient( - cred.applicationName, - cred.applicationVersion, - cred.accessKeyId, - cred.secretAccessKey, + cred.ApplicationName, + cred.ApplicationVersion, + cred.AccessKeyId, + cred.SecretAccessKey, config); return service; @@ -5556,7 +4658,7 @@ namespace bnhtrade.Core // Create a request. GetMyFeesEstimateRequest request = new GetMyFeesEstimateRequest(); - request.SellerId = cred.merchantId; + request.SellerId = cred.MerchantId; request.MWSAuthToken = "example"; //FeesEstimateRequestList requestList = new FeesEstimateRequestList(); @@ -5634,7 +4736,7 @@ namespace bnhtrade.Core { CredentialMws cred = new CredentialMws(); - this.merchantId = cred.merchantId; + this.merchantId = cred.MerchantId; //this.marketplaceId = cred.marketPlaceId; //this.accessKeyId = cred.accessKeyId; //this.secretAccessKey = cred.secretAccessKey; @@ -6158,14 +5260,16 @@ namespace bnhtrade.Core sqlCommand.Parameters.AddWithValue("@settlementId", settlementRef); } + var parseDateTime = new Core.Logic.Utilities.DateTimeParse(); + if (indexSettlementStartDate == -1 || items[indexSettlementStartDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@settlementStartDate", DBNull.Value); } - else { sqlCommand.Parameters.AddWithValue("@settlementStartDate", MiscFunction.ParseMwsReportDateTime(items[indexSettlementStartDate])); } + else { sqlCommand.Parameters.AddWithValue("@settlementStartDate", parseDateTime.ParseMwsReportDateTime(items[indexSettlementStartDate])); } if (indexSettlementEndDate == -1 || items[indexSettlementEndDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@settlementEndDate", DBNull.Value); } - else { sqlCommand.Parameters.AddWithValue("@settlementEndDate", MiscFunction.ParseMwsReportDateTime(items[indexSettlementEndDate])); } + else { sqlCommand.Parameters.AddWithValue("@settlementEndDate", parseDateTime.ParseMwsReportDateTime(items[indexSettlementEndDate])); } if (indexDepositDate == -1 || items[indexDepositDate].Length == 0) { sqlCommand.Parameters.AddWithValue("@depositDate", DBNull.Value); } - else { sqlCommand.Parameters.AddWithValue("@depositDate", MiscFunction.ParseMwsReportDateTime(items[indexDepositDate])); } + else { sqlCommand.Parameters.AddWithValue("@depositDate", parseDateTime.ParseMwsReportDateTime(items[indexDepositDate])); } if (indexTotalAmount == -1 || items[indexTotalAmount].Length == 0) { sqlCommand.Parameters.AddWithValue("@totalAmount", DBNull.Value); } else { sqlCommand.Parameters.AddWithValue("@settlementotalAmounttId", settlementAmount); } @@ -6252,7 +5356,7 @@ namespace bnhtrade.Core else { sqlCommand.Parameters.AddWithValue("@FulfillmentRef", items[indexFulfillmentId]); } if (indexPostedDateTime == -1 || items[indexPostedDateTime].Length == 0) { sqlCommand.Parameters.AddWithValue("@PostedDateTimeUTC", DBNull.Value); } - else { sqlCommand.Parameters.AddWithValue("@PostedDateTimeUTC", MiscFunction.ParseMwsReportDateTime(items[indexPostedDateTime])); } + else { sqlCommand.Parameters.AddWithValue("@PostedDateTimeUTC", new Logic.Utilities.DateTimeParse().ParseMwsReportDateTime(items[indexPostedDateTime])); } if (indexOrderItemCode == -1 || items[indexOrderItemCode].Length == 0) { sqlCommand.Parameters.AddWithValue("@OrderItemCode", DBNull.Value); } else { sqlCommand.Parameters.AddWithValue("@OrderItemCode", long.Parse(items[indexOrderItemCode])); } @@ -8647,18 +7751,6 @@ namespace bnhtrade.Core string fullPath = directoryPath + fileName; return fullPath; } - public static DateTime ParseMwsReportDateTime(string reportDateTime) - { - string isoDateTime = - reportDateTime.Substring(6, 4) + "-" + - reportDateTime.Substring(3, 2) + "-" + - reportDateTime.Substring(0, 2) + "T" + - reportDateTime.Substring(11, 2) + ":" + - reportDateTime.Substring(14, 2) + ":" + - reportDateTime.Substring(17, 2) + "Z"; - return DateTime.Parse(isoDateTime); - } - } public class TempFunction { diff --git a/src/bnhtrade.Core/Test/Account/GetTaxInfo.cs b/src/bnhtrade.Core/Test/Account/Account.cs similarity index 80% rename from src/bnhtrade.Core/Test/Account/GetTaxInfo.cs rename to src/bnhtrade.Core/Test/Account/Account.cs index 51a90fd..6d7a44a 100644 --- a/src/bnhtrade.Core/Test/Account/GetTaxInfo.cs +++ b/src/bnhtrade.Core/Test/Account/Account.cs @@ -6,9 +6,9 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Test.Account { - public class GetTaxInfo + public class Account { - public GetTaxInfo(string sqlConnectionString) + public Account(string sqlConnectionString) { //var inst = new Data.Database.Account.GetTaxCode(sqlConnectionString); //inst. diff --git a/src/bnhtrade.Core/Test/AutoExec.cs b/src/bnhtrade.Core/Test/AutoExec.cs index cf522dd..b49d881 100644 --- a/src/bnhtrade.Core/Test/AutoExec.cs +++ b/src/bnhtrade.Core/Test/AutoExec.cs @@ -25,7 +25,7 @@ namespace bnhtrade.Core.Test private void Import() { - var instance = new Test.Import.AmazonSettlement(sqlConnectionString); + var instance = new Test.Import.Import(sqlConnectionString); } } } diff --git a/src/bnhtrade.Core/Test/Export/Export.cs b/src/bnhtrade.Core/Test/Export/Export.cs new file mode 100644 index 0000000..565c35c --- /dev/null +++ b/src/bnhtrade.Core/Test/Export/Export.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Test.Export +{ + public class Export + { + private string sqlConnectionString; + public Export(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + + UpdateStatusInfo(); + } + + private void SubmitAmazonInventoryLoader() + { + // load temp file + var filestream = new FileStream(@"C:\Users\Bobbie\Downloads\Step666.txt", FileMode.Open); + var memStream = new MemoryStream(); + filestream.CopyTo(memStream); + + var logicBit = new Core.Logic.Export.AmazonSubmitFile(sqlConnectionString); + Model.Export.AmazonFeedSubmission kkkkkkkk; + logicBit.SubmitInventoryLoader(memStream, out kkkkkkkk); + } + + private void GetAmamzonFeedList() + { + var something = new Data.AmazonMWS.Feeds.GetFeedSubmissions(); + var somethingelse = new Data.Database.Export.ReadAmazonFeedSubmission(sqlConnectionString).GetOpenFeeds(); + List idList = somethingelse.Select(x => x.FeedSubmissionId).ToList(); + } + + private void UpdateStatusInfo() + { + new Core.Logic.Export.AmazonSubmitFileStatus(sqlConnectionString).UpdateStatusInfo(); + } + } +} diff --git a/src/bnhtrade.Core/Test/Import/AmazonSettlement.cs b/src/bnhtrade.Core/Test/Import/AmazonSettlement.cs index a4fac03..c5a1669 100644 --- a/src/bnhtrade.Core/Test/Import/AmazonSettlement.cs +++ b/src/bnhtrade.Core/Test/Import/AmazonSettlement.cs @@ -6,10 +6,10 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Test.Import { - public class AmazonSettlement + public class Import { private string sqlConnectionString; - public AmazonSettlement(string sqlConnectionString) + public Import(string sqlConnectionString) { this.sqlConnectionString = sqlConnectionString; ReadSettlementFromDatabase(); diff --git a/src/bnhtrade.Core/Test/InboundShipmentInfo.cs b/src/bnhtrade.Core/Test/InboundShipmentInfo.cs index 95ad727..ac60d83 100644 --- a/src/bnhtrade.Core/Test/InboundShipmentInfo.cs +++ b/src/bnhtrade.Core/Test/InboundShipmentInfo.cs @@ -16,19 +16,19 @@ namespace bnhtrade.Core.Test } public void SetDatabase() { - var info = new Model.AmazonFBAInbound.ShipmentInfo(); - info.AmazonShipmentId = "BOBBIE2"; + var info = new Model.AmazonFba.ShipmentInfo(); + info.FbaShipmentId = "BOBBIE2"; info.DestinationFulfillmentCenterId = "HODG"; - info.LastUpdatedUtc = DateTime.UtcNow; + info.LastUpdated = DateTime.Now; info.ShipmentName = "the one"; info.ShipmentStatus = "WORKING"; bool all = info.IsSetAll(); bool allHead = info.IsSetAllHeaderInfo(); - var itemInfoList = new List(); + var itemInfoList = new List(); - var itemInfo01 = new Model.AmazonFBAInbound.ShipmentItemInfo(); + var itemInfo01 = new Model.AmazonFba.ShipmentItemInfo(); itemInfo01.AmazonFNSKU = "Z0000000"; itemInfo01.AmazonShipmentId = "BOBBIE2"; itemInfo01.QuantityReceived = 4; @@ -36,7 +36,7 @@ namespace bnhtrade.Core.Test itemInfo01.SKUNumber = "000291-10"; itemInfoList.Add(itemInfo01); - var itemInfo02 = new Model.AmazonFBAInbound.ShipmentItemInfo(); + var itemInfo02 = new Model.AmazonFba.ShipmentItemInfo(); itemInfo02.AmazonFNSKU = "Z0000001"; itemInfo02.AmazonShipmentId = "BOBBIE2"; itemInfo02.QuantityReceived = 3; @@ -54,10 +54,10 @@ namespace bnhtrade.Core.Test // Console.WriteLine("Qty Received: " + item.QuantityReceived); //} - var howto = new Data.Database.FBAInbound.SetShipmentInfo(sqlConnectionString); + var howto = new Data.Database.AmazonShipment.SetShipmentInfo(sqlConnectionString); howto.Excecute(info); - var testkkkk = new Data.Database.FBAInbound.GetShipmentPrimaryKey(sqlConnectionString); + var testkkkk = new Data.Database.AmazonShipment.ReadShipmentPrimaryKey(sqlConnectionString); int pknumber = testkkkk.ByAmazonShipmentId("FBA15CJCZ12"); Console.WriteLine("ShipmentPK: " + pknumber); } diff --git a/src/bnhtrade.Core/Test/Logic/Export.cs b/src/bnhtrade.Core/Test/Logic/Export.cs index 124b83d..1d0de9d 100644 --- a/src/bnhtrade.Core/Test/Logic/Export.cs +++ b/src/bnhtrade.Core/Test/Logic/Export.cs @@ -6,10 +6,10 @@ using System.Threading.Tasks; namespace bnhtrade.Core.Test.Logic { - public class Export + public class Logic { private string sqlConnectionString; - public Export(string sqlConnectionString) + public Logic(string sqlConnectionString) { this.sqlConnectionString = sqlConnectionString; diff --git a/src/bnhtrade.Core/Test/Sku/Sku.cs b/src/bnhtrade.Core/Test/Sku/Sku.cs new file mode 100644 index 0000000..7f41598 --- /dev/null +++ b/src/bnhtrade.Core/Test/Sku/Sku.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Test.Sku +{ + public class Sku + { + private string sqlConnectionString; + public Sku(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + + // method you want to start here + UpdateFbaPricing(); + + } + public void UpdateFbaPricing() + { + var instance = new bnhtrade.Core.Logic.Sku.Price.FbaPricing(sqlConnectionString); + instance.Update(); + } + } +} diff --git a/src/bnhtrade.Core/bnhtrade.Core.csproj b/src/bnhtrade.Core/bnhtrade.Core.csproj index 23a6b72..310cfd0 100644 --- a/src/bnhtrade.Core/bnhtrade.Core.csproj +++ b/src/bnhtrade.Core/bnhtrade.Core.csproj @@ -26,7 +26,7 @@ AnyCPU - pdbonly + none true ..\..\artifiacts\Release\ TRACE @@ -37,10 +37,28 @@ + + ..\..\packages\CsvHelper.15.0.0\lib\net47\CsvHelper.dll + + + ..\..\packages\Dapper.2.0.30\lib\net461\Dapper.dll + + + ..\..\packages\Dapper.Contrib.2.0.30\lib\net461\Dapper.Contrib.dll + + + ..\..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + @@ -54,60 +72,113 @@ + + + - - - - + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + - + + + + + + + + - - + + + + + + + + + + + - + + + + - + + + + + + + + + + + - - + + - + @@ -116,7 +187,7 @@ Settings.settings - + @@ -128,8 +199,9 @@ - - + + + diff --git a/src/bnhtrade.Core/packages.config b/src/bnhtrade.Core/packages.config index 7f80eca..65ffe0d 100644 --- a/src/bnhtrade.Core/packages.config +++ b/src/bnhtrade.Core/packages.config @@ -1,4 +1,11 @@  + + + + + + + \ No newline at end of file diff --git a/src/bnhtrade.ScheduledTasks/App.config b/src/bnhtrade.ScheduledTasks/App.config index 710e132..1efce96 100644 --- a/src/bnhtrade.ScheduledTasks/App.config +++ b/src/bnhtrade.ScheduledTasks/App.config @@ -1,12 +1,19 @@ - + - + + + + + + + + + \ No newline at end of file diff --git a/src/bnhtrade.ScheduledTasks/Program.cs b/src/bnhtrade.ScheduledTasks/Program.cs index 0a3311e..95ee4bb 100644 --- a/src/bnhtrade.ScheduledTasks/Program.cs +++ b/src/bnhtrade.ScheduledTasks/Program.cs @@ -9,6 +9,7 @@ using System.Configuration; using System.Transactions; using bnhtrade.Core; using bnhtrade.Core.Stock; +using bnhtrade.Core.Model; namespace bnhtradeScheduledTasks { @@ -214,20 +215,19 @@ namespace bnhtradeScheduledTasks else if (input == "3") { Console.Clear(); - var task = new StockReconciliation(); - var result = new StockReconciliation.ReconcileStockTransactionsResult(); - try - { - result = task.ReconcileStockTransactions(sqlConnectionString, false); - Console.WriteLine(result.ItemsCompleted + " of " + (result.ItemsCompleted + result.ItemsRemaining) + " items completed."); - Console.WriteLine("Current transaction ID=" + result.StockTransactionId); - Console.WriteLine(result.ProgressMessage); + //try + //{ + var recon = new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile(sqlConnectionString); + recon.ReconcileStockTransactions(false); + Console.WriteLine(recon.ItemsCompleted + " of " + (recon.ItemsCompleted + recon.ItemsRemaining) + " items completed."); + Console.WriteLine("Current transaction ID=" + recon.CurrentSkuTransaction.SkuTransactionId); + Console.WriteLine(recon.ProgressMessage); Console.WriteLine(""); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message.ToString()); - } + //} + //catch (Exception ex) + //{ + //Console.WriteLine(ex.Message.ToString()); + //} Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } @@ -239,7 +239,7 @@ namespace bnhtradeScheduledTasks { task.UpdateFbaStockImportData(sqlConnectionString); task.ProcessFbaStockImportData(sqlConnectionString); - task.ReconcileStockTransactions(sqlConnectionString, false); + new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile(sqlConnectionString).ReconcileStockTransactions(false); } catch (Exception ex) { @@ -253,7 +253,8 @@ namespace bnhtradeScheduledTasks Console.Clear(); //try //{ - bnhtrade.Core.Inventory.InventoryPricing.AmazonMinMaxTemp(sqlConnectionString); + Console.WriteLine("Currently disabled"); + //bnhtrade.Core.Inventory.InventoryPricing.AmazonMinMaxTemp(sqlConnectionString); //} //catch (Exception ex) //{ @@ -283,14 +284,14 @@ namespace bnhtradeScheduledTasks Console.WriteLine("Main Menu > Dev Funcions"); Console.WriteLine(); Console.WriteLine("<1> Get Amazon UTC time"); - Console.WriteLine("<2> Test Stock Journal Reallocate"); - Console.WriteLine("<3> test Product Update Amazon Estimate Fee"); - Console.WriteLine("<4> Process Amazon Reimbursement Report (into transactiontable)"); - Console.WriteLine("<5> Test Stock Table Delete"); - Console.WriteLine("<6> Test Owner intro insert"); - Console.WriteLine("<7> Currency exchange rate insert"); - Console.WriteLine("<8> SQL Loop function"); - Console.WriteLine("<9> AUTOEXEC TEST"); + Console.WriteLine("<2> Test Account"); + Console.WriteLine("<3> Test Export"); + Console.WriteLine("<4> Test Import"); + Console.WriteLine("<5> Test Logic"); + Console.WriteLine("<6> Test SKU"); + Console.WriteLine("<7> Test xxxxxxx"); + Console.WriteLine("<8> Test xxxxxxx"); + Console.WriteLine("<9> Detele Sku Transaction"); Console.WriteLine(); Console.WriteLine("<0> Back"); Console.WriteLine(""); @@ -314,23 +315,19 @@ namespace bnhtradeScheduledTasks else if (input == "2") { Console.Clear(); - int result = new int(); - try - { - result = TempStuff.TempTasks.testStockReallocate(); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - Console.WriteLine(result); + + new bnhtrade.Core.Test.Account.Account(sqlConnectionString); + + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } else if (input == "3") { Console.Clear(); - TempStuff.TempTasks.test_ProductUpdateAmazonEstimateFee(); + + new bnhtrade.Core.Test.Export.Export(sqlConnectionString); + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); @@ -338,57 +335,40 @@ namespace bnhtradeScheduledTasks else if (input == "4") { Console.Clear(); - var task = new StockReconciliation(); - task.WIP_ProcessFbaReimbursementData(sqlConnectionString); + + new bnhtrade.Core.Test.Import.Import(sqlConnectionString); + + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } else if (input == "5") { Console.Clear(); - int result = new int(); - try - { - TempStuff.TempTasks.testStockJournalDelete(); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - Console.WriteLine(result); + + new bnhtrade.Core.Test.Logic.Logic(sqlConnectionString); + + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } else if (input == "6") { Console.Clear(); - int result = 0; - try - { - result = TempStuff.TempTasks.input6(); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - Console.WriteLine(result.ToString()); + + new bnhtrade.Core.Logic.Sku.Price.FbaPricing(sqlConnectionString).Update(); + + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } else if (input == "7") { Console.Clear(); - //bool result = false; - int result = 0; - try - { - result = TempStuff.TempTasks.CurrencyExchangeInsert(); - Console.WriteLine("Result: " + result.ToString()); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } + + Console.WriteLine("Nothing......"); + + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } @@ -396,10 +376,9 @@ namespace bnhtradeScheduledTasks { Console.Clear(); - var jjjj = new bnhtrade.Core.Test.InboundShipmentInfo(sqlConnectionString); - jjjj.GetMWSInfo(); + Console.WriteLine("Nothing......"); - //Console.WriteLine(result.ToString()); + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } @@ -407,14 +386,12 @@ namespace bnhtradeScheduledTasks { Console.Clear(); - var inst = new bnhtrade.Core.Test.AutoExec(sqlConnectionString); + new bnhtrade.Core.Logic.Stock.SkuTransactionPersistance(sqlConnectionString).DeleteJournalEntry(80774); + Console.WriteLine("Done"); Console.WriteLine("Complete, press any key to continue..."); Console.ReadKey(); } - - - } while (true); } } while (true); @@ -442,15 +419,15 @@ namespace bnhtradeScheduledTasks Console.WriteLine("Starting (unsafe) stock reconciliation..."); Console.Clear(); StockReconciliation task = new StockReconciliation(); - StockReconciliation.ReconcileStockTransactionsResult result = new StockReconciliation.ReconcileStockTransactionsResult(); - result = task.ReconcileStockTransactions(sqlConnectionString, false); - Console.WriteLine("Progress: " + result.ProgressMessage); - Console.WriteLine("Reconciled date: " + result.LastItemDateTime.ToString()); - Console.WriteLine("Transactions completed: " + result.ItemsCompleted); - Console.WriteLine("Transactions remaining: " + result.ItemsRemaining); - if (!result.ReconciliationComplete) + var recon = new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile(sqlConnectionString); + recon.ReconcileStockTransactions(false); + Console.WriteLine("Progress: " + recon.ProgressMessage); + Console.WriteLine("Reconciled date: " + recon.LastItemDateTime.ToString()); + Console.WriteLine("Transactions completed: " + recon.ItemsCompleted); + Console.WriteLine("Transactions remaining: " + recon.ItemsRemaining); + if (!recon.ReconciliationComplete) { - Console.WriteLine("Halted at Stock Transaction ID: " + result.StockTransactionId); + Console.WriteLine("Halted at Stock Transaction ID: " + recon.CurrentSkuTransaction.SkuTransactionId); } Console.WriteLine("Exiting application..."); } @@ -503,76 +480,4 @@ namespace bnhtradeScheduledTasks MiscFunction.EventLogInsert("Nightly scheduled tasks finished."); } } -} -namespace TempStuff -{ - public class TempTasks - { - static string sqlConnectionString = ConfigurationManager.ConnectionStrings["bnhtradeDbConnString"].ConnectionString; - - public static void testStockTableDelete() - { - //bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockTableDelete(sqlConnectionString, 15776); - } - - public static bool testStockConsistCheck() - { - //return bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockJournalConsistencyCheck(sqlConnectionString, 22677); - return false; - } - - public static void testStockDelete() - { - //bnhtradeDatabaseClient.Stock.StockQuery.WIP_StockDelete(sqlConnectionString, 15798); - } - - public static void testStockJournalDelete() - { - //bnhtradeDatabaseClient.Stock.StockQuery.StockJournalDelete(sqlConnectionString, 33763); - } - - - public static int testStockReallocate() - { - int creditStatusId = 4; - int debitStatusId = 21; - DateTime entryDate = new DateTime(2099, 06, 15); - - //return bnhtradeDatabaseClient.Stock.StockQuery.StockReallocateByStockId(sqlConnectionString, 4, 15776, 1, debitStatusId, creditStatusId, entryDate); - - return 0; - } - public static void testPurchaseLineInsert() - { - DateTime entrdate = DateTime.Parse("07/09/2016 08:13:54"); - - //return bnhtradeDatabaseClient.Purchase.PurchaseQuery.WIP_PurchaseLineNetTransactionInsert(sqlConnectionString, 10164, "GBP", 138, 9.98m, entrdate); - bnhtrade.Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetUpdate(sqlConnectionString, 10164, "GBP", 138, 100000); - } - public static void test_ProductUpdateAmazonEstimateFee() - { - var list = new List<(string asin, decimal price)>(); - - list.Add(("B000MGVBG4", 1.99m)); - - bnhtrade.Core.Product.ProductQuery.ProductUpdateAmazonEstimateFee(sqlConnectionString, list); - } - public static void test_AmazonInventoryTableUpdate() - { - //bnhtradeDatabaseClient.Inventory.InventoryPricing.AmazonInventoryTableUpdate(sqlConnectionString); - } - public static int input6() - { - DateTime entrdate = DateTime.Parse("28/11/2018 08:13:54"); - - return bnhtrade.Core.Stock.StockCreate.WIP_StockInsertOwnerIntroduced(sqlConnectionString, 0.01m, 7, 15374, 51, 16, entrdate, 51); - } - public static int CurrencyExchangeInsert() - { - DateTime start = new DateTime(2019, 03, 01); - DateTime finish = new DateTime(2019, 04, 01); - - return bnhtrade.Core.Account.AccountQuery.CurrencyExchangeRateInsert(sqlConnectionString, 1, "USD", 222m, start, finish, true ); - } - } -} +} \ No newline at end of file diff --git a/src/bnhtrade.ScheduledTasks/bnhtrade.ScheduledTasks.csproj b/src/bnhtrade.ScheduledTasks/bnhtrade.ScheduledTasks.csproj index 26d4af0..065c7b5 100644 --- a/src/bnhtrade.ScheduledTasks/bnhtrade.ScheduledTasks.csproj +++ b/src/bnhtrade.ScheduledTasks/bnhtrade.ScheduledTasks.csproj @@ -1,5 +1,6 @@  + Debug @@ -26,6 +27,8 @@ false false true + + AnyCPU @@ -39,7 +42,7 @@ AnyCPU - pdbonly + none true ..\..\artifiacts\Release\ TRACE @@ -72,6 +75,7 @@ + SettingsSingleFileGenerator Settings.Designer.cs @@ -96,4 +100,10 @@ + + + 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}. + + + \ No newline at end of file diff --git a/src/bnhtrade.ScheduledTasks/packages.config b/src/bnhtrade.ScheduledTasks/packages.config new file mode 100644 index 0000000..a791492 --- /dev/null +++ b/src/bnhtrade.ScheduledTasks/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file