From 0e8c8f179c43592ab566495eaabcf2a6c6c0a96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tommy=20=C3=96man?= Date: Sun, 4 Jun 2023 23:28:20 +0200 Subject: [PATCH] =?UTF-8?q?=C3=84ndrad=20inl=C3=A4sningsmetod=20f=C3=B6r?= =?UTF-8?q?=20Xlsx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyYearlyCountings/Data/DataContext.cs | 4 + MyYearlyCountings/Facades/IReadingIn.cs | 2 +- MyYearlyCountings/Facades/ReadingIn.cs | 112 +++++++----------- MyYearlyCountings/Helpers/Extensions.cs | 12 ++ MyYearlyCountings/Models/CalDay.cs | 18 +++ MyYearlyCountings/Models/CalHour.cs | 18 +++ MyYearlyCountings/Models/CalMonth.cs | 17 +++ MyYearlyCountings/Models/CalYear.cs | 16 +++ MyYearlyCountings/MyYearlyCountings.csproj | 15 +-- MyYearlyCountings/Program.cs | 3 + MyYearlyCountings/UI/KeyHandling.cs | 21 ++-- MyYearlyCountings/Worker.cs | 10 +- .../appsettings.Development.json | 5 + TransactionsTest.xlsx | Bin 0 -> 11669 bytes 14 files changed, 155 insertions(+), 98 deletions(-) create mode 100644 MyYearlyCountings/Models/CalDay.cs create mode 100644 MyYearlyCountings/Models/CalHour.cs create mode 100644 MyYearlyCountings/Models/CalMonth.cs create mode 100644 MyYearlyCountings/Models/CalYear.cs create mode 100644 TransactionsTest.xlsx diff --git a/MyYearlyCountings/Data/DataContext.cs b/MyYearlyCountings/Data/DataContext.cs index 1a5b8b5..a59f929 100644 --- a/MyYearlyCountings/Data/DataContext.cs +++ b/MyYearlyCountings/Data/DataContext.cs @@ -22,5 +22,9 @@ public class DataContext : DbContext public DbSet Members { get; set; } public DbSet AccountRecords { get; set; } + public DbSet CalYears { get; set; } + public DbSet CalMonths { get; set; } + public DbSet CalDays { get; set; } + public DbSet CalHours { get; set; } } diff --git a/MyYearlyCountings/Facades/IReadingIn.cs b/MyYearlyCountings/Facades/IReadingIn.cs index eed3b07..4e19e72 100644 --- a/MyYearlyCountings/Facades/IReadingIn.cs +++ b/MyYearlyCountings/Facades/IReadingIn.cs @@ -3,6 +3,6 @@ public interface IReadingIn { bool ReadAndSaveInvoices(string fullFileName); - IEnumerable ReadExcelInvoices(string fullFileName); + IEnumerable readXLS(string FilePath); } } \ No newline at end of file diff --git a/MyYearlyCountings/Facades/ReadingIn.cs b/MyYearlyCountings/Facades/ReadingIn.cs index 168853e..57cf467 100644 --- a/MyYearlyCountings/Facades/ReadingIn.cs +++ b/MyYearlyCountings/Facades/ReadingIn.cs @@ -2,8 +2,9 @@ using Microsoft.Extensions.Logging; using MyYearlyCountings.Helpers; using MyYearlyCountings.Repositories; +using OfficeOpenXml; using System.Runtime.InteropServices; -using Excel = Microsoft.Office.Interop.Excel; +//using Excel = Microsoft.Office.Interop.Excel; namespace MyYearlyCountings.Facades; @@ -25,78 +26,69 @@ public class ReadingIn : IReadingIn } // @"C:\dev\MyYearlyCountings\TransactionsTest.xls" - public IEnumerable ReadExcelInvoices(string fullFileName) + + public IEnumerable readXLS(string FilePath) { List records = new List(); AccountRecord? record = null; - - Excel.Application xlApp = new Excel.Application(); - Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(fullFileName); - Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[1]; - Excel.Range xlRange = xlWorksheet.UsedRange; - - var rowCount = xlRange.Rows.Count; - var colCount = xlRange.Columns.Count; - var prt = false; - - - //iterate over the rows and columns and print to the console as it appears in the file - //excel is not zero based!! - for (int i = 1; i <= rowCount; i++) + FileInfo existingFile = new FileInfo(FilePath); + using (ExcelPackage package = new ExcelPackage(existingFile)) { - for (int j = 1; j <= colCount; j++) + //get the first worksheet in the workbook + ExcelWorksheet worksheet = package.Workbook.Worksheets[0]; + int colCount = worksheet.Dimension.End.Column; //get Column Count + int rowCount = worksheet.Dimension.End.Row; //get row count + bool prt = false; + for (int row = 1; row <= rowCount; row++) { - //new line - if (j == 1) + if (prt) { - if (prt) - { - Console.Write("\r\n"); - records.Add(record); - } - prt = false; - + Console.WriteLine(); + records.Add(record); } - //write the value to the console - if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null) + prt = false; + for (int col = 1; col <= colCount; col++) { - string xx = xlRange.Cells[i, j].Value2.ToString(); - if ((j == 1) && xx.IsNumeric()) + if (worksheet.Cells[row, col].Value == null) { - DateTime dt = DateTime.FromOADate(xlRange.Cells[i, j].Value2); - prt = true; - if (prt) - { - Console.Write(dt.ToShortDateString() + "\t"); - record = new AccountRecord(); - record.BetalDatum = dt; - } + // Console.WriteLine(" Row:" + row + " column:" + col + " Value:" + "null"); } else { + if (col == 1 && worksheet.Cells[row, col].Value.ToString().IsDate()) + { + prt = true; + record = new AccountRecord(); + } + //Console.WriteLine(" Row:" + row + " column:" + col + " Value:" + worksheet.Cells[row, col].Value.ToString().Trim()); if (prt) { - Console.Write(xlRange.Cells[i, j].Value2.ToString() + "\t"); - switch (j) + Console.Write($"{worksheet.Cells[row, col].Value.ToString().Trim()}/t"); + switch (col) { + case 1: + { + record.BetalDatum = DateTime.Parse( worksheet.Cells[row, col].Value.ToString().Trim()); + break; + } case 3: { - record.Mottagare = xlRange.Cells[i, j].Value2.ToString(); + record.Mottagare = worksheet.Cells[row, col].Value.ToString().Trim(); break; } case 5: { - record.Konto = xlRange.Cells[i, j].Value2.ToString(); + record.Konto = worksheet.Cells[row, col].Value.ToString().Trim(); break; } case 7: { - record.Belopp = xlRange.Cells[i, j].Value2; + record.Belopp = double.Parse(worksheet.Cells[row, col].Value.ToString().Trim()); break; } case 9: { - record.Avisering = xlRange.Cells[i, j].Value2.ToString(); + record.Avisering = worksheet.Cells[row, col].Value.ToString().Trim(); break; } @@ -104,47 +96,25 @@ public class ReadingIn : IReadingIn } } } - //add useful things here! } } - - //cleanup - GC.Collect(); - GC.WaitForPendingFinalizers(); - - //rule of thumb for releasing com objects: - // never use two dots, all COM objects must be referenced and released individually - // ex: [somthing].[something].[something] is bad - - //release com objects to fully kill excel process from running in the background - Marshal.ReleaseComObject(xlRange); - Marshal.ReleaseComObject(xlWorksheet); - - //close and release - xlWorkbook.Close(); - Marshal.ReleaseComObject(xlWorkbook); - - //quit and release - xlApp.Quit(); - Marshal.ReleaseComObject(xlApp); - return records; } - public bool ReadAndSaveInvoices(string fullFileName) { var result = true; - var restab = ReadExcelInvoices(fullFileName); + var restab = readXLS(fullFileName); if (restab != null) { try { - restab.ToList().ForEach(x => { - _accountRecordRepository.AddAccountRecord(x); + restab.ToList().ForEach(x => + { + _accountRecordRepository.AddAccountRecord(x); }); -// restab.ToList().ForEach(x => { _accountRecordRepository.AddAccountRecord(x); }); + // restab.ToList().ForEach(x => { _accountRecordRepository.AddAccountRecord(x); }); } catch (Exception ex) { diff --git a/MyYearlyCountings/Helpers/Extensions.cs b/MyYearlyCountings/Helpers/Extensions.cs index b3b984f..816c0c1 100644 --- a/MyYearlyCountings/Helpers/Extensions.cs +++ b/MyYearlyCountings/Helpers/Extensions.cs @@ -11,4 +11,16 @@ public static class Extensions } else return false; } + + public static bool IsDate(this string value) { + if (!string.IsNullOrEmpty(value) && value.Length<20) + { + if (DateTime.TryParse(value, out DateTime date)) + { + return true; + } + else return false; + } + else return false; + } } diff --git a/MyYearlyCountings/Models/CalDay.cs b/MyYearlyCountings/Models/CalDay.cs new file mode 100644 index 0000000..e2b5e7e --- /dev/null +++ b/MyYearlyCountings/Models/CalDay.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyYearlyCountings.Models +{ + public class CalDay + { + public int Id { get; set; } + public int Year { get; set; } + public int Month { get; set; } + public int Day { get; set; } + public string DayName { get; set; } = string.Empty; + public string DayComment { get; set; } = string.Empty; + } +} diff --git a/MyYearlyCountings/Models/CalHour.cs b/MyYearlyCountings/Models/CalHour.cs new file mode 100644 index 0000000..9688486 --- /dev/null +++ b/MyYearlyCountings/Models/CalHour.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyYearlyCountings.Models +{ + public class CalHour + { + public int Id { get; set; } + public int Year { get; set; } + public int Month { get; set; } + public int Day { get; set; } + public int Hour { get; set; } + public string HourComment { get; set; } = string.Empty; + } +} diff --git a/MyYearlyCountings/Models/CalMonth.cs b/MyYearlyCountings/Models/CalMonth.cs new file mode 100644 index 0000000..ce9f617 --- /dev/null +++ b/MyYearlyCountings/Models/CalMonth.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyYearlyCountings.Models +{ + public class CalMonth + { + public int Id { get; set; } + public int Year { get; set; } + public int Month { get; set; } + public string MonthName { get; set; } = string.Empty; + public string MonthComment { get; set; } = string.Empty; + } +} diff --git a/MyYearlyCountings/Models/CalYear.cs b/MyYearlyCountings/Models/CalYear.cs new file mode 100644 index 0000000..6812d25 --- /dev/null +++ b/MyYearlyCountings/Models/CalYear.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyYearlyCountings.Models +{ + public class CalYear + { + public int Id { get; set; } + public int Year { get; set; } + public string YearComment { get; set; } = string.Empty; + + } +} diff --git a/MyYearlyCountings/MyYearlyCountings.csproj b/MyYearlyCountings/MyYearlyCountings.csproj index 6687585..8af53a9 100644 --- a/MyYearlyCountings/MyYearlyCountings.csproj +++ b/MyYearlyCountings/MyYearlyCountings.csproj @@ -10,18 +10,7 @@ - - tlbimp - 9 - 1 - 00020813-0000-0000-c000-000000000046 - 0 - false - true - - - - + @@ -47,7 +36,7 @@ Always - Always + PreserveNewest diff --git a/MyYearlyCountings/Program.cs b/MyYearlyCountings/Program.cs index 599bf1e..a8320b0 100644 --- a/MyYearlyCountings/Program.cs +++ b/MyYearlyCountings/Program.cs @@ -8,6 +8,9 @@ using Microsoft.Extensions.Hosting; using MyYearlyCountings.Repositories; using MyYearlyCountings.Data; using MyYearlyCountings.Facades; +using OfficeOpenXml; + +ExcelPackage.LicenseContext = LicenseContext.NonCommercial; IHost host = CreateHostBuilder(args).Build(); var worker = ActivatorUtilities.CreateInstance((IServiceProvider)host.Services); diff --git a/MyYearlyCountings/UI/KeyHandling.cs b/MyYearlyCountings/UI/KeyHandling.cs index 7144894..6e4dfc7 100644 --- a/MyYearlyCountings/UI/KeyHandling.cs +++ b/MyYearlyCountings/UI/KeyHandling.cs @@ -6,18 +6,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace MyYearlyCountings.UI +namespace MyYearlyCountings.UI; + +public class KeyHandling { - public class KeyHandling + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + + public KeyHandling(IConfiguration configuration, ILogger logger) { - private readonly IConfiguration _configuration; - private readonly ILogger _logger; - - public KeyHandling(IConfiguration configuration, ILogger logger) - { - _configuration = configuration; - _logger = logger; - } - + _configuration = configuration; + _logger = logger; } + } diff --git a/MyYearlyCountings/Worker.cs b/MyYearlyCountings/Worker.cs index 7811122..631693d 100644 --- a/MyYearlyCountings/Worker.cs +++ b/MyYearlyCountings/Worker.cs @@ -41,12 +41,18 @@ public class Worker { if (_configuration["UI"] == "XLS") { - if (!_readingIn.ReadAndSaveInvoices(@"C:\dev\MyYearlyCountings\TransactionsTest.xls")) + if (!_readingIn.ReadAndSaveInvoices(@"C:\dev\MyYearlyCountings\TransactionsTest.xlsx")) { - var resUlt = _readingIn.ReadExcelInvoices(@"C:\dev\MyYearlyCountings\TransactionsTest.xls"); + var resUlt = _readingIn.readXLS(@"C:\dev\MyYearlyCountings\TransactionsTest.xlsx"); resUlt.ToList().ForEach(rec => _logger.LogInformation($"Konto :{rec.Konto}, {rec.Belopp}")); } } + else if(_configuration["UI"] == "XLSNEW") + { + var records = _readingIn.readXLS(@"C:\dev\MyYearlyCountings\TransactionsTest.xlsx"); + records.ToList().ForEach(rec => _logger.LogInformation($"Konto :{rec.Konto}, {rec.Belopp}")); + records.ToList().ForEach(rec => _accountRecordRepository.AddAccountRecord(rec)); + } else { var ar = new AccountRecord { Konto = "BG 0867-4533", Mottagare = "NoOne", Belopp = 1270.34, BetalDatum = DateTime.Now.AddDays(10), Avisering = "Efaktura" }; diff --git a/MyYearlyCountings/appsettings.Development.json b/MyYearlyCountings/appsettings.Development.json index c552cd8..8826c54 100644 --- a/MyYearlyCountings/appsettings.Development.json +++ b/MyYearlyCountings/appsettings.Development.json @@ -1,4 +1,9 @@ { + "EPPlus": { + "ExcelPackage": { + "LicenseContext": "Polyform NonCommercial" //The license context used + } + }, "ConnectionStrings": { "DefaultConnection": "Data Source=.\\Local.db" } diff --git a/TransactionsTest.xlsx b/TransactionsTest.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9409c970430d0da2d0613f9aad1ec853a17163dc GIT binary patch literal 11669 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 VgL>Uv0092=6ZjgSU+8{a{U2NYqHzEK literal 0 HcmV?d00001