devexpress management
This commit is contained in:
parent
f084c3ab7f
commit
631bcdd290
|
|
@ -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<IActionResult> Test()
|
||||
|
|
@ -101,5 +106,217 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
return Json(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<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 });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class UploadModel
|
||||
{
|
||||
public int ShippingDocumentId { get; set; }
|
||||
public List<IFormFile> Files { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,36 +7,41 @@
|
|||
}
|
||||
|
||||
<div>
|
||||
@(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 @@
|
|||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab">
|
||||
@(Html.DevExtreme().FileUploader()
|
||||
.ID(new JS("'shippingDocumentUploader-' + data.Id"))
|
||||
.Name("myFile")
|
||||
.Multiple(true)
|
||||
.Accept("application/pdf")
|
||||
.UploadMode(FileUploadMode.Instantly)
|
||||
.UploadUrl(Url.Action("UploadFile", "Shipping"))
|
||||
.OnValueChanged("fileUploader_valueChanged")
|
||||
.OnUploaded("fileUploader_fileUploaded")
|
||||
)
|
||||
<div class="content" id="selected-files">
|
||||
<div>
|
||||
<h4>Selected Files</h4>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" asp-controller="ManagementPage" asp-action="UploadFile">
|
||||
@(Html.DevExtreme().FileUploader()
|
||||
.ID(new JS("'shippingDocumentUploader-' + data.Id"))
|
||||
.Name("files")
|
||||
.Multiple(true)
|
||||
.Accept("application/pdf")
|
||||
.UploadMode(FileUploadMode.UseForm)
|
||||
)
|
||||
|
||||
<input type="hidden" name="ShippingDocumentId" value="<%- data.Id %>" />
|
||||
|
||||
@(Html.DevExtreme().Button()
|
||||
.Text("Upload Files")
|
||||
.Type(ButtonType.Success)
|
||||
.UseSubmitBehavior(true)
|
||||
)
|
||||
</form>
|
||||
|
||||
<div class="content" id="selected-files">
|
||||
<div>
|
||||
<h4>Selected Files</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* <div id="@(new JS("'shippingDocumentGridContainer-' + data.ID"))"></div>
|
||||
@(Html.DevExtreme().DataGrid<FruitBank.Common.Entities.ShippingDocument>()
|
||||
|
|
@ -193,6 +206,12 @@
|
|||
return rowData.Status === "Completed";
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function calculateItemsCount(rowData) {
|
||||
return rowData.ShippingItems.length;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
function onDeleteBtnClick(){
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
using System.Text.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Models
|
||||
{
|
||||
public class AIChatRequestBase
|
||||
{
|
||||
[JsonProperty("model")]
|
||||
[JsonPropertyName("model")]
|
||||
public string Model { get; set; } = "gpt-4o-mini";
|
||||
[JsonProperty("temperature")]
|
||||
|
||||
[JsonPropertyName("temperature")]
|
||||
public double Temperature { get; set; } = 0.2;
|
||||
[JsonProperty("messages")]
|
||||
|
||||
[JsonPropertyName("messages")]
|
||||
public AIChatMessage[] Messages { get; set; } = Array.Empty<AIChatMessage>();
|
||||
[JsonProperty("stream")]
|
||||
|
||||
[JsonPropertyName("stream")]
|
||||
public bool Stream { get; set; } = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
private readonly CerebrasAPIService _cerebrasApiService;
|
||||
private readonly OpenAIApiService _openAIApiService;
|
||||
private readonly IStoreContext _storeContext;
|
||||
public AICalculationService(CerebrasAPIService cerebrasApiService, IStoreContext storeContext)
|
||||
public AICalculationService(CerebrasAPIService cerebrasApiService, IStoreContext storeContext, OpenAIApiService openAIApiService)
|
||||
{
|
||||
_cerebrasApiService = cerebrasApiService;
|
||||
_storeContext = storeContext;
|
||||
_openAIApiService = openAIApiService;
|
||||
}
|
||||
|
||||
public async Task<string> GetWelcomeMessageAsync(Customer customer)
|
||||
|
|
@ -32,14 +33,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
|
||||
string userMessage = "Hello";
|
||||
|
||||
var response = await _cerebrasApiService.GetSimpleResponseAsync(systemMessage, userMessage);
|
||||
var response = await _openAIApiService.GetSimpleResponseAsync(systemMessage, userMessage);
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task<string> GetOpenAIPDFAnalyzisFromText(string pdfText, string userQuestion)
|
||||
{
|
||||
string systemMessage = $"You are a helpful assistant of a webshop, you work in the administration area, with the ADMIN user. The ADMIN user is asking you questions about a PDF document, that you have access to. The content of the PDF document is the following: {pdfText}";
|
||||
var response = await _cerebrasApiService.GetSimpleResponseAsync(systemMessage, userQuestion);
|
||||
var response = await _openAIApiService.GetSimpleResponseAsync(systemMessage, userQuestion);
|
||||
|
||||
var fixedResponse = TextHelper.FixJsonWithoutAI(response);
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
new AIChatMessage { Role = "assistant", Content = assistantMessage },
|
||||
new AIChatMessage { Role = "user", Content = userMessage }
|
||||
},
|
||||
Stream = false
|
||||
Stream = true
|
||||
};
|
||||
|
||||
var requestJson = JsonSerializer.Serialize(requestBody, new JsonSerializerOptions
|
||||
|
|
@ -175,7 +175,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
new AIChatMessage { Role = "assistant", Content = assistantMessage },
|
||||
new AIChatMessage { Role = "user", Content = userMessage }
|
||||
},
|
||||
Stream = false
|
||||
Stream = true
|
||||
};
|
||||
|
||||
var requestJson = JsonSerializer.Serialize(requestBody, new JsonSerializerOptions
|
||||
|
|
|
|||
Loading…
Reference in New Issue