using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Centron.BusinessLogic; using Centron.BusinessLogic.EmployeeArea; using Centron.BusinessLogic.Sales.Receipts.ArticleSearch; using Centron.BusinessLogic.Sales.Receipts.DataAndResults; using Centron.BusinessLogic.Warehousing; using Centron.BusinessLogic.WebServices.Sales.Receipts; using Centron.BusinessLogic.WebServices.Sales.Receipts.ArticleSearch; using Centron.BusinessLogic.WebServices.Warehousing; using Centron.Data.Entities.Administration.Logins; using Centron.Data.WebServices.Sales.Receipts.Articles; using Centron.Data.WebServices.Sales.Receipts.CreditVouchers; using Centron.Data.WebServices.Sales.Receipts.Invoices; using Centron.Data.WebServices.Sales.Receipts.Offers; using Centron.Data.WebServices.Warehousing.Barcode; using Centron.Interfaces; using Centron.Interfaces.Administration.Environment; using Centron.Interfaces.BL; using Centron.Interfaces.Sales.Receipts; using Centron.Interfaces.Sales.Receipts.InsertReceipts; using Centron.Tests.EndToEnd.Infrastructure; using Centron.Tests.EndToEnd.Infrastructure.Verifier; using CentronSoftware.Centron.WebServices.EntitiesWrongPlace.Sales.Receipts.DataAndResults; using Xunit; using Xunit.Abstractions; using Centron.Core.Extensions; using Centron.Data.WebServices.Sales.Receipts; using Centron.Data.WebServices.Sales.Receipts.Orders; using CentronSoftware.Centron.WebServices.Extensions; namespace Centron.Tests.EndToEnd.Tests.Receipts { public class ReceiptTest : EndToEndTest { public ReceiptTest(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { // We have a bit of flakiness with this property, if the code is VERY FAST, it will be the same value as CreatedDate and ChangedDate // But if the code is a bit slower, it will get a different value, and the Verifier will treat it as an error // It's annoying, and I don't wanna deal with this issue right now, so ignore the property for now this.Verifier.Settings.IgnoreProperty(f => f.VariableDateField); // Same with these 2, get outta here! this.Verifier.Settings.IgnoreProperty(f => f.ChangedAt); this.Verifier.Settings.IgnoreProperty(f => f.CreatedAt); } public override void Execute() { this.PrepareDatabase(); var offer = this.CreateNewOffer(); var articles = this.SearchArticles(); this.AddPositions(offer, articles); this.UpdateOffer(offer); offer = this.SaveOffer(offer); var barcode = this.CreateBarcode(articles); var invoice = this.ForwardToInvoice(offer, barcode); this.OfferShouldBeClosed(offer); this.RemoveOnePositionFromInvoice(invoice); var creditVoucher = this.ForwardToCreditVoucher(invoice); this.InvoiceShouldBeClosed(invoice); this.CheckReceiptItemOriginToReceiptKind(); } private void PrepareDatabase() { // There is no Bankverbindung for the customer 10022 - but we are creating invoices for him // So we just move the existing Bankverbindung to customer 10022, so he can use it for this test this.Sql("UPDATE dbo.Bankverbindungen SET ObjectI3D = 10022"); // Make sure that we have one article with a ListPrice this.Sql("UPDATE dbo.ARTIK SET Listenpreis = 10 WHERE I3D = 4356"); } private ReceiptOfferDTO CreateNewOffer() { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var result = session.GetBL().CreateNewReceipt(CentronObjectKindNumeric.OfferClass, new LoggedInUser(user), 10022, new CreateReceiptData(), null, null, true, false, true); this.Verifier.Verify("CreateNewOffer", result); return (ReceiptOfferDTO)result.Data.Receipt; } } private IList SearchArticles() { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var result1 = session.GetBL().SearchArticles("L:Eigene E6U64ABE", true, new OverriddenArticleSearchFilter {ExternalArticleSearches = new ExternalSearchedArticleKind[0]}, 10022, CentronObjectKindNumeric.OfferClass, null, new LoggedInUser(user)); this.Verifier.Verify("SearchArticlesResult1", result1); var result2 = session.GetBL().SearchArticles("L:Eigene HP Enterprise", true, new OverriddenArticleSearchFilter { ExternalArticleSearches = new ExternalSearchedArticleKind[0] }, 10022, CentronObjectKindNumeric.OfferClass, null, new LoggedInUser(user)); this.Verifier.Verify("SearchArticlesResult2", result2); return result1.Data.Articles.Concat(new [] { result2.Data.Articles[8] }).ToList(); } } private void AddPositions(ReceiptOfferDTO receipt, IList articles) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); foreach (var article in articles) { var receiptItemsResult = session.GetBL().CreateArticleReceiptItems( receipt, article.IsExternalArticle, article.I3D, article.ExternalArticleKind, article.ExternalArticleId, -1, new Data.Entities.Administration.Logins.LoggedInUser(user)); this.Verifier.Verify($"ReceiptItemsResultFor{article.I3D}", receiptItemsResult); receipt.Items.AddRange(receiptItemsResult.Data.ReceiptItems.Cast()); } } } private void UpdateOffer(ReceiptOfferDTO offer) { offer.IsCart = true; offer.CartName = "Einkaufswagen"; offer.CartDescription = "Lorem ipsum oder so"; offer.CartCreatorContactPersonI3D = 15; } private ReceiptOfferDTO SaveOffer(ReceiptOfferDTO receipt) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var watch = Stopwatch.StartNew(); var saveResult = session.GetBL().SaveReceipt(receipt, user, new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet, null); watch.Stop(); this.TestOutputHelper.WriteLine($"Saving the offer took {watch.Elapsed}"); this.Verifier.Verify("SaveOfferResult", saveResult); return (ReceiptOfferDTO) saveResult.Data.Receipt; } } private BarCode2DTO CreateBarcode(IList articles) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var article = articles.First(f => f.I3D == 4348); var barcodeResult = session.GetBL().CreateNewSerialNumber( article.I3D, new List { "My-Cool-Barcode" }, -1, "Need a barcode to create a invoice", user, adjustStockInventory: true, returnBarcodesWithAdditionalInformations: true, string.Empty); this.Verifier.Verify("CreatedBarcode", barcodeResult); return barcodeResult.Data[0]; } } private ReceiptInvoiceDTO ForwardToInvoice(ReceiptOfferDTO offer, BarCode2DTO barcode) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var forwardResult = session.GetBL().ForwardReceipt( CentronObjectKindNumeric.InvoiceClass, user, new ForwardReceiptData { CreateReceiptData = new CreateReceiptData { IgnoreCallbacks = true, }, CreateReceiptItemsFromExistingItemsData = new List { new() { IgnoreCallbacks = true, }, }, IgnoreCallbacks = true }, new List { new ReceiptToForward { ReceiptKind = offer.ReceiptKind, ReceiptI3D = offer.I3D } }, null, InsertReceiptTakeoverOptions.Reference, true, false); this.Verifier.Verify("ForwardOfferToInvoiceResult", forwardResult); var invoice = (ReceiptInvoiceDTO)forwardResult.Data.Receipt; invoice.DeliveryDate = new DateTime(2025, 9, 18); var articlePosition = invoice.Items.FirstOrDefault(f => f.ArticleI3D == 4348); articlePosition.Barcodes.Add(new ReceiptItemBarcode { BarcodeI3D = barcode.I3D, IsActive = true }); using (var saveSession = new BLSession()) { var watch = Stopwatch.StartNew(); var saveInvoiceResult = saveSession.GetBL().SaveReceipt( invoice, user, new SaveReceiptData { IgnoreCallbacks = false, InsertFreightArticle = false }, false, CreatedThroughApplication.CentronNet, null); watch.Stop(); this.TestOutputHelper.WriteLine($"Saving the invoice took {watch.Elapsed}"); this.Verifier.Verify("SaveInvoiceResult", saveInvoiceResult); return (ReceiptInvoiceDTO)saveInvoiceResult.Data.Receipt; } } } private void OfferShouldBeClosed(ReceiptOfferDTO offer) { using (var session = new BLSession()) { var loadedOffer = session.GetBL().GetReceiptByI3D(offer.I3D, offer.ReceiptKind); this.Verifier.Verify("OfferAfterCreatingInvoice", loadedOffer); } } private void RemoveOnePositionFromInvoice(ReceiptInvoiceDTO invoice) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var loadedInvoice = (ReceiptInvoiceDTO)session.GetBL().GetReceiptByI3D(invoice.I3D, invoice.ReceiptKind).Data; loadedInvoice.Items.RemoveWhere(f => f.I3D == 26142); var savedInvoice = session.GetBL().SaveReceipt( loadedInvoice, user, new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet, null); this.Verifier.Verify("InvoiceAfterRemovingOnePosition", savedInvoice); } } private ReceiptCreditVoucherDTO ForwardToCreditVoucher(ReceiptInvoiceDTO invoice) { using (var session = new BLSession()) { var user = session.GetBL().GetAppUser(f => f.I3D == 11); var forwardResult = session.GetBL().ForwardReceipt( CentronObjectKindNumeric.CreditVoucherClass, user, new ForwardReceiptData { CreateReceiptData = new CreateReceiptData { IgnoreCallbacks = true, }, CreateReceiptItemsFromExistingItemsData = new List { new() { IgnoreCallbacks = true, }, }, IgnoreCallbacks = true }, new List { new ReceiptToForward { ReceiptKind = invoice.ReceiptKind, ReceiptI3D = invoice.I3D } }, null, InsertReceiptTakeoverOptions.Reference, true, false); this.Verifier.Verify("ForwardInvoiceToCreditVoucherResult", forwardResult); ReceiptCreditVoucherDTO creditVoucher = (ReceiptCreditVoucherDTO)forwardResult.Data.Receipt; var saveCreditVoucherResult = session.GetBL().SaveReceipt( creditVoucher, user, new SaveReceiptData { IgnoreCallbacks = true }, false, CreatedThroughApplication.CentronNet, null); this.Verifier.Verify("SaveCreditVoucherResult", saveCreditVoucherResult); return (ReceiptCreditVoucherDTO)saveCreditVoucherResult.Data.Receipt; } } private void InvoiceShouldBeClosed(ReceiptInvoiceDTO invoice) { using (var session = new BLSession()) { var loadedInvoice = session.GetBL().GetReceiptByI3D(invoice.I3D, invoice.ReceiptKind); this.Verifier.Verify("InvoiceShouldBeClosed", loadedInvoice); } } private void CheckReceiptItemOriginToReceiptKind() { var allOriginKinds = Enum.GetValues(typeof(ReceiptItemOrigin)).Cast().ToList(); foreach (var originKind in allOriginKinds) { var receiptKind = originKind.ToReceiptKind(); // The ToReceiptKind method should only return receipt-kinds or NULL, but nothing else! // For example HelpdeskClass is a invalid value that would lead to many issues! Assert.True(receiptKind == null || receiptKind.Value.IsCustomerReceipt() || receiptKind.Value.IsSupplierReceipt()); } } } }