diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs
index 9092246..8b63095 100644
--- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs
@@ -15,9 +15,11 @@ using Nop.Web.Framework;
using Nop.Web.Framework.Mvc.Filters;
using System.Text;
using System.Text.Json;
+//using AutoGen.Core;
using AyCode.Core.Consts;
using UglyToad.PdfPig.DocumentLayoutAnalysis.TextExtractor;
using AyCode.Core.Extensions;
+//using AutoGen.Gemini;
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
{
@@ -309,8 +311,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
try
{
// ✅ Use the service we implemented earlier
- //pdfText = await _openAIApiService.AnalyzePdfAsync(stream, currentFile.FileName, "Please extract all readable text from this PDF.");
- pdfText = await _openAIApiService.AnalyzePdfAsync(stream, currentFile.FileName, DefaultFullPrompt);
+ pdfText = await _openAIApiService.AnalyzePdfAsync(stream, currentFile.FileName, "Please extract all readable text from this PDF.");
+ //pdfText = await _openAIApiService.AnalyzePdfAsync(stream, currentFile.FileName, DefaultFullPrompt);
}
catch (Exception aiEx)
{
@@ -365,35 +367,87 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
shippingDocumentAnalysisResult = await ProcessRawText(shippingDocumentId, partnerId, pdfText, shippingDocumentAnalysisResult, filesList, dbFile);
await SaveDocumentToFileSystem(currentFile, shippingDocumentId, $"{Guid.NewGuid()}_{currentFile.FileName}");//shippingDocumentAnalysisResult.Partner.Name);
- //Ez rész a catch végéig nekem teszt! - J
- //try
- //{
- // responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{currentFile.Name}:{AcEnv.NL}{pdfText}";
+ return Ok($"Files for Shipping Document ID {shippingDocumentId} were uploaded successfully!{AcEnv.NL}{AcEnv.NL}{responseRawPdfTexts}");
- // var transactionSuccess = await SaveFileInfoToDb(shippingDocumentId, shippingDocumentAnalysisResult, filesList, dbFile, pdfText);
- // if (!transactionSuccess)
- // {
- // _logger.Error($"(transactionSuccess == false)");
- // return BadRequest($"Error saving file! RawText:{AcEnv.NL}{pdfText}");
- // }
+ //Ez rész a catch végéig nekem teszt! - J.
+ try
+ {
+ //responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{currentFile.Name}:{AcEnv.NL}{pdfText}";
- // if (await SaveDocumentToFileSystem(currentFile, shippingDocumentId, $"{Guid.NewGuid()}_{currentFile.FileName}"))
- // {
- // //var partnerResponse = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(
- // // pdfText,
- // // $"{DefaultFullPrompt}"
- // //);
+ var transactionSuccess = await SaveFileInfoToDb(shippingDocumentId, shippingDocumentAnalysisResult, filesList, dbFile, pdfText);
+ if (!transactionSuccess)
+ {
+ _logger.Error($"(transactionSuccess == false)");
+ return BadRequest($"Error saving file! RawText:{AcEnv.NL}{pdfText}");
+ }
- // //responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{AcEnv.NL}Response json:{AcEnv.NL}{partnerResponse}";
- // }
- // //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.");
- //}
+ if (await SaveDocumentToFileSystem(currentFile, shippingDocumentId, $"{Guid.NewGuid()}_{currentFile.FileName}"))
+ {
+ await using var stream = currentFile.OpenReadStream();
+
+ try
+ {
+ await _openAIApiService.CleanupAllVectorStoresAsync();
+ await _openAIApiService.CleanupAllAssistantsAsync();
+ pdfText = await _openAIApiService.AnalyzePdfAsync(stream, currentFile.FileName, "nyerd ki az összes adatot könnyen értelmezhető .txt formátumba!");
+
+ var projectID = "864202751803"; //"AIzaSyBAk5dyHnFrt8Upvqb2ICZmxws0Cf1de9M";//Environment.GetEnvironmentVariable("AIzaSyBAk5dyHnFrt8Upvqb2ICZmxws0Cf1de9M");
+ var apiKey = "AIzaSyBAk5dyHnFrt8Upvqb2ICZmxws0Cf1de9M";
+
+ if (projectID is not null)
+ {
+ //var geminiAgent = new GeminiChatAgent(
+ // name: "gemini",
+ // model: "gemini-2.5-flash",
+ // //location: "us-east4",
+ // //project: projectID,
+ // apiKey: apiKey,
+ // systemMessage: "Fruitbank egy zöldséges nagyker, ahol a bejövő szállítmányokat kezelik.")
+ // .RegisterMessageConnector()
+ // .RegisterPrintMessage();
+
+ ////var imagePath = Path.Combine("resource", "images", "background.png");
+ ////var image = await File.ReadAllBytesAsync(imagePath);
+ //var imageMessage = new ImageMessage(Role.User, BinaryData.FromStream(stream, "application/pdf"));
+
+ //var reply = await geminiAgent.SendAsync(DefaultFullPrompt, [imageMessage]);
+ //pdfText = reply.From;
+
+ //pdfText = "Feladó (Expediteur): Victor i Merce, S.L., Mercabarna, Pab.F-6035-6036, 08040 Barcelona, Spanyolország, CIF: ESB61478095.\r\n- Szállítmányozó (Transporteur): FRUIT BANK KFT, Rippl-Rónai utca 18, 1068 Budapest, Magyarország, CIF: HU14902170.\r\n- Címzett (Destinataire): FRUIT BANK KFT, Rippl-Rónai utca 18, 1068 Budapest, Magyarország, CIF: HU14902170.\r\n- Szállítás helye és ideje (Lugar y fecha de carga): 08040 Barcelona, Barcelona (Spanyolország), 2025. október 30.\r\n- Áru részletei (Mercancia): 140 TTE.MADURO G, összesen 840,00 kg bruttó tömeg.\r\n- Szállítás kifizetése a célállomáson (Transporte a payer par): TRANSPORTE A PAGAR EN DESTINO.\r\n\r\n\r\n\r\n";
+
+ responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{currentFile.Name}:{AcEnv.NL}{pdfText}";
+
+ //pdfText = await _openAIApiService.GetSimpleResponseAsync("You are an assistant of FRUITBANK that extracts data from text. The user provides a text, and asks you questions about it. You extract the information without futher explanation.",
+ pdfText = await _openAIApiService.GetSimpleResponseAsync(DefaultFullPrompt, pdfText);
+
+ responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{currentFile.Name}:{AcEnv.NL}{pdfText}";
+ }
+ else
+ {
+ Console.WriteLine("Please set GCP_VERTEX_PROJECT_ID environment variable.");
+ }
+ }
+ catch (Exception aiEx)
+ {
+ Console.Error.WriteLine($"OpenAI Assistants API failed: {aiEx.Message}");
+ return StatusCode(500, $"Failed to process PDF: {aiEx.Message}");
+ }
+
+ //var partnerResponse = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(
+ // pdfText,
+ // $"{DefaultFullPrompt}"
+ //);
+
+ //responseRawPdfTexts += $"{AcEnv.NL}{AcEnv.NL}{AcEnv.NL}Response json:{AcEnv.NL}{partnerResponse}";
+ }
+ //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.");
+ }
}
//iteration 2: iterate documents again
@@ -945,9 +999,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
}
private const string DefaultFullPrompt = $"Role:\r\nYou are an AI data extraction assistant for Fruitbank, a " +
- $"fruit and vegetable wholesale company. Your task is to analyze a list of extracted pdf " +
- $"documents (delivery notes, invoices, or order confirmations) and extract structured information about " +
- $"the shipment and its items.\r\n\r\n🎯 Goal:\r\nRead the provided extracted pdf text and extract all shipment " +
+ $"fruit and vegetable wholesale company. Your task is to analyze a " +
+ $"provided text (delivery notes, invoices, or order confirmations) and extract structured information about " +
+ $"the shipment and its items.\r\n\r\n🎯 Goal:\r\nRead the provided text and extract all shipment " +
$"details and items according to the data model below.\r\n Generate the complete JSON output following this " +
$"structure.\r\n\r\n🧩 Data Models:\r\n\r\npublic " +
$"class Partner\r\n{{\r\n " +
@@ -1005,7 +1059,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
$"(e.g. sequential: 1, 2, 3…).\r\n\r\n- When a field is missing or unclear, return it as an empty " +
$"string or 0 (depending on type).\r\nDo not omit any fields.\r\n\r\n- " +
$"All dates must be in ISO 8601 format (yyyy-MM-dd).\r\n\r\n🧭 Instructions to the AI\r\n" +
- $"1. Analyze the provided PDF files one by one carefully.\r\n" +
+ $"1. Analyze the provided text one by one carefully.\r\n" +
$"2. Identify the Partner/Company details, " +
$"document identifiers, and each shipment item.\r\n" +
$"3. FruitBank is not a partner! Always look for THE OTHER partner on the document. \r\n " +
@@ -1016,7 +1070,83 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
$"és a zöldség vagy gyümölcs nevét fordítsd le magyarra!\r\n" +
$"7. A ShippingDocument-et tedd bele a Partner entitásba!\r\n" +
$"8. ShippingItem-eket tedd bele a ShippingDocument-be!\r\n" +
- $"9. Do not assume or modify any data, if you don't find a value, return null, if you find a value, keep it unmodified.";
+ $"9. Do not assume or modify any data, if you don't find a value, return null, if you find a value, keep it unmodified.\r\n" +
+ $"10. Magyarázat nélkül válaszolj!";
+ //+ $"\r\n\r\n" + $"***POVIDED TEXT***:";
+
+ //private const string DefaultFullPrompt = $"Role:\r\nYou are an AI data extraction assistant for Fruitbank, a " +
+ // $"fruit and vegetable wholesale company. Your task is to analyze a list of extracted pdf " +
+ // $"documents (delivery notes, invoices, or order confirmations) and extract structured information about " +
+ // $"the shipment and its items.\r\n\r\n🎯 Goal:\r\nRead the provided extracted pdf text and extract all shipment " +
+ // $"details and items according to the data model below.\r\n Generate the complete JSON output following this " +
+ // $"structure.\r\n\r\n🧩 Data Models:\r\n\r\npublic " +
+ // $"class Partner\r\n{{\r\n " +
+ // $"/// \r\n /// Partner entity primary key\r\n /// \r\n " +
+ // $"public int Id {{ get; set; }}\r\n " +
+ // $"/// \r\n /// Partner company name\r\n /// \r\n " +
+ // $"public string Name {{ get; set; }}\r\n " +
+ // $"/// \r\n /// Partner company TaxId\r\n /// \r\n " +
+ // $"public string TaxId {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company Certification if exists\r\n /// \r\n " +
+ // $"public string CertificationNumber {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address PostalCode\r\n /// \r\n " +
+ // $"public string PostalCode {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address Country\r\n /// \r\n " +
+ // $"public string Country {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address State if exists\r\n /// \r\n " +
+ // $"public string State {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address County if exists\r\n /// \r\n " +
+ // $"public string County {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address City\r\n /// \r\n " +
+ // $"public string City {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Partner company address Street\r\n /// \r\n " +
+ // $"public string Street {{ get; set; }}\r\n\t/// \r\n " +
+ // $"/// Entities of ShippingDocument\r\n /// \r\n\tpublic List " +
+ // $"ShippingDocuments {{ get; set; }}\t\r\n}}\r\n\r\npublic class ShippingDocument\r\n{{\r\n " +
+ // $"/// \r\n /// ShippingItem entity primary key\r\n /// \r\n " +
+ // $"public int Id {{ get; set; }}\r\n /// \r\n /// Partner entity primary key\r\n " +
+ // $"/// \r\n public int PartnerId {{ get; set; }}\t\r\n\t/// \r\n " +
+ // $"/// Entities of ShippingItem\r\n /// \r\n\t" +
+ // $"public List ShippingItems {{ get; set; }}\r\n /// \r\n " +
+ // $"/// DocumentIdNumber if exists\r\n /// \r\n public string DocumentIdNumber {{ get; set; }}\r\n " +
+ // $"/// \r\n /// \r\n /// \r\n public DateTime ShippingDate {{ get; set; }}\r\n " +
+ // $"/// \r\n /// Shipping pickup Contry of origin\r\n /// \r\n " +
+ // $"public string Country {{ get; set; }}\r\n\t/// \r\n /// Sum of ShippingItem pallets\r\n " +
+ // $"/// \r\n public int TotalPallets {{ get; set; }}\r\n\t/// \r\n " +
+ // $"/// Filename of pdf\r\n /// \r\n\tpublic string PdfFileName {{ get; set; }}\r\n}}\r\n\r\n" +
+ // $"public class ShippingItem\r\n{{\r\n /// \r\n /// ShippingItem entity primary key\r\n /// " +
+ // $"\r\n public int Id {{ get; set; }}\r\n /// \r\n /// " +
+ // $"ShippingDocument entity primary key\r\n /// \r\n " +
+ // $"public int ShippingDocumentId {{ get; set; }}\r\n /// " +
+ // $"\r\n /// Name of the fruit or vegitable\r\n /// \r\n " +
+ // $"public string Name {{ get; set; }}\r\n\t/// \r\n /// Translated Name to Hungarian\r\n " +
+ // $"/// \r\n public string HungarianName {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Pallets of fruit or vegitable item\r\n /// \r\n " +
+ // $"public int PalletsOnDocument {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Quantity of fruit or vegitable item\r\n /// \r\n " +
+ // $"public int QuantityOnDocument {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Net weight in kg. of fruit or vegitable item\r\n /// \r\n " +
+ // $"public double NetWeightOnDocument {{ get; set; }}\r\n /// \r\n " +
+ // $"/// Gross weight in kg. of fruit or vegitable item\r\n /// \r\n " +
+ // $"public double GrossWeightOnDocument {{ get; set; }}\r\n}}\r\n\r\n🧾 Output Requirements\r\n- " +
+ // $"Output must be a single valid JSON object containing:\r\n- One Partner object\r\n- " +
+ // $"One ShippingDocument object\r\n- A list of all related ShippingItem objects\r\n\r\n- " +
+ // $"Primary keys (Partner.Id, ShippingDocument.Id, ShippingItem.Id) should be auto-generated integers " +
+ // $"(e.g. sequential: 1, 2, 3…).\r\n\r\n- When a field is missing or unclear, return it as an empty " +
+ // $"string or 0 (depending on type).\r\nDo not omit any fields.\r\n\r\n- " +
+ // $"All dates must be in ISO 8601 format (yyyy-MM-dd).\r\n\r\n🧭 Instructions to the AI\r\n" +
+ // $"1. Analyze the provided PDF files one by one carefully.\r\n" +
+ // $"2. Identify the Partner/Company details, " +
+ // $"document identifiers, and each shipment item.\r\n" +
+ // $"3. FruitBank is not a partner! Always look for THE OTHER partner on the document. \r\n " +
+ // $"4. Generate a complete hierarchical JSON of ALL received documents in ONE JSON structure according to the " +
+ // $"data model above.\r\n5. Do not include any explanations or text outside the JSON output. " +
+ // $"Only return the structured JSON.\r\n" +
+ // $"6. A teljes ShippingItem.Name-et tedd bele a ShippingItem.HungarianName-be " +
+ // $"és a zöldség vagy gyümölcs nevét fordítsd le magyarra!\r\n" +
+ // $"7. A ShippingDocument-et tedd bele a Partner entitásba!\r\n" +
+ // $"8. ShippingItem-eket tedd bele a ShippingDocument-be!\r\n" +
+ // $"9. Do not assume or modify any data, if you don't find a value, return null, if you find a value, keep it unmodified.";
}
public class UploadModel
diff --git a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs
index d7f16e7..e66ec5d 100644
--- a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs
@@ -1,4 +1,5 @@
-using AyCode.Core.Loggers;
+using AyCode.Core.Extensions;
+using AyCode.Core.Loggers;
using AyCode.Services.SignalRs;
using DocumentFormat.OpenXml.Office2010.Excel;
using FruitBank.Common.Dtos;
@@ -17,6 +18,7 @@ using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
+using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Customers;
using Nop.Services.Localization;
using Nop.Web.Framework.Controllers;
@@ -27,6 +29,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
//https://linq2db.github.io/articles/sql/Join-Operators.html
public class FruitBankDataController(
FruitBankDbContext ctx,
+ MeasurementService measurementService,
IWorkContext workContext,
ICustomerService customerService,
ICustomerRegistrationService customerRegistrationService,
@@ -36,6 +39,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
{
private readonly ILogger _logger = new Logger(logWriters.ToArray());
+ [SignalR(SignalRTags.ProcessAndSaveFullShippingJson)]
+ public async Task> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId)
+ {
+ return await measurementService.ProcessAndSaveFullShippingJson(fullShippingJson, customerId);
+ }
[SignalR(SignalRTags.GetMeasuringModels)]
public Task> GetMeasuringModels()
@@ -127,6 +135,17 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
return shippingItem;
}
+ [SignalR(SignalRTags.AddShippingItem)]
+ public async Task AddShippingItem(ShippingItem shippingItem)
+ {
+ ArgumentNullException.ThrowIfNull(shippingItem);
+
+ _logger.Detail($"AddShippingItem invoked; id: {shippingItem.Id}");
+
+ if (!await ctx.AddShippingItemAsync(shippingItem)) return null;
+ return await ctx.ShippingItems.GetByIdAsync(shippingItem.Id, shippingItem.ShippingDocument != null);
+ }
+
[SignalR(SignalRTags.UpdateShippingItem)]
public async Task UpdateShippingItem(ShippingItem shippingItem)
{
@@ -218,6 +237,17 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
return await ctx.ShippingDocuments.GetByIdAsync(id, true);
}
+ [SignalR(SignalRTags.AddShippingDocument)]
+ public async Task AddShippingDocument(ShippingDocument shippingDocument)
+ {
+ ArgumentNullException.ThrowIfNull(shippingDocument);
+
+ _logger.Detail($"AddShippingDocument invoked; id: {shippingDocument.Id}");
+
+ await ctx.ShippingDocuments.InsertAsync(shippingDocument);
+ return await ctx.ShippingDocuments.GetByIdAsync(shippingDocument.Id, shippingDocument.Shipping != null || shippingDocument.Partner != null);
+ }
+
[SignalR(SignalRTags.UpdateShippingDocument)]
public async Task UpdateShippingDocument(ShippingDocument shippingDocument)
{
diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs
index b60b8ad..1d2311b 100644
--- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs
@@ -152,6 +152,25 @@ public class FruitBankDbContext : MgDbContextBase,
//public async Task GetMeasuringAttributeValuesByProductIdAsync(int productId)
// => await _fruitBankAttributeService.GetMeasuringAttributeValuesAsync(productId);
+ //public async Task> ProcessAndSaveFullShippingDocumentJson(string fullShippingDocumentJson)
+ //{
+ // var partners = fullShippingDocumentJson.JsonTo>();
+ // if (partners != null)
+ // {
+ // foreach (var partner in partners)
+ // {
+ // //await Partners.InsertAsync(partner);
+ // if (partner.ShippingDocuments == null) continue;
+
+ // foreach (var shippingDocument in partner.ShippingDocuments)
+ // {
+ // await ShippingDocuments.InsertAsync(shippingDocument);
+
+ // }
+ // }
+ // }
+ //}
+
public async Task DeleteShippingSafeAsync(Shipping shipping)
{
await TransactionSafeAsync(async _ =>
@@ -186,6 +205,14 @@ public class FruitBankDbContext : MgDbContextBase,
Logger.Error("shippingItem.IsMeasurable && !shippingItem.IsValidMeasuringValues()");
return Task.FromResult(false);
}
+ public Task AddShippingItemSafeAsync(ShippingItem shippingItem)
+ => TransactionSafeAsync(async _ => await AddShippingItemAsync(shippingItem));
+
+ public async Task AddShippingItemAsync(ShippingItem shippingItem)
+ {
+ await ShippingItems.InsertAsync(shippingItem);
+ return true;
+ }
public Task UpdateShippingItemSafeAsync(ShippingItem shippingItem)
=> TransactionSafeAsync(async _ => await UpdateShippingItemAsync(shippingItem));
@@ -268,7 +295,7 @@ public class FruitBankDbContext : MgDbContextBase,
}
//if (productIdUnchanged || !dbShippingItem.IsMeasured) return true;
- if (!productIdChanged && (shippingItem.IsMeasured || !dbShippingItem.IsMeasured)) return true;
+ if (!dbShippingItem.ProductId.HasValue || (!productIdChanged && (shippingItem.IsMeasured || !dbShippingItem.IsMeasured))) return true;
productDto = await ProductDtos.GetByIdAsync(dbShippingItem.ProductId!.Value, true);
@@ -460,6 +487,22 @@ public class FruitBankDbContext : MgDbContextBase,
return orderDto;
}
+ public async Task SetOrderStatusToPendingSafeAsync(Order order)
+ => await TransactionSafeAsync(async _ => await SetOrderStatusToPendingAsync(order));
+
+ public async Task SetOrderStatusToPendingAsync(Order order)
+ {
+ if (order.OrderStatus == OrderStatus.Pending) return true;
+
+ var prevOrderStatus = order.OrderStatus;
+ order.OrderStatus = OrderStatus.Pending;
+
+ await Orders.UpdateAsync(order, false);
+ await _eventPublisher.PublishAsync(new OrderStatusChangedEvent(order, prevOrderStatus));
+
+ return true;
+ }
+
public Task DeleteOrderItemConstraintsSafeAsync(OrderItem orderItem, bool publishEvent = false)
{
return TransactionSafeAsync(async _ =>
diff --git a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
index f9e70c8..1bb38be 100644
--- a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
+++ b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
@@ -27,10 +27,12 @@
+
+
diff --git a/Nop.Plugin.Misc.AIPlugin/Services/MeasurementService.cs b/Nop.Plugin.Misc.AIPlugin/Services/MeasurementService.cs
index 518e5f3..c21fabe 100644
--- a/Nop.Plugin.Misc.AIPlugin/Services/MeasurementService.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Services/MeasurementService.cs
@@ -1,14 +1,21 @@
-using AyCode.Core.Loggers;
+using AyCode.Core.Extensions;
+using AyCode.Core.Loggers;
+using AyCode.Services.Server.SignalRs;
using FruitBank.Common.Dtos;
+using FruitBank.Common.Entities;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Server.Services.SignalRs;
using FruitBank.Common.Services;
using Mango.Nop.Core.Extensions;
using Mango.Nop.Core.Loggers;
+using Microsoft.CodeAnalysis.Operations;
using Nop.Core.Domain.Catalog;
+using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders;
+using Nop.Core.Events;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Services.Catalog;
+using Nop.Services.Events;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
@@ -16,18 +23,21 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
public class MeasurementService : MeasurementServiceBase, IMeasurementService
{
private readonly FruitBankDbContext _dbContext;
+ private readonly IEventPublisher _eventPublisher;
+ private readonly FruitBankAttributeService _fruitBankAttributeService;
private readonly SignalRSendToClientService _signalRSendToClientService;
private readonly CustomPriceCalculationService _customPriceCalculationService;
- public MeasurementService(FruitBankDbContext dbContext, SignalRSendToClientService signalRSendToClientService, FruitBankAttributeService fruitBankAttributeService,
- IPriceCalculationService customPriceCalculationService, IEnumerable logWriters) : base(new Logger(logWriters.ToArray()))
+ public MeasurementService(FruitBankDbContext dbContext, SignalRSendToClientService signalRSendToClientService, FruitBankAttributeService fruitBankAttributeService,
+ IPriceCalculationService customPriceCalculationService, IEventPublisher eventPublisher, IEnumerable logWriters) : base(new Logger(logWriters.ToArray()))
{
_dbContext = dbContext;
+ _eventPublisher = eventPublisher;
+ _fruitBankAttributeService = fruitBankAttributeService;
_signalRSendToClientService = signalRSendToClientService;
_customPriceCalculationService = (CustomPriceCalculationService)customPriceCalculationService;
}
-
public async Task DeleteOrderItemConstraintsAsync(int orderItemId) => await DeleteOrderItemConstraintsAsync(await _dbContext.OrderItems.GetByIdAsync(orderItemId));
public async Task DeleteOrderItemConstraintsAsync(OrderItem orderItem)
@@ -56,4 +66,82 @@ public class MeasurementService : MeasurementServiceBase, IMeasurementSe
await _customPriceCalculationService.CheckAndUpdateOrderTotalPrice(order);
}
}
+
+ public async Task OrderItemMeasuringReset(int orderItemId)
+ => await OrderItemMeasuringReset(await _dbContext.OrderItems.GetByIdAsync(orderItemId));
+
+ public async Task OrderItemMeasuringReset(OrderItem orderItem)
+ {
+ var order = await _dbContext.Orders.GetByIdAsync(orderItem.OrderId);
+ var orderItemPallets = await _dbContext.OrderItemPallets.GetAllByOrderItemId(orderItem.Id, false).ToListAsync();
+
+ var result = await _dbContext.TransactionSafeAsync(async _ =>
+ {
+ await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync(order.Id, nameof(IOrderDto.RevisorId), 0);
+
+ foreach (var orderItemPallet in orderItemPallets)
+ {
+ orderItemPallet.RevisorId = 0;
+ await _dbContext.OrderItemPallets.UpdateAsync(orderItemPallet);
+ }
+
+ if (order.OrderStatus == OrderStatus.Complete)
+ await _dbContext.SetOrderStatusToPendingAsync(order);
+
+ return true;
+ });
+
+ if (!result) return result;
+
+ foreach (var orderItemPallet in orderItemPallets)
+ await _signalRSendToClientService.SendOrderItemPalletChanged(orderItemPallet);
+
+ await _signalRSendToClientService.SendOrderChanged(await _dbContext.OrderDtos.GetByIdAsync(orderItem.OrderId, true));
+ return result;
+ }
+
+ public async Task?> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId)
+ {
+ var partners = fullShippingJson.JsonTo>();
+ if (partners == null || partners.Count == 0) return partners;
+
+ var a = partners.SelectMany(x => x.ShippingDocuments?.SelectMany(sd => sd.ShippingItems?.Where(si => si.ProductId.GetValueOrDefault(0) > 0).Select(si => si.ProductId!.Value) ?? []) ?? []).ToHashSet();
+ var productDtosById = await _dbContext.ProductDtos.GetAllByIds(a, false, false).ToDictionaryAsync(k => k.Id, v => v);
+
+ var result = await _dbContext.TransactionSafeAsync(async _ =>
+ {
+ foreach (var partner in partners)
+ {
+ //await _dbContext.Partners.InsertAsync(partner, false);
+ if (partner.ShippingDocuments == null) continue;
+
+ foreach (var shippingDocument in partner.ShippingDocuments)
+ {
+ //shippingDocument.PartnerId = 0;
+ await _dbContext.ShippingDocuments.InsertAsync(shippingDocument, false);
+
+ if (shippingDocument.ShippingItems == null) continue;
+
+ foreach (var shippingItem in shippingDocument.ShippingItems)
+ {
+ if (shippingItem.ProductId != null && productDtosById.TryGetValue(shippingItem.ProductId.Value, out var productDto))
+ {
+ shippingItem.Name = productDto.Name;
+ shippingItem.IsMeasurable = productDto.IsMeasurable;
+
+ //TODO: Update Product Incoming attribute! - J.
+ }
+ else shippingItem.ProductId = null;
+
+ shippingItem.ShippingDocumentId = shippingDocument.Id;
+ await _dbContext.ShippingItems.InsertAsync(shippingItem, false);
+ }
+ }
+ }
+
+ return true;
+ });
+
+ return result ? partners : null;
+ }
}
\ No newline at end of file
diff --git a/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs b/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
index e94d49f..70802ee 100644
--- a/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
@@ -312,6 +312,34 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
_assistantId ??= await FindOrCreateAssistantAsync("PDF and Image Analyzer Assistant");
}
+ public async Task CleanupAllVectorStoresAsync()
+ {
+ Console.WriteLine("Cleaning up all existing vector stores...");
+ var listRequest = new HttpRequestMessage(HttpMethod.Get, $"{BaseUrl}/vector_stores");
+ listRequest.Headers.Add("OpenAI-Beta", "assistants=v2");
+
+ var response = await _httpClient.SendAsync(listRequest);
+ if (response.IsSuccessStatusCode)
+ {
+ using var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
+ var vectorStores = json.RootElement.GetProperty("data");
+
+ foreach (var vectorStore in vectorStores.EnumerateArray())
+ {
+ var id = vectorStore.GetProperty("id").GetString();
+ var name = vectorStore.TryGetProperty("name", out var nameElement) && nameElement.ValueKind != JsonValueKind.Null
+ ? nameElement.GetString()
+ : "Unnamed";
+
+ var deleteRequest = new HttpRequestMessage(HttpMethod.Delete, $"{BaseUrl}/vector_stores/{id}");
+ deleteRequest.Headers.Add("OpenAI-Beta", "assistants=v2");
+ await _httpClient.SendAsync(deleteRequest);
+
+ Console.WriteLine($"Deleted vector store: {name} ({id})");
+ }
+ Console.WriteLine("Vector store cleanup complete!");
+ }
+ }
//TEMPORARY: Cleanup all assistants (for testing purposes) - A.
public async Task CleanupAllAssistantsAsync()
{
@@ -347,8 +375,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
public async Task AnalyzePdfAsync(Stream file, string fileName, string userPrompt)
{
-
await EnsureAssistantAndVectorStoreAsync();
+
var fileId = await UploadFileAsync(file, fileName);
var isImage = IsImageFile(fileName);
@@ -640,7 +668,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
var assistantBody = new
{
name = name,
- instructions = "You are an assistant that analyzes uploaded files. When you receive an image, analyze and describe what you see in the image in detail. When you receive a PDF or text document, use the file_search tool to find and analyze relevant information. Always respond directly to the user's question about the file they uploaded.",
+ instructions = "You are an assistant that analyzes uploaded files. When you receive an image, analyze and describe what you see in the image in detail. When you receive a PDF or text document, use the file_search tool to find and analyze relevant information. Always respond directly according to the user's instructions about the current file they upload.",
model = "gpt-4o",
tools = new[] { new { type = "file_search" } }
};