using Dapper; using Microsoft.AspNetCore.Http; using MisIngredientesVue.Core.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace MisIngredientesVue.Core.Services { public interface ISettingsService { Task GetSettingValue(string tenantId, string name); Task> GetSettings(string tenantId, params string[] types); Task> SaveSettings(string tenantId, List settings); Task GetEmailTemplate(string tenantId, string key); Task> GetEmailTemplates(string tenantId); Task GetEmailTemplateBody(string tenantId, string key); Task SaveEmailTemplate(string tenantId, string key, string value, byte[] file = null); } public class SettingsService : ISettingsService { private static readonly Dictionary DefaultValues = new Dictionary() { { ClientSettingType.CompanyName, "Mi Negocio" }, { ClientSettingType.CompanyLogoUrl, $"/api/account/logo/[TENANT_ID]" }, { ClientSettingType.OrdersDeliveryType, "0" }, { ClientSettingType.OrdersDeliveryTypeDays, "1" }, { ClientSettingType.OrdersMinTotal, "0" }, { ClientSettingType.OrdersShowPromissoryNote, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnMonday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnTuesday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnWednesday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnThursday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnFriday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnSaturday, "True" }, { ClientSettingType.OrdersAvailabilityForDeliveryOnSunday, "False" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnMonday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnTuesday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnWednesday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnThursday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnFriday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnSaturday, "18:00" }, { ClientSettingType.OrdersAvailabilityForDeliveryTimeOnSunday, "18:00" }, { ClientSettingType.OrdersHolidays, "" }, { ClientSettingType.OrdersTimezone, "America/Mexico_City" }, { ClientSettingType.CatalogsCalculateProductPriceExpirationContinue, "False" }, { ClientSettingType.CatalogsCalculateProductPriceExpirationContinueDays, "15" }, { ClientSettingType.CatalogsCalculateProductPriceExpirationDeny, "False" }, { ClientSettingType.CatalogsCalculateProductPriceExpirationDenyDays, "15" }, { ClientSettingType.CatalogsRoundProductCosts, "False" }, { ClientSettingType.CatalogsUseMarginInsteadOfProfit, "False" }, }; private readonly IRepository _repository; private readonly IFileStorageService _fileStorageService; public SettingsService(IRepository repository, IFileStorageService fileStorageService) { _repository = repository; _fileStorageService = fileStorageService; } public async Task GetSettingValue(string tenantId, string name) { var val = await _repository.QueryFirstOrDefault("SELECT value FROM settings WHERE name = @name AND tenantId = @tenantId", new { tenantId, name }); if (string.IsNullOrEmpty(val) && DefaultValues.ContainsKey(name)) val = DefaultValues[name].Replace("[TENANT_ID]", tenantId); if (typeof(T) == typeof(string)) return (T)Convert.ChangeType(val, typeof(T)); if (typeof(T) == typeof(int)) return (T)Convert.ChangeType(Convert.ToInt32(val), typeof(T)); if (typeof(T) == typeof(decimal)) return (T)Convert.ChangeType(Convert.ToDecimal(val, System.Globalization.CultureInfo.InvariantCulture), typeof(T)); if (typeof(T) == typeof(bool)) return (T)Convert.ChangeType(Convert.ToBoolean(val), typeof(T)); if (typeof(T) == typeof(float)) return (T)Convert.ChangeType(Convert.ToSingle(val), typeof(T)); if (typeof(T) == typeof(long)) return (T)Convert.ChangeType(Convert.ToInt64(val), typeof(T)); if (typeof(T) == typeof(DateTime)) return (T)Convert.ChangeType(Convert.ToDateTime(val), typeof(T)); throw new Exception($"Can't convert value {val} to type {typeof(T).Name}"); } public async Task> GetSettings(string tenantId, params string[] types) { return await _repository.Query>(async (db) => { var queryBuilder = new List(); var parameters = new DynamicParameters(); parameters.Add("tenantId", tenantId); var index = 0; foreach (var type in types) { index++; var varName = $"type{index}"; queryBuilder.Add($"name LIKE @{varName}"); parameters.Add(varName, type + ".%"); } var typesQuery = string.Join(" OR ", queryBuilder); var query = $"SELECT * from settings WHERE tenantId = @tenantId AND ({typesQuery})"; var databaseValues = (await db.QueryAsync(query, parameters)).ToList(); foreach (var key in DefaultValues.Keys.Where(key => types.Any(type => key.StartsWith($"{type}.")))) { if(!databaseValues.Any(x => x.Name == key)) { databaseValues.Add(new ClientSetting() { Name = key, Value = DefaultValues[key] }); } } return databaseValues; }); } public async Task> SaveSettings(string tenantId, List settings) { return await _repository.Query>(async (db) => { var queryBuilder = new List(); var parameters = new DynamicParameters(); parameters.Add("tenantId", tenantId); var index = 0; foreach (var setting in settings) { index++; var query = @$"INSERT INTO public.settings (tenantid, name, value) VALUES (@tenantId, @name{index}, @val{index}) ON CONFLICT(tenantid, name) DO UPDATE SET value = @val{index};"; queryBuilder.Add(query); parameters.Add($"name{index}", setting.Name); parameters.Add($"val{index}", setting.Value); } await db.QueryAsync(string.Join(" ", queryBuilder), parameters); return settings.Select(x => new ClientSetting() { Name = x.Name, Value = x.Value }); }); } public async Task> GetEmailTemplates(string tenantId) { return await _repository.Query(async (db) => { return await db.QueryAsync("SELECT id, key FROM emailtemplates WHERE tenantId = @tenantId", new { tenantId }); }); } public async Task GetEmailTemplateBody(string tenantId, string key) { var template = await GetEmailTemplate(tenantId, key); return await ReplaceImage($@" {template.Value} "); } private async Task ReplaceImage(string str) { if (str != null && !str.Contains("CUSTOM_USER_IMAGE")) return str; var pattern = @"\[CUSTOM_USER_IMAGE=(.*)\]"; var matches = Regex.Matches(str, pattern); var id = matches[0].Groups[1].Value; var content = await _fileStorageService.LoadFile(id, "companylogosmi"); return str.Replace(matches[0].Groups[0].Value, $""); } public async Task GetEmailTemplate(string tenantId, string key) { if(key == EmailTemplateKey.UsersWelcome) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

¡Felicidades! Has creado tu cuenta en Mis ingredientes. Comienza a simplificar tu proceso de entregas a tus clientes.

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (key == EmailTemplateKey.UsersResetPassword) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

Recibimos una solicitud de cambio de contraseña para tu cuenta. Si tú no realizaste esta solicitud por favor ignora este correo.

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (key == EmailTemplateKey.UsersConfirmation) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

Bienvenid@, estás a un solo paso de tener cuenta en Mis Ingredientes y es el más sencillo, sólo tienes que confirmar tu correo haciendo clic aquí:

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (key == EmailTemplateKey.OrdersExternalUserCancellation) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

Oh no!!! [COMPANY_LEGAL_NAME] ha decidido cancelar tu pedido programado con fecha de entrega de [FECHA_ENTREGA] y con folio [FOLIO]. Comunícate con [COMPANY_LEGAL_NAME] para conocer la razón de la cancelación y no te quedes sin tu pedido.

Este pedido fue procesado a través de Mis Ingredientes.

Si eres un negocio gastronómico, simplifica y automatiza tu proceso de compra desde un sólo lugar.

Más informes da clic aquí.

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (key == EmailTemplateKey.OrdersRequest) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

Se ha generado un pedido de la marca [MARCA], sucursal [SUCURSAL] con fecha de entrega de [FECHA_ENTREGA].

Ingresa a tu cuenta para aceptar este pedido cambiando el estatus de solicitado a pendiente. En cuanto realices esta acción se le notificará a tu cliente la confirmación a través correo electrónico.

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (key == EmailTemplateKey.OrdersExternalUserConfirmation) { return new EmailTemplate() { TenantId = tenantId, Key = key, Value = @"

Muchas gracias, tu pedido ha sido enviado a [COMPANY_LEGAL_NAME]. En cuanto [COMPANY_LEGAL_NAME] acepte tu pedido recibirás un correo de confirmación.

Cualquier duda comúnicate con [COMPANY_LEGAL_NAME].

Este pedido fue procesado a través de Mis Ingredientes.

Si eres un negocio gastronómico, simplifica y automatiza tu proceso de compra desde un sólo lugar.

Más informes da clic aquí.

© 2021 Mis Ingredientes. Cambiando la forma en que abasteces tu cocina.
" }; } if (string.IsNullOrEmpty(tenantId)) throw new ArgumentException(tenantId); var template = await _repository.Query(async (db) => { var res = await db.QueryFirstOrDefaultAsync("SELECT * FROM emailtemplates WHERE key = @key AND tenantId = @tenantId", new { tenantId, key }); if(res != null) res.Value = await ReplaceImage(res.Value); return res; }); if (template != null) return template; switch (key) { case EmailTemplateKey.UsersNew: return await SaveEmailTemplate(tenantId, key, @"

Ha recibido una invitación para unirse como colaborador de [COMPANY_NAME]. Por favor haga clic en el siguiente enlace para iniciar sesión.

[LOGIN_URL]

Utilice la siguiente contraseña temporal: [TEMP_PASSWORD]

"); case EmailTemplateKey.InvoicingCancelled: return await SaveEmailTemplate(tenantId, key, @"
[COMPANY_LEGAL_NAME]

Envía a usted el archivo XML correspondiente a la cancelación del CFDI con Folio Fiscal [UUID].

Este correo electrónico ha sido generado automáticamente por lo que le solicitamos no responder a este mensaje, ya que las respuestas a este correo electrónico no serán leídas. En caso de tener alguna duda referente a la información contenida en el Comprobante Fiscal Digital contacte a [COMPANY_LEGAL_NAME] para su aclaración.

Está recibiendo este correo electrónico debido a que ha proporcionado la dirección de correo electrónico [CLIENT_EMAIL] a [COMPANY_LEGAL_NAME] para hacerle llegar su Factura Electrónica.

"); case EmailTemplateKey.InvoicingInvoiceFiles: return await SaveEmailTemplate(tenantId, key, @"
[COMPANY_LEGAL_NAME]

Envía a usted el archivo XML correspondiente al Comprobante Fiscal Digital con Serie: [SERIE] y Folio: [FOLIO]. Así como su representación impresa.

Este correo electrónico ha sido generado automáticamente por lo que le solicitamos no responder a este mensaje, ya que las respuestas a este correo electrónico no serán leídas. En caso de tener alguna duda referente a la información contenida en el Comprobante Fiscal Digital contacte a [COMPANY_LEGAL_NAME] para su aclaración.

Está recibiendo este correo electrónico debido a que ha proporcionado la dirección de correo electrónico [CLIENT_EMAIL] a [COMPANY_LEGAL_NAME] para hacerle llegar su Factura Electrónica.

"); case EmailTemplateKey.OrderTemplatesPriceList: return await SaveEmailTemplate(tenantId, key, @"

Lista de precios actualizada

"); case EmailTemplateKey.ProductsPriceList: return await SaveEmailTemplate(tenantId, key, @"

Lista de precios actualizada

"); } throw new Exception("Invalid email template key"); } public async Task SaveEmailTemplate(string tenantId, string key, string value, byte[] file = null) { if (string.IsNullOrEmpty(key)) throw new Exception(); return await _repository.Query(async (db) => { if (file != null && value.Contains("[CUSTOM_USER_IMAGE]")) { var guid = "e_" + Guid.NewGuid().ToString("N").ToLower(); await _fileStorageService.SaveFile(guid, "companylogosmi", file); value = value.Replace("[CUSTOM_USER_IMAGE]", $"[CUSTOM_USER_IMAGE={guid}]"); } var query = @$"INSERT INTO public.emailtemplates (tenantid, key, value) VALUES (@tenantId, @key, @value) ON CONFLICT(tenantid, key) DO UPDATE SET value = @value;"; await db.QueryAsync(query, new { key, value, tenantId }); return new EmailTemplate() { TenantId = tenantId, Key = key, Value = value }; }); } } }