Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ShippingController.cs

509 lines
21 KiB
C#

using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using FruitBank.Common.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Messages;
using Nop.Services.Security;
using Nop.Web.Areas.Admin.Controllers;
using Nop.Web.Areas.Admin.Models.Orders;
using Nop.Web.Framework;
using Nop.Web.Framework.Models;
using Nop.Web.Framework.Models.Extensions;
using Nop.Web.Framework.Mvc.Filters;
using System.Text;
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
{
[Area(AreaNames.ADMIN)]
[AuthorizeAdmin]
public class ShippingController : BaseAdminController
{
private readonly IPermissionService _permissionService;
protected readonly INotificationService _notificationService;
protected readonly ShippingItemDbTable _shippingItemDbTable;
protected readonly ShippingDbTable _shippingDbTable;
protected readonly ShippingDocumentDbTable _shippingDocumentDbTable;
protected readonly FruitBankDbContext _dbContext;
protected readonly AICalculationService _aiCalculationService;
public ShippingController(IPermissionService permissionService, INotificationService notificationService, ShippingItemDbTable shippingItemDbTable, ShippingDbTable shippingDbTable, ShippingDocumentDbTable shippingDocumentDbTable, FruitBankDbContext dbContext, AICalculationService aICalculationService)
{
_permissionService = permissionService;
_notificationService = notificationService;
_shippingItemDbTable = shippingItemDbTable;
_shippingDbTable = shippingDbTable;
_shippingDocumentDbTable = shippingDocumentDbTable;
_dbContext = dbContext;
//_shippingModelFactory = shippingModelFactory;
_aiCalculationService = aICalculationService;
}
[HttpGet]
public async Task<IActionResult> List()
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
// Create model and load data
var model = new ShippingListModel();
// TODO: Replace with your actual service call
// model.ShippingList = await _shippingService.GetAllShippingsAsync();
// Mock data for now
model.ShippingList = _dbContext.Shippings.GetAll(true).ToList();
var valami = model;
//model. = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId);
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/List.cshtml", model);
}
[HttpPost]
public async Task<IActionResult> List(ShippingListModel model)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
// Apply filters to mock data
model.ShippingList = _shippingDbTable.GetAll().ToList();
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/List.cshtml", model);
}
[HttpGet]
public async Task<IActionResult> ShippingDocumentList()
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
// Create model and load data
//var model = _shippingDocumentDbTable.GetAll().ToList();
var model = _dbContext.ShippingDocuments.GetAll(true).ToList();
// TODO: Replace with your actual service call
// model.ShippingList = await _shippingService.GetAllShippingsAsync();
// Mock data for now
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/List.cshtml", model);
}
[HttpPost]
public async Task<IActionResult> ShippingDocumentList(int shippingId)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
// Apply filters to mock data
var model = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId);
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/List.cshtml", model);
}
//TODO IMPLEMENT DEVEXTREME FILETRING AND LOADING
//[HttpGet]
//public async Task<IActionResult> GetDocumentByShippingId(int shippingId, DataSourceLoadOptions loadOptions)
//{
// // 1. Get the IQueryable from your service.
// // This is the key step. It's more efficient to work with IQueryable
// // so that filtering, sorting, and paging are done by the database.
// var documentQuery = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId);
// // 2. Process the data using DevExtreme.AspNet.Data.
// // This is where all the magic happens. The Load method takes care of
// // applying all the grid's client-side settings (sorting, filtering,
// // grouping, paging) to your data query.
// var loadResult = DataSourceLoader.Load(documentQuery, loadOptions);
// // 3. Return the result in the format DevExtreme expects.
// return Json(loadResult);
//}
[HttpGet]
public async Task<IActionResult> GetShippingDocumentsByShippingId(int shippingId)
{
var result = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId);
// 3. Return the result in the format DevExtreme expects.
return Json(result);
}
[HttpPost]
public async Task<IActionResult> Delete(int id)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return Json(new { success = false, message = "Access denied" });
try
{
// TODO: Implement actual deletion
return Json(new { success = true, message = "Shipment deleted successfully" });
}
catch (Exception ex)
{
return Json(new { success = false, message = ex.Message });
}
}
[HttpGet]
public async Task<IActionResult> Create()
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
var model = new CreateShippingModel
{
ShippingDate = DateTime.Now
};
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Create.cshtml", model);
}
[HttpPost]
public async Task<IActionResult> Create(CreateShippingModel model)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
if (!ModelState.IsValid)
{
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Create.cshtml", model);
}
string licencePlate = "";
if (model.LicencePlate.Length > 3)
{
licencePlate = model.LicencePlate?.Trim().ToUpper() ?? string.Empty;
}
try
{
var shipment = new Shipping
{
LicencePlate = licencePlate,
ShippingDate = model.ShippingDate,
IsAllMeasured = false,
};
await _shippingDbTable.InsertAsync(shipment);
_notificationService.SuccessNotification($"Shipment created successfully. You can now upload documents. Shipping Id: {shipment.Id}");
// Redirect to Edit action where user can upload files
return RedirectToAction("Edit", new { id = shipment.Id });
}
catch (Exception ex)
{
_notificationService.ErrorNotification($"Error creating shipment: {ex.Message}");
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Create.cshtml", model);
}
}
[HttpGet]
public async Task<IActionResult> Edit(int id)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
try
{
// TODO: Load shipment from database
var shipment = await _shippingDbTable.GetByIdAsync(id);
if (shipment == null)
return RedirectToAction("List");
// TODO: Load existing documents
// var documents = await _documentService.GetShipmentDocumentsAsync(id);
// For now, create a mock model
var model = new EditShippingModel
{
Id = shipment.Id,
ShippingDate = shipment.ShippingDate, // Replace with: shipment.ShipmentDate
LicencePlate = shipment.LicencePlate, // Replace with: shipment.TrackingNumber
ExistingDocuments = new List<ShippingDocumentModel>()
// Replace with: documents.Select(d => new ShipmentDocumentModel { ... }).ToList()
};
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Edit.cshtml", model);
}
catch (Exception ex)
{
_notificationService.ErrorNotification($"Error loading shipment: {ex.Message}");
return RedirectToAction("List");
}
}
[HttpPost]
public async Task<IActionResult> Edit(EditShippingModel model)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
if (!ModelState.IsValid)
{
// Reload existing documents if validation fails
// model.ExistingDocuments = await LoadExistingDocuments(model.Id);
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Edit.cshtml", model);
}
try
{
// TODO: Update shipment in database
// var shipment = await _shipmentService.GetShipmentByIdAsync(model.Id);
// shipment.Name = model.ShipmentName;
// shipment.Description = model.Description;
// shipment.ShipmentDate = model.ShipmentDate;
// shipment.TrackingNumber = model.TrackingNumber;
// await _shipmentService.UpdateShippingAsync(shipment);
_notificationService.SuccessNotification("Shipment updated successfully");
return RedirectToAction("Edit", new { id = model.Id });
}
catch (Exception ex)
{
_notificationService.ErrorNotification($"Error updating shipment: {ex.Message}");
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Shipping/Edit.cshtml", model);
}
}
[HttpPost]
[RequestSizeLimit(10485760)] // 10MB
[RequestFormLimits(MultipartBodyLengthLimit = 10485760)]
public async Task<IActionResult> UploadFile(IFormFile file, int shippingId)
{
try
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return Json(new { success = false, errorMessage = "Access denied" });
if (file == null || file.Length == 0)
return Json(new { success = false, errorMessage = "No file selected" });
// 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 savedDocument = await _documentService.InsertDocumentAsync(document);
// Mock saved document ID
var documentId = 1; // Replace with: savedDocument.Id
// Return structured document model
var documentModel = new ShippingDocumentModel
{
Id = documentId,
ShippingId = shippingId,
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
};
return Json(new
{
success = true,
document = documentModel
});
}
catch (Exception ex)
{
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)
{
try
{
// Try to parse as JSON first
var data = System.Text.Json.JsonSerializer.Deserialize<ExtractedDocumentData>(
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<IActionResult> 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 });
}
}
[HttpPost]
public async Task<IActionResult> DeleteDocument(int documentId)
{
try
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return Json(new DocumentOperationResult { Success = false, Message = "Access denied" });
// TODO: Implement document deletion
// var document = await _documentService.GetDocumentByIdAsync(documentId);
// if (document == null)
// return Json(new DocumentOperationResult { Success = false, Message = "Document not found" });
// Delete physical file
// var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", document.FilePath.TrimStart('/'));
// if (System.IO.File.Exists(fullPath))
// System.IO.File.Delete(fullPath);
// Delete database record
// await _documentService.DeleteDocumentAsync(document);
return Json(new DocumentOperationResult
{
Success = true,
Message = "Document deleted successfully",
DocumentId = documentId
});
}
catch (Exception ex)
{
return Json(new DocumentOperationResult { Success = false, Message = ex.Message });
}
}
// Helper method for loading existing documents (to be implemented)
// private async Task<List<ShipmentDocumentModel>> LoadExistingDocuments(int shipmentId)
// {
// var documents = await _documentService.GetShipmentDocumentsAsync(shipmentId);
// return documents.Select(d => new ShipmentDocumentModel
// {
// Id = d.Id,
// ShipmentId = d.ShipmentId,
// FileName = d.FileName,
// FilePath = d.FilePath,
// FileSize = d.FileSize,
// UploadDate = d.UploadDate,
// ContentType = d.ContentType,
// IsActive = d.IsActive
// }).ToList();
// }
}
}