using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using Dapper; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.Mvc; using MisIngredientes.Core.Models; using MisIngredientesVue.Core.Models; using MisIngredientesVue.Core.Services; using MisIngredientesVue.Core.Extensions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using MisIngredientesVue.Hubs; using Microsoft.AspNetCore.SignalR; namespace MisIngredientesVue.Controllers { [Route("api/[controller]")] [ApiController] public class ProductsController : Controller { private readonly IProductsService _productsService; private readonly IActivityLogsService _activityLogsService; private readonly IHubContext _hubcontext; public ProductsController( IHubContext hubcontext, IProductsService productsService, IActivityLogsService activityLogsService) { _productsService = productsService; _hubcontext = hubcontext; _activityLogsService = activityLogsService; } [Route("{id}")] [HttpGet] public async Task Get(int id) { if (User.Identity.IsClient()) return Ok(await _productsService.GetClientProductById(User.Identity.GetTenantId(), id, User.Identity.GetAssignedBranchIds())); return Ok(await _productsService.GetProductById(User.Identity.GetTenantId(), id)); } [HttpGet] public async Task Get(int skip, int take, string sortBy, string sortOrder, string q, int includeDeleted = 0, int loadInventories = 0) { if (User.Identity.IsClient()) { var findAll = await _productsService.GetClientProducts(User.Identity.GetTenantId(), skip, take, sortBy, sortOrder, q, User.Identity.GetAssignedBranchIds(), loadInventories == 1); return Ok(new PagedResults(findAll.Results, findAll.Total, skip, take, sortBy, sortOrder) { CustomData = findAll.CustomData }); } else { var findAll = await _productsService.GetProducts(User.Identity.GetTenantId(), skip, take, sortBy, sortOrder, q, includeDeleted, User.Identity.HasFreeSubscription()); return Ok(new PagedResults(findAll.Results, findAll.Total, skip, take, sortBy, sortOrder)); } } [Route("sendlist")] [HttpPost] public async Task SendList(int id, [FromBody] SendEmailRequest request) { await _productsService.SendList(User.Identity.GetTenantId(), request.Recipients, request.EmailBody, User.Identity.GetSubscriptionLevel() == 0); return Ok(); } [Route("excel")] [HttpPost] public async Task GetExcel(string sortBy, string sortOrder, string q) { if (!User.Identity.IsClient()) { var memoryStream = await _productsService.GetExcel(User.Identity.GetTenantId(), Request.GetTimeOffset(), sortBy, sortOrder, q); return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); } else { var memoryStream = await _productsService.GetClientExcel(User.Identity.GetTenantId(), Request.GetTimeOffset(), sortBy, sortOrder, q); return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); } } [HttpGet] [Route("claveprodserv")] public dynamic GetClavesDeProducto(string term) { var claves = CClaveProdServ.CLAVES.Where(m => m.Key.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0 || m.Value.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0).OrderBy(x => x.Value.Length).Take(7); return from c in claves select new { name = c.Key + " - " + c.Value, id = c.Key }; } [HttpGet] [Route("purchasezones")] public async Task GetPurchaseZones(string term) { return Ok(await _productsService.GetPurchaseZones(User.Identity.GetTenantId(), term)); } [HttpGet] [Route("buyers")] public async Task GetBuyers(string term) { return Ok(await _productsService.GetBuyers(User.Identity.GetTenantId(), term)); } [HttpGet] [Route("suppliers")] public async Task GetSuppliers(string term) { return Ok(await _productsService.GetSuppliers(User.Identity.GetTenantId(), term)); } [HttpGet] [Route("categories")] public async Task GetCategories(string term) { return Ok(await _productsService.GetCategories(User.Identity.GetTenantId(), term)); } [Route("catalogsearch")] [HttpGet] public async Task SearchProducts(string q) { if(User.Identity.IsClient()) { return Ok(await _productsService.SearchClientProducts(User.Identity.GetTenantId(), q, true)); } return Ok(await _productsService.SearchProducts(User.Identity.GetTenantId(), q)); } [AllowAnonymous] [Route("public/catalogsearch")] [HttpGet] public async Task PublicSearchProducts(string t, string q) { if (string.IsNullOrEmpty(t) || string.IsNullOrEmpty(q)) return BadRequest(); return Ok(await _productsService.SearchProducts(t, q, true)); } [AllowAnonymous] [Route("public/templatesearch")] [HttpGet] public async Task PublicTemplateSearchProducts(string templateId, string q) { if (string.IsNullOrEmpty(templateId) || string.IsNullOrEmpty(q)) return BadRequest(); return Ok(await _productsService.SearchPublicTemplateProducts(templateId, q)); } [Route("quicksearch")] [HttpGet] public async Task GetProducts(string q) { return Ok(await _productsService.QuickSearchProducts(User.Identity.GetTenantId(), q)); } [Route("templatesearch")] [HttpGet] public async Task SearchTemplateProducts(int templateId, string q) { if(User.Identity.IsClient()) return Ok(await _productsService.SearchClientTemplateProducts(User.Identity.GetTenantId(), templateId, q)); return Ok(await _productsService.SearchTemplateProducts(User.Identity.GetTenantId(), templateId, q)); } //Si supplierId = 0 significa que es la plantilla global [Route("suppliertemplatesearch")] [HttpGet] public async Task SearchSupplierTemplateProducts(int supplierId, int? clientId, string q) { if (User.Identity.IsClient()) return Ok(await _productsService.SearchSupplierTemplateProducts(User.Identity.GetTenantId(), supplierId, null, q)); return Ok(await _productsService.SearchSupplierTemplateProducts(User.Identity.GetTenantId(), supplierId, clientId, q)); } [Route("{id}")] [HttpPatch] public async Task Patch(int id, [FromBody] JsonPatchDocument changes) { var product = await _productsService.PatchProduct(User.Identity.GetTenantId(), User.Identity.GetUserId(), id, changes); await _hubcontext.Clients.Group(User.Identity.GetTenantId()).SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Realizó modificaciones al producto {product.Name}"); return Ok(product); } [Route("distinct/{propName}")] [HttpGet] public async Task GetDistinct(string propName, string q) { return Ok(await _productsService.GetDistinct(User.Identity.GetTenantId(), propName, q)); } [HttpPost] public async Task Post(Product product) { if (User.Identity.IsClient()) { product.ContinueStockMode = true; var insertedProduct = await _productsService.InsertProduct(User.Identity.GetTenantId(), User.Identity.GetUserId(), product); return Ok(insertedProduct); } else { var insertedProduct = await _productsService.InsertProduct(User.Identity.GetTenantId(), User.Identity.GetUserId(), product); await _hubcontext.Clients.Group(User.Identity.GetTenantId()).SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Insertó el producto {insertedProduct.Name}"); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), insertedProduct.Id, "products", ActivityLogType.Add, $"Insertó el producto {insertedProduct.Name}"); return Ok(insertedProduct); } } [Route("refresh")] [HttpPost] public async Task RefreshProducts(RefreshProductsRequest request) { var count = await _productsService.RefreshProducts( User.Identity.GetTenantId(), request.Skip, request.Count); return Ok(new { count }); } //Este método se usa por Cerebro [Route("upsertbycode")] [HttpPut] public async Task UpsertByCode(Product product) { var silentMode = Request.Headers.ContainsKey("X-Silent-Mode") && Request.Headers["X-Silent-Mode"] == "1"; var upsertedProduct = await _productsService.UpsertProductByCode(User.Identity.GetTenantId(), User.Identity.GetUserId(), product, silentMode); await _hubcontext.Clients.Group(User.Identity.GetTenantId()).SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Inserceditó el producto con código {product.Name}"); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), upsertedProduct.Id, "products", ActivityLogType.Edit, $"Desde Cerebro se actualizó el producto {upsertedProduct.Name}"); return Ok(upsertedProduct); } [Route("bulk")] [HttpPost] public async Task BulkUpload(BulkUploadProduct[] products) { await _productsService.InsertBulk(User.Identity.GetTenantId(), User.Identity.GetUserId(), products, User.Identity.HasFreeSubscription()); //await _hubcontext.Clients.All.SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Realizó una carga masiva de productos"); //await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), 0, "products", ActivityLogType.Edit, $"Realizó una carga masiva de {products.Length} producto(s)"); return Ok(); } [Route("{id}/branchinventory")] [HttpPut] public async Task UpdateProductBranchMinQty(int id, [FromBody] UpdateProductBranchInventoryRequest request) { if (!User.Identity.IsClient()) return BadRequest(); var branches = User.Identity.GetAssignedBranchIds(); if (branches.Length != 1) return BadRequest(); await _productsService.UpdateProductBranchInventory(User.Identity.GetTenantId(), id, branches[0], request.Qty, request.MinQty, request.MaxQty); return Ok(); } [Route("{id}/branches/{branchId}/qty")] [HttpPut] public async Task UpdateProductBranchQty(int id, int branchId, [FromBody]UpdateProductBranchQtyRequest request) { if (!User.Identity.IsClient()) return BadRequest(); await _productsService.UpdateProductBranchQty(User.Identity.GetTenantId(), id, branchId, request.Qty); return Ok(); } [Route("{id}/branches/{branchId}/minqty")] [HttpPut] public async Task UpdateProductBranchMinQty(int id, int branchId, [FromBody] UpdateProductBranchMinQtyRequest request) { if (!User.Identity.IsClient()) return BadRequest(); await _productsService.UpdateProductBranchMinQty(User.Identity.GetTenantId(), id, branchId, request.MinQty); return Ok(); } [Route("{id}/branches/{branchId}/maxqty")] [HttpPut] public async Task UpdateProductBranchMaxQty(int id, int branchId, [FromBody] UpdateProductBranchMaxQtyRequest request) { if (!User.Identity.IsClient()) return BadRequest(); await _productsService.UpdateProductBranchMaxQty(User.Identity.GetTenantId(), id, branchId, request.MaxQty); return Ok(); } [Route("{id}")] [HttpPut] public async Task Put(int id, Product product) { if (id != product.Id) return BadRequest(); //TODO: Investigar if (User.Identity.IsClient()) { product.ContinueStockMode = true; await _productsService.UpdateClientProduct(User.Identity.GetTenantId(), User.Identity.GetUserId(), product, User.Identity.GetAssignedBranchIds()); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), product.Id, "products", ActivityLogType.Edit, $"Actualizó el producto {product.Name}"); return Ok(); } else { await _productsService.UpdateProduct(User.Identity.GetTenantId(), User.Identity.GetUserId(), product); await _hubcontext.Clients.Group(User.Identity.GetTenantId()).SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Realizó modificaciones al producto {product.Name}"); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), product.Id, "products", ActivityLogType.Edit, $"Actualizó el producto {product.Name}"); return Ok(); } } [Route("{id}/rate")] [HttpPut] public async Task UpdateRate(int id, UpdateRateRequest updateRateRequest) { await _productsService.UpdateRate(User.Identity.GetTenantId(), User.Identity.GetUserId(), id, updateRateRequest.SupplierCost, updateRateRequest.SalePriceRate); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), 0, "products", ActivityLogType.Edit, $"Actualizó el costo y el margen del producto"); return Ok(); } [Route("delete")] [HttpPut] public async Task Delete([FromBody]int[] items) { var silentMode = Request.Headers.ContainsKey("X-Silent-Mode") && Request.Headers["X-Silent-Mode"] == "1"; await _productsService.DeleteProducts(User.Identity.GetTenantId(), User.Identity.GetUserId(), items, silentMode); await _hubcontext.Clients.Group(User.Identity.GetTenantId()).SendAsync("ReceiveMessage", User.Identity.GetFullName(), $"Eliminó uno o más productos"); await _activityLogsService.Log(User.Identity.GetTenantId(), User.Identity.GetUserId(), 0, "products", ActivityLogType.Edit, $"Actualizó el costo y el margen del producto"); return Ok(); } } public class UpdateProductBranchQtyRequest { public decimal Qty { get; set; } } public class UpdateProductBranchMinQtyRequest { public decimal MinQty { get; set; } } public class UpdateProductBranchMaxQtyRequest { public decimal MaxQty { get; set; } } public class UpdateProductBranchInventoryRequest { public decimal Qty { get; set; } public decimal MinQty { get; set; } public decimal MaxQty { get; set; } } public class UpdateRateRequest { public decimal SupplierCost { get; set; } public decimal SalePriceRate { get; set; } } public class RefreshProductsRequest { public int Skip { get; set; } public int Count { get; set; } } }