Files
Christoph Schwörer f045b99a25 Codebasis als Dateien ins Arbeitsrepo statt als Gitlink
QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
2026-08-26 07:43:51 +02:00

282 lines
12 KiB
C#

using System;
using System.Linq;
using Centron.BusinessLogic;
using Centron.BusinessLogic.Administration.Settings;
using Centron.BusinessLogic.Mail.Factory;
using Centron.BusinessLogic.WebServices.Accounts.SpecialPrices;
using Centron.BusinessLogic.WebServices.Administration.Logins;
using Centron.BusinessLogic.WebServices.Sales.Receipts;
using Centron.Data.WebServices.Sales.Receipts;
using Centron.Data.WebServices.Sales.Receipts.Orders;
using Centron.Interfaces;
using Centron.Interfaces.Accounts.SpecialPrices;
using Centron.Interfaces.BL;
using Centron.Interfaces.Sales.Receipts;
using Centron.Tests.EndToEnd.Infrastructure;
using CentronSoftware.Centron.WebServices.Entities.Accounts.SpecialPrices;
using CentronSoftware.Centron.WebServices.Entities.Sales.Receipts;
using CentronSoftware.Centron.WebServices.EntitiesWrongPlace.Administration.Rights;
using Xunit;
using Xunit.Abstractions;
namespace Centron.Tests.EndToEnd.Tests.ReceiptCartReleaseSystem;
public class ReceiptCartReleaseSystemTests : EndToEndTest
{
public ReceiptCartReleaseSystemTests(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
{
// Order Table
this.Verifier.Settings.IgnoreColumn("Date");
this.Verifier.Settings.IgnoreColumn("CreatedAt");
this.Verifier.Settings.IgnoreColumn("ChangedAt");
this.Verifier.Settings.IgnoreColumn("ReminderDate");
this.Verifier.Settings.IgnoreColumn("ConcurrencyControlGuid");
this.Verifier.Settings.IgnoreColumn("RichText");
this.Verifier.Settings.IgnoreColumn("PaymentConditionText");
this.Verifier.Settings.IgnoreColumn("ToDoI3D");
this.Verifier.Settings.IgnoreColumn("CreatedThroughApplicationVersion");
this.Verifier.Settings.IgnoreColumn("ChangedThroughApplicationVersion");
// AnlageLog Table
this.Verifier.Settings.IgnoreColumn("Datum");
this.Verifier.Settings.IgnoreColumn("CentronVersion");
// ReceiptLogDTO
this.Verifier.Settings.IgnoreProperty<ReceiptLogDTO>(f => f.CentronVersion);
this.Verifier.Settings.IgnoreProperty<ReceiptLogDTO>(f => f.Employee);
}
// This test checks that the release-system workflow for receipt-carts is working correctly
// See the ReceiptCartState enum for the different states, and also for more information on how the workflow is supposed to work
private const int ArticleI3D = 80;
public override void Execute()
{
this.PrepareDatabase();
// Create a cart
var cartI3D = this.CreateCart();
// Make sure the right-checks work
this.AssertRightsMissingFor(cartI3D, new []
{
ReceiptCartAction.CheckerApprove,
ReceiptCartAction.CheckerDecline,
ReceiptCartAction.OrdererApprove,
ReceiptCartAction.OrdererDecline
});
// Give us the rights to call the release-system workflow methods
this.AddRights();
// Check successful release-system workflow
// This goes through every step of the workflow
// Created -> ReadyForCheck -> DeclinedByChecker -> ReadyForCheck -> Checked -> DeclinedByOrderer -> ReadyForCheck -> Checked -> Ordered
this.AssertCartState(
cartI3D,
ReceiptCartState.Created,
possibleActions: new []{ ReceiptCartAction.ReadyForCheck });
this.ExecuteAction(cartI3D, ReceiptCartAction.ReadyForCheck);
this.AssertCartState(
cartI3D,
ReceiptCartState.ReadyForCheck,
possibleActions: new [] { ReceiptCartAction.CheckerApprove, ReceiptCartAction.CheckerDecline });
this.ExecuteAction(cartI3D, ReceiptCartAction.CheckerDecline);
this.AssertCartState(
cartI3D,
ReceiptCartState.DeclinedByChecker,
possibleActions: new [] { ReceiptCartAction.ImproveCheckerDeclined });
this.ExecuteAction(cartI3D, ReceiptCartAction.ImproveCheckerDeclined);
this.AssertCartState(
cartI3D,
ReceiptCartState.ReadyForCheck,
possibleActions: new [] { ReceiptCartAction.CheckerApprove, ReceiptCartAction.CheckerDecline });
this.ExecuteAction(cartI3D, ReceiptCartAction.CheckerApprove);
this.AssertCartState(
cartI3D,
ReceiptCartState.Checked,
possibleActions: new [] { ReceiptCartAction.OrdererApprove, ReceiptCartAction.OrdererDecline });
this.ExecuteAction(cartI3D, ReceiptCartAction.OrdererDecline);
this.AssertCartState(
cartI3D,
ReceiptCartState.DeclinedByOrderer,
possibleActions: new [] { ReceiptCartAction.ImproveOrdererDeclined });
this.ExecuteAction(cartI3D, ReceiptCartAction.ImproveOrdererDeclined);
this.AssertCartState(
cartI3D,
ReceiptCartState.ReadyForCheck,
possibleActions: new [] { ReceiptCartAction.CheckerApprove, ReceiptCartAction.CheckerDecline });
this.ExecuteAction(cartI3D, ReceiptCartAction.CheckerApprove);
// CartState already asserted above
// Check logs now, because after the orderer approves the cart, the cart will not be accessible anymore
this.VerifyReceiptLogs(cartI3D);
var orderCartResult = this.ExecuteAction(cartI3D, ReceiptCartAction.OrdererApprove);
this.AssertCartState(
cartI3D,
ReceiptCartState.Ordered,
possibleActions: new ReceiptCartAction[0]); //At this point, no actions are possible anymore
this.VerifyOrderCartResult(orderCartResult);
this.VerifyOfferState(cartI3D);
}
private void PrepareDatabase()
{
using var session = new BLSession();
// Create a special price so we can test
session.GetBL<AccountSpecialPriceWebServiceBL>().SaveAccountSpecialPrice(this.GetLoggedInUser().User, new AccountSpecialPriceDTO
{
ObjectKind = CentronObjectKindNumeric.CustomerClass,
ObjectI3D = 10000,
ValueKind = SpecialPriceKind.ReduceListPrice,
Value = 10,
ArticleI3D = ArticleI3D,
CreatedByI3D = 1,
CreatedDate = new DateTime(2022, 1, 1)
});
// Specify email settings, otherwise the release-system workflow won't send any mails
var settings = session.GetBL<ReceiptCartWebServiceBL>().GetWebCartSettings(this.GetLoggedInUser());
settings.CartOrderedEmailSender = "noreply@c-entron.de";
settings.CartOrderedInternalEmailReceiver = "vertrieb@c-entron.de";
session.GetBL<ReceiptCartWebServiceBL>().UpdateWebCartSettings(settings);
// Set a easy list-price to calculate with
this.Sql($"UPDATE dbo.ARTIK SET Listenpreis = 600 WHERE I3D = {ArticleI3D}");
// Update setting, so offers don't close automatically
this.WithSession(session =>
{
var settings = session.GetBL<AppSettingsBL>().GetSettingsForUpdate(AppSettingsConst.CloseOfferAutomatically);
settings.UpdateInt(AppSettingsConst.CloseOfferAutomatically, 1); // 1 = Never
settings.SaveSettings();
});
}
private int CreateCart()
{
var cart = this.WithSession(s => s.GetBL<ReceiptCartWebServiceBL>().CreateNewCart(this.GetLoggedInUserWebAccount(), "Test-Cart", string.Empty));
this.WithSession(s => s.GetBL<ReceiptCartWebServiceBL>().AddArticleToCart(cart.I3D, ArticleI3D, 10, this.GetLoggedInUserWebAccount()));
var updateCartInfo = new UpdateCartInfoDTO
{
AssembleArticles = true,
ProjectNumber = "Projektnummer",
PurchaseOrderNumber = "Besondere Bestellnummer",
IsPartialDeliveryPossible = false,
DeliveryAddressZip = "12345",
DeliveryAddressCity = "Stadt",
DeliveryAddressStreet = "Straße",
DeliveryAddressCountryI3D = 2,
DeliveryAddressFirstName = "Günther",
DeliveryAddressLastName = "Netzer",
DeliveryAddressDepartment = "Lieferung auf das Helikopterpad bitte",
DeliveryAddressSalutationI3D = 2,
};
this.WithSession(s => s.GetBL<ReceiptCartWebServiceBL>().UpdateCartInfo(cart.I3D, updateCartInfo, this.GetLoggedInUserWebAccount()));
return cart.I3D;
}
private void AssertRightsMissingFor(int cartI3D, ReceiptCartAction[] actions)
{
// In the beginning we don't have
foreach (var action in actions)
{
using var session = new BLSession();
var method = action.GetActualMethod(session);
var ex = Assert.Throws<ResultException>(() => method(cartI3D, this.GetLoggedInUserWebAccount()));
Assert.Equal("Sie haben nicht die benötigten Rechte für diese Operation.", ex.Message);
}
}
private void AddRights()
{
var webAccount = this.WithSession(s => s.GetBL<WebAccountWebServiceBL>().GetWebAccountByContactPersonI3D(23)).ThrowIfError();
var webRights = this.WithSession(s => s.GetBL<WebAccountWebServiceBL>().GetAllWebRights()).ThrowIfError();
webAccount.WebRights.Add(webRights.First(f => f.I3D == (int)WebAccountRightsConst.WEBRIGHT_WEBCART2_CHECK_CART));
webAccount.WebRights.Add(webRights.First(f => f.I3D == (int)WebAccountRightsConst.WEBRIGHT_WEBCART2_ORDER_CART));
this.WithSession(s => s.GetBL<WebAccountWebServiceBL>().SaveWebAccount(webAccount, this.GetLoggedInUser()));
}
private void AssertCartState(int cartI3D, ReceiptCartState cartState, ReceiptCartAction[] possibleActions)
{
// Ensure that the current cart-state is the expected one
// Also make sure, that we can NOT call any of the not-possible action
var currentCartState = Enum.Parse<ReceiptCartState>(this.Sql<string>($"SELECT O.CartState FROM dbo.Offers O WHERE O.I3D = {cartI3D}"));
Assert.Equal(cartState, currentCartState);
var notPossibleActions = Enum.GetValues<ReceiptCartAction>().Except(possibleActions);
foreach (var notPossibleAction in notPossibleActions)
{
using var session = new BLSession();
var method = notPossibleAction.GetActualMethod(session);
var ex = Assert.Throws<ResultException>(() => method(cartI3D, this.GetLoggedInUserWebAccount()));
// After the cart is ordered, we don't allow access to it anymore, and behave as it doesn't exist
var expectedMessage = cartState is ReceiptCartState.Ordered
? "Der Warenkorb wurde nicht gefunden."
: "Der Warenkorb befindet sich bereits an einem anderen Schritt des Freigabewesens.";
Assert.Equal(expectedMessage, ex.Message);
}
}
private OrderCartResultDTO ExecuteAction(int cartI3D, ReceiptCartAction action)
{
// Execute the given ReceiptCartAction, to move the cart forward into the next step of the release-system workflow
OrderCartResultDTO result = null;
var mails = TestMails.Start(() =>
{
using var session = new BLSession();
var method = action.GetActualMethod(session);
result = method(cartI3D, this.GetLoggedInUserWebAccount());
});
this.Verifier.Verify($"{action}_Mails", mails);
return result;
}
private void VerifyOrderCartResult(OrderCartResultDTO orderCartResult)
{
this.Verifier.Verify("OrderCartResult", orderCartResult);
var order = (ReceiptOrderDTO)this.WithSession(s => s.GetBL<ReceiptWebServiceBL>().GetReceiptByI3D(orderCartResult.OrderI3D, CentronObjectKindNumeric.OrderClass)).ThrowIfError();
this.Verifier.Verify($"Order", order);
}
private void VerifyOfferState(int cartI3D)
{
this.Verifier.VerifySql("OfferState", $"SELECT State FROM dbo.Offers WHERE I3D = {cartI3D}");
}
private void VerifyReceiptLogs(int cartI3D)
{
this.Verifier.VerifySql("ReceiptLogsTable", $"SELECT * FROM dbo.AnlageLog WHERE AnlageI3D = {cartI3D} AND AnlageArt = 1 ORDER BY I3D");
var logs = this.WithSession(s => s.GetBL<ReceiptCartWebServiceBL>().GetCartLogs(cartI3D, this.GetLoggedInUserWebAccount()));
this.Verifier.Verify("ReceiptLogs", logs);
}
}