using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Microsoft.EntityFrameworkCore; using System.Linq; using AyaNova.Models; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; using System.Collections.Generic; using System.Text; using System; namespace AyaNova.Api.Controllers { [ApiController] [ApiVersion("8.0")] [Route("api/v{version:apiVersion}/unit")] [Produces("application/json")] [Authorize] public class UnitController : ControllerBase { private readonly AyContext ct; private readonly ILogger log; private readonly ApiServerState serverState; /// /// ctor /// /// /// /// public UnitController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) { ct = dbcontext; log = logger; serverState = apiServerState; } /// /// Create Unit /// /// /// From route path /// [HttpPost] public async Task PostUnit([FromBody] Unit newObject, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); UnitBiz biz = UnitBiz.GetBiz(ct, HttpContext); if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); Unit o = await biz.CreateAsync(newObject); if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else return CreatedAtAction(nameof(UnitController.GetUnit), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } // /// // /// Duplicate Unit // /// (Wiki and Attachments are not duplicated) // /// // /// Source object id // /// From route path // /// Unit // [HttpPost("duplicate/{id}")] // public async Task DuplicateUnit([FromRoute] long id, ApiVersion apiVersion) // { // if (!serverState.IsOpen) // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); // UnitBiz biz = UnitBiz.GetBiz(ct, HttpContext); // if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) // return StatusCode(403, new ApiNotAuthorizedResponse()); // if (!ModelState.IsValid) // return BadRequest(new ApiErrorResponse(ModelState)); // Unit o = await biz.DuplicateAsync(id); // if (o == null) // return BadRequest(new ApiErrorResponse(biz.Errors)); // else // return CreatedAtAction(nameof(UnitController.GetUnit), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); // } /// /// Get Unit /// /// /// Unit [HttpGet("{id}")] public async Task GetUnit([FromRoute] long id) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); UnitBiz biz = UnitBiz.GetBiz(ct, HttpContext); if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); var o = await biz.GetAsync(id); if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); return Ok(ApiOkResponse.Response(o)); } /// /// Update Unit /// /// /// [HttpPut] public async Task PutUnit([FromBody] Unit updatedObject) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); UnitBiz biz = UnitBiz.GetBiz(ct, HttpContext); if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); var o = await biz.PutAsync(updatedObject);//In future may need to return entire object, for now just concurrency token if (o == null) { if (biz.Errors.Exists(z => z.Code == ApiErrorCode.CONCURRENCY_CONFLICT)) return StatusCode(409, new ApiErrorResponse(biz.Errors)); else return BadRequest(new ApiErrorResponse(biz.Errors)); } return Ok(ApiOkResponse.Response(new { Concurrency = o.Concurrency })); ; } /// /// Delete Unit /// /// /// NoContent [HttpDelete("{id}")] public async Task DeleteUnit([FromRoute] long id) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); UnitBiz biz = UnitBiz.GetBiz(ct, HttpContext); if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!await biz.DeleteAsync(id)) return BadRequest(new ApiErrorResponse(biz.Errors)); return NoContent(); } /// /// Get service address for this Unit /// /// /// Service address [HttpGet("address/{id}")] public async Task GetUnitServiceAddress([FromRoute] long id) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.Unit)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); var unt = await ct.Unit.AsNoTracking().Where(x => x.Id == id).FirstOrDefaultAsync(); if (unt == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); return Ok(ApiOkResponse.Response(new { unit = new AddressRecord(unt.Serial, unt.Address, unt.City, unt.Region, unt.Country, unt.Latitude, unt.Longitude) })); } /// /// Get Unit list by tag and optionally customer /// /// /// List of units [HttpPost("bulk-add-selection-list")] public async Task GetBulkAddList([FromBody] UnitListByTagParams searchParam) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.Part)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); if (searchParam.tags.Count == 0) //note: this error only applies to api users so not translated return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "tags", "tags are required")); //build query //select id,serial,customerid from aunit where aunit.tags @> array['red','blue'::varchar(255)] AND customerid=19 /* select aunit.id,aunit.serial, acustomer.name from aunit left join acustomer on aunit.customerid=acustomer.id where aunit.tags @> array['red','blue'::varchar(255)] AND customerid=19 */ StringBuilder sbQuery = new StringBuilder(); sbQuery.Append("select aunit.id,aunit.serial, acustomer.name from aunit left join acustomer on aunit.customerid=acustomer.id where aunit.tags "); StringBuilder sb = new StringBuilder(); sb.Append("@> array["); foreach (string s in searchParam.tags) sb.Append($"'{s}',"); sbQuery.Append(sb.ToString().TrimEnd(',')); sbQuery.Append("::varchar(255)]"); if (searchParam.restrictToCustomerId != null && searchParam.restrictToCustomerId != 0) sbQuery.Append($" and customerid={searchParam.restrictToCustomerId}"); List slist = new List(); using (var cmd = ct.Database.GetDbConnection().CreateCommand()) { await ct.Database.OpenConnectionAsync(); cmd.CommandText = sbQuery.ToString(); using (var dr = await cmd.ExecuteReaderAsync()) { while (dr.Read()) { slist.Add(new InternalUnitListForSorting(dr.GetString(2), dr.GetString(1), dr.GetInt64(0))); } } } var sorted = slist.OrderBy(z => z.CustomerName).ThenBy(z => z.UnitSerial); //return Ok(ApiOkResponse.Response(sorted.Select(z => new NameIdItem { Id = z.unitid, Name = $"{z.serial} {z.customername}" }).ToList())); return Ok(ApiOkResponse.Response(sorted)); } public record UnitListByTagParams(List tags, long? restrictToCustomerId); private record InternalUnitListForSorting(string CustomerName, string UnitSerial, long UnitId); //------------ /// /// Get Unit service and warranty info /// /// /// Service and warranty info [HttpGet("service-warranty-info/{id}")] public async Task GetUnitServiceWarrantyInfo([FromRoute] long id) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.Unit)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); var u = await ct.Unit.AsNoTracking().Where(x => x.Id == id).FirstOrDefaultAsync(); if (u == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); UnitServiceWarrantyInfo ret = new UnitServiceWarrantyInfo(); ret.PurchaseReceiptNumber = u.Receipt; ret.PurchaseDate = u.PurchasedDate; ret.PurchaseFromVendorId = u.PurchasedFromVendorId; if (u.PurchasedFromVendorId != null) ret.PurchasedFromVendor = await ct.Vendor.AsNoTracking().Where(x => x.Id == u.PurchasedFromVendorId).Select(x => x.Name).FirstOrDefaultAsync(); //Warranty terms //WarrantyLength is in months //UnitModel warranty has precedence always except when Unit OverrideModelWarranty is true or there is no unitmodel set UnitModel unitModel = null; if (u.UnitModelId != null) unitModel = await ct.UnitModel.AsNoTracking().Where(x => x.Id == u.UnitModelId).FirstOrDefaultAsync(); if (u.OverrideModelWarranty || unitModel == null) { //get warranty terms from the unit itself ret.LifeTimeWarranty = u.LifeTimeWarranty; ret.WarrantyTerms = u.WarrantyTerms; if (!u.LifeTimeWarranty && u.WarrantyLength != null && u.PurchasedDate != null) ret.WarrantyExpiryDate = ((DateTime)u.PurchasedDate).AddMonths((int)u.WarrantyLength); } else { //get warranty terms from the unit model ret.LifeTimeWarranty = unitModel.LifeTimeWarranty; ret.WarrantyTerms = unitModel.WarrantyTerms; if (!unitModel.LifeTimeWarranty && unitModel.WarrantyLength != null && u.PurchasedDate != null) ret.WarrantyExpiryDate = ((DateTime)u.PurchasedDate).AddMonths((int)unitModel.WarrantyLength); } //Recent workorders //arbitrarily returning last 3 work orders to account for one of them being the current active work order and not wanting to try to filter in closed status workorders for reasons //limiting to three because there is already an all workorders option from unit itself if they are really researching the history and it's about three clicks away from this info List RecentWorkOrders = new List(); var lastWoItemIds = await ct.WorkOrderItemUnit.AsNoTracking().Where(z => z.UnitId == id).OrderByDescending(z => z.Id).Take(3).Select(z => z.WorkOrderItemId).ToListAsync(); foreach (long woitemid in lastWoItemIds) { var woid = await ct.WorkOrderItem.AsNoTracking().Where(x => x.Id == woitemid).OrderByDescending(x => x.WorkOrderId).Select(x => x.WorkOrderId).FirstOrDefaultAsync(); ret.RecentWorkOrders.Add( await ct.WorkOrder.AsNoTracking().Where(x => x.Id == woid).Select(x => new RecentWorkOrder(x.Serial, x.Id, x.ServiceDate)).FirstOrDefaultAsync() ); } return Ok(ApiOkResponse.Response(ret)); } internal record RecentWorkOrder(long? Serial, long? Id, DateTime? ServiceDate); internal class UnitServiceWarrantyInfo { internal List RecentWorkOrders { get; set; } internal DateTime? PurchaseDate { get; set; } internal string PurchasedFromVendor { get; set; } internal long? PurchaseFromVendorId { get; set; } internal string PurchaseReceiptNumber { get; set; } internal bool LifeTimeWarranty { get; set; } internal DateTime? WarrantyExpiryDate { get; set; } internal string WarrantyTerms { get; set; } } }//eoc }//eons