Merge branch '4.80' of https://git.aycode.com/Adam/Mango.Nop.Plugins into 4.80
This commit is contained in:
commit
c561c14359
File diff suppressed because one or more lines are too long
|
|
@ -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<FruitBankDataController>(logWriters.ToArray());
|
||||
|
||||
[SignalR(SignalRTags.ProcessAndSaveFullShippingJson)]
|
||||
public async Task<List<Partner>> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId)
|
||||
{
|
||||
return await measurementService.ProcessAndSaveFullShippingJson(fullShippingJson, customerId);
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.GetMeasuringModels)]
|
||||
public Task<List<MeasuringModel>> GetMeasuringModels()
|
||||
|
|
@ -127,6 +135,17 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
|||
return shippingItem;
|
||||
}
|
||||
|
||||
[SignalR(SignalRTags.AddShippingItem)]
|
||||
public async Task<ShippingItem> 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<ShippingItem> 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<ShippingDocument> 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<ShippingDocument> UpdateShippingDocument(ShippingDocument shippingDocument)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -152,6 +152,25 @@ public class FruitBankDbContext : MgDbContextBase,
|
|||
//public async Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesByProductIdAsync(int productId)
|
||||
// => await _fruitBankAttributeService.GetMeasuringAttributeValuesAsync<Product>(productId);
|
||||
|
||||
//public async Task<List<Partner>> ProcessAndSaveFullShippingDocumentJson(string fullShippingDocumentJson)
|
||||
//{
|
||||
// var partners = fullShippingDocumentJson.JsonTo<List<Partner>>();
|
||||
// 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<bool> AddShippingItemSafeAsync(ShippingItem shippingItem)
|
||||
=> TransactionSafeAsync(async _ => await AddShippingItemAsync(shippingItem));
|
||||
|
||||
public async Task<bool> AddShippingItemAsync(ShippingItem shippingItem)
|
||||
{
|
||||
await ShippingItems.InsertAsync(shippingItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<bool> 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<bool> SetOrderStatusToPendingSafeAsync(Order order)
|
||||
=> await TransactionSafeAsync(async _ => await SetOrderStatusToPendingAsync(order));
|
||||
|
||||
public async Task<bool> 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 _ =>
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Common" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.10" />
|
||||
<!--<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.10" />-->
|
||||
<PackageReference Include="PdfPig" Version="0.1.11" />
|
||||
<PackageReference Include="PdfPig.Rendering.Skia" Version="0.1.11.5" />
|
||||
<PackageReference Include="SendGrid" Version="9.29.3" />
|
||||
<PackageReference Include="System.Memory.Data" Version="9.0.10" />
|
||||
<PackageReference Include="Tesseract" Version="5.2.0" />
|
||||
<PackageReference Include="TesseractOCR" Version="5.5.1" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -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<Logger>, 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<IAcLogWriterBase> logWriters) : base(new Logger<MeasurementService>(logWriters.ToArray()))
|
||||
public MeasurementService(FruitBankDbContext dbContext, SignalRSendToClientService signalRSendToClientService, FruitBankAttributeService fruitBankAttributeService,
|
||||
IPriceCalculationService customPriceCalculationService, IEventPublisher eventPublisher, IEnumerable<IAcLogWriterBase> logWriters) : base(new Logger<MeasurementService>(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<Logger>, IMeasurementSe
|
|||
await _customPriceCalculationService.CheckAndUpdateOrderTotalPrice(order);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> OrderItemMeasuringReset(int orderItemId)
|
||||
=> await OrderItemMeasuringReset(await _dbContext.OrderItems.GetByIdAsync(orderItemId));
|
||||
|
||||
public async Task<bool> 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, int>(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<List<Partner>?> ProcessAndSaveFullShippingJson(string fullShippingJson, int customerId)
|
||||
{
|
||||
var partners = fullShippingJson.JsonTo<List<Partner>>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<string?> 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" } }
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue