diff --git a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/DesignTimeBuild/.dtbcache.v2 b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/DesignTimeBuild/.dtbcache.v2 index 995be35..708b329 100644 Binary files a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/DesignTimeBuild/.dtbcache.v2 and b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/DesignTimeBuild/.dtbcache.v2 differ diff --git a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.futdcache.v2 b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.futdcache.v2 index 3805995..f8e4cf6 100644 Binary files a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.futdcache.v2 and b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.futdcache.v2 differ diff --git a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.suo b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.suo index 4adef06..1dd33e0 100644 Binary files a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.suo and b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/.suo differ diff --git a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/DocumentLayout.json b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/DocumentLayout.json index 8859089..9fb6c65 100644 --- a/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/DocumentLayout.json +++ b/Projekt_Calcan_Conze/.vs/Projekt_Calcan_Conze/v17/DocumentLayout.json @@ -24,9 +24,9 @@ "RelativeDocumentMoniker": "Projekt_Calcan_Conze\\Program.cs", "ToolTip": "C:\\Jan_bib_Module\\PMC\\Projekt\\Projekt_Calcan_Conze\\Projekt_Calcan_Conze\\Program.cs", "RelativeToolTip": "Projekt_Calcan_Conze\\Program.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAA==", + "ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAA7AAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2024-08-30T08:39:28.715Z", + "WhenOpened": "2024-09-02T11:44:49.844Z", "EditorCaption": "" } ] diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Constants.cs b/Projekt_Calcan_Conze/Core/Constants.cs similarity index 58% rename from Projekt_Calcan_Conze/Projekt_Calcan_Conze/Constants.cs rename to Projekt_Calcan_Conze/Core/Constants.cs index 3edb462..961b120 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Constants.cs +++ b/Projekt_Calcan_Conze/Core/Constants.cs @@ -1,13 +1,27 @@ -namespace Projekt_Calcan_Conze_Import; +namespace Core; -internal static class Constants +public static class Constants { - public const char Separator = ';'; - public const string FemaleAttributeIdentifier = "Frau"; - public const string MaleAttributeIdentifier = "Herr"; - public const string DiverseAttributeIdentifier = "Divers"; - public const string AddressAttributeIdentifier = "Adresse"; - public const string EmailAttributeIdentifier = "E-Mail"; - public const string PhoneNumberAttributeIdentifier = "Telefon"; + //set the correct values for your server, user, password and database name + public const string ConnectionString = "server=localhost;uid=root;pwd=root;database=import_export"; + public const string DateOfBirthFormat = "dd.MM.yyyy"; + + public const string DateFormat = "yyyy-MM-dd"; + + public const string MoneyFormat = "F3"; + + public const char Separator = ';'; + + public const string FemaleAttributeIdentifier = "Frau"; + + public const string MaleAttributeIdentifier = "Herr"; + + public const string DiverseAttributeIdentifier = "Divers"; + + public const string AddressAttributeIdentifier = "Adresse"; + + public const string EmailAttributeIdentifier = "E-Mail"; + + public const string PhoneNumberAttributeIdentifier = "Telefon"; } \ No newline at end of file diff --git a/Projekt_Calcan_Conze/Core/Core.csproj b/Projekt_Calcan_Conze/Core/Core.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Projekt_Calcan_Conze/Core/Core.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze.sln b/Projekt_Calcan_Conze/Projekt_Calcan_Conze.sln index 4d48572..4a235ca 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze.sln +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze.sln @@ -5,7 +5,9 @@ VisualStudioVersion = 17.10.34916.146 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Projekt_Calcan_Conze_Import", "Projekt_Calcan_Conze\Projekt_Calcan_Conze_Import.csproj", "{44DD7752-6BB5-4C3A-9053-671D8ADE49C4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Projekt_Calcan_Conze_Export", "Projekt_Calcan_Conze_Export\Projekt_Calcan_Conze_Export.csproj", "{9E018F4D-EED3-44D0-9179-E6637B984D74}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Projekt_Calcan_Conze_Export", "Projekt_Calcan_Conze_Export\Projekt_Calcan_Conze_Export.csproj", "{9E018F4D-EED3-44D0-9179-E6637B984D74}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{1A945077-A135-4756-974C-A87109DF411E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {9E018F4D-EED3-44D0-9179-E6637B984D74}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E018F4D-EED3-44D0-9179-E6637B984D74}.Release|Any CPU.ActiveCfg = Release|Any CPU {9E018F4D-EED3-44D0-9179-E6637B984D74}.Release|Any CPU.Build.0 = Release|Any CPU + {1A945077-A135-4756-974C-A87109DF411E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A945077-A135-4756-974C-A87109DF411E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A945077-A135-4756-974C-A87109DF411E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A945077-A135-4756-974C-A87109DF411E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/DTOs/UserDto.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/DTOs/UserDto.cs index e8e9faf..225dab2 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/DTOs/UserDto.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/DTOs/UserDto.cs @@ -1,4 +1,6 @@ -namespace Projekt_Calcan_Conze_Import.DTOs; +using Projekt_Calcan_Conze_Import.DTOs; + +namespace Projekt_Calcan_Conze_Import.DTOs; internal class UserDto { diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/ImportUsers.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/ImportUsers.cs index 7e82111..ce310e8 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/ImportUsers.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/ImportUsers.cs @@ -1,7 +1,10 @@ using System.Net.Mail; +using Core; + using Projekt_Calcan_Conze_Import.DTOs; using Projekt_Calcan_Conze_Import.Models; +using Projekt_Calcan_Conze_Import.DTOs; using Projekt_Calcan_Conze_Import.Models; namespace Projekt_Calcan_Conze_Import; diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Models/User.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Models/User.cs index 9cba554..bb5aea8 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Models/User.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Models/User.cs @@ -1,5 +1,8 @@ using System.Text; +using Core; +using Projekt_Calcan_Conze_Import.Models; + namespace Projekt_Calcan_Conze_Import.Models; internal class User diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Program.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Program.cs index 48c480d..4b467f0 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Program.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Program.cs @@ -1,5 +1,6 @@ using Projekt_Calcan_Conze_Import; using Projekt_Calcan_Conze_Import.Repositories; +using Projekt_Calcan_Conze_Import; try { diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Import.csproj b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Import.csproj index e92aac5..21db241 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Import.csproj +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Import.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repository/Database.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repositories/Database.cs similarity index 98% rename from Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repository/Database.cs rename to Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repositories/Database.cs index 322c1d0..7ed4485 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repository/Database.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/Repositories/Database.cs @@ -1,16 +1,18 @@ using System.Data; +using Core; + using Projekt_Calcan_Conze_Import.DTOs; using Projekt_Calcan_Conze_Import.Models; namespace Projekt_Calcan_Conze_Import.Repositories; using MySql.Data.MySqlClient; +using Projekt_Calcan_Conze_Import.DTOs; +using Projekt_Calcan_Conze_Import.Models; internal static class Database { - //set the correct values for your server, user, password and database name - private const string ConnectionString = "server=localhost;uid=root;pwd=root;database=import_export"; public static async Task> GetUserIdentifiers(string clientNumber) { @@ -19,7 +21,7 @@ internal static class Database try { // use "using" to automatically close the connection when done - await using var dbConnection = new MySqlConnection(ConnectionString); + await using var dbConnection = new MySqlConnection(Constants.ConnectionString); // open a connection await dbConnection.OpenAsync(); @@ -67,7 +69,7 @@ internal static class Database { try { - await using var dbConnection = new MySqlConnection(ConnectionString); + await using var dbConnection = new MySqlConnection(Constants.ConnectionString); await dbConnection.OpenAsync(); var transaction = await dbConnection.BeginTransactionAsync(); diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.assets.json b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.assets.json index f125653..19af514 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.assets.json +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.assets.json @@ -535,6 +535,16 @@ "runtime": { "lib/net7.0/ZstdSharp.dll": {} } + }, + "Core/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "compile": { + "bin/placeholder/Core.dll": {} + }, + "runtime": { + "bin/placeholder/Core.dll": {} + } } } }, @@ -1778,10 +1788,16 @@ "zstdsharp.port.0.7.1.nupkg.sha512", "zstdsharp.port.nuspec" ] + }, + "Core/1.0.0": { + "type": "project", + "path": "../Core/Core.csproj", + "msbuildProject": "../Core/Core.csproj" } }, "projectFileDependencyGroups": { "net8.0": [ + "Core >= 1.0.0", "MySql.Data >= 8.4.0" ] }, @@ -1811,7 +1827,11 @@ "frameworks": { "net8.0": { "targetAlias": "net8.0", - "projectReferences": {} + "projectReferences": { + "C:\\Jan_bib_Module\\PMC\\Projekt\\Projekt_Calcan_Conze\\Core\\Core.csproj": { + "projectPath": "C:\\Jan_bib_Module\\PMC\\Projekt\\Projekt_Calcan_Conze\\Core\\Core.csproj" + } + } } }, "warningProperties": { diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.nuget.cache b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.nuget.cache index 4ffd075..0077d92 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.nuget.cache +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze/obj/project.nuget.cache @@ -1,6 +1,6 @@ { "version": 2, - "dgSpecHash": "xTy/jRXZQLw=", + "dgSpecHash": "4Akg//gURuM=", "success": true, "projectFilePath": "C:\\Jan_bib_Module\\PMC\\Projekt\\Projekt_Calcan_Conze\\Projekt_Calcan_Conze\\Projekt_Calcan_Conze_Import.csproj", "expectedPackageFiles": [ diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Constants.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Constants.cs deleted file mode 100644 index a2ab145..0000000 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Constants.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Projekt_Calcan_Conze_Export; - -internal static class Constants -{ - public const string DateFormat = "yyyy-MM-dd"; - - public const string Separator = ";"; - - public const string MoneyFormat = "F2"; -} \ No newline at end of file diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Models/Billing.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Models/Billing.cs index fb0b4c0..10edb12 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Models/Billing.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Models/Billing.cs @@ -1,4 +1,6 @@ -namespace Projekt_Calcan_Conze_Export.Models; +using Core; + +namespace Projekt_Calcan_Conze_Export.Models; internal class Billing { @@ -74,7 +76,7 @@ internal class BillingPosition public double BaseAmount { get; } - public int Count { get; } + public int Count { get; set; } public double TotalAmount => this.BaseAmount * this.Count; } \ No newline at end of file diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Program.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Program.cs index 03edec9..89d6ff0 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Program.cs +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Program.cs @@ -1,8 +1,9 @@ using System.Globalization; -using Projekt_Calcan_Conze_Export; -using Projekt_Calcan_Conze_Export.Models; -using Microsoft.VisualBasic; +using Core; + +using Projekt_Calcan_Conze_Export.Repositories; +using Projekt_Calcan_Conze_Export.Repositories; try { @@ -83,26 +84,22 @@ try } } - List billings = - [ - new Billing( - startDate: startDate.Value, - endDate: endDate.Value, - customerNumber: clientNumber, - customerName: "Max Mustermann", - positions: - [ - new BillingPosition( - description: "Testposition", - baseAmount: 100.0, - count: 3) - ]) - ]; - string fileName = - $"{DateTime.Today.ToString(Constants.DateFormat)}_{clientNumber}_{startDate.Value.ToString(Constants.DateFormat)}_{endDate.Value.ToString(Constants.DateFormat)}.csv"; - File.WriteAllLines( - Path.Combine(directoryPath, fileName), - billings.SelectMany(billing => billing.ToCsvLines())); + Console.WriteLine(); + + var billing = await Database.CreateBilling(startDate.Value, endDate.Value, clientNumber); + + if (billing is null) + { + Console.WriteLine("Es konnte keine Rechnung erstellt werden."); + } + else + { + string fileName = + $"{DateTime.Today.ToString(Constants.DateFormat)}_{clientNumber}_{startDate.Value.ToString(Constants.DateFormat)}_{endDate.Value.ToString(Constants.DateFormat)}.csv"; + string filePath = Path.Combine(directoryPath, fileName); + File.WriteAllLines(filePath, billing.ToCsvLines()); + Console.WriteLine($"Die Rechnung wurde unter \"{filePath}\" abgelegt."); + } } catch (Exception ex) { diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Projekt_Calcan_Conze_Export.csproj b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Projekt_Calcan_Conze_Export.csproj index 2150e37..b4cb502 100644 --- a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Projekt_Calcan_Conze_Export.csproj +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Projekt_Calcan_Conze_Export.csproj @@ -7,4 +7,12 @@ enable + + + + + + + + diff --git a/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Repositories/Database.cs b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Repositories/Database.cs new file mode 100644 index 0000000..ff53824 --- /dev/null +++ b/Projekt_Calcan_Conze/Projekt_Calcan_Conze_Export/Repositories/Database.cs @@ -0,0 +1,162 @@ +using System.Data; + +using Core; + +using Projekt_Calcan_Conze_Export.Models; + +using MySql.Data.MySqlClient; +using Projekt_Calcan_Conze_Export.Models; + +namespace Projekt_Calcan_Conze_Export.Repositories; + +internal static class Database +{ + public static async Task CreateBilling(DateOnly startDate, DateOnly endDate, string customerNumber) + { + Billing? billing = null; + + try + { + await using var dbConnection = new MySqlConnection(Constants.ConnectionString); + await dbConnection.OpenAsync(); + var transaction = await dbConnection.BeginTransactionAsync(); + + try + { + // ensure wasBilled column exists and activityDateTime does not refresh on update + var createWasBilledColumnCommand = + new MySqlCommand + { + Connection = dbConnection, + Transaction = transaction, + CommandText = + """ + ALTER TABLE activity ADD IF NOT EXISTS wasBilled BIT NOT NULL DEFAULT 0; + ALTER TABLE activity CHANGE COLUMN activityDatetime activityDatetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + ALTER TABLE activity ALTER COLUMN activityDatetime DROP DEFAULT; + """ + }; + await createWasBilledColumnCommand.ExecuteNonQueryAsync(); + + // tables: activityType, activity, contract, user, client + // one activityType can be assigned to multiple contracts, one contract has one activityType + // one contract can have multiple activities, one activity belongs to one contract + // one activity has one user, one user can have multiple activities + // one user belongs to one client, one client can have multiple users + // one contract belongs to one client, one client can have multiple contracts + // get all contracts of the client by the client number and the start and end date + // include all activities of the contracts + // include the client name (column of client table) + // only get activities that were not billed yet (wasBilled = 0) + var getActivities = + new MySqlCommand + { + Connection = dbConnection, + Transaction = transaction, + CommandText = + """ + SELECT + activity.id, + activity.contractId, + contract.amount, + contract.description + FROM activity + JOIN contract ON activity.contractId = contract.id + JOIN activityType ON contract.activityTypeId = activityType.id + JOIN user ON activity.userId = user.id + JOIN client ON contract.clientId = client.id + WHERE client.clientno = @clientNumber + AND activity.activityDateTime >= @startDate + AND activity.activityDateTime <= @endDate + AND activity.wasBilled = 0 + """ + }; + getActivities.Parameters.AddWithValue("@clientNumber", customerNumber); + getActivities.Parameters.AddWithValue("@startDate", startDate.ToString("yyyy-MM-dd")); + getActivities.Parameters.AddWithValue("@endDate", endDate.ToString("yyyy-MM-dd")); + + await using var activityReader = await getActivities.ExecuteReaderAsync(); + Dictionary positions = []; + List activityIds = []; + + while (await activityReader.ReadAsync()) + { + activityIds.Add(activityReader.GetInt32("id")); + int contractId = activityReader.GetInt32("contractId"); + + if (positions.TryGetValue(contractId, out var positionDto)) + { + positionDto.Count++; + } + else + { + positions[contractId] = + new BillingPosition( + description: activityReader.GetString("description"), + baseAmount: activityReader.GetDouble("amount"), + count: 1); + } + } + + await activityReader.CloseAsync(); + + // get the customer name separately in case we have no activities + + var getCustomerNameCommand = + new MySqlCommand + { + Connection = dbConnection, + Transaction = transaction, + CommandText = + """ + SELECT name + FROM client + WHERE clientno = @clientNumber + """ + }; + getCustomerNameCommand.Parameters.AddWithValue("@clientNumber", customerNumber); + + string customerName = await getCustomerNameCommand.ExecuteScalarAsync() as string ?? string.Empty; + + billing = + new Billing( + startDate: startDate, + endDate: endDate, + customerNumber: customerNumber, + customerName: customerName, + positions: positions.Values.ToList()); + + // set wasBilled to 1 for all retrieved activities + + string activityIdsString = string.Join(',', activityIds.Select((_, i) => $"@activityId{i}")); + var updateWasBilledCommand = + new MySqlCommand + { + Connection = dbConnection, + Transaction = transaction, + CommandText = $"UPDATE activity SET wasBilled = 1 WHERE id IN ({activityIdsString})" + }; + + for (int i = 0; i < activityIds.Count; i++) + { + updateWasBilledCommand.Parameters.AddWithValue($"@activityId{i}", activityIds[i]); + } + + await updateWasBilledCommand.ExecuteNonQueryAsync(); + } + catch (Exception) + { + await transaction.RollbackAsync(); + throw; + } + + await transaction.CommitAsync(); + } + catch (Exception ex) + { + Console.WriteLine("An error occurred while writing to or reading from the database: " + ex.Message); + } + + return billing; + } +} \ No newline at end of file