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
400 lines
17 KiB
C#
400 lines
17 KiB
C#
using Centron.BusinessLogic;
|
|
using Centron.BusinessLogic.EmployeeArea;
|
|
using Centron.BusinessLogic.Sales.CustomerAssets.TimerBilling;
|
|
using Centron.BusinessLogic.WebServices.Sales.Receipts;
|
|
using Centron.Data.WebServices.Sales.Receipts.Invoices;
|
|
using Centron.Interfaces;
|
|
using Centron.Tests.EndToEnd.Infrastructure;
|
|
using CentronSoftware.Centron.WebServices.Entities.Sales.CustomerAssets.TimerBilling;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Centron.BusinessLogic.Administration.Settings;
|
|
using Centron.BusinessLogic.Sales.Receipts.DataAndResults;
|
|
using Centron.BusinessLogic.Sales.Receipts.Internal;
|
|
using Centron.BusinessLogic.Sales.Support;
|
|
using Centron.BusinessLogic.WebServices.Sales.Support;
|
|
using Centron.Data.Entities.Sales.Support.HelpdeskTimerArea;
|
|
using Centron.Data.WebServices.Sales.Receipts;
|
|
using Centron.Data.WebServices.Sales.Receipts.Offers;
|
|
using Centron.Data.WebServices.Sales.Support;
|
|
using Centron.Interfaces.Administration.Environment;
|
|
using Centron.Interfaces.Administration.Settings;
|
|
using Centron.Interfaces.Sales.Receipts;
|
|
using CentronSoftware.Centron.WebServices.Extensions;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace Centron.Tests.EndToEnd.Tests.TimerBilling
|
|
{
|
|
public class TimerBillingTest : EndToEndTest
|
|
{
|
|
public TimerBillingTest(ITestOutputHelper testOutputHelper)
|
|
: base(testOutputHelper)
|
|
{
|
|
}
|
|
|
|
public override void Execute()
|
|
{
|
|
this.PrepareDatabase();
|
|
|
|
this.CreateReceiptWithDate(CentronObjectKindNumeric.InvoiceClass, reminderDateInDays: 0);
|
|
this.CreateReceiptWithDate(CentronObjectKindNumeric.InvoiceClass, reminderDateInDays: 10);
|
|
|
|
this.CreateReceiptWithDate(CentronObjectKindNumeric.DeliveryListClass, reminderDateInDays: 0);
|
|
this.CreateReceiptWithDate(CentronObjectKindNumeric.DeliveryListClass, reminderDateInDays: 10);
|
|
|
|
// Reset it to 0, so the invoices created afterwards don't change
|
|
this.SetReminderDateInDays(0);
|
|
|
|
this.FindTimersAndCreateInvoiceForCustomer(10008);
|
|
this.FindTimersAndCreateInvoiceForCustomer(10012);
|
|
this.FindTimersAndCreateInvoiceForCustomer(10017);
|
|
this.FindTimersAndCreateInvoiceForCustomer(10024);
|
|
|
|
this.ValidateUseTicketTimeAsServicePeriod();
|
|
this.ValidateBreakTimeFormat();
|
|
|
|
// Timer from orders
|
|
this.ExecuteMatrix(
|
|
new bool?[] {null, true, false},
|
|
new bool[] {true, false},
|
|
(takePriceFromOrder, globalTakePriceFromOrder) =>
|
|
{
|
|
this.CreateReceiptWithTimerFromOrder(takePriceFromOrder, globalTakePriceFromOrder);
|
|
});
|
|
|
|
// Timer with Master-Data-List infos
|
|
this.CreateInvoiceFromTicketWithMasterDataList();
|
|
|
|
// Timer start- and end-time fix
|
|
this.ExecuteMatrix(
|
|
new bool[] {true, false},
|
|
new bool[] {true, false},
|
|
(startTimeFormat, endTimeFormat) =>
|
|
{
|
|
this.CreateReceiptWithTimerFormat(startTimeFormat, endTimeFormat);
|
|
});
|
|
|
|
this.TestGetContractsMethod();
|
|
}
|
|
|
|
private void TestGetContractsMethod()
|
|
{
|
|
// This is just a function test so the different combinations work. We use in GetContracts a complex table valued function
|
|
// If it is called for one customer or one contract, we pass down it too the function too.
|
|
|
|
using var session = new BLSession();
|
|
var result = session.GetBL<TimerBillingBL>().GetContracts(new List<int>()
|
|
{
|
|
10000
|
|
}, null);
|
|
Verifier.Verify("TimerBillingTest_TestGetContractsMethod_SingleCustomer", result);
|
|
|
|
result = session.GetBL<TimerBillingBL>().GetContracts(null, new List<int>()
|
|
{
|
|
28
|
|
});
|
|
Verifier.Verify("TimerBillingTest_TestGetContractsMethod_SingleContract", result);
|
|
|
|
result = session.GetBL<TimerBillingBL>().GetContracts(new List<int>()
|
|
{
|
|
10000, 10003
|
|
}, null);
|
|
Verifier.Verify("TimerBillingTest_TestGetContractsMethod_MultipleCustomer", result);
|
|
|
|
result = session.GetBL<TimerBillingBL>().GetContracts(null, new List<int>()
|
|
{
|
|
28, 6
|
|
});
|
|
Verifier.Verify("TimerBillingTest_TestGetContractsMethod_MultipleContract", result);
|
|
}
|
|
|
|
private void PrepareDatabase()
|
|
{
|
|
this.Sql($"UPDATE dbo.Stammdat SET WertText = 'g' WHERE I3D = {(int)AppSettingsConst.HelpdeskTimerStartTimeFormat}");
|
|
this.Sql($"UPDATE dbo.Stammdat SET WertText = 'g' WHERE I3D = {(int)AppSettingsConst.HelpdeskTimerEndTimeFormat}");
|
|
}
|
|
|
|
private void CreateReceiptWithDate(CentronObjectKindNumeric receiptKind, int reminderDateInDays)
|
|
{
|
|
this.SetReminderDateInDays(reminderDateInDays);
|
|
|
|
// Prepare
|
|
var customerI3D = 10008;
|
|
var name = $"{receiptKind.GetReceiptName()}WithDateResultForCustomer{customerI3D}ReminderIn{reminderDateInDays}";
|
|
|
|
var timerI3Ds = this.FindTimers(customerI3D);
|
|
|
|
var billingDate = new DateTime(2021, 10, 30);
|
|
var settings = new TimerBillingSettingsDTO
|
|
{
|
|
ReceiptKind = receiptKind,
|
|
BillingDate = billingDate
|
|
};
|
|
|
|
// Act
|
|
var receipt = this.CreateReceipt(name, timerI3Ds, settings);
|
|
|
|
// Assert
|
|
Assert.Equal(billingDate, receipt.Date);
|
|
|
|
// The ReminderDate should be X days after the receipt-date
|
|
// So when today is X, billing date is X + 7, and reminderDateInDays is 5,
|
|
// then reminderDate should be X + 7 + 5
|
|
var expectedReminderDate = reminderDateInDays == 0
|
|
? (DateTime?)null
|
|
: billingDate.AddDays(reminderDateInDays);
|
|
Assert.Equal(expectedReminderDate, receipt.Get((IReceiptWithReminderDate r) => r.ReminderDate));
|
|
}
|
|
|
|
private void SetReminderDateInDays(int reminderDateInDays)
|
|
{
|
|
// Set reminder date settings
|
|
using (var session = new BLSession())
|
|
{
|
|
var updateSettings = session.GetBL<AppSettingsBL>().GetSettingsForUpdate(
|
|
AppSettingsConst.InvoiceReminderDays,
|
|
ApplicationSettingID.DeliveryListReminderDays);
|
|
|
|
updateSettings.UpdateInt(AppSettingsConst.InvoiceReminderDays, reminderDateInDays);
|
|
updateSettings.UpdateInt(ApplicationSettingID.DeliveryListReminderDays, reminderDateInDays);
|
|
|
|
updateSettings.SaveSettings();
|
|
}
|
|
}
|
|
|
|
private void FindTimersAndCreateInvoiceForCustomer(int customerI3D)
|
|
{
|
|
var name = $"InvoiceResultForCustomer{customerI3D}";
|
|
|
|
var timerI3Ds = this.FindTimers(customerI3D);
|
|
|
|
var settings = new TimerBillingSettingsDTO
|
|
{
|
|
InsertHelpdeskDescription = true,
|
|
InsertHelpdeskShortDescription = true,
|
|
InsertTimerText = true,
|
|
InsertTimerTime = true,
|
|
InsertTheFollowingAreTimersFromHelpdeskText = true,
|
|
Sorting = Interfaces.Sales.Receipts.TimerBilling.TimerSorting.ChronologicalUp,
|
|
|
|
ReceiptKind = CentronObjectKindNumeric.InvoiceClass,
|
|
AdditionalText = "Hier mein Text!"
|
|
};
|
|
|
|
var invoice = this.CreateReceipt(name, timerI3Ds, settings);
|
|
this.SaveInvoice(invoice);
|
|
}
|
|
|
|
private List<int> FindTimers(int customerI3D)
|
|
{
|
|
using (var session = new BLSession())
|
|
{
|
|
var filter = new TimerBillingFilter
|
|
{
|
|
OnlyOpenHelpdesks = true,
|
|
CustomerI3Ds = new List<int>
|
|
{
|
|
customerI3D
|
|
}
|
|
};
|
|
|
|
var timers = session.GetBL<TimerBillingBL>().SearchTimers(filter);
|
|
this.Verifier.Verify("FindTimersForCustomer" + customerI3D, timers);
|
|
|
|
return timers.Select(f => f.I3D).ToList();
|
|
}
|
|
}
|
|
|
|
private ReceiptBaseDTO CreateReceipt(string name, List<int> timerI3Ds, TimerBillingSettingsDTO settings)
|
|
{
|
|
using (var session = new BLSession())
|
|
{
|
|
var user = session.GetBL<AppUserBL>().GetAppUser(f => f.I3D == 11);
|
|
var invoiceResult = session.GetBL<ReceiptWebServiceBL>().CreateNewReceiptForHelpdekTimers(timerI3Ds, settings, user);
|
|
|
|
// Allow the caller to pass in a NULL name, to skip the .Verify call
|
|
if (name is not null)
|
|
this.Verifier.Verify(name, invoiceResult);
|
|
|
|
return invoiceResult.Data;
|
|
}
|
|
}
|
|
|
|
private void SaveInvoice(ReceiptBaseDTO invoice)
|
|
{
|
|
using (var session = new BLSession())
|
|
{
|
|
var user = session.GetBL<AppUserBL>().GetAppUser(f => f.I3D == 11);
|
|
var saveResult = session.GetBL<ReceiptWebServiceBL>().SaveReceipt(invoice, user, new SaveReceiptData
|
|
{
|
|
IgnoreCallbacks = true
|
|
}, false, CreatedThroughApplication.CentronNet, null);
|
|
|
|
this.Verifier.Verify($"SavedInvoice{invoice.Number}", saveResult);
|
|
}
|
|
}
|
|
|
|
private void ValidateBreakTimeFormat()
|
|
{
|
|
// Set break-time format
|
|
using (var session = new BLSession())
|
|
{
|
|
var updateSettings = session.GetBL<AppSettingsBL>().GetSettingsForUpdate(
|
|
ApplicationSettingID.HelpdeskTimerBreakTimeFormat);
|
|
|
|
updateSettings.UpdateString(ApplicationSettingID.HelpdeskTimerBreakTimeFormat, "davon @@Stunden@@ bzw. @@Minuten@@ bzw. @@StundenDezimal@@ Pause");
|
|
|
|
updateSettings.SaveSettings();
|
|
}
|
|
|
|
// Test the logic
|
|
using (var session = new BLSession())
|
|
{
|
|
var testTimer = new HelpdeskTimer
|
|
{
|
|
Start = new DateTime(2021, 1, 1, 15, 30, 0),
|
|
Stop = new DateTime(2021, 1, 1, 17, 45, 0),
|
|
LunchTime = (int)TimeSpan.FromMinutes(12).TotalSeconds
|
|
};
|
|
var text = session.GetBL<ReceiptItemTimerBL>().GetTimerTimeText(testTimer);
|
|
this.Verifier.Verify("TimerTimeTextWithBreak", text);
|
|
}
|
|
}
|
|
|
|
private void ValidateUseTicketTimeAsServicePeriod()
|
|
{
|
|
const int timerI3D = 10511;
|
|
var (start, stop) = this.GetHelpdeskTimerPeriod(timerI3D);
|
|
|
|
var receiptWithServicePeriod = this.CreateReceipt(null, new List<int> { timerI3D }, new TimerBillingSettingsDTO
|
|
{
|
|
ReceiptKind = CentronObjectKindNumeric.InvoiceClass,
|
|
UseTicketTimeAsServicePeriod = true,
|
|
});
|
|
|
|
var itemWithServicePeriod = receiptWithServicePeriod.GetReceiptItems().OfType<ReceiptInvoiceItemDTO>().First(f => f.ServicePeriodFrom != null);
|
|
Assert.Equal(start, itemWithServicePeriod.ServicePeriodFrom);
|
|
Assert.Equal(stop, itemWithServicePeriod.ServicePeriodTo);
|
|
|
|
var receiptPeriod = Assert.IsType<ReceiptInvoiceDTO>(receiptWithServicePeriod);
|
|
Assert.Equal(start, receiptPeriod.ServicePeriodFrom);
|
|
Assert.Equal(stop, receiptPeriod.ServicePeriodTo);
|
|
|
|
var receiptWithoutServicePeriod = this.CreateReceipt(null, new List<int> { timerI3D }, new TimerBillingSettingsDTO
|
|
{
|
|
ReceiptKind = CentronObjectKindNumeric.InvoiceClass,
|
|
UseTicketTimeAsServicePeriod = false,
|
|
});
|
|
|
|
foreach (var itemWithoutServicePeriod in receiptWithoutServicePeriod.GetReceiptItems().OfType<ReceiptInvoiceItemDTO>())
|
|
{
|
|
Assert.Null(itemWithoutServicePeriod.ServicePeriodFrom);
|
|
Assert.Null(itemWithoutServicePeriod.ServicePeriodTo);
|
|
}
|
|
|
|
var receiptWithoutPeriod = Assert.IsType<ReceiptInvoiceDTO>(receiptWithoutServicePeriod);
|
|
Assert.Null(receiptWithoutPeriod.ServicePeriodFrom);
|
|
Assert.Null(receiptWithoutPeriod.ServicePeriodTo);
|
|
}
|
|
|
|
private (DateTime Start, DateTime Stop) GetHelpdeskTimerPeriod(int timerI3D)
|
|
{
|
|
using var session = new BLSession();
|
|
var timer = session.GetBL<HelpdeskTimerBL>().GetHelpdeskTimerByI3D(timerI3D);
|
|
return (timer.Start, timer.Stop);
|
|
}
|
|
|
|
private void CreateReceiptWithTimerFromOrder(bool? takePriceFromOrder, bool globalTakePriceFromOrder)
|
|
{
|
|
var name = $"CreateReceiptWithTimerFromOrder_PriceFromOrder_{takePriceFromOrder?.ToString() ?? "NULL"}_GlobalPriceFromOrder_{globalTakePriceFromOrder}";
|
|
|
|
const int TimerI3DFromOrder = 10511;
|
|
const int OrderItemI3D = 7258;
|
|
|
|
var settings = new TimerBillingSettingsDTO
|
|
{
|
|
ReceiptKind = CentronObjectKindNumeric.InvoiceClass,
|
|
TakePriceFromOrder = globalTakePriceFromOrder,
|
|
OrderItemI3DForHelpdeskTimerI3Ds = new List<TimerBillingOrderItemI3DForHelpdeskTimerI3D>
|
|
{
|
|
new()
|
|
{
|
|
HelpdeskTimerI3D = TimerI3DFromOrder,
|
|
OrderItemI3D = OrderItemI3D,
|
|
TakePriceFromOrder = takePriceFromOrder
|
|
}
|
|
}
|
|
};
|
|
|
|
var invoice = this.CreateReceipt(name:null, new List<int> { TimerI3DFromOrder }, settings);
|
|
var item = invoice.GetReceiptItems().First(f => f.ArticleI3D == 12);
|
|
this.Verifier.Verify(name, item);
|
|
|
|
// Important here is mostly the IReceiptItemBase.BasePrice property
|
|
var expectedPriceFromOrder = takePriceFromOrder ?? globalTakePriceFromOrder;
|
|
var expectedPrice = expectedPriceFromOrder ? 400 : 0;
|
|
var price = item.BasePrice;
|
|
|
|
Assert.Equal(expectedPrice, price);
|
|
}
|
|
|
|
private void CreateInvoiceFromTicketWithMasterDataList()
|
|
{
|
|
// Add new timer to Helpdesk Ticket I3D 9447
|
|
int? timerI3D;
|
|
using (var session = new BLSession())
|
|
{
|
|
timerI3D = session.GetBL<HelpdeskTimerWebServiceBL>().SaveHelpdeskTimer(new HelpdeskTimerDTO
|
|
{
|
|
Start = new DateTime(2022, 2, 10, 12, 0, 0),
|
|
Stop = new DateTime(2022, 2, 10, 14, 30, 0),
|
|
Calculable = true,
|
|
HelpdeskI3D = 9447,
|
|
InternalNote = "Interne Notiz Blabla",
|
|
ExternalNote = "Externe Notiz Blabla",
|
|
IsPlanned = false,
|
|
ArticleI3D = 94,
|
|
State = 1,
|
|
}, this.GetLoggedInUser());
|
|
|
|
Assert.NotNull(timerI3D);
|
|
}
|
|
|
|
// Activate the setting to add Master-Data-List info when billing timers
|
|
this.Sql($"UPDATE dbo.Stammdat SET Wert = 1 WHERE I3D = {(int)AppSettingsConst.HelpdeskToCustomerAssetInsertMasterSheetData}");
|
|
|
|
// Act
|
|
var settings = new TimerBillingSettingsDTO
|
|
{
|
|
ReceiptKind = CentronObjectKindNumeric.InvoiceClass,
|
|
};
|
|
|
|
var receipt = this.CreateReceipt("InvoiceFromTicketWithMasterDataList", new List<int> {timerI3D.Value}, settings);
|
|
}
|
|
|
|
private void CreateReceiptWithTimerFormat(bool hasStartTimeFormat, bool hasEndTimeFormat)
|
|
{
|
|
var startTimeFormat = hasStartTimeFormat ? "g" : "";
|
|
this.Sql($"UPDATE dbo.Stammdat SET WertText = '{startTimeFormat}' WHERE I3D = {(int)AppSettingsConst.HelpdeskTimerStartTimeFormat}");
|
|
var endTimeFormat = hasEndTimeFormat ? "g" : "";
|
|
this.Sql($"UPDATE dbo.Stammdat SET WertText = '{endTimeFormat}' WHERE I3D = {(int)AppSettingsConst.HelpdeskTimerEndTimeFormat}");
|
|
|
|
using (var session = new BLSession())
|
|
{
|
|
var testTimer = new HelpdeskTimer
|
|
{
|
|
Start = new DateTime(2021, 1, 1, 15, 30, 0),
|
|
Stop = new DateTime(2021, 1, 1, 17, 45, 0),
|
|
LunchTime = (int)TimeSpan.FromMinutes(12).TotalSeconds
|
|
};
|
|
var text = session.GetBL<ReceiptItemTimerBL>().GetTimerTimeText(testTimer);
|
|
this.Verifier.Verify($"TimerTimeText_HasStartTime_{hasStartTimeFormat}_HasEndTime_{hasEndTimeFormat}", text);
|
|
}
|
|
}
|
|
}
|
|
}
|