Keresés partnerre a rendelések között, Felhasználó létrehozásakor automatikus számlázási cím hozzáadás, adószám szinkronizálás, egyéb kisebb fixek
This commit is contained in:
parent
9a94bc6c06
commit
30c8cd3e00
|
|
@ -17,6 +17,7 @@ using Nop.Core.Domain.Payments;
|
|||
using Nop.Core.Domain.Shipping;
|
||||
using Nop.Core.Domain.Tax;
|
||||
using Nop.Core.Events;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
|
||||
|
|
@ -157,7 +158,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
public virtual async Task<IActionResult> List(List<int> orderStatuses = null, List<int> paymentStatuses = null, List<int> shippingStatuses = null)
|
||||
{
|
||||
//prepare model
|
||||
var model = await _orderModelFactory.PrepareOrderSearchModelAsync(new OrderSearchModel
|
||||
var model = await _orderModelFactory.PrepareOrderSearchModelAsync(new OrderSearchModelExtended
|
||||
{
|
||||
OrderStatusIds = orderStatuses,
|
||||
PaymentStatusIds = paymentStatuses,
|
||||
|
|
@ -169,7 +170,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
|
||||
[HttpPost]
|
||||
[CheckPermission(StandardPermission.Orders.ORDERS_VIEW)]
|
||||
public async Task<IActionResult> OrderList(OrderSearchModel searchModel)
|
||||
public async Task<IActionResult> OrderList(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
//prepare model
|
||||
var orderListModel = await GetOrderListModelByFilter(searchModel);
|
||||
|
|
@ -213,7 +214,7 @@ 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(OrderSearchModel searchModel)
|
||||
public async Task<OrderListModelExtended> GetOrderListModelByFilter(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
//return _customOrderService.
|
||||
var orderListModel = await _orderModelFactory.PrepareOrderListModelExtendedAsync(searchModel);
|
||||
|
|
@ -736,7 +737,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
[HttpPost, ActionName("ExportXml")]
|
||||
[FormValueRequired("exportxml-all")]
|
||||
[CheckPermission(StandardPermission.Orders.ORDERS_IMPORT_EXPORT)]
|
||||
public virtual async Task<IActionResult> ExportXmlAll(OrderSearchModel model)
|
||||
public virtual async Task<IActionResult> ExportXmlAll(OrderSearchModelExtended model)
|
||||
{
|
||||
var startDateValue = model.StartDate == null ? null
|
||||
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync());
|
||||
|
|
@ -832,7 +833,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
[HttpPost, ActionName("ExportExcel")]
|
||||
[FormValueRequired("exportexcel-all")]
|
||||
[CheckPermission(StandardPermission.Orders.ORDERS_IMPORT_EXPORT)]
|
||||
public virtual async Task<IActionResult> ExportExcelAll(OrderSearchModel model)
|
||||
public virtual async Task<IActionResult> ExportExcelAll(OrderSearchModelExtended model)
|
||||
{
|
||||
var startDateValue = model.StartDate == null ? null
|
||||
: (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.StartDate.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync());
|
||||
|
|
|
|||
|
|
@ -63,125 +63,137 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
// Validate and get order
|
||||
var order = await _orderService.GetOrderByIdAsync(orderId);
|
||||
if (order == null)
|
||||
{
|
||||
return Json(new { success = false, message = "Order not found" });
|
||||
}
|
||||
|
||||
// Validate and get customer
|
||||
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
|
||||
if (customer == null)
|
||||
{
|
||||
return Json(new { success = false, message = "Customer not found" });
|
||||
}
|
||||
|
||||
// Get billing address
|
||||
// Get and validate billing address
|
||||
var billingAddress = await _customerService.GetCustomerBillingAddressAsync(customer);
|
||||
if (billingAddress == null)
|
||||
{
|
||||
return Json(new { success = false, message = "Billing address not found" });
|
||||
}
|
||||
|
||||
var billingCountry = await _countryService.GetCountryByAddressAsync(billingAddress);
|
||||
var billingCountryCode = billingCountry?.TwoLetterIsoCode ?? "HU";
|
||||
|
||||
// Get shipping address
|
||||
var shippingAddress = await _customerService.GetCustomerShippingAddressAsync(customer);
|
||||
|
||||
if (shippingAddress == null)
|
||||
{
|
||||
shippingAddress = billingAddress;
|
||||
}
|
||||
|
||||
var shippingCountry = shippingAddress != null
|
||||
? await _countryService.GetCountryByAddressAsync(shippingAddress)
|
||||
: null;
|
||||
// Get shipping address (fallback to billing if not found)
|
||||
var shippingAddress = await _customerService.GetCustomerShippingAddressAsync(customer) ?? billingAddress;
|
||||
var shippingCountry = await _countryService.GetCountryByAddressAsync(shippingAddress);
|
||||
var shippingCountryCode = shippingCountry?.TwoLetterIsoCode ?? billingCountryCode;
|
||||
|
||||
// Create order request
|
||||
var orderRequest = new OrderCreateRequest
|
||||
{
|
||||
VevoNev = $"{billingAddress.FirstName} {billingAddress.LastName}",
|
||||
VevoIrsz = billingAddress.ZipPostalCode ?? "",
|
||||
VevoTelep = billingAddress.City ?? "",
|
||||
VevoNev = customer.Company ?? string.Empty,
|
||||
VevoIrsz = billingAddress.ZipPostalCode ?? string.Empty,
|
||||
VevoTelep = billingAddress.City ?? string.Empty,
|
||||
VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(),
|
||||
VevoOrszag = billingCountryCode,
|
||||
VevoAdoszam = billingAddress.Company, // Or a custom field for tax number
|
||||
MegrendelestombID = 1, // Configure this based on your setup
|
||||
VevoAdoszam = customer.VatNumber,
|
||||
MegrendelestombID = 1,
|
||||
MegrendelesKelte = order.CreatedOnUtc.ToLocalTime(),
|
||||
Hatarido = DateTime.Now.AddDays(7), // 7 days delivery time
|
||||
Devizanem = "Ft", //TODO get real deault - A.
|
||||
Hatarido = DateTime.Now.AddDays(7),
|
||||
Devizanem = "Ft", // TODO: get real default - A.
|
||||
FizetesiMod = order.PaymentMethodSystemName ?? "átutalás",
|
||||
Email = billingAddress.Email,
|
||||
Telefon = billingAddress.PhoneNumber,
|
||||
Email = customer.Email ?? string.Empty,
|
||||
Telefon = billingAddress.PhoneNumber ?? string.Empty,
|
||||
MegrendelesSzamStr = order.Id.ToString()
|
||||
};
|
||||
|
||||
// Add shipping address if different
|
||||
if (shippingAddress != null)
|
||||
{
|
||||
orderRequest.SzallNev = $"{shippingAddress.FirstName} {shippingAddress.LastName}";
|
||||
orderRequest.SzallIrsz = shippingAddress.ZipPostalCode ?? "";
|
||||
orderRequest.SzallTelep = shippingAddress.City ?? "";
|
||||
// Add shipping address details
|
||||
orderRequest.SzallNev = $"{shippingAddress.FirstName} {shippingAddress.LastName}".Trim();
|
||||
orderRequest.SzallIrsz = shippingAddress.ZipPostalCode ?? string.Empty;
|
||||
orderRequest.SzallTelep = shippingAddress.City ?? string.Empty;
|
||||
orderRequest.SzallUtcaHsz = $"{shippingAddress.Address1} {shippingAddress.Address2}".Trim();
|
||||
orderRequest.SzallOrszag = shippingCountryCode;
|
||||
|
||||
// Get and validate order items
|
||||
var orderItems = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id, true).ToListAsync();
|
||||
|
||||
if (orderItems == null || orderItems.Count == 0)
|
||||
{
|
||||
return Json(new { success = false, message = "Order has no items" });
|
||||
}
|
||||
|
||||
// Add order items
|
||||
//var orderItems = await _orderService.GetOrderItemsAsync(order.Id);
|
||||
var orderItems = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id, true).ToListAsync();
|
||||
Console.WriteLine($"Order Items Count: {orderItems.Count}");
|
||||
foreach (var item in orderItems)
|
||||
{
|
||||
//var productDTO = await _productService.GetProductByIdAsync(item.ProductId);
|
||||
var product = _dbContext.ProductDtos.GetById(item.ProductId);
|
||||
//string unit = product != null && product.IsMeasurable ? "kg" : "kt";
|
||||
if(item.IsMeasurable) { // in case of measurable products, quantity is in fact weight stored in item.EnteredQuantity
|
||||
var productName = product?.Name ?? "Product";
|
||||
|
||||
if (item.IsMeasurable)
|
||||
{
|
||||
// For measurable products, quantity is weight stored in NetWeight
|
||||
orderRequest.AddItem(new InnVoiceOrderItem
|
||||
{
|
||||
TetelNev = product?.Name ?? "Product",
|
||||
AfaSzoveg = "27%", // Configure VAT rate as needed
|
||||
TetelNev = productName,
|
||||
AfaSzoveg = "27%", // TODO: Configure VAT rate dynamically
|
||||
Brutto = true,
|
||||
EgysegAr = item.UnitPriceInclTax,
|
||||
Mennyiseg = Convert.ToDecimal(item.NetWeight),
|
||||
Mennyiseg = item.NetWeight > 0 ? Convert.ToDecimal(item.NetWeight) : 0,
|
||||
MennyisegEgyseg = "kg",
|
||||
CikkSzam = ""
|
||||
CikkSzam = string.Empty
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
orderRequest.AddItem(new InnVoiceOrderItem
|
||||
{
|
||||
TetelNev = product?.Name ?? "Product",
|
||||
AfaSzoveg = "27%", // Configure VAT rate as needed
|
||||
TetelNev = productName,
|
||||
AfaSzoveg = "27%", // TODO: Configure VAT rate dynamically
|
||||
Brutto = true,
|
||||
EgysegAr = item.UnitPriceInclTax,
|
||||
Mennyiseg = item.Quantity,
|
||||
MennyisegEgyseg = "kt",
|
||||
CikkSzam = ""
|
||||
CikkSzam = string.Empty
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create order via API
|
||||
var response = await _innVoiceOrderService.CreateOrderAsync(orderRequest);
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
return Json(new { success = false, message = "No response from InnVoice API" });
|
||||
}
|
||||
|
||||
if (response.IsSuccess)
|
||||
{
|
||||
// Save the TechId, TableId, and PrintUrl to the order for future reference
|
||||
var currentStore = await _storeContext.GetCurrentStoreAsync();
|
||||
var storeId = currentStore?.Id ?? 0;
|
||||
|
||||
// Save InnVoice order details as attributes
|
||||
await _genericAttributeService.SaveAttributeAsync(
|
||||
order,
|
||||
"InnVoiceOrderTechId",
|
||||
response.TechId,
|
||||
(await _storeContext.GetCurrentStoreAsync()).Id
|
||||
storeId
|
||||
);
|
||||
|
||||
await _genericAttributeService.SaveAttributeAsync(
|
||||
order,
|
||||
"InnVoiceOrderTableId",
|
||||
response.TableId?.ToString(),
|
||||
(await _storeContext.GetCurrentStoreAsync()).Id
|
||||
response.TableId?.ToString() ?? string.Empty,
|
||||
storeId
|
||||
);
|
||||
|
||||
await _genericAttributeService.SaveAttributeAsync(
|
||||
order,
|
||||
"InnVoiceOrderPrintLink",
|
||||
response.PrintUrl?.ToString(),
|
||||
(await _storeContext.GetCurrentStoreAsync()).Id
|
||||
response.PrintUrl?.ToString() ?? string.Empty,
|
||||
storeId
|
||||
);
|
||||
|
||||
return Json(new
|
||||
|
|
@ -196,17 +208,18 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
|||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
message = $"InnVoice API Error: {response.Message}"
|
||||
message = $"InnVoice API Error: {response.Message ?? "Unknown error"}"
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception here
|
||||
// _logger.LogError(ex, "Error creating order {OrderId} in InnVoice", orderId);
|
||||
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Nop.Web.Areas.Admin.Models.Orders;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order
|
||||
{
|
||||
public partial record OrderSearchModelExtended : OrderSearchModel
|
||||
{
|
||||
|
||||
[NopResourceDisplayName("Admin.Orders.List.BillingCompany")]
|
||||
public string BillingCompany { get; set; }
|
||||
|
||||
//public IList<SelectListItem> AvailableCompanies { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
@model OrderSearchModel
|
||||
@model OrderSearchModelExtended
|
||||
|
||||
|
||||
@inject IStoreService storeService
|
||||
@using FruitBank.Common.Interfaces
|
||||
@using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order
|
||||
@using Nop.Plugin.Misc.FruitBankPlugin.Models
|
||||
@using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders
|
||||
@using Nop.Services.Stores
|
||||
|
|
@ -96,7 +98,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.OrderListButtons, additionalData = Model })
|
||||
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.OrderListButtons, additionalData = (OrderSearchModel)Model })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -174,6 +176,45 @@
|
|||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-md-4">
|
||||
<nop-label asp-for="BillingCompany" />
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<input type="text" id="search-company-name" autocomplete="off" class="form-control" />
|
||||
<span id="search-company-friendly-name"></span>
|
||||
<button type="button" id="search-company-clear" class="btn bg-gray" style="display: none; margin-top: 5px;">@T("Admin.Common.Clear")</button>
|
||||
<input asp-for="BillingCompany" autocomplete="off" style="display: none;" />
|
||||
<script>
|
||||
$(function() {
|
||||
$('#search-company-name').autocomplete({
|
||||
delay: 500,
|
||||
minLength: 3,
|
||||
source: '@Url.Action("CustomerSearchAutoComplete", "CustomOrder")',
|
||||
select: function(event, ui) {
|
||||
|
||||
|
||||
$('#@Html.IdFor(model => model.BillingCompany)').val(ui.item.value);
|
||||
$('#search-company-friendly-name').text(ui.item.label);
|
||||
|
||||
$('#search-company-clear').show();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
//remove button
|
||||
$('#search-company-clear').click(function() {
|
||||
$('#@Html.IdFor(model => model.BillingCompany)').val('');
|
||||
$('#search-company-friendly-name').text('');
|
||||
$('#search-company-clear').hide();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row" @(Model.IsLoggedInAsVendor? Html.Raw("style='display: none;'") : null)>
|
||||
<div class="col-md-4">
|
||||
<nop-label asp-for="OrderStatusIds" />
|
||||
|
|
@ -326,6 +367,7 @@
|
|||
new FilterParameter(nameof(Model.BillingEmail)),
|
||||
new FilterParameter(nameof(Model.BillingPhone)),
|
||||
new FilterParameter(nameof(Model.BillingLastName)),
|
||||
new FilterParameter(nameof(Model.BillingCompany)),
|
||||
new FilterParameter(nameof(Model.BillingCountryId)),
|
||||
new FilterParameter(nameof(Model.PaymentMethodSystemName)),
|
||||
new FilterParameter(nameof(Model.ProductId)),
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public class FruitBankDbContext : MgDbContextBase,
|
|||
public IRepository<Customer> Customers { get; set; }
|
||||
public IRepository<CustomerRole> CustomerRoles { get; set; }
|
||||
public IRepository<CustomerCustomerRoleMapping> CustomerRoleMappings { get; set; }
|
||||
public IRepository<CustomerAddressMapping> CustomerAddressMappings { get; set; }
|
||||
|
||||
public FruitBankDbContext(INopDataProvider dataProvider, ILockService lockService, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext,
|
||||
PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingDocumentDbTable shippingDocumentDbTable, ShippingItemDbTable shippingItemDbTable,
|
||||
|
|
@ -72,6 +73,7 @@ public class FruitBankDbContext : MgDbContextBase,
|
|||
IRepository<Product> productRepository,
|
||||
IRepository<Customer> customerRepository,
|
||||
IRepository<CustomerCustomerRoleMapping> customerCustomerRoleMappingRepository,
|
||||
IRepository<CustomerAddressMapping> customerAddressMappingRepository,
|
||||
IRepository<CustomerRole> customerRoleRepository,IEventPublisher eventPublisher,
|
||||
IEnumerable<IAcLogWriterBase> logWriters) : base(productRepository, orderRepository, orderItemRepository, dataProvider, lockService, new Logger<FruitBankDbContext>(logWriters.ToArray()))
|
||||
{
|
||||
|
|
@ -100,6 +102,7 @@ public class FruitBankDbContext : MgDbContextBase,
|
|||
Customers = customerRepository;
|
||||
CustomerRoles = customerRoleRepository;
|
||||
CustomerRoleMappings = customerCustomerRoleMappingRepository;
|
||||
CustomerAddressMappings = customerAddressMappingRepository;
|
||||
}
|
||||
|
||||
public IQueryable<Customer> GetCustomersBySystemRoleName(string systemRoleName)
|
||||
|
|
@ -528,4 +531,15 @@ public class FruitBankDbContext : MgDbContextBase,
|
|||
var list = await ShippingDocuments.GetAll(true).Where(sd => sd.ShippingId == shippingId).ToListAsync();
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<CustomerAddressMapping?> AddCustomerAddressMappingAsync(int customerId, int addressId)
|
||||
{
|
||||
var customerAddressMapping = new CustomerAddressMapping
|
||||
{
|
||||
CustomerId = customerId,
|
||||
AddressId = addressId
|
||||
};
|
||||
await CustomerAddressMappings.InsertAsync(customerAddressMapping);
|
||||
return customerAddressMapping;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
|||
using Nop.Plugin.Misc.FruitBankPlugin.Factories.MgBase;
|
||||
using FruitBank.Common.Dtos;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
||||
{
|
||||
|
|
@ -149,7 +150,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
|||
_orderMeasurementService = orderMeasurementService;
|
||||
}
|
||||
#endregion Ctor
|
||||
public override async Task<OrderSearchModel> PrepareOrderSearchModelAsync(OrderSearchModel searchModel)
|
||||
public override async Task<OrderSearchModelExtended> PrepareOrderSearchModelAsync(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
var baseModel = await base.PrepareOrderSearchModelAsync(searchModel);
|
||||
return baseModel;
|
||||
|
|
@ -158,7 +159,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Factories
|
|||
public override async Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
|
||||
=> await base.PrepareOrderListModelAsync(searchModel);
|
||||
|
||||
public async Task<OrderListModelExtended> PrepareOrderListModelExtendedAsync(OrderSearchModel searchModel)
|
||||
public async Task<OrderListModelExtended> PrepareOrderListModelExtendedAsync(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
Dictionary<int, OrderDto> orderDtosById = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using AyCode.Core.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Newtonsoft.Json;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Catalog;
|
||||
using Nop.Core.Domain.Common;
|
||||
|
|
@ -8,6 +10,7 @@ using Nop.Core.Domain.Directory;
|
|||
using Nop.Core.Domain.Orders;
|
||||
using Nop.Core.Domain.Shipping;
|
||||
using Nop.Core.Domain.Tax;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Services;
|
||||
|
|
@ -30,7 +33,9 @@ using Nop.Services.Stores;
|
|||
using Nop.Services.Tax;
|
||||
using Nop.Services.Vendors;
|
||||
using Nop.Web.Areas.Admin.Factories;
|
||||
using Nop.Web.Areas.Admin.Models.Common;
|
||||
using Nop.Web.Areas.Admin.Models.Orders;
|
||||
using Nop.Web.Framework.Extensions;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Factories.MgBase;
|
||||
|
||||
|
|
@ -138,18 +143,120 @@ public class MgOrderModelFactory<TOrderListModelExt, TOrderModelExt> : OrderMode
|
|||
}
|
||||
#endregion Cotr
|
||||
|
||||
public override Task<OrderSearchModel> PrepareOrderSearchModelAsync(OrderSearchModel searchModel)
|
||||
=> base.PrepareOrderSearchModelAsync(searchModel);
|
||||
|
||||
public override Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
|
||||
=> base.PrepareOrderListModelAsync(searchModel);
|
||||
|
||||
public virtual async Task<TOrderListModelExt> PrepareOrderListModelExtendedAsync(OrderSearchModel searchModel, Func<OrderListModel, TOrderModelExt, Task> dataItemCopiedCallback)
|
||||
public virtual async Task<OrderSearchModelExtended> PrepareOrderSearchModelAsync(OrderSearchModelExtended searchModel)
|
||||
{
|
||||
var orderListModel = await PrepareOrderListModelAsync(searchModel);
|
||||
var extendedRows = new List<TOrderModelExt>(orderListModel.RecordsFiltered);
|
||||
ArgumentNullException.ThrowIfNull(searchModel);
|
||||
|
||||
foreach (var orderModel in orderListModel.Data.ToList())
|
||||
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
|
||||
searchModel.BillingPhoneEnabled = _addressSettings.PhoneEnabled;
|
||||
|
||||
var licenseCheckModel = new LicenseCheckModel();
|
||||
try
|
||||
{
|
||||
var result = await _nopHttpClient.GetLicenseCheckDetailsAsync();
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
licenseCheckModel = JsonConvert.DeserializeObject<LicenseCheckModel>(result);
|
||||
if (licenseCheckModel.DisplayWarning == false && licenseCheckModel.BlockPages == false)
|
||||
await _settingService.SetSettingAsync($"{nameof(AdminAreaSettings)}.{nameof(AdminAreaSettings.CheckLicense)}", false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
searchModel.LicenseCheckModel = licenseCheckModel;
|
||||
|
||||
//prepare available order, payment and shipping statuses
|
||||
await _baseAdminModelFactory.PrepareOrderStatusesAsync(searchModel.AvailableOrderStatuses);
|
||||
if (searchModel.AvailableOrderStatuses.Any())
|
||||
{
|
||||
if (searchModel.OrderStatusIds?.Any() ?? false)
|
||||
{
|
||||
var ids = searchModel.OrderStatusIds.Select(id => id.ToString());
|
||||
var statusItems = searchModel.AvailableOrderStatuses.Where(statusItem => ids.Contains(statusItem.Value)).ToList();
|
||||
foreach (var statusItem in statusItems)
|
||||
{
|
||||
statusItem.Selected = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
searchModel.AvailableOrderStatuses.FirstOrDefault().Selected = true;
|
||||
}
|
||||
|
||||
await _baseAdminModelFactory.PreparePaymentStatusesAsync(searchModel.AvailablePaymentStatuses);
|
||||
if (searchModel.AvailablePaymentStatuses.Any())
|
||||
{
|
||||
if (searchModel.PaymentStatusIds?.Any() ?? false)
|
||||
{
|
||||
var ids = searchModel.PaymentStatusIds.Select(id => id.ToString());
|
||||
var statusItems = searchModel.AvailablePaymentStatuses.Where(statusItem => ids.Contains(statusItem.Value)).ToList();
|
||||
foreach (var statusItem in statusItems)
|
||||
{
|
||||
statusItem.Selected = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
searchModel.AvailablePaymentStatuses.FirstOrDefault().Selected = true;
|
||||
}
|
||||
|
||||
await _baseAdminModelFactory.PrepareShippingStatusesAsync(searchModel.AvailableShippingStatuses);
|
||||
if (searchModel.AvailableShippingStatuses.Any())
|
||||
{
|
||||
if (searchModel.ShippingStatusIds?.Any() ?? false)
|
||||
{
|
||||
var ids = searchModel.ShippingStatusIds.Select(id => id.ToString());
|
||||
var statusItems = searchModel.AvailableShippingStatuses.Where(statusItem => ids.Contains(statusItem.Value)).ToList();
|
||||
foreach (var statusItem in statusItems)
|
||||
{
|
||||
statusItem.Selected = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
searchModel.AvailableShippingStatuses.FirstOrDefault().Selected = true;
|
||||
}
|
||||
|
||||
//prepare available stores
|
||||
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
|
||||
|
||||
//prepare available vendors
|
||||
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
|
||||
|
||||
//prepare available warehouses
|
||||
await _baseAdminModelFactory.PrepareWarehousesAsync(searchModel.AvailableWarehouses);
|
||||
|
||||
|
||||
//prepare available payment methods
|
||||
searchModel.AvailablePaymentMethods = (await _paymentPluginManager.LoadAllPluginsAsync()).Select(method =>
|
||||
new SelectListItem { Text = method.PluginDescriptor.FriendlyName, Value = method.PluginDescriptor.SystemName }).ToList();
|
||||
searchModel.AvailablePaymentMethods.Insert(0, new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.Common.All"), Value = string.Empty });
|
||||
|
||||
//prepare available billing countries
|
||||
searchModel.AvailableCountries = (await _countryService.GetAllCountriesForBillingAsync(showHidden: true))
|
||||
.Select(country => new SelectListItem { Text = country.Name, Value = country.Id.ToString() }).ToList();
|
||||
searchModel.AvailableCountries.Insert(0, new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.Common.All"), Value = "0" });
|
||||
|
||||
//searchModel.AvailableCompanies = (await _customerService.GetAllCustomersAsync())
|
||||
// .Select(customer => new SelectListItem { Text = customer.Company, Value = customer.Id.ToString() }).ToList();
|
||||
//searchModel.AvailableCompanies.Insert(0, new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.Common.All"), Value = "0" });
|
||||
|
||||
//prepare grid
|
||||
searchModel.SetGridPageSize();
|
||||
|
||||
searchModel.HideStoresList = _catalogSettings.IgnoreStoreLimitations || searchModel.AvailableStores.SelectionIsNotPossible();
|
||||
|
||||
return searchModel;
|
||||
}
|
||||
|
||||
public override async Task<OrderListModel> PrepareOrderListModelAsync(OrderSearchModel searchModel)
|
||||
{
|
||||
var preFiltered = await base.PrepareOrderListModelAsync(searchModel);
|
||||
return preFiltered;
|
||||
}
|
||||
public virtual async Task<TOrderListModelExt> PrepareOrderListModelExtendedAsync(OrderSearchModelExtended searchModel, Func<OrderListModel, TOrderModelExt, Task> dataItemCopiedCallback)
|
||||
{
|
||||
var prefiltered = await PrepareOrderListModelAsync(searchModel);
|
||||
|
||||
var extendedRows = new List<TOrderModelExt>(prefiltered.RecordsFiltered);
|
||||
|
||||
foreach (var orderModel in prefiltered.Data.ToList())
|
||||
{
|
||||
var orderModelExtended = Activator.CreateInstance<TOrderModelExt>();
|
||||
|
||||
|
|
@ -157,15 +264,22 @@ public class MgOrderModelFactory<TOrderListModelExt, TOrderModelExt> : OrderMode
|
|||
extendedRows.Add(orderModelExtended);
|
||||
|
||||
if (dataItemCopiedCallback == null) continue;
|
||||
await dataItemCopiedCallback.Invoke(orderListModel, orderModelExtended);
|
||||
await dataItemCopiedCallback.Invoke(prefiltered, orderModelExtended);
|
||||
}
|
||||
|
||||
orderListModel.Data = null;
|
||||
prefiltered.Data = null;
|
||||
|
||||
//var orderListModelExtended = orderListModel.ToJson().JsonTo<TOrderListModelExt>();
|
||||
var orderListModelExtended = orderListModel.CloneTo<TOrderListModelExt>();
|
||||
orderListModelExtended.Data = extendedRows;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
var orderListModelExtended = prefiltered.CloneTo<TOrderListModelExt>();
|
||||
orderListModelExtended.Data = extendedRows;
|
||||
orderListModelExtended.RecordsFiltered = extendedRows.Count;
|
||||
return orderListModelExtended;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,17 @@
|
|||
using FruitBank.Common.Interfaces;
|
||||
using FruitBank.Common.Server;
|
||||
using Mango.Nop.Core.Dtos;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Catalog;
|
||||
using Nop.Core.Domain.Common;
|
||||
using Nop.Core.Domain.Customers;
|
||||
using Nop.Core.Domain.Orders;
|
||||
using Nop.Core.Domain.Tax;
|
||||
using Nop.Core.Events;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Models;
|
||||
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
|
||||
using Nop.Services.Catalog;
|
||||
|
|
@ -16,11 +24,10 @@ using Nop.Web.Framework.Events;
|
|||
using Nop.Web.Framework.Menu;
|
||||
using Nop.Web.Models.Sitemap;
|
||||
using System.Linq;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
||||
{
|
||||
public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer<OrderPlacedEvent>, IConsumer<EntityUpdatedEvent<Order>>, IConsumer<AdminMenuCreatedEvent>
|
||||
public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer<EntityUpdatedEvent<Customer>>, IConsumer<EntityInsertedEvent<Customer>>, IConsumer<OrderPlacedEvent>, IConsumer<EntityUpdatedEvent<Order>>, IConsumer<AdminMenuCreatedEvent>
|
||||
{
|
||||
private readonly IGenericAttributeService _genericAttributeService;
|
||||
private readonly IProductService _productService;
|
||||
|
|
@ -32,7 +39,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
private readonly IAdminMenu _adminMenu;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IAddressService _addressService;
|
||||
private readonly FruitBankAttributeService _fruitBankAttributeService;
|
||||
private readonly FruitBankDbContext _dbContext;
|
||||
|
||||
public EventConsumer(
|
||||
IGenericAttributeService genericAttributeService,
|
||||
|
|
@ -46,7 +55,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
IAdminMenu adminMenu,
|
||||
ILocalizationService localizationService,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
FruitBankAttributeService fruitBankAttributeService) : base(pluginManager)
|
||||
IAddressService addressService,
|
||||
FruitBankAttributeService fruitBankAttributeService,
|
||||
FruitBankDbContext dbContext) : base(pluginManager)
|
||||
{
|
||||
_genericAttributeService = genericAttributeService;
|
||||
_productService = productService;
|
||||
|
|
@ -58,7 +69,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
_adminMenu = adminMenu;
|
||||
_localizationService = localizationService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_addressService = addressService;
|
||||
_fruitBankAttributeService = fruitBankAttributeService;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
protected override string PluginSystemName => "Misc.FruitBankPlugin";
|
||||
|
|
@ -210,5 +223,82 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
public async Task HandleEventAsync(EntityInsertedEvent<Customer> eventMessage)
|
||||
{
|
||||
await ProcessCustomerEventAsync(eventMessage?.Entity);
|
||||
}
|
||||
|
||||
public async Task HandleEventAsync(EntityUpdatedEvent<Customer> eventMessage)
|
||||
{
|
||||
await ProcessCustomerEventAsync(eventMessage?.Entity);
|
||||
}
|
||||
|
||||
private async Task ProcessCustomerEventAsync(Customer customer)
|
||||
{
|
||||
if (customer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsRegisteredCustomer(customer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await EnsureBillingAddressAsync(customer);
|
||||
await SynchronizeTaxInformationAsync(customer);
|
||||
}
|
||||
|
||||
private bool IsRegisteredCustomer(Customer customer)
|
||||
{
|
||||
var customerRoles = _dbContext.GetCustomerRolesByCustomerId(customer.Id);
|
||||
return customerRoles?.Any(role => role.SystemName == "Registered") ?? false;
|
||||
}
|
||||
|
||||
private async Task EnsureBillingAddressAsync(Customer customer)
|
||||
{
|
||||
if (customer.BillingAddressId != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var address = new Address
|
||||
{
|
||||
ZipPostalCode = customer.ZipPostalCode,
|
||||
City = customer.City,
|
||||
Address1 = customer.StreetAddress,
|
||||
Address2 = customer.StreetAddress2,
|
||||
CountryId = customer.CountryId > 0 ? customer.CountryId : null,
|
||||
StateProvinceId = customer.StateProvinceId > 0 ? customer.StateProvinceId : null,
|
||||
PhoneNumber = customer.Phone,
|
||||
Company = customer.Company,
|
||||
FirstName = customer.FirstName,
|
||||
LastName = customer.LastName,
|
||||
Email = customer.Email,
|
||||
County = customer.County
|
||||
};
|
||||
|
||||
await _addressService.InsertAddressAsync(address);
|
||||
await _dbContext.AddCustomerAddressMappingAsync(customer.Id, address.Id);
|
||||
customer.BillingAddressId = address.Id;
|
||||
}
|
||||
|
||||
private async Task SynchronizeTaxInformationAsync(Customer customer)
|
||||
{
|
||||
var taxId = await _fruitBankAttributeService.GetGenericAttributeValueAsync<Customer, string>(customer.Id, "TaxId");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(taxId) && string.IsNullOrWhiteSpace(customer.VatNumber))
|
||||
{
|
||||
customer.VatNumber = taxId;
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(taxId) && !string.IsNullOrWhiteSpace(customer.VatNumber))
|
||||
{
|
||||
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Customer, string>(
|
||||
customer.Id,
|
||||
"TaxId",
|
||||
customer.VatNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
|
|||
private readonly string _password;
|
||||
private readonly string _baseUrl;
|
||||
|
||||
public InnVoiceOrderService(string companyName = "fruitbank", string username = "fruitbank", string password = "YkKzM1dwJax0HTIPWIMABSqdSA", string baseUrl = "https://api.innvoice.hu")
|
||||
public InnVoiceOrderService(string companyName = "fruitbank", string username = "fruitbank", string password = "YkKzM1dwJax0HTlPWlMABSqdSA", string baseUrl = "https://api.innvoice.hu")
|
||||
{
|
||||
_companyName = companyName ?? throw new ArgumentNullException(nameof(companyName));
|
||||
_username = username ?? throw new ArgumentNullException(nameof(username));
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@
|
|||
<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> Order</h5>
|
||||
<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>
|
||||
|
|
@ -20,22 +21,22 @@
|
|||
<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> View Order PDF
|
||||
<i class="fas fa-file-pdf"></i> PDF megtekintése
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 text-right">
|
||||
<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> Create Order in InnVoice
|
||||
<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> Refresh Order
|
||||
<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>
|
||||
|
|
@ -49,16 +50,16 @@
|
|||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</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>
|
||||
<button type="button" id="checkInvoiceBtn" class="btn btn-secondary" style="display: none;">
|
||||
<i class="fas fa-sync"></i> Refresh Invoice
|
||||
</button>
|
||||
</div>
|
||||
</div> *@
|
||||
</div>
|
||||
|
||||
<!-- Attributes Section (NO FORM TAG - just a div) -->
|
||||
|
|
|
|||
Loading…
Reference in New Issue