diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs index 077459e..ce0c8f3 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs @@ -1,13 +1,16 @@ using FruitBank.Common.Entities; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Azure; using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; +using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Services.Security; using Nop.Web.Areas.Admin.Controllers; using Nop.Web.Framework; using Nop.Web.Framework.Mvc.Filters; +using System.Text; namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers { @@ -17,11 +20,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers { private readonly IPermissionService _permissionService; protected readonly FruitBankDbContext _dbContext; + protected readonly AICalculationService _aiCalculationService; - public ManagementPageController(IPermissionService permissionService, FruitBankDbContext fruitBankDbContext) + public ManagementPageController(IPermissionService permissionService, FruitBankDbContext fruitBankDbContext, AICalculationService aiCalculationService) { _permissionService = permissionService; _dbContext = fruitBankDbContext; + _aiCalculationService = aiCalculationService; } public async Task Test() @@ -101,5 +106,217 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return Json(model); } + [HttpGet] + public async Task GetShippingItemsByShippingDocumentId(int shippingDocumentId) + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) + return AccessDeniedView(); + + // Mock data for now + var model = await _dbContext.ShippingItems.GetAll(true).Where(sd => sd.ShippingDocumentId == shippingDocumentId).OrderByDescending(sd => sd.Created).ToListAsync(); + var valami = model; + //model. = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId); + return Json(model); + } + + [HttpGet] + public async Task GetShippingDocumentsByShippingDocumentId(int shippingDocumentId) + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) + return AccessDeniedView(); + + // Mock data for now + var model = await _dbContext.ShippingDocumentToFiles.GetAll().Where(f => f.ShippingDocumentId == shippingDocumentId).OrderByDescending(sd => sd.Created).ToListAsync(); + var valami = model; + //model. = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId); + return Json(model); + } + + [HttpPost] + [RequestSizeLimit(10485760)] // 10MB + [RequestFormLimits(MultipartBodyLengthLimit = 10485760)] + public async Task UploadFile(UploadModel model) + { + var files = model.Files; + var shippingDocumentId = model.ShippingDocumentId; + try + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) + return Json(new { success = false, errorMessage = "Access denied" }); + + if (files == null || files.Count == 0) + return Json(new { success = false, errorMessage = "No file selected" }); + + foreach (var file in files) + { + // Validate file type (PDF only) + if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase)) + return Json(new { success = false, errorMessage = "Only PDF files are allowed" }); + + // Validate file size (max 10MB) + if (file.Length > 10 * 1024 * 1024) + return Json(new { success = false, errorMessage = "File size must be less than 10MB" }); + + // Create upload directory if it doesn't exist + var uploadsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", "shippingDocuments"); + Directory.CreateDirectory(uploadsPath); + + // Generate unique filename + var fileName = $"{Guid.NewGuid()}_{file.FileName}"; + var filePath = Path.Combine(uploadsPath, fileName); + + // Save file + using (var stream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + // Extract text with PdfPig + var pdfText = new StringBuilder(); + using (var pdf = UglyToad.PdfPig.PdfDocument.Open(filePath)) + { + foreach (var page in pdf.GetPages()) + { + pdfText.AppendLine(page.Text); + } + } + + // Log extracted text for debugging + Console.WriteLine("Extracted PDF text:"); + Console.WriteLine(pdfText.ToString()); + + // Analyze PDF with AI to extract structured data + var aiAnalysis = await _aiCalculationService.GetOpenAIPDFAnalyzisFromText( + pdfText.ToString(), + "Extract the following information from this shipping document and return as JSON: documentDate, recipientName, senderName, invoiceNumber, totalAmount, itemCount, notes. If a field is not found, return null for that field." + ); + + // Parse AI response (assuming it returns JSON) + var extractedData = ParseShippingDocumentAIResponse(aiAnalysis); + + //TODO: Save document record to database + Console.WriteLine("AI Analysis Result:"); + Console.WriteLine(extractedData.RecipientName); + Console.WriteLine(extractedData.SenderName); + Console.WriteLine(extractedData.InvoiceNumber); + Console.WriteLine(extractedData.TotalAmount); + Console.WriteLine(extractedData.ItemCount); + Console.WriteLine(extractedData.Notes); + + + var documentId = 1; // Replace with: savedDocument.Id + + // Return structured document model + var documentModel = new ShippingDocumentModel + { + Id = documentId, + ShippingId = shippingDocumentId, + FileName = file.FileName, + FilePath = $"/uploads/shippingDocuments/{fileName}", + FileSize = (int)(file.Length / 1024), + DocumentDate = extractedData.DocumentDate, + RecipientName = extractedData.RecipientName, + SenderName = extractedData.SenderName, + InvoiceNumber = extractedData.InvoiceNumber, + TotalAmount = extractedData.TotalAmount, + ItemCount = extractedData.ItemCount, + Notes = extractedData.Notes, + RawAIAnalysis = aiAnalysis // Store the raw AI response for debugging + }; + + } + + // var savedDocument = await _documentService.InsertDocumentAsync(document); + + // Mock saved document ID + + + //return Json(new + //{ + // success = true, + // document = documentModel + //}); + + return Ok($"Files for Shipping Document ID {shippingDocumentId} were uploaded successfully!"); + } + catch (Exception ex) + { + Console.WriteLine($"Error uploading file: {ex}"); + //return Json(new { success = false, errorMessage = ex.Message }); + return BadRequest("No files were uploaded."); + } + } + + private ExtractedDocumentData ParseShippingDocumentAIResponse(string aiResponse) + { + try + { + // Try to parse as JSON first + var data = System.Text.Json.JsonSerializer.Deserialize( + aiResponse, + new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true } + ); + return data ?? new ExtractedDocumentData(); + } + catch + { + // If JSON parsing fails, return empty data with the raw response in notes + return new ExtractedDocumentData + { + Notes = $"AI Analysis (raw): {aiResponse}" + }; + } + } + + // Helper class for extracted data + private class ExtractedDocumentData + { + public DateTime? DocumentDate { get; set; } + public string RecipientName { get; set; } + public string SenderName { get; set; } + public string InvoiceNumber { get; set; } + public decimal? TotalAmount { get; set; } + public int? ItemCount { get; set; } + public string Notes { get; set; } + } + + [HttpPost] + public async Task DeleteUploadedFile(string filePath) + { + try + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) + return Json(new { success = false, message = "Access denied" }); + + if (string.IsNullOrEmpty(filePath)) + return Json(new { success = false, message = "Invalid file path" }); + + // TODO: Delete document record from database first + // var document = await _documentService.GetDocumentByFilePathAsync(filePath); + // if (document != null) + // await _documentService.DeleteDocumentAsync(document); + + var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", filePath.TrimStart('/')); + + if (System.IO.File.Exists(fullPath)) + { + System.IO.File.Delete(fullPath); + return Json(new { success = true }); + } + + return Json(new { success = false, message = "File not found" }); + } + catch (Exception ex) + { + return Json(new { success = false, message = ex.Message }); + } + } + + } + + public class UploadModel + { + public int ShippingDocumentId { get; set; } + public List Files { get; set; } } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ShippingController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ShippingController.cs index 4cbc8a6..2215faf 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ShippingController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ShippingController.cs @@ -380,14 +380,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers Console.WriteLine($"Error uploading file: {ex}"); return Json(new { success = false, errorMessage = ex.Message }); } - } - - //public IActionResult ReloadPartialView() - //{ - // // ... (logic to get updated data for the partial view) ... - // var model = new ShippingDocumentListModel(); - // return PartialView("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Components/_DocumentsGridPartial.cshtml", model); - //} + } private ExtractedDocumentData ParseShippingDocumentAIResponse(string aiResponse) { diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml index 86c1076..d9b544d 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml @@ -7,36 +7,41 @@ }
- @(Html.DevExtreme().DataGrid() - .ID(Model.Id.ToString()) - .ShowBorders(true) - .DataSource(ds => ds.Mvc() - .Controller("ManagementPage") - .LoadAction("GetShippingDocuments")) - .KeyExpr("Id") - .SearchPanel(sp => sp.Visible(true)) - .HeaderFilter(hf => hf.Visible(true)) - .Paging(p => p.PageSize(15)) - .Pager(p => p.Visible(true)) - .OnRowExpanded("onRowExpanded") - .Editing(editing => { - editing.Mode(GridEditMode.Cell); - editing.AllowUpdating(true); - editing.AllowAdding(true); - editing.AllowDeleting(true); - }) - .Columns(c => { - - c.Add().DataField("Id").AllowEditing(false); - c.Add().DataField("PartnerId"); + @( + Html.DevExtreme().DataGrid() + .ID("orderDataGridContainer") + .ShowBorders(true) + .DataSource(ds => ds.Mvc() + .Controller("ManagementPage") + .LoadAction("GetShippingDocuments")) + .KeyExpr("Id") + .SearchPanel(sp => sp.Visible(true)) + .HeaderFilter(hf => hf.Visible(true)) + .Paging(p => p.PageSize(15)) + .Pager(p => p.Visible(true)) + .OnRowExpanded("onRowExpanded") + .Editing(editing => { + editing.Mode(GridEditMode.Cell); + editing.AllowUpdating(true); + editing.AllowAdding(true); + editing.AllowDeleting(true); + }) + .Columns(c => { + + c.Add().DataField("Id").AllowEditing(false); + c.Add().DataField("Partner.Name").AllowEditing(false); + c.Add() + .Caption("Items in order") + .DataType(GridColumnDataType.Number) + .CalculateCellValue("calculateItemsCount").AllowEditing(false); + c.Add().DataField("PartnerId"); c.Add().DataField("DocumentIdNumber"); c.Add().DataField("IsAllMeasured"); - @* c.AddFor(m => m.Partner.Name); *@ - + c.Add() .Caption("Completed") .DataType(GridColumnDataType.Boolean) - .CalculateCellValue("calculateCellValue"); + .CalculateCellValue("calculateCellValue").AllowEditing(false); }) .Toolbar(toolbar => { toolbar.Items(items => { @@ -131,21 +136,29 @@