diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs index b253e2a..91aaba9 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs @@ -765,6 +765,48 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // }; //} + + /// + /// Add a note to an order that will be displayed in the external application + /// + [HttpPost] + public async Task AddOrderNote(int orderId, string note) + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_CREATE_EDIT_DELETE)) + return Json(new { success = false, message = "Access denied" }); + + if (orderId <= 0) + { + return Json(new { success = false, message = "Invalid order ID" }); + } + + if (string.IsNullOrWhiteSpace(note)) + { + return Json(new { success = false, message = "Note text is required" }); + } + + try + { + // Create and insert the order note + await InsertOrderNoteAsync(orderId, displayToCustomer: false, note); + + return Json(new + { + success = true, + message = "Order note added successfully" + }); + } + catch (Exception ex) + { + return Json(new + { + success = false, + message = $"Error adding order note: {ex.Message}" + }); + } + } + + private static OrderNote CreateOrderNote(int orderId, bool displayToCustomer, string note) { return new OrderNote @@ -878,7 +920,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers if (string.IsNullOrWhiteSpace(term) || term.Length < 2) return Json(new List()); - const int maxResults = 15; + const int maxResults = 30; // Search products by name or SKU var products = await _productService.SearchProductsAsync( @@ -892,16 +934,21 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers foreach (var product in products) { var productDto = productDtosById[product.Id]; - - result.Add(new + if (productDto != null) { - label = $"{product.Name} [RENDELHETŐ: {(product.StockQuantity + productDto.IncomingQuantity)}] [ÁR: {product.Price}]", - value = product.Id, - sku = product.Sku, - price = product.Price, - stockQuantity = product.StockQuantity, - incomingQuantity = productDto.IncomingQuantity, - }); + if(productDto.AvailableQuantity > 0) + { + result.Add(new + { + label = $"{product.Name} [RENDELHETŐ: {(product.StockQuantity + productDto.IncomingQuantity)}] [ÁR: {product.Price}]", + value = product.Id, + sku = product.Sku, + price = product.Price, + stockQuantity = product.StockQuantity, + incomingQuantity = productDto.IncomingQuantity, + }); + } + } } return Json(result); diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Extras/VoiceRecorder.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Extras/VoiceRecorder.cshtml index 643d1bb..dfba28b 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Extras/VoiceRecorder.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Extras/VoiceRecorder.cshtml @@ -1,4 +1,4 @@ -@{ +@{ Layout = "_ConfigurePlugin"; } @@ -13,6 +13,21 @@ Voice Recorder Click the button below to start recording your voice message. + + Important: When you click "Start Recording", your browser will ask for permission to use your microphone. Please click "Allow" to enable voice recording. + + + + Microphone Permission Required + Your browser blocked microphone access. To enable it: + + Chrome/Edge: Click the camera/microphone icon in the address bar (or the lock icon) → Site settings → Allow Microphone + Firefox: Click the microphone icon in the address bar → Click the X to remove the block → Refresh the page + Safari: Safari menu → Settings for This Website → Microphone → Allow + + After allowing permission, refresh this page and try again. + + @@ -70,9 +85,29 @@ const responseMessage = document.getElementById('responseMessage'); const transcriptionResult = document.getElementById('transcriptionResult'); const transcriptionText = document.getElementById('transcriptionText'); + const permissionInstructions = document.getElementById('permissionInstructions'); recordButton.addEventListener('click', async () => { try { + // Hide permission instructions if shown + permissionInstructions.style.display = 'none'; + + // Check if we're on HTTPS or localhost + const isSecure = window.location.protocol === 'https:' || + window.location.hostname === 'localhost' || + window.location.hostname === '127.0.0.1'; + + if (!isSecure) { + showMessage('Error: Microphone access requires HTTPS connection. Please access this page via HTTPS.', 'danger'); + return; + } + + // Check if getUserMedia is supported + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + showMessage('Error: Your browser does not support audio recording. Please use a modern browser like Chrome, Firefox, or Edge.', 'danger'); + return; + } + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream); @@ -103,7 +138,35 @@ } catch (error) { console.error('Error accessing microphone:', error); - showMessage('Error: Could not access microphone. Please check permissions.', 'danger'); + + let errorMessage = 'Error: Could not access microphone. '; + let showInstructions = false; + + if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') { + errorMessage = 'Microphone access was denied. Please see the instructions below to enable microphone access.'; + showInstructions = true; + } else if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') { + errorMessage += 'No microphone found. Please connect a microphone and try again.'; + } else if (error.name === 'NotReadableError' || error.name === 'TrackStartError') { + errorMessage += 'Microphone is already in use by another application. Please close other applications using the microphone.'; + } else if (error.name === 'OverconstrainedError' || error.name === 'ConstraintNotSatisfiedError') { + errorMessage += 'Microphone does not meet the required constraints.'; + } else if (error.name === 'NotSupportedError') { + errorMessage += 'This page must be accessed via HTTPS to use the microphone.'; + } else if (error.name === 'TypeError') { + errorMessage += 'This page must be accessed via HTTPS to use the microphone.'; + } else { + errorMessage += error.message || 'Unknown error occurred.'; + } + + showMessage(errorMessage, 'danger'); + + // Show permission instructions if needed + if (showInstructions) { + permissionInstructions.style.display = 'block'; + // Scroll to instructions + permissionInstructions.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } } }); @@ -133,7 +196,7 @@ // Get the antiforgery token const token = document.querySelector('input[name="__RequestVerificationToken"]').value; - const response = await fetch('@Url.Action("ReceiveVoiceRecording", "FruitBankAudio")', { + const response = await fetch('@Url.Action("ReceiveVoiceRecording", "FruitBankAdmin")', { method: 'POST', headers: { 'RequestVerificationToken': token diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/_CustomOrderDetails.Products.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/_CustomOrderDetails.Products.cshtml index 901e7a7..cfb2b49 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/_CustomOrderDetails.Products.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/_CustomOrderDetails.Products.cshtml @@ -355,7 +355,9 @@ - Eltérés: @item.AverageWeightDifference (KG), Mért átlag: @item.AverageWeight (KG/rekesz) + Eltérés: @item.AverageWeightDifference (KG) + Mért átlag: @item.AverageWeight (KG/rekesz) + Elvárt: @item.ProductAverageWeight diff --git a/Nop.Plugin.Misc.AIPlugin/Factories/CustomOrderModelFactory.cs b/Nop.Plugin.Misc.AIPlugin/Factories/CustomOrderModelFactory.cs index 3d94a7e..9acf046 100644 --- a/Nop.Plugin.Misc.AIPlugin/Factories/CustomOrderModelFactory.cs +++ b/Nop.Plugin.Misc.AIPlugin/Factories/CustomOrderModelFactory.cs @@ -228,6 +228,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Factories orderItemModelExtended.ProductStockQuantity = orderItemDto.ProductDto!.StockQuantity; orderItemModelExtended.ProductIncomingQuantity = orderItemDto.ProductDto.IncomingQuantity; orderItemModelExtended.ProductAvailableQuantity = orderItemDto.ProductDto.AvailableQuantity; + orderItemModelExtended.ProductAverageWeight = orderItemDto.ProductDto.AverageWeight; orderItemModelExtended.AverageWeight = orderItemDto.AverageWeight; orderItemModelExtended.AverageWeightIsValid = orderItemDto.AverageWeightIsValid; orderItemModelExtended.AverageWeightDifference = orderItemDto.AverageWeightDifference; diff --git a/Nop.Plugin.Misc.AIPlugin/Models/Orders/OrderModelExtended.cs b/Nop.Plugin.Misc.AIPlugin/Models/Orders/OrderModelExtended.cs index a43ba95..065baef 100644 --- a/Nop.Plugin.Misc.AIPlugin/Models/Orders/OrderModelExtended.cs +++ b/Nop.Plugin.Misc.AIPlugin/Models/Orders/OrderModelExtended.cs @@ -14,6 +14,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Models.Orders public int ProductStockQuantity { get; set; } public int ProductIncomingQuantity { get; set; } public int ProductAvailableQuantity { get; set; } + public double ProductAverageWeight { get; set; } public double AverageWeight { get; set; } public bool AverageWeightIsValid { get; set; } public double AverageWeightDifference { get; set; } diff --git a/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml b/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml index 652506f..de9ec7f 100644 --- a/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml @@ -29,7 +29,7 @@ - + Mentés @@ -38,16 +38,21 @@ - + Újramérés engedélyezése - + Üzenet küldése + + + Jegyzet hozzáadása + + @@ -60,7 +65,7 @@ - + @@ -161,6 +166,40 @@ + + + + + + + Jegyzet hozzáadása + + + × + + + + + Jegyzet szövege: + + Ez a jegyzet megjelenik az external alkalmazásban a kollégák számára. + + + + + + + + + +
Click the button below to start recording your voice message.
Your browser blocked microphone access. To enable it:
After allowing permission, refresh this page and try again.