210 lines
8.4 KiB
C#
210 lines
8.4 KiB
C#
using Nop.Core;
|
|
using Nop.Core.Domain.Common;
|
|
using Nop.Core.Domain.Messages;
|
|
using Nop.Core.Domain.Orders;
|
|
using Nop.Core.Events;
|
|
using Nop.Services.Affiliates;
|
|
using Nop.Services.Catalog;
|
|
using Nop.Services.Common;
|
|
using Nop.Services.Customers;
|
|
using Nop.Services.Localization;
|
|
using Nop.Services.Messages;
|
|
using Nop.Services.Orders;
|
|
using Nop.Services.Stores;
|
|
|
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
|
|
|
|
public class FruitBankNotificationService(
|
|
CommonSettings commonSettings,
|
|
IMessageTemplateService messageTemplateService,
|
|
IEmailAccountService emailAccountService,
|
|
EmailAccountSettings emailAccountSettings,
|
|
IMessageTokenProvider messageTokenProvider,
|
|
IWorkflowMessageService workflowMessageService,
|
|
ICustomerService customerService,
|
|
IStoreContext storeContext,
|
|
IAddressService addressService,
|
|
|
|
IAffiliateService affiliateService,
|
|
IEventPublisher eventPublisher,
|
|
ILanguageService languageService,
|
|
ILocalizationService localizationService,
|
|
IOrderService orderService,
|
|
IProductService productService,
|
|
IQueuedEmailService queuedEmailService,
|
|
IStoreService storeService,
|
|
ITokenizer tokenizer,
|
|
MessagesSettings messagesSettings) : WorkflowMessageService(commonSettings,
|
|
emailAccountSettings,
|
|
addressService,
|
|
affiliateService,
|
|
customerService,
|
|
emailAccountService,
|
|
eventPublisher,
|
|
languageService,
|
|
localizationService,
|
|
messageTemplateService,
|
|
messageTokenProvider,
|
|
orderService,
|
|
productService,
|
|
queuedEmailService,
|
|
storeContext,
|
|
storeService,
|
|
tokenizer,
|
|
messagesSettings)
|
|
{
|
|
public const string ORDER_AUDITED_TEMPLATE_NAME = "FruitBank.OrderAudited.CustomerNotification";
|
|
public const string ORDER_STARTED_TEMPLATE_NAME = "FruitBank.OrderStarted.CustomerNotification";
|
|
|
|
|
|
|
|
|
|
public override async Task<IList<int>> SendOrderPlacedCustomerNotificationAsync(Order order, int languageId,
|
|
string attachmentFilePath = null, string attachmentFileName = null)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(order);
|
|
|
|
var store = await _storeService.GetStoreByIdAsync(order.StoreId) ?? await _storeContext.GetCurrentStoreAsync();
|
|
languageId = await EnsureLanguageIsActiveAsync(languageId, store.Id);
|
|
|
|
var messageTemplates = await GetActiveMessageTemplatesAsync(MessageTemplateSystemNames.ORDER_PLACED_CUSTOMER_NOTIFICATION, store.Id);
|
|
if (!messageTemplates.Any())
|
|
return new List<int>();
|
|
|
|
//tokens
|
|
var commonTokens = new List<Token>();
|
|
await _messageTokenProvider.AddOrderTokensAsync(commonTokens, order, languageId);
|
|
await _messageTokenProvider.AddCustomerTokensAsync(commonTokens, order.CustomerId);
|
|
|
|
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
|
|
|
|
return await messageTemplates.SelectAwait(async messageTemplate =>
|
|
{
|
|
//email account
|
|
var emailAccount = await GetEmailAccountOfMessageTemplateAsync(messageTemplate, languageId);
|
|
|
|
var tokens = new List<Token>(commonTokens);
|
|
await _messageTokenProvider.AddStoreTokensAsync(tokens, store, emailAccount, languageId);
|
|
|
|
//event notification
|
|
await _eventPublisher.MessageTokensAddedAsync(messageTemplate, tokens);
|
|
|
|
var billingAddress = await _addressService.GetAddressByIdAsync(order.BillingAddressId);
|
|
string toEmail;
|
|
|
|
//we surely have shipping address for orders with shipping method, but let's be safe
|
|
if (billingAddress.Email != null)
|
|
{
|
|
|
|
|
|
if (!billingAddress.Email.EndsWith("inval.id"))
|
|
{
|
|
toEmail = billingAddress.Email;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Customer {customer.Id} has BillinggAddressId but emailaddress is invalid: {billingAddress.Email}");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Customer {customer.Id} has BillinggAddressId but emailaddress not found.");
|
|
return -1;
|
|
}
|
|
|
|
var toName = $"{billingAddress.FirstName} {billingAddress.LastName}";
|
|
|
|
return await SendNotificationAsync(messageTemplate, emailAccount, languageId, tokens, toEmail, toName,
|
|
attachmentFilePath, attachmentFileName);
|
|
}).ToListAsync();
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Re-sends the order info email to the customer on demand from the admin.
|
|
/// Reuses the OrderPlaced template which already contains the full order table.
|
|
/// </summary>
|
|
public Task<IList<int>> SendOrderInfoEmailAsync(Order order)
|
|
=> SendOrderPlacedCustomerNotificationAsync(order, order.CustomerLanguageId);
|
|
|
|
/// <summary>
|
|
/// Sends the "order started" (being prepared) customer notification.
|
|
/// For measurable orders, informs the customer that final prices will be
|
|
/// confirmed after weighing. Fires once when MeasuringStatus transitions to Started.
|
|
/// </summary>
|
|
///
|
|
public async Task<int> SendOrderStartedCustomerNotificationAsync(Order order, bool isMeasurable)
|
|
{
|
|
var measurableNote = isMeasurable
|
|
? "<p>Rendelésed mérhető tételeket tartalmaz. A végleges ár a mérés után kerül megerősítésre.</p>"
|
|
: string.Empty;
|
|
|
|
return await SendNotificationAsync(ORDER_STARTED_TEMPLATE_NAME, order, measurableNote);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends the "order audited" customer notification.
|
|
/// For measurable orders, confirms that weights have been recorded and
|
|
/// the final price is as shown on the order.
|
|
/// Fires once when MeasuringStatus transitions to Audited.
|
|
/// </summary>
|
|
public async Task<int> SendOrderAuditedCustomerNotificationAsync(Order order, bool isMeasurable)
|
|
{
|
|
var measurableNote = isMeasurable
|
|
? "<p>A mért tételek súlyait rögzítettük, a végleges ár a rendelésen feltüntetett összeg.</p>"
|
|
: string.Empty;
|
|
|
|
return await SendNotificationAsync(ORDER_AUDITED_TEMPLATE_NAME, order, measurableNote);
|
|
}
|
|
|
|
// ── shared core ─────────────────────────────────────────────────────────
|
|
|
|
private async Task<int> SendNotificationAsync(string templateName, Order order, string measurableNote)
|
|
{
|
|
var store = await storeContext.GetCurrentStoreAsync();
|
|
|
|
var templates = await messageTemplateService.GetMessageTemplatesByNameAsync(templateName, store.Id);
|
|
var messageTemplate = templates?.FirstOrDefault();
|
|
|
|
if (messageTemplate is null || !messageTemplate.IsActive)
|
|
return 0;
|
|
|
|
var emailAccount = await emailAccountService.GetEmailAccountByIdAsync(messageTemplate.EmailAccountId)
|
|
?? await emailAccountService.GetEmailAccountByIdAsync(emailAccountSettings.DefaultEmailAccountId);
|
|
|
|
var tokens = new List<Token>();
|
|
await messageTokenProvider.AddStoreTokensAsync(tokens, store, emailAccount, order.CustomerLanguageId);
|
|
await messageTokenProvider.AddOrderTokensAsync(tokens, order, order.CustomerLanguageId);
|
|
|
|
var customer = await customerService.GetCustomerByIdAsync(order.CustomerId);
|
|
await messageTokenProvider.AddCustomerTokensAsync(tokens, customer);
|
|
|
|
tokens.Add(new Token("Order.MeasurableNote", measurableNote, true));
|
|
|
|
int addressId = 0;
|
|
|
|
string customerEmail = customer.Email;
|
|
//bool customerHasShippingAddress = customer.ShippingAddressId.HasValue;
|
|
|
|
if (customer.ShippingAddressId.HasValue)
|
|
{
|
|
addressId = (int)customer.ShippingAddressId;
|
|
|
|
customerEmail = (await addressService.GetAddressByIdAsync(addressId)).Email ?? customer.Email;
|
|
}
|
|
|
|
Console.WriteLine($"Customer email determined as: {customerEmail} (addressId: {addressId})");
|
|
|
|
var toName = $"{customer.FirstName} {customer.LastName}".Trim();
|
|
if (string.IsNullOrWhiteSpace(toName)) toName = customer.Email;
|
|
|
|
return await workflowMessageService.SendNotificationAsync(
|
|
messageTemplate, emailAccount,
|
|
order.CustomerLanguageId,
|
|
tokens,
|
|
customerEmail, toName);
|
|
}
|
|
}
|