merge
This commit is contained in:
commit
9b0afb2d2c
|
|
@ -183,7 +183,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
OrderStatusIds = orderStatuses,
|
||||
PaymentStatusIds = paymentStatuses,
|
||||
ShippingStatusIds = shippingStatuses,
|
||||
});
|
||||
AvailablePageSizes = "20,50,100,500",
|
||||
|
||||
});
|
||||
|
||||
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/List.cshtml", model);
|
||||
}
|
||||
|
|
@ -234,12 +236,79 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/Edit.cshtml", model);
|
||||
}
|
||||
|
||||
//public async Task<OrderListModelExtended> GetOrderListModelByFilter(OrderSearchModelExtended searchModel)
|
||||
//{
|
||||
// //return _customOrderService.
|
||||
// var orderListModel = await _orderModelFactory.PrepareOrderListModelExtendedAsync(searchModel);
|
||||
|
||||
// _logger.Detail($"Total: {orderListModel.RecordsTotal}, Data Count: {orderListModel.Data.Count()}");
|
||||
// foreach (var item in orderListModel.Data.Take(3))
|
||||
// {
|
||||
// _logger.Detail($"Order: {item.Id}, {item.CustomOrderNumber}");
|
||||
// }
|
||||
|
||||
// return orderListModel;
|
||||
//}
|
||||
|
||||
public async Task<OrderListModelExtended> GetOrderListModelByFilter(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
//return _customOrderService.
|
||||
|
||||
var sortColumnIndex = Request.Form["order[0][column]"].FirstOrDefault();
|
||||
var sortDirection = Request.Form["order[0][dir]"].FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrEmpty(sortColumnIndex))
|
||||
{
|
||||
// Get the column name from the column index
|
||||
var columnName = Request.Form[$"columns[{sortColumnIndex}][data]"].FirstOrDefault();
|
||||
|
||||
searchModel.SortColumn = columnName;
|
||||
searchModel.SortColumnDirection = sortDirection; // "asc" or "desc"
|
||||
}
|
||||
|
||||
// Get the paginated data
|
||||
var orderListModel = await _orderModelFactory.PrepareOrderListModelExtendedAsync(searchModel);
|
||||
|
||||
_logger.Detail($"Total: {orderListModel.RecordsTotal}, Data Count: {orderListModel.Data.Count()}");
|
||||
|
||||
// Apply sorting if specified
|
||||
if (!string.IsNullOrEmpty(searchModel.SortColumn) && orderListModel.Data.Any())
|
||||
{
|
||||
var sortedData = orderListModel.Data.AsQueryable();
|
||||
|
||||
sortedData = searchModel.SortColumn.ToLowerInvariant() switch
|
||||
{
|
||||
"id" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.Id)
|
||||
: sortedData.OrderByDescending(o => o.Id),
|
||||
"customercompany" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.CustomerCompany)
|
||||
: sortedData.OrderByDescending(o => o.CustomerCompany),
|
||||
"customordernumber" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.CustomOrderNumber)
|
||||
: sortedData.OrderByDescending(o => o.CustomOrderNumber),
|
||||
"ordertotal" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.OrderTotal)
|
||||
: sortedData.OrderByDescending(o => o.OrderTotal),
|
||||
"createdon" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.CreatedOn)
|
||||
: sortedData.OrderByDescending(o => o.CreatedOn),
|
||||
"orderstatusid" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.OrderStatusId)
|
||||
: sortedData.OrderByDescending(o => o.OrderStatusId),
|
||||
"paymentstatusid" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.PaymentStatusId)
|
||||
: sortedData.OrderByDescending(o => o.PaymentStatusId),
|
||||
"shippingstatusid" => searchModel.SortColumnDirection == "asc"
|
||||
? sortedData.OrderBy(o => o.ShippingStatusId)
|
||||
: sortedData.OrderByDescending(o => o.ShippingStatusId),
|
||||
_ => sortedData
|
||||
};
|
||||
|
||||
orderListModel.Data = sortedData.ToList();
|
||||
|
||||
_logger.Detail($"Sorted by {searchModel.SortColumn} {searchModel.SortColumnDirection}");
|
||||
}
|
||||
|
||||
foreach (var item in orderListModel.Data.Take(3))
|
||||
{
|
||||
_logger.Detail($"Order: {item.Id}, {item.CustomOrderNumber}");
|
||||
|
|
@ -248,6 +317,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
return orderListModel;
|
||||
}
|
||||
|
||||
|
||||
public virtual IActionResult Test()
|
||||
{
|
||||
// Your custom logic here
|
||||
|
|
|
|||
|
|
@ -219,15 +219,32 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
return Json(model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> ProcessShippingDocument(int shippingDocumentId)
|
||||
{
|
||||
return Ok("Ok");
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[RequestSizeLimit(10485760)] // 10MB
|
||||
[RequestFormLimits(MultipartBodyLengthLimit = 10485760)]
|
||||
public async Task<IActionResult> UploadFile(List<IFormFile> files, int shippingDocumentId, int? partnerId)
|
||||
{
|
||||
|
||||
//an empty shippingdocument created by the user
|
||||
var shippingDocument = await _dbContext.ShippingDocuments.GetByIdAsync(shippingDocumentId);
|
||||
|
||||
|
||||
|
||||
ShippingDocumentAnalysisResult shippingDocumentAnalysisResult = new ShippingDocumentAnalysisResult();
|
||||
shippingDocumentAnalysisResult.Partner = new Partner();
|
||||
shippingDocumentAnalysisResult.ShippingDocument = shippingDocument;
|
||||
shippingDocumentAnalysisResult.ShippingItems = new List<ShippingItem>();
|
||||
shippingDocumentAnalysisResult.ShippingDocument.ShippingDocumentToFiles = new List<ShippingDocumentToFiles>();
|
||||
|
||||
|
||||
|
||||
//checks
|
||||
// - files exist
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
|
||||
|
|
@ -243,7 +260,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
_logger.Debug($"Associated with Partner ID: {partnerId.Value}");
|
||||
|
||||
//let's get the partner
|
||||
var partner = await _dbContext.Partners.GetByIdAsync(partnerId.Value);
|
||||
shippingDocumentAnalysisResult.Partner = await _dbContext.Partners.GetByIdAsync(partnerId.Value);
|
||||
}
|
||||
|
||||
var filesList = new List<Files>();
|
||||
|
|
@ -252,34 +269,34 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
//iteratation 1: iterate documents to determine their type by AI
|
||||
|
||||
|
||||
foreach (var file in files)
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
|
||||
var fileName = file.FileName;
|
||||
var fileSize = file.Length;
|
||||
var fileName = files[i].FileName;
|
||||
var fileSize = files[i].Length;
|
||||
var dbFile = new Files();
|
||||
string pdfText = "";
|
||||
|
||||
_logger.Detail($"Received file: {fileName} for Document ID: {shippingDocumentId}, content type: {file.ContentType}");
|
||||
_logger.Detail($"Received file: {fileName} for Document ID: {shippingDocumentId}, content type: {files[i].ContentType}");
|
||||
|
||||
if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) && !file.ContentType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase))
|
||||
if (!files[i].ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) && !files[i].ContentType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase))
|
||||
return Json(new { success = false, errorMessage = "Only PDF or jpg files are allowed" });
|
||||
|
||||
// Validate file size (max 20MB)
|
||||
if (file.Length > 20 * 1024 * 1024)
|
||||
if (files[i].Length > 20 * 1024 * 1024)
|
||||
return Json(new { success = false, errorMessage = "File size must be less than 10MB" });
|
||||
|
||||
// - get text extracted from pdf
|
||||
// Validate file type (PDF only)
|
||||
//if (file.Length > 0 && file.ContentType == "application/pdf")
|
||||
if (file.Length > 0)
|
||||
if (files[i].Length > 0)
|
||||
{
|
||||
if (file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
|
||||
if (files[i].ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Open the PDF from the IFormFile's stream directly in memory
|
||||
using (var stream = file.OpenReadStream())
|
||||
using (var stream = files[i].OpenReadStream())
|
||||
using (var pdf = UglyToad.PdfPig.PdfDocument.Open(stream))
|
||||
{
|
||||
// Now you can analyze the PDF content
|
||||
|
|
@ -296,7 +313,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
try
|
||||
{
|
||||
// ✅ Use the service we implemented earlier
|
||||
pdfText = await _openAIApiService.AnalyzePdfAsync(stream, file.FileName, "Please extract all readable text from this PDF.");
|
||||
pdfText = await _openAIApiService.AnalyzePdfAsync(stream, files[i].FileName, "Please extract all readable text from this PDF.");
|
||||
}
|
||||
catch (Exception aiEx)
|
||||
{
|
||||
|
|
@ -306,14 +323,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
}
|
||||
|
||||
// For demonstration, let's just log the extracted text
|
||||
_logger.Detail($"Extracted text from {file.FileName}: {pdfText}");
|
||||
_logger.Detail($"Extracted text from {files[i].FileName}: {pdfText}");
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle potential exceptions during PDF processing
|
||||
Console.Error.WriteLine($"Error processing PDF file {file.FileName}: {ex.Message}");
|
||||
Console.Error.WriteLine($"Error processing PDF file {files[i].FileName}: {ex.Message}");
|
||||
return StatusCode(500, $"Error processing PDF file: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
|
@ -322,13 +339,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
try
|
||||
{
|
||||
// Open the Image from the IFormFile's stream directly in memory
|
||||
using (var stream = file.OpenReadStream())
|
||||
using (var stream = files[i].OpenReadStream())
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
// ✅ Use the service we implemented earlier
|
||||
pdfText = await _openAIApiService.AnalyzePdfAsync(stream, file.FileName, "Please extract all readable text from this image.");
|
||||
pdfText = await _openAIApiService.AnalyzePdfAsync(stream, files[i].FileName, "Please extract all readable text from this image.");
|
||||
}
|
||||
catch (Exception aiEx)
|
||||
{
|
||||
|
|
@ -337,7 +354,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
}
|
||||
|
||||
// For demonstration, let's just log the extracted text
|
||||
_logger.Detail($"Extracted text from {file.FileName}: {pdfText}");
|
||||
_logger.Detail($"Extracted text from {files[i].FileName}: {pdfText}");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -345,7 +362,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
catch (Exception ex)
|
||||
{
|
||||
// Handle potential exceptions during PDF processing
|
||||
Console.Error.WriteLine($"Error processing PDF file {file.FileName}: {ex.Message}");
|
||||
Console.Error.WriteLine($"Error processing PDF file {files[i].FileName}: {ex.Message}");
|
||||
return StatusCode(500, $"Error processing PDF file: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
|
@ -362,31 +379,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
var metaAnalyzis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(pdfText.ToString(), analysisPrompt);
|
||||
|
||||
var extractedMetaData = ParseMetaDataAIResponse(metaAnalyzis);
|
||||
|
||||
if (extractedMetaData.DocumentNumber != null)
|
||||
{
|
||||
dbFile.RawText = pdfText;
|
||||
dbFile.FileExtension = "pdf";
|
||||
dbFile.FileName = extractedMetaData.DocumentNumber;
|
||||
}
|
||||
|
||||
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
||||
{
|
||||
await _dbContext.Files.InsertAsync(dbFile);
|
||||
filesList.Add(dbFile);
|
||||
|
||||
var shippingDocumentToFiles = new ShippingDocumentToFiles
|
||||
{
|
||||
ShippingDocumentId = shippingDocumentId,
|
||||
FilesId = dbFile.Id,
|
||||
DocumentType = extractedMetaData.DocumentType != null ? (DocumentType)Enum.Parse(typeof(DocumentType), extractedMetaData.DocumentType) : DocumentType.Unknown
|
||||
};
|
||||
|
||||
_logger.Detail(shippingDocumentToFiles.DocumentType.ToString());
|
||||
|
||||
await _dbContext.ShippingDocumentToFiles.InsertAsync(shippingDocumentToFiles);
|
||||
return true;
|
||||
});
|
||||
bool transactionSuccess = await SaveFileInfoToDB(shippingDocumentId, shippingDocumentAnalysisResult, filesList, dbFile, pdfText, extractedMetaData);
|
||||
|
||||
if (!transactionSuccess) _logger.Error($"(transactionSuccess == false)");
|
||||
|
||||
|
|
@ -399,12 +392,12 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
//find partner in DB... there is a serious chance that the partner Name and Taxid determines the partner
|
||||
|
||||
var partners = await _dbContext.Partners.GetAll().ToListAsync();
|
||||
foreach (var partner in partners)
|
||||
foreach (var dbpartner in partners)
|
||||
{
|
||||
if (pdfText.Contains(partner.Name) || (partner.TaxId != null && pdfText.Contains(partner.TaxId)))
|
||||
if (pdfText.Contains(dbpartner.Name) || (dbpartner.TaxId != null && pdfText.Contains(dbpartner.TaxId)))
|
||||
{
|
||||
partnerId = partner.Id;
|
||||
_logger.Detail($"Found existing partner in DB: {partner.Name} (ID: {partner.Id})");
|
||||
partnerId = dbpartner.Id;
|
||||
_logger.Detail($"Found existing partner in DB: {dbpartner.Name} (ID: {dbpartner.Id})");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -413,48 +406,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
{
|
||||
_logger.Detail("No existing partner found in DB, proceeding to extract partner info via AI.");
|
||||
|
||||
string partnerAnalysisPrompt = "You are an agent of Fruitbank, helping to analyze pdf content. Determine which partner of Fruitbank sent this document, extract their data and return them as JSON: name, taxId, certificationNumber, postalCode, country, state, county, city, street. " +
|
||||
"If you can't find information of any of these, return null value for that field.";
|
||||
// string partnerAnalysisPrompt = "You are an agent of Fruitbank, helping to analyze pdf content. Determine which partner of Fruitbank sent this document, extract their data and return them as JSON: name, taxId, certificationNumber, postalCode, country, state, county, city, street. " +
|
||||
//"If you can't find information of any of these, return null value for that field.";
|
||||
|
||||
//here I can start preparing the file entity
|
||||
var partnerAnalyzis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(pdfText.ToString(), partnerAnalysisPrompt);
|
||||
var extractedPartnerData = ParsePartnerDataAIResponse(partnerAnalyzis);
|
||||
// //here I can start preparing the file entity
|
||||
// var partnerAnalyzis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(pdfText.ToString(), partnerAnalysisPrompt);
|
||||
|
||||
if (extractedPartnerData.Name != null)
|
||||
{
|
||||
_logger.Detail("AI Analysis Partner Result:");
|
||||
_logger.Detail(extractedPartnerData.Name);
|
||||
}
|
||||
|
||||
if (extractedPartnerData.TaxId != null)
|
||||
{
|
||||
_logger.Detail(extractedPartnerData.TaxId);
|
||||
}
|
||||
|
||||
if (extractedPartnerData.Country != null)
|
||||
{
|
||||
|
||||
_logger.Detail(extractedPartnerData.Country);
|
||||
}
|
||||
|
||||
if (extractedPartnerData.State != null)
|
||||
{
|
||||
_logger.Detail(extractedPartnerData.State);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//shortcut
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
var partnerPrompt = @"Extract the partner/company information from the following text and return ONLY a valid JSON object with these exact fields:
|
||||
var partnerPrompt = @"Extract the partner/company information from the following text and return ONLY a valid JSON object with these exact fields:
|
||||
{
|
||||
""Name"": ""company name"",
|
||||
""TaxId"": ""tax identification number"",
|
||||
|
|
@ -472,13 +430,54 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
Text to analyze:
|
||||
" + pdfText;
|
||||
|
||||
var partnerResponse = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(
|
||||
pdfText,
|
||||
partnerPrompt
|
||||
);
|
||||
var partnerResponse = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(
|
||||
pdfText,
|
||||
partnerPrompt
|
||||
);
|
||||
|
||||
shippingDocumentAnalysisResult.Partner = JsonSerializer.Deserialize<Partner>(CleanJsonResponse(partnerResponse),
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
|
||||
if (shippingDocumentAnalysisResult.Partner.Name != null)
|
||||
{
|
||||
_logger.Detail("AI Analysis Partner Result:");
|
||||
_logger.Detail(shippingDocumentAnalysisResult.Partner.Name);
|
||||
}
|
||||
|
||||
if (shippingDocumentAnalysisResult.Partner.TaxId != null)
|
||||
{
|
||||
_logger.Detail(shippingDocumentAnalysisResult.Partner.TaxId);
|
||||
}
|
||||
|
||||
if (shippingDocumentAnalysisResult.Partner.Country != null)
|
||||
{
|
||||
|
||||
_logger.Detail(shippingDocumentAnalysisResult.Partner.Country);
|
||||
}
|
||||
|
||||
if (shippingDocumentAnalysisResult.Partner.State != null)
|
||||
{
|
||||
_logger.Detail(shippingDocumentAnalysisResult.Partner.State);
|
||||
}
|
||||
|
||||
if (shippingDocumentAnalysisResult.Partner != null)
|
||||
{
|
||||
shippingDocumentAnalysisResult.Partner = shippingDocumentAnalysisResult.Partner;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//shortcut
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var partner = JsonSerializer.Deserialize<Partner>(CleanJsonResponse(partnerResponse),
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
// Step 2: Extract Shipping Document Information
|
||||
var shippingDocPrompt = @"Extract the shipping document information from the following text and return ONLY a valid JSON object with these exact fields:
|
||||
|
|
@ -504,20 +503,20 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
|
||||
// Step 3: Extract Shipping Items
|
||||
var itemsPrompt = @"Extract all shipping items (fruits, vegetables, or products) from the following text and return ONLY a valid JSON array with objects having these exact fields:
|
||||
[
|
||||
{
|
||||
""Name"": ""product name"",
|
||||
""PalletsOnDocument"": number_of_pallets,
|
||||
""QuantityOnDocument"": quantity_count,
|
||||
""NetWeightOnDocument"": net_weight_in_kg,
|
||||
""GrossWeightOnDocument"": gross_weight_in_kg
|
||||
}
|
||||
]
|
||||
[
|
||||
{
|
||||
""Name"": ""product name"",
|
||||
""PalletsOnDocument"": number_of_pallets,
|
||||
""QuantityOnDocument"": quantity_count,
|
||||
""NetWeightOnDocument"": net_weight_in_kg,
|
||||
""GrossWeightOnDocument"": gross_weight_in_kg
|
||||
}
|
||||
]
|
||||
|
||||
If a numeric field is not found, use 0. Return ONLY the JSON array, no additional text or explanation.
|
||||
If a numeric field is not found, use 0. Return ONLY the JSON array, no additional text or explanation.
|
||||
|
||||
Text to analyze:
|
||||
" + pdfText;
|
||||
Text to analyze:
|
||||
" + pdfText;
|
||||
|
||||
var itemsResponse = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(
|
||||
pdfText,
|
||||
|
|
@ -530,7 +529,7 @@ Text to analyze:
|
|||
// Prepare result
|
||||
var result = new ShippingDocumentAnalysisResult
|
||||
{
|
||||
Partner = partner,
|
||||
Partner = shippingDocumentAnalysisResult.Partner,
|
||||
ShippingDocument = new ShippingDocument
|
||||
{
|
||||
DocumentIdNumber = shippingDocData.DocumentIdNumber,
|
||||
|
|
@ -541,56 +540,40 @@ Text to analyze:
|
|||
ShippingItems = items
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
//return Ok(result);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
return BadRequest($"Failed to parse AI response: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"An error occurred: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// - save the documents to file system - wwwroot/uploads/orders/order-{orderId}/fileId-documentId.pdf
|
||||
// where documentId is the number or id IN the document
|
||||
//try
|
||||
//{
|
||||
// // Create upload directory if it doesn't exist
|
||||
// var uploadsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", "orders", "order" + shippingDocumentId.ToString(), "documents");
|
||||
// Directory.CreateDirectory(uploadsPath);
|
||||
try
|
||||
{
|
||||
// Create upload directory if it doesn't exist
|
||||
var uploadsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads", "orders", "order" + shippingDocumentId.ToString(), "documents");
|
||||
Directory.CreateDirectory(uploadsPath);
|
||||
|
||||
// // Generate unique filename
|
||||
// fileName = $"{Guid.NewGuid()}_{file.FileName}";
|
||||
// var filePath = Path.Combine(uploadsPath, fileName);
|
||||
// Generate unique filename
|
||||
fileName = $"{Guid.NewGuid()}_{files[i].FileName}";
|
||||
var filePath = Path.Combine(uploadsPath, fileName);
|
||||
|
||||
// // Save file
|
||||
// using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
// {
|
||||
// await file.CopyToAsync(stream);
|
||||
// }
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// _logger.Error($"Error saving file: {ex.Message}", ex);
|
||||
// //return Json(new { success = false, errorMessage = ex.Message });
|
||||
// return BadRequest("No files were uploaded.");
|
||||
//}
|
||||
// Save file
|
||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
await files[i].CopyToAsync(stream);
|
||||
}
|
||||
|
||||
return Ok(shippingDocumentAnalysisResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Error saving file: {ex.Message}", ex);
|
||||
//return Json(new { success = false, errorMessage = ex.Message });
|
||||
return BadRequest("No files were uploaded.");
|
||||
}
|
||||
|
||||
|
||||
// - create a list of documents to read information and to save the document's information to DB
|
||||
|
|
@ -680,6 +663,35 @@ Text to analyze:
|
|||
return Ok($"Files for Shipping Document ID {shippingDocumentId} were uploaded successfully!");
|
||||
}
|
||||
|
||||
private async Task<bool> SaveFileInfoToDB(int shippingDocumentId, ShippingDocumentAnalysisResult shippingDocumentAnalysisResult, List<Files> filesList, Files dbFile, string pdfText, ExtractedDocumentMetaData extractedMetaData)
|
||||
{
|
||||
if (extractedMetaData.DocumentNumber != null)
|
||||
{
|
||||
dbFile.RawText = pdfText;
|
||||
dbFile.FileExtension = "pdf";
|
||||
dbFile.FileName = extractedMetaData.DocumentNumber;
|
||||
}
|
||||
|
||||
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
||||
{
|
||||
await _dbContext.Files.InsertAsync(dbFile);
|
||||
filesList.Add(dbFile);
|
||||
|
||||
var shippingDocumentToFiles = new ShippingDocumentToFiles
|
||||
{
|
||||
ShippingDocumentId = shippingDocumentId,
|
||||
FilesId = dbFile.Id,
|
||||
DocumentType = extractedMetaData.DocumentType != null ? (DocumentType)Enum.Parse(typeof(DocumentType), extractedMetaData.DocumentType) : DocumentType.Unknown
|
||||
};
|
||||
|
||||
_logger.Detail(shippingDocumentToFiles.DocumentType.ToString());
|
||||
shippingDocumentAnalysisResult.ShippingDocument.ShippingDocumentToFiles.Add(shippingDocumentToFiles);
|
||||
await _dbContext.ShippingDocumentToFiles.InsertAsync(shippingDocumentToFiles);
|
||||
return true;
|
||||
});
|
||||
return transactionSuccess;
|
||||
}
|
||||
|
||||
|
||||
//[HttpPost]
|
||||
//public async Task<IActionResult> UploadFile(List<IFormFile> files, int shippingDocumentId)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order
|
|||
[NopResourceDisplayName("Admin.Orders.List.BillingCompany")]
|
||||
public string BillingCompany { get; set; }
|
||||
|
||||
//public IList<SelectListItem> AvailableCompanies { get; set; }
|
||||
public string SortColumn { get; set; }
|
||||
public string SortColumnDirection { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
|
||||
<div class="col-6">
|
||||
<form method="post" enctype="multipart/form-data" asp-controller="ManagementPage" asp-action="UploadFile">
|
||||
@(Html.DevExtreme().FileUploader()
|
||||
.ID("shippingDocumentUploader-" + contextId)
|
||||
|
|
@ -31,6 +30,12 @@
|
|||
.UseSubmitBehavior(true)
|
||||
)
|
||||
</form>
|
||||
|
||||
|
||||
<button type="button" class="btn btn-primary mt-2" onclick="processShippingDocument_@(contextId)()">
|
||||
<i class="fas fa-cog"></i> Process Shipping Document
|
||||
</button>
|
||||
|
||||
<div class="content" id="selected-files">
|
||||
<div>
|
||||
<h4>Selected Files</h4>
|
||||
|
|
@ -56,6 +61,27 @@
|
|||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Process Shipping Document function
|
||||
function processShippingDocument_@(contextId)() {
|
||||
var shippingDocumentId = @contextId;
|
||||
|
||||
$.ajax({
|
||||
url: '@Url.Action("ProcessShippingDocument", "ManagementPage")',
|
||||
type: 'POST',
|
||||
data: { shippingDocumentId: shippingDocumentId },
|
||||
success: function(response) {
|
||||
DevExpress.ui.notify("Shipping document processed successfully!", "success", 2000);
|
||||
// Refresh the file manager
|
||||
var fileManager = $("#@fileManagerId").dxFileManager("instance");
|
||||
if (fileManager) {
|
||||
fileManager.refresh();
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
DevExpress.ui.notify("Error processing shipping document: " + error, "error", 3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fileUploader_valueChanged(e) {
|
||||
var files = e.value;
|
||||
|
|
|
|||
|
|
@ -348,8 +348,10 @@
|
|||
Name = "orders-grid",
|
||||
UrlRead = new DataUrl("OrderList", "CustomOrder", null),
|
||||
SearchButtonId = "search-orders",
|
||||
// Ordering = true,
|
||||
// ServerSide = false,
|
||||
Ordering = true,
|
||||
ServerSide = true,
|
||||
Paging = true,
|
||||
PagingType = "simple_numbers", // or Full
|
||||
Length = Model.PageSize,
|
||||
LengthMenu = Model.AvailablePageSizes,
|
||||
FooterCallback = !Model.IsLoggedInAsVendor ? "ordersfootercallback" : null,
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@
|
|||
},
|
||||
new ColumnProperty(nameof(ProductModelExtended.IncomingQuantity))
|
||||
{
|
||||
Title = "Bejövő"//T("Admin.Catalog.Products.Fields.Tare").Text
|
||||
Title = "Kamionon"//T("Admin.Catalog.Products.Fields.Tare").Text
|
||||
},
|
||||
new ColumnProperty(nameof(ProductModelExtended.NetWeight))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -268,9 +268,12 @@ public class MgOrderModelFactory<TOrderListModelExt, TOrderModelExt> : OrderMode
|
|||
}
|
||||
|
||||
prefiltered.Data = null;
|
||||
var totalRecords = prefiltered.RecordsTotal;
|
||||
var filteredRecords = prefiltered.RecordsFiltered;
|
||||
|
||||
|
||||
//var orderListModelExtended = orderListModel.ToJson().JsonTo<TOrderListModelExt>();
|
||||
if(searchModel.BillingCompany != null)
|
||||
if (searchModel.BillingCompany != null)
|
||||
{
|
||||
//extendedRows = extendedRows.Where(x => x.CustomerCompany != null && x.CustomerCompany.IndexOf(searchModel.BillingCompany, StringComparison.InvariantCultureIgnoreCase) >= 0).ToList();
|
||||
extendedRows = extendedRows.Where(x => x.CustomerId == Convert.ToInt32(searchModel.BillingCompany)).ToList();
|
||||
|
|
@ -279,7 +282,9 @@ public class MgOrderModelFactory<TOrderListModelExt, TOrderModelExt> : OrderMode
|
|||
|
||||
var orderListModelExtended = prefiltered.CloneTo<TOrderListModelExt>();
|
||||
orderListModelExtended.Data = extendedRows;
|
||||
orderListModelExtended.RecordsFiltered = extendedRows.Count;
|
||||
|
||||
orderListModelExtended.RecordsTotal = totalRecords;
|
||||
orderListModelExtended.RecordsFiltered = filteredRecords;
|
||||
return orderListModelExtended;
|
||||
}
|
||||
}
|
||||
|
|
@ -146,6 +146,11 @@ public class RouteProvider : IRouteProvider
|
|||
name: "Plugin.FruitBank.Admin.Order.Edit",
|
||||
pattern: "Admin/Order/Edit/{id}",
|
||||
defaults: new { controller = "CustomOrder", action = "Edit", area = AreaNames.ADMIN });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(
|
||||
name: "Plugin.FruitBank.Admin.ManagementPage.ProcessShippingDocument",
|
||||
pattern: "Admin/ManagamentPage/ProcessShippingDocument/{id}",
|
||||
defaults: new { controller = "ManagementPage", action = "ProcessShippingdocument", area = AreaNames.ADMIN });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
|
||||
public async Task<string> GetOpenAIPDFAnalysisFromText(string pdfText, string userQuestion)
|
||||
{
|
||||
var systemMessage = $"You are a pdf analyzis assistant, the 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 systemMessage = $"You are a pdf analyzis assistant of FRUITBANK, the 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 _openAIApiService.GetSimpleResponseAsync(systemMessage, userQuestion);
|
||||
|
||||
if (response == null) return string.Empty;
|
||||
|
|
|
|||
|
|
@ -2,41 +2,80 @@
|
|||
@model OrderAttributesModel
|
||||
|
||||
<!-- InnVoice Management Section -->
|
||||
<div class="card card-default mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-file-invoice"></i>
|
||||
InnVoice Management
|
||||
<!-- Order Subsection -->
|
||||
<div class="form-group row">
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="card card-default mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-file-invoice"></i>
|
||||
Megrendelés beállítások
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3 text-right">
|
||||
<strong>Mérés információ</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
@(Model.IsMeasurable ? "Mérendő" : "Nem mérendő")
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3">
|
||||
<nop-label asp-for="DateOfReceipt" />
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<nop-editor asp-for="DateOfReceipt" asp-template="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button type="button" id="saveAttributesBtn" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Attributes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Order Subsection -->
|
||||
<div class="form-group row">
|
||||
<h3>Innvoice</h3>
|
||||
<div class="col-12 col-md-3">
|
||||
<h5><i class="fas fa-shopping-cart"></i> Megrendelés beküldése Innvoice-ba</h5>
|
||||
<div id="orderStatus" class="alert alert-info" style="display: none;">
|
||||
<i class="fas fa-info-circle"></i> <span id="orderStatusMessage"></span>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="card card-default mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-file-invoice"></i>
|
||||
InnVoice Management
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="col-6">
|
||||
<h5><i class="fas fa-shopping-cart"></i> Megrendelés beküldése Innvoice-ba</h5>
|
||||
<div id="orderStatus" class="alert alert-info" style="display: none;">
|
||||
<i class="fas fa-info-circle"></i> <span id="orderStatusMessage"></span>
|
||||
</div>
|
||||
<div id="orderDetails" style="display: none;">
|
||||
<p><strong>Order Table ID:</strong> <span id="orderTableId"></span></p>
|
||||
<p><strong>Order Tech ID:</strong> <span id="orderTechId"></span></p>
|
||||
<p>
|
||||
<a id="orderPdfLink" href="#" target="_blank" class="btn btn-sm btn-info">
|
||||
<i class="fas fa-file-pdf"></i> PDF megtekintése
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="orderDetails" style="display: none;">
|
||||
<p><strong>Order Table ID:</strong> <span id="orderTableId"></span></p>
|
||||
<p><strong>Order Tech ID:</strong> <span id="orderTechId"></span></p>
|
||||
<p>
|
||||
<a id="orderPdfLink" href="#" target="_blank" class="btn btn-sm btn-info">
|
||||
<i class="fas fa-file-pdf"></i> PDF megtekintése
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div class="col-6 text-right float-end">
|
||||
<button type="button" id="createOrderBtn" class="btn btn-success">
|
||||
<i class="fas fa-shopping-cart"></i> Létrehozás
|
||||
</button>
|
||||
<button type="button" id="checkOrderBtn" class="btn btn-secondary" style="display: none;">
|
||||
<i class="fas fa-sync"></i> Invoice adat ellenőrzése
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 text-right float-end">
|
||||
<button type="button" id="createOrderBtn" class="btn btn-success">
|
||||
<i class="fas fa-shopping-cart"></i> Létrehozás
|
||||
</button>
|
||||
<button type="button" id="checkOrderBtn" class="btn btn-secondary" style="display: none;">
|
||||
<i class="fas fa-sync"></i> Invoice adat ellenőrzése
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@* <div class="col-12 col-md-3">
|
||||
@* <div class="col-12 col-md-3">
|
||||
<h5><i class="fas fa-file-invoice-dollar"></i> Invoice</h5>
|
||||
<div id="invoiceStatus" class="alert alert-info" style="display: none;">
|
||||
<i class="fas fa-info-circle"></i> <span id="invoiceStatusMessage"></span>
|
||||
|
|
@ -52,7 +91,7 @@
|
|||
</div>
|
||||
</div> *@
|
||||
|
||||
@* <div class="col-12 col-md-3 text-right">
|
||||
@* <div class="col-12 col-md-3 text-right">
|
||||
<button type="button" id="createInvoiceBtn" class="btn btn-success">
|
||||
<i class="fas fa-file-invoice-dollar"></i> Create Invoice
|
||||
</button>
|
||||
|
|
@ -60,41 +99,10 @@
|
|||
<i class="fas fa-sync"></i> Refresh Invoice
|
||||
</button>
|
||||
</div> *@
|
||||
</div>
|
||||
|
||||
<!-- Attributes Section (NO FORM TAG - just a div) -->
|
||||
<div id="orderAttributesSection">
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3 text-right">
|
||||
<strong>Mérés információ</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
@(Model.IsMeasurable ? "Mérendő" : "Nem mérendő")
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-3">
|
||||
<nop-label asp-for="DateOfReceipt" />
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<nop-editor asp-for="DateOfReceipt" asp-template="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button type="button" id="saveAttributesBtn" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Attributes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var createOrderUrl = '/Admin/InnVoiceOrder/CreateOrder';
|
||||
|
|
|
|||
Loading…
Reference in New Issue