Files
raven/server/AyaNova/Controllers/UnitController.cs
2021-07-08 18:39:15 +00:00

323 lines
16 KiB
C#

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<UnitController> log;
private readonly ApiServerState serverState;
/// <summary>
/// ctor
/// </summary>
/// <param name="dbcontext"></param>
/// <param name="logger"></param>
/// <param name="apiServerState"></param>
public UnitController(AyContext dbcontext, ILogger<UnitController> logger, ApiServerState apiServerState)
{
ct = dbcontext;
log = logger;
serverState = apiServerState;
}
/// <summary>
/// Create Unit
/// </summary>
/// <param name="newObject"></param>
/// <param name="apiVersion">From route path</param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> 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));
}
// /// <summary>
// /// Duplicate Unit
// /// (Wiki and Attachments are not duplicated)
// /// </summary>
// /// <param name="id">Source object id</param>
// /// <param name="apiVersion">From route path</param>
// /// <returns>Unit</returns>
// [HttpPost("duplicate/{id}")]
// public async Task<IActionResult> 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));
// }
/// <summary>
/// Get Unit
/// </summary>
/// <param name="id"></param>
/// <returns>Unit</returns>
[HttpGet("{id}")]
public async Task<IActionResult> 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));
}
/// <summary>
/// Update Unit
/// </summary>
/// <param name="updatedObject"></param>
/// <returns></returns>
[HttpPut]
public async Task<IActionResult> 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 })); ;
}
/// <summary>
/// Delete Unit
/// </summary>
/// <param name="id"></param>
/// <returns>NoContent</returns>
[HttpDelete("{id}")]
public async Task<IActionResult> 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();
}
/// <summary>
/// Get service address for this Unit
/// </summary>
/// <param name="id"></param>
/// <returns>Service address</returns>
[HttpGet("address/{id}")]
public async Task<IActionResult> 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)
}));
}
/// <summary>
/// Get Unit list by tag and optionally customer
/// </summary>
/// <param name="searchParam"></param>
/// <returns>List of units</returns>
[HttpPost("bulk-add-selection-list")]
public async Task<IActionResult> 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<InternalUnitListForSorting> slist = new List<InternalUnitListForSorting>();
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<string> tags, long? restrictToCustomerId);
private record InternalUnitListForSorting(string CustomerName, string UnitSerial, long UnitId);
//------------
/// <summary>
/// Get Unit service and warranty info
/// </summary>
/// <param name="id"></param>
/// <returns>Service and warranty info</returns>
[HttpGet("service-warranty-info/{id}")]
public async Task<IActionResult> 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<RecentWorkOrder> RecentWorkOrders = new List<RecentWorkOrder>();
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<RecentWorkOrder> 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