From 1da4b1e7513c47edabe6b28fe77b1d79802fddb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20=C5=A0taleker?= Date: Sat, 28 Feb 2026 12:25:39 +0100 Subject: [PATCH] import excel na novo z izpiso napak --- .../Projects/CreatePartItemImportExcel.cshtml | 211 ++++++++++++++---- .../CreatePartItemImportExcel.cshtml.cs | 157 ++++++++++--- .../Projects/CreatePartItemUploadExcel.cshtml | 50 ----- .../CreatePartItemUploadExcel.cshtml.cs | 131 ----------- EveryThing/Pages/Projects/Edit.cshtml | 2 +- 5 files changed, 301 insertions(+), 250 deletions(-) delete mode 100644 EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml delete mode 100644 EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml.cs diff --git a/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml b/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml index f257e92..e8de1d5 100644 --- a/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml +++ b/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml @@ -7,65 +7,200 @@ Layout = "~/Pages/Layouts/_Layout.cshtml"; } -
+

+ + Projekt / Uvoz pozicij dela projekta + +

-

- - Projekt / Uvoz pozicij dela projekta - -

- -
-
-
+
+
+
+ +
- Povezovanje @Model.FileName z pozicijo + Podatki pozicije
- - - -
- @{ - foreach (var item in Model.ExcelItems) - { -
- - -
- } - } +
+ +
+
+ + +
+
+ +
+
-
- - +@Html.AntiForgeryToken() @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} } diff --git a/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml.cs b/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml.cs index ee15c53..a908eb2 100644 --- a/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml.cs +++ b/EveryThing/Pages/Projects/CreatePartItemImportExcel.cshtml.cs @@ -48,31 +48,48 @@ namespace EveryThing.Pages.Projects public string SelectedItems { get; set; } - public IActionResult OnGet(int idProject, int idProjectPart, string fileName) + public IActionResult OnGet(int idProject, int idProjectPart) { - var user = _userManager.GetUserAsync(User).Result; - IdProject = idProject; IdProjectPart = idProjectPart; - FileName = fileName; - - var tmpList = typeof(Models.Project.ProjectPartItem).GetProperties() - .Where(x => x.GetCustomAttributes(true).Length > 0 && x.GetCustomAttributes(true).Any(y => y.GetType() == typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))) - .Select(x => new - { - Name = x.Name, - Display = ((System.ComponentModel.DataAnnotations.DisplayAttribute)x.GetCustomAttributes(true).First(y => y.GetType() == typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))).Name - }).ToList(); - tmpList.Insert(0, new { Name = "", Display = "Ni izbrano" }); - - ViewData["ProjectPartItems"] = new SelectList(tmpList, "Name", "Display"); - ExcelItems = new List(); - var path = Path.Combine(_hostingEnvironment.WebRootPath, "Uploads", "TempExcelImport", fileName); - var xlWorkbook = new XLWorkbook(path); - - //ONLY FIRST LIST + return Page(); + } + + public async Task OnPostUpload(int idProject, int idProjectPart, List postedFiles) + { + if (postedFiles == null + || postedFiles.Count != 1) + { + return new JsonResult(new { successful = false, error = "Izberite eno datoteko." }); + } + var path = Path.Combine(_hostingEnvironment.WebRootPath, "Uploads", "TempExcelImport"); + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + else + { + //Pocistimo mapo + foreach (var fileInfo in new DirectoryInfo(path).GetFiles("*.*")) + { + fileInfo.Delete(); + } + } + + var postedFile = postedFiles[0]; + + var fileName = postedFile.FileName; + await using (var stream = new FileStream(Path.Combine(path, fileName), FileMode.Create)) + { + await postedFile.CopyToAsync(stream); + } + + // Read excel headers + var excelItems = new List(); + var filePath = Path.Combine(path, fileName); + var xlWorkbook = new XLWorkbook(filePath); var worksheet = xlWorkbook.Worksheet(1); int i = 1; @@ -82,26 +99,36 @@ namespace EveryThing.Pages.Projects int j = 1; while (!row.Cell(j).IsEmpty()) { - var cellData = row.Cell(j).Value; - - ExcelItems.Add(new ExcelItem + excelItems.Add(new ExcelItem { CellIndex = j, - Name = cellData.ToString(), + Name = row.Cell(j).Value.ToString(), }); - j++; } } - return Page(); + // Build mapping options + var mappingOptions = typeof(Models.Project.ProjectPartItem).GetProperties() + .Where(x => x.GetCustomAttributes(true).Length > 0 && x.GetCustomAttributes(true).Any(y => y.GetType() == typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))) + .Select(x => new + { + name = x.Name, + display = ((System.ComponentModel.DataAnnotations.DisplayAttribute)x.GetCustomAttributes(true).First(y => y.GetType() == typeof(System.ComponentModel.DataAnnotations.DisplayAttribute))).Name + }).ToList(); + + return new JsonResult(new { successful = true, fileName, excelItems, mappingOptions }); } - public async Task OnPostAsync(string selectedItems) + public async Task OnPostImport(string selectedItems, string fileName, int idProjectPart, int idProject) { - if (selectedItems == "") + FileName = fileName; + IdProjectPart = idProjectPart; + IdProject = idProject; + + if (string.IsNullOrEmpty(selectedItems)) { - return Page(); //TODO Error + return new JsonResult(new { successful = false, error = "Izberite vsaj eno polje." }); } var user = _userManager.GetUserAsync(User).Result; @@ -128,6 +155,73 @@ namespace EveryThing.Pages.Projects //ONLY FIRST LIST var worksheet = xlWorkbook.Worksheet(1); + // Build display name lookup for properties + var propertyDisplayNames = typeof(Models.Project.ProjectPartItem).GetProperties() + .Where(x => x.GetCustomAttributes(true).Any(y => y is System.ComponentModel.DataAnnotations.DisplayAttribute)) + .ToDictionary( + x => x.Name, + x => ((System.ComponentModel.DataAnnotations.DisplayAttribute)x.GetCustomAttributes(true).First(y => y is System.ComponentModel.DataAnnotations.DisplayAttribute)).Name + ); + + // Validation pass - check all rows before importing + var errors = new List(); + int validationRow = 2; // Skip header + while (!worksheet.Row(validationRow).IsEmpty()) + { + IXLRow row = worksheet.Row(validationRow); + + // Check if all mapped cells in the row are empty + bool allEmpty = excelItems.All(ei => + row.Cell(ei.CellIndex) == null || string.IsNullOrWhiteSpace(row.Cell(ei.CellIndex).Value.ToString())); + + if (allEmpty) + { + errors.Add(new { row = validationRow, property = "-", value = "", message = "Vsa polja v vrstici so prazna." }); + validationRow++; + continue; + } + + foreach (var excelItem in excelItems) + { + if (row.Cell(excelItem.CellIndex) == null) + continue; + + string value = row.Cell(excelItem.CellIndex).Value.ToString(); + string displayName = propertyDisplayNames.ContainsKey(excelItem.Name) ? propertyDisplayNames[excelItem.Name] : excelItem.Name; + + // Empty individual cells are allowed - skip validation + if (string.IsNullOrWhiteSpace(value)) + continue; + + if (excelItem.Name is "IdItemFk" or "IdMaterialFk" or "IdMaterialSupplierFk") + { + // These are text lookups, no type conversion needed + continue; + } + + // Validate type conversion for other properties + var propertyInfo = typeof(Models.Project.ProjectPartItem).GetProperties().FirstOrDefault(x => x.Name == excelItem.Name); + if (propertyInfo != null) + { + try + { + var targetType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType; + Convert.ChangeType(value, targetType); + } + catch + { + errors.Add(new { row = validationRow, property = displayName, value, message = $"Ni mogoče pretvoriti v tip {propertyInfo.PropertyType.Name}." }); + } + } + } + validationRow++; + } + + if (errors.Count > 0) + { + return new JsonResult(new { successful = false, validationErrors = errors }); + } + var insertedParts = _context.ProjectPartItems.Where(x => x.IdProjectPartFk == IdProjectPart); var currentPositionNumber = insertedParts.Any() @@ -158,6 +252,9 @@ namespace EveryThing.Pages.Projects string value = row.Cell(excelItem.CellIndex).Value.ToString(); + if (string.IsNullOrWhiteSpace(value)) + continue; + if (excelItem.Name is "IdItemFk" or "IdMaterialFk") { var completableItem = _context.CodeTableItems.FirstOrDefault(x => x.Title == value && x.Active == true); @@ -218,7 +315,7 @@ namespace EveryThing.Pages.Projects System.IO.File.Delete(path); - return RedirectToPage("./Edit", new {id = IdProject}); + return new JsonResult(new { successful = true, redirectUrl = Url.Page("./Edit", new { id = IdProject }) }); } public class ExcelItem diff --git a/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml b/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml deleted file mode 100644 index f73b834..0000000 --- a/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml +++ /dev/null @@ -1,50 +0,0 @@ -@page -@using EveryThing.Models.Project -@model EveryThing.Pages.Projects.CreatePartItemUploadExcelModel - -@{ - ViewData["Title"] = "Uvoz pozicij dela projekta"; - Layout = "~/Pages/Layouts/_Layout.cshtml"; -} - -
- -

- - Projekt / Uvoz pozicij dela projekta - -

- -
-
-
-
- Podatki pozicije -
-
- - -
-
-
- - -
-
-
-
- -
-
-
- -
- -
- -@section Scripts { - @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} -} diff --git a/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml.cs b/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml.cs deleted file mode 100644 index 7ce5754..0000000 --- a/EveryThing/Pages/Projects/CreatePartItemUploadExcel.cshtml.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Mvc.Rendering; -using EveryThing.Data; -using EveryThing.Models; -using EveryThing.Models.Project; -using Microsoft.AspNetCore.Http; -using System.IO; -using Microsoft.AspNetCore.Hosting; - -namespace EveryThing.Pages.Projects -{ - [Authorize(Roles = "Administrator,ProjecThingUser")] - public class CreatePartItemUploadExcelModel : PageModel - { - private readonly IWebHostEnvironment _hostingEnvironment; - private readonly ApplicationDbContext _context; - private readonly UserManager _userManager; - private readonly SignInManager _loginManager; - private readonly RoleManager _roleManager; - - public CreatePartItemUploadExcelModel(ApplicationDbContext context, UserManager userManager, SignInManager loginManager, RoleManager roleManager, IWebHostEnvironment environment) - { - _context = context; - _userManager = userManager; - _loginManager = loginManager; - _roleManager = roleManager; - _hostingEnvironment = environment; - } - - - [BindProperty] - public IFormFile File { get; set; } - [BindProperty] - public int IdProject { get; set; } - [BindProperty] - public int IdProjectPart { get; set; } - - - public IActionResult OnGet(int idProject, int idProjectPart) - { - var user = _userManager.GetUserAsync(User).Result; - - IdProject = idProject; - IdProjectPart = idProjectPart; - - - return Page(); - } - - //public async Task OnPostAsync() - //{ - // if (!ModelState.IsValid) - // { - // return Page(); - // } - // string uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads"); - - // if (File.Length > 0) - // { - // string filePath = Path.Combine(uploads, File.FileName); - // using (Stream fileStream = new FileStream(filePath, FileMode.Create)) - // { - // await File.CopyToAsync(fileStream); - // } - // } - - // return RedirectToPage("./Edit"); - //} - - //public async Task OnPostUploadAsync(List files) - //{ - // long size = files.Sum(f => f.Length); - - // foreach (var formFile in files) - // { - // if (formFile.Length > 0) - // { - // var filePath = Path.GetTempFileName(); - // System.Diagnostics.Debug.WriteLine(filePath); - // using (var stream = System.IO.File.Create(filePath)) - // { - // await formFile.CopyToAsync(stream); - // } - // } - // } - - // // Process uploaded files - // // Don't rely on or trust the FileName property without validation. - - // return RedirectToPage("./Edit"); - //} - - public async Task OnPostUpload(int idProject, int idProjectPart, List postedFiles) - { - if (postedFiles == null - || postedFiles.Count != 1) - { - return Page();//TODO return error - } - var path = Path.Combine(_hostingEnvironment.WebRootPath, "Uploads", "TempExcelImport"); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - else - { - //Pocistimo mapo - foreach (var fileInfo in new DirectoryInfo(path).GetFiles("*.*")) - { - fileInfo.Delete(); - } - } - - var postedFile = postedFiles[0]; - - var fileName = postedFile.FileName;//Guid.NewGuid().ToString().Replace("-", "_") + Path.GetExtension(postedFile.FileName); - await using (var stream = new FileStream(Path.Combine(path, fileName), FileMode.Create)) - { - await postedFile.CopyToAsync(stream); - } - return RedirectToPage("./CreatePartItemImportExcel", new { idProject = idProject, idProjectPart = idProjectPart, fileName = fileName}); - } - } -} diff --git a/EveryThing/Pages/Projects/Edit.cshtml b/EveryThing/Pages/Projects/Edit.cshtml index e1242cf..458fc5e 100644 --- a/EveryThing/Pages/Projects/Edit.cshtml +++ b/EveryThing/Pages/Projects/Edit.cshtml @@ -727,7 +727,7 @@