diff --git a/.vscode/launch.json b/.vscode/launch.json index 49746e6c..fcc80a75 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -54,7 +54,7 @@ "AYANOVA_FOLDER_BACKUP_FILES": "c:\\temp\\RavenTestData\\backupfiles", "AYANOVA_FOLDER_TEMPORARY_SERVER_FILES": "c:\\temp\\RavenTestData\\tempfiles", "AYANOVA_SERVER_TEST_MODE": "true", - "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "false", + "AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small", "AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-7", "AYANOVA_BACKUP_PG_DUMP_PATH": "C:\\data\\code\\postgres_13\\bin\\" }, diff --git a/devdocs/solutions.txt b/devdocs/solutions.txt index c2891833..a55d719e 100644 --- a/devdocs/solutions.txt +++ b/devdocs/solutions.txt @@ -233,4 +233,4 @@ https://en.wikipedia.org/wiki/Non-functional_requirement ## ASCII ART -//http://www.patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=work-order \ No newline at end of file +//http://www.patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=quote \ No newline at end of file diff --git a/server/AyaNova/Controllers/PMTemplateController.cs b/server/AyaNova/Controllers/PMTemplateController.cs deleted file mode 100644 index 6732ebc7..00000000 --- a/server/AyaNova/Controllers/PMTemplateController.cs +++ /dev/null @@ -1,159 +0,0 @@ -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 AyaNova.Models; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Biz; - - -namespace AyaNova.Api.Controllers -{ - [ApiController] - [ApiVersion("8.0")] - [Route("api/v{version:apiVersion}/pm-template")] - [Produces("application/json")] - [Authorize] - public class PMTemplateController : ControllerBase - { - private readonly AyContext ct; - private readonly ILogger log; - private readonly ApiServerState serverState; - - /// - /// ctor - /// - /// - /// - /// - public PMTemplateController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) - { - ct = dbcontext; - log = logger; - serverState = apiServerState; - } - - /// - /// Create PMTemplate - /// - /// - /// From route path - /// - [HttpPost] - public async Task PostPMTemplate([FromBody] PMTemplate newObject, ApiVersion apiVersion) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - PMTemplateBiz biz = PMTemplateBiz.GetBiz(ct, HttpContext); - if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - PMTemplate o = await biz.CreateAsync(newObject); - if (o == null) - return BadRequest(new ApiErrorResponse(biz.Errors)); - else - return CreatedAtAction(nameof(PMTemplateController.GetPMTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - } - - // /// - // /// Duplicate PMTemplate - // /// (Wiki and Attachments are not duplicated) - // /// - // /// Source object id - // /// From route path - // /// PMTemplate - // [HttpPost("duplicate/{id}")] - // public async Task DuplicatePMTemplate([FromRoute] long id, ApiVersion apiVersion) - // { - // if (!serverState.IsOpen) - // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - // PMTemplateBiz biz = PMTemplateBiz.GetBiz(ct, HttpContext); - // if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - // return StatusCode(403, new ApiNotAuthorizedResponse()); - // if (!ModelState.IsValid) - // return BadRequest(new ApiErrorResponse(ModelState)); - // PMTemplate o = await biz.DuplicateAsync(id); - // if (o == null) - // return BadRequest(new ApiErrorResponse(biz.Errors)); - // else - // return CreatedAtAction(nameof(PMTemplateController.GetPMTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - // } - - /// - /// Get PMTemplate - /// - /// - /// PMTemplate - [HttpGet("{id}")] - public async Task GetPMTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - PMTemplateBiz biz = PMTemplateBiz.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 PMTemplate - /// - /// - /// - [HttpPut] - public async Task PutPMTemplate([FromBody] PMTemplate updatedObject) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - PMTemplateBiz biz = PMTemplateBiz.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 PMTemplate - /// - /// - /// NoContent - [HttpDelete("{id}")] - public async Task DeletePMTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - PMTemplateBiz biz = PMTemplateBiz.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(); - } - - - - - - //------------ - - - }//eoc -}//eons \ No newline at end of file diff --git a/server/AyaNova/Controllers/QuoteTemplateController.cs b/server/AyaNova/Controllers/QuoteTemplateController.cs deleted file mode 100644 index 47d33b04..00000000 --- a/server/AyaNova/Controllers/QuoteTemplateController.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Authorization; - -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using AyaNova.Models; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Biz; - - -namespace AyaNova.Api.Controllers -{ - - [ApiController] - [ApiVersion("8.0")] - [Route("api/v{version:apiVersion}/quote-template")] - [Produces("application/json")] - [Authorize] - public class QuoteTemplateController : ControllerBase - { - private readonly AyContext ct; - private readonly ILogger log; - private readonly ApiServerState serverState; - - - /// - /// ctor - /// - /// - /// - /// - public QuoteTemplateController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) - { - ct = dbcontext; - log = logger; - serverState = apiServerState; - } - - - /// - /// Get full QuoteTemplate object - /// - /// - /// A single QuoteTemplate - [HttpGet("{id}")] - public async Task GetQuoteTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - //Instantiate the business object handler - QuoteTemplateBiz biz = QuoteTemplateBiz.GetBiz(ct, HttpContext); - - //NOTE: This is the first check and often the only check but in some cases with some objects this will also need to check biz object rules - 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)); - - // NOTE: HERE would be the second check of biz rules before returning the object - // in cases where there is also a business rule to affect retrieval on top of basic rights - - return Ok(ApiOkResponse.Response(o)); - } - - - - /// - /// Update QuoteTemplate - /// - /// - /// - /// - [HttpPut("{id}")] - public async Task PutQuoteTemplate([FromRoute] long id, [FromBody] QuoteTemplate inObj) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Instantiate the business object handler - QuoteTemplateBiz biz = QuoteTemplateBiz.GetBiz(ct, HttpContext); - - var o = await biz.GetAsync(id, false); - if (o == null) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - try - { - if (!await biz.PutAsync(o, inObj)) - return BadRequest(new ApiErrorResponse(biz.Errors)); - } - catch (DbUpdateConcurrencyException) - { - if (!await biz.ExistsAsync(id)) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - else - return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); - } - return Ok(ApiOkResponse.Response(new { Concurrency = o.Concurrency })); - } - - - /// - /// Create QuoteTemplate - /// - /// - /// From route path - /// - [HttpPost] - public async Task PostQuoteTemplate([FromBody] QuoteTemplate inObj, ApiVersion apiVersion) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - //Instantiate the business object handler - QuoteTemplateBiz biz = QuoteTemplateBiz.GetBiz(ct, HttpContext); - - //If a user has change roles - if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Create and validate - QuoteTemplate o = await biz.CreateAsync(inObj); - if (o == null) - return BadRequest(new ApiErrorResponse(biz.Errors)); - else - return CreatedAtAction(nameof(QuoteTemplateController.GetQuoteTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - - - } - - // /// - // /// Duplicate QuoteTemplate - // /// - // /// Create a duplicate of this items id - // /// From route path - // /// - // [HttpPost("duplicate/{id}")] - // public async Task DuplicateQuoteTemplate([FromRoute] long id, ApiVersion apiVersion) - // { - // if (!serverState.IsOpen) - // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - // //Instantiate the business object handler - // QuoteTemplateBiz biz = QuoteTemplateBiz.GetBiz(ct, HttpContext); - - // //If a user has change roles - // if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - // return StatusCode(403, new ApiNotAuthorizedResponse()); - - // if (!ModelState.IsValid) - // return BadRequest(new ApiErrorResponse(ModelState)); - - // var oSrc = await biz.GetAsync(id, false); - // if (oSrc == null) - // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - // //Create and validate - // QuoteTemplate o = await biz.DuplicateAsync(oSrc); - // if (o == null) - // return BadRequest(new ApiErrorResponse(biz.Errors)); - // else - // return CreatedAtAction(nameof(QuoteTemplateController.GetQuoteTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - - // } - - - - /// - /// Delete QuoteTemplate - /// - /// - /// Ok - [HttpDelete("{id}")] - public async Task DeleteQuoteTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Instantiate the business object handler - QuoteTemplateBiz biz = QuoteTemplateBiz.GetBiz(ct, HttpContext); - - var o = await biz.GetAsync(id, false); - if (o == null) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - if (!await biz.DeleteAsync(o)) - return BadRequest(new ApiErrorResponse(biz.Errors)); - - return NoContent(); - } - - - - - - //------------ - - - }//eoc -}//eons \ No newline at end of file diff --git a/server/AyaNova/Controllers/WorkOrderTemplateController.cs b/server/AyaNova/Controllers/WorkOrderTemplateController.cs deleted file mode 100644 index daef62b2..00000000 --- a/server/AyaNova/Controllers/WorkOrderTemplateController.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Authorization; - -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using AyaNova.Models; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Biz; - - -namespace AyaNova.Api.Controllers -{ - - [ApiController] - [ApiVersion("8.0")] - [Route("api/v{version:apiVersion}/workorder-template")] - [Produces("application/json")] - [Authorize] - public class WorkOrderTemplateController : ControllerBase - { - private readonly AyContext ct; - private readonly ILogger log; - private readonly ApiServerState serverState; - - - /// - /// ctor - /// - /// - /// - /// - public WorkOrderTemplateController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) - { - ct = dbcontext; - log = logger; - serverState = apiServerState; - } - - - /// - /// Get full WorkOrderTemplate object - /// - /// - /// A single WorkOrderTemplate - [HttpGet("{id}")] - public async Task GetWorkOrderTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - //Instantiate the business object handler - WorkOrderTemplateBiz biz = WorkOrderTemplateBiz.GetBiz(ct, HttpContext); - - //NOTE: This is the first check and often the only check but in some cases with some objects this will also need to check biz object rules - 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)); - - // NOTE: HERE would be the second check of biz rules before returning the object - // in cases where there is also a business rule to affect retrieval on top of basic rights - - return Ok(ApiOkResponse.Response(o)); - } - - - - /// - /// Update WorkOrderTemplate - /// - /// - /// - /// - [HttpPut("{id}")] - public async Task PutWorkOrderTemplate([FromRoute] long id, [FromBody] WorkOrderTemplate inObj) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Instantiate the business object handler - WorkOrderTemplateBiz biz = WorkOrderTemplateBiz.GetBiz(ct, HttpContext); - - var o = await biz.GetAsync(id, false); - if (o == null) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - try - { - if (!await biz.PutAsync(o, inObj)) - return BadRequest(new ApiErrorResponse(biz.Errors)); - } - catch (DbUpdateConcurrencyException) - { - if (!await biz.ExistsAsync(id)) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - else - return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); - } - return Ok(ApiOkResponse.Response(new { Concurrency = o.Concurrency })); - } - - - /// - /// Create WorkOrderTemplate - /// - /// - /// From route path - /// - [HttpPost] - public async Task PostWorkOrderTemplate([FromBody] WorkOrderTemplate inObj, ApiVersion apiVersion) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - //Instantiate the business object handler - WorkOrderTemplateBiz biz = WorkOrderTemplateBiz.GetBiz(ct, HttpContext); - - //If a user has change roles - if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Create and validate - WorkOrderTemplate o = await biz.CreateAsync(inObj); - if (o == null) - return BadRequest(new ApiErrorResponse(biz.Errors)); - else - return CreatedAtAction(nameof(WorkOrderTemplateController.GetWorkOrderTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - - - } - - // /// - // /// Duplicate WorkOrderTemplate - // /// - // /// Create a duplicate of this items id - // /// From route path - // /// - // [HttpPost("duplicate/{id}")] - // public async Task DuplicateWorkOrderTemplate([FromRoute] long id, ApiVersion apiVersion) - // { - // if (!serverState.IsOpen) - // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - // //Instantiate the business object handler - // WorkOrderTemplateBiz biz = WorkOrderTemplateBiz.GetBiz(ct, HttpContext); - - // //If a user has change roles - // if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) - // return StatusCode(403, new ApiNotAuthorizedResponse()); - - // if (!ModelState.IsValid) - // return BadRequest(new ApiErrorResponse(ModelState)); - - // var oSrc = await biz.GetAsync(id, false); - // if (oSrc == null) - // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - // //Create and validate - // WorkOrderTemplate o = await biz.DuplicateAsync(oSrc); - // if (o == null) - // return BadRequest(new ApiErrorResponse(biz.Errors)); - // else - // return CreatedAtAction(nameof(WorkOrderTemplateController.GetWorkOrderTemplate), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - - // } - - - - /// - /// Delete WorkOrderTemplate - /// - /// - /// Ok - [HttpDelete("{id}")] - public async Task DeleteWorkOrderTemplate([FromRoute] long id) - { - if (!serverState.IsOpen) - return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); - - if (!ModelState.IsValid) - return BadRequest(new ApiErrorResponse(ModelState)); - - //Instantiate the business object handler - WorkOrderTemplateBiz biz = WorkOrderTemplateBiz.GetBiz(ct, HttpContext); - - var o = await biz.GetAsync(id, false); - if (o == null) - return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); - - if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) - return StatusCode(403, new ApiNotAuthorizedResponse()); - - if (!await biz.DeleteAsync(o)) - return BadRequest(new ApiErrorResponse(biz.Errors)); - - return NoContent(); - } - - - - - - //------------ - - - }//eoc -}//eons \ No newline at end of file diff --git a/server/AyaNova/PickList/WorkOrderTemplatePickList.cs b/server/AyaNova/PickList/WorkOrderTemplatePickList.cs deleted file mode 100644 index fcefe517..00000000 --- a/server/AyaNova/PickList/WorkOrderTemplatePickList.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json.Linq; -using AyaNova.Biz; -namespace AyaNova.PickList -{ - internal class WorkOrderTemplatePickList : AyaPickList - { - public WorkOrderTemplatePickList() - { - - DefaultListAType = AyaType.WorkOrderTemplate; - SQLFrom = "from aworkordertemplate"; - AllowedRoles = BizRoles.GetRoleSet(DefaultListAType).Select; - dynamic dTemplate = new JArray(); - - dynamic cm = new JObject(); - cm.fld = "name"; - dTemplate.Add(cm); - - - - base.DefaultTemplate = dTemplate.ToString(Newtonsoft.Json.Formatting.None); - - //NOTE: Due to the join, all the sql id and name fields that can conflict with the joined table need to be specified completely - ColumnDefinitions = new List(); - ColumnDefinitions.Add(new AyaPickListFieldDefinition - { - TKey = "Active", - FieldKey = "active", - ColumnDataType = UiFieldDataType.Bool, - SqlValueColumnName = "aworkordertemplate.active", - IsActiveColumn = true - }); - ColumnDefinitions.Add(new AyaPickListFieldDefinition - { - TKey = "Name", - FieldKey = "name", - ColumnDataType = UiFieldDataType.Text, - SqlIdColumnName = "aworkordertemplate.id", - SqlValueColumnName = "aworkordertemplate.name", - IsRowId = true - }); - - } - }//eoc -}//eons \ No newline at end of file diff --git a/server/AyaNova/biz/AyaType.cs b/server/AyaNova/biz/AyaType.cs index e91a618f..e6b4932e 100644 --- a/server/AyaNova/biz/AyaType.cs +++ b/server/AyaNova/biz/AyaType.cs @@ -54,9 +54,9 @@ namespace AyaNova.Biz [CoreBizObject] PMItem = 22, [CoreBizObject] - PMTemplate = 23, + unused23 = 23, [CoreBizObject] - PMTemplateItem = 24, + unused24 = 24, [CoreBizObject] Project = 25, [CoreBizObject] @@ -66,9 +66,9 @@ namespace AyaNova.Biz [CoreBizObject] QuoteItem = 28, [CoreBizObject] - QuoteTemplate = 29, + unused29 = 29, [CoreBizObject] - QuoteTemplateItem = 30, + unused30 = 30, [CoreBizObject] Unit = 31, [CoreBizObject] @@ -100,9 +100,9 @@ namespace AyaNova.Biz WorkOrderItemUnit = 44, //--- [CoreBizObject] - WorkOrderTemplate = 45, + unused45 = 45, [CoreBizObject] - WorkOrderTemplateItem = 46, + unused46 = 46, GlobalOps = 47,//really only used for rights, not an object type of any kind BizMetrics = 48,//deprecate? Not used for anything as of nov 2020 Backup = 49, diff --git a/server/AyaNova/biz/BizObjectExistsInDatabase.cs b/server/AyaNova/biz/BizObjectExistsInDatabase.cs index 88537e15..9e8d733d 100644 --- a/server/AyaNova/biz/BizObjectExistsInDatabase.cs +++ b/server/AyaNova/biz/BizObjectExistsInDatabase.cs @@ -56,10 +56,7 @@ namespace AyaNova.Biz return await ct.PM.AnyAsync(z => z.Id == id); case AyaType.PMItem: return await ct.PMItem.AnyAsync(z => z.Id == id); - case AyaType.PMTemplate: - return await ct.PMTemplate.AnyAsync(z => z.Id == id); - case AyaType.PMTemplateItem: - return await ct.PMTemplateItem.AnyAsync(z => z.Id == id); + case AyaType.Project: return await ct.Project.AnyAsync(z => z.Id == id); case AyaType.PurchaseOrder: @@ -68,10 +65,7 @@ namespace AyaNova.Biz return await ct.Quote.AnyAsync(z => z.Id == id); case AyaType.QuoteItem: return await ct.QuoteItem.AnyAsync(z => z.Id == id); - case AyaType.QuoteTemplate: - return await ct.QuoteTemplate.AnyAsync(z => z.Id == id); - case AyaType.QuoteTemplateItem: - return await ct.QuoteTemplateItem.AnyAsync(z => z.Id == id); + case AyaType.Unit: return await ct.Unit.AnyAsync(z => z.Id == id); case AyaType.UnitModel: @@ -104,10 +98,7 @@ namespace AyaNova.Biz case AyaType.WorkOrderItemOutsideService: return await ct.WorkOrderItemOutsideService.AnyAsync(z => z.Id == id); //--- - case AyaType.WorkOrderTemplate: - return await ct.WorkOrderTemplate.AnyAsync(z => z.Id == id); - case AyaType.WorkOrderTemplateItem: - return await ct.WorkOrderTemplateItem.AnyAsync(z => z.Id == id); + case AyaType.Report: return await ct.Report.AnyAsync(z => z.Id == id); case AyaType.Reminder: diff --git a/server/AyaNova/biz/BizObjectFactory.cs b/server/AyaNova/biz/BizObjectFactory.cs index f7d72403..d38dc6fc 100644 --- a/server/AyaNova/biz/BizObjectFactory.cs +++ b/server/AyaNova/biz/BizObjectFactory.cs @@ -64,9 +64,7 @@ namespace AyaNova.Biz case AyaType.PM: return new PMBiz(ct, userId, translationId, roles); - case AyaType.PMTemplate: - return new PMTemplateBiz(ct, userId, translationId, roles); - + case AyaType.Project: return new ProjectBiz(ct, userId, translationId, roles); case AyaType.PurchaseOrder: @@ -74,9 +72,7 @@ namespace AyaNova.Biz case AyaType.Quote: return new QuoteBiz(ct, userId, translationId, roles); - case AyaType.QuoteTemplate: - return new QuoteTemplateBiz(ct, userId, translationId, roles); - + case AyaType.Unit: return new UnitBiz(ct, userId, translationId, roles); case AyaType.UnitModel: @@ -98,9 +94,7 @@ namespace AyaNova.Biz case AyaType.WorkOrderItemOutsideService: return new WorkOrderBiz(ct, userId, translationId, roles, UserType.NotService);//default to not service for now arbitrarily on the principle of least access //--- - case AyaType.WorkOrderTemplate: - return new WorkOrderTemplateBiz(ct, userId, translationId, roles); - + case AyaType.Reminder: return new ReminderBiz(ct, userId, translationId, roles); case AyaType.Review: diff --git a/server/AyaNova/biz/BizRoles.cs b/server/AyaNova/biz/BizRoles.cs index c7d10ee3..48cb55a9 100644 --- a/server/AyaNova/biz/BizRoles.cs +++ b/server/AyaNova/biz/BizRoles.cs @@ -269,25 +269,7 @@ namespace AyaNova.Biz Select = AuthorizationRoles.All }); - //////////////////////////////////////////////////////////// - //PMTemplate - // - roles.Add(AyaType.PMTemplate, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); - - //////////////////////////////////////////////////////////// - //PMTemplateItem - // - roles.Add(AyaType.PMTemplateItem, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); + //////////////////////////////////////////////////////////// //Project @@ -400,26 +382,7 @@ namespace AyaNova.Biz Select = AuthorizationRoles.All }); - //////////////////////////////////////////////////////////// - //QuoteTemplate - // - roles.Add(AyaType.QuoteTemplate, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); - - //////////////////////////////////////////////////////////// - //QuoteTemplateItem - // - roles.Add(AyaType.QuoteTemplateItem, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); - + //////////////////////////////////////////////////////////// //Unit // @@ -597,28 +560,6 @@ namespace AyaNova.Biz //--- - //////////////////////////////////////////////////////////// - //WorkOrderTemplate - // - roles.Add(AyaType.WorkOrderTemplate, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); - - //////////////////////////////////////////////////////////// - //WorkOrderTemplateItem - // - roles.Add(AyaType.WorkOrderTemplateItem, new BizRoleSet() - { - Change = AuthorizationRoles.BizAdmin | AuthorizationRoles.Service | AuthorizationRoles.Sales | AuthorizationRoles.Tech | AuthorizationRoles.Accounting, - ReadFullRecord = AuthorizationRoles.BizAdminRestricted | AuthorizationRoles.ServiceRestricted | AuthorizationRoles.SalesRestricted | AuthorizationRoles.TechRestricted, - Select = AuthorizationRoles.All - }); - - - //////////////////////////////////////////////////////////// //GLOBAL BIZ SETTINGS diff --git a/server/AyaNova/biz/PMTemplateBiz.cs b/server/AyaNova/biz/PMTemplateBiz.cs deleted file mode 100644 index 45ff6334..00000000 --- a/server/AyaNova/biz/PMTemplateBiz.cs +++ /dev/null @@ -1,309 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using AyaNova.Util; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Models; - -namespace AyaNova.Biz -{ - internal class PMTemplateBiz : BizObject, ISearchAbleObject, INotifiableObject - { - internal PMTemplateBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles) - { - ct = dbcontext; - UserId = currentUserId; - UserTranslationId = userTranslationId; - CurrentUserRoles = UserRoles; - BizType = AyaType.PMTemplate; - } - - internal static PMTemplateBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) - { - if (httpContext != null) - return new PMTemplateBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); - else - return new PMTemplateBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - //EXISTS - internal async Task ExistsAsync(long id) - { - return await ct.PMTemplate.AnyAsync(z => z.Id == id); - } - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //CREATE - // - internal async Task CreateAsync(PMTemplate newObject) - { - await ValidateAsync(newObject, null); - if (HasErrors) - return null; - else - { - newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); - newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields); - await ct.PMTemplate.AddAsync(newObject); - await ct.SaveChangesAsync(); - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); - await SearchIndexAsync(newObject, true); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); - await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - return newObject; - } - } - - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //DUPLICATE - // // - // internal async Task DuplicateAsync(long id) - // { - // PMTemplate dbObject = await GetAsync(id, false); - // if (dbObject == null) - // { - // AddError(ApiErrorCode.NOT_FOUND, "id"); - // return null; - // } - // PMTemplate newObject = new PMTemplate(); - // CopyObject.Copy(dbObject, newObject, "Wiki"); - // string newUniqueName = string.Empty; - // bool NotUnique = true; - // long l = 1; - // do - // { - // newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObject.Name, l++, 255); - // NotUnique = await ct.PMTemplate.AnyAsync(z => z.Name == newUniqueName); - // } while (NotUnique); - // newObject.Name = newUniqueName; - // newObject.Id = 0; - // newObject.Concurrency = 0; - // await ct.PMTemplate.AddAsync(newObject); - // await ct.SaveChangesAsync(); - // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); - // await SearchIndexAsync(newObject, true); - // await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); - // await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - // return newObject; - // } - - //////////////////////////////////////////////////////////////////////////////////////////////// - //GET - // - internal async Task GetAsync(long id, bool logTheGetEvent = true) - { - var ret = await ct.PMTemplate.SingleOrDefaultAsync(z => z.Id == id); - if (logTheGetEvent && ret != null) - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, AyaEvent.Retrieved), ct); - return ret; - } - - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE PARTASSEMBLYBIZ / some of WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //UPDATE - // - internal async Task PutAsync(PMTemplate putObject) - { - PMTemplate dbObject = await ct.PMTemplate.SingleOrDefaultAsync(z => z.Id == putObject.Id); - if (dbObject == null) - { - AddError(ApiErrorCode.NOT_FOUND, "id"); - return null; - } - PMTemplate SnapshotOfOriginalDBObj = new PMTemplate(); - CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); - CopyObject.Copy(putObject, dbObject, "Id"); - dbObject.Tags = TagBiz.NormalizeTags(dbObject.Tags); - dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields); - ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency; - await ValidateAsync(dbObject, SnapshotOfOriginalDBObj); - if (HasErrors) return null; - try - { - await ct.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) - { - if (!await ExistsAsync(putObject.Id)) - AddError(ApiErrorCode.NOT_FOUND); - else - AddError(ApiErrorCode.CONCURRENCY_CONFLICT); - return null; - } - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); - await SearchIndexAsync(dbObject, false); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags); - await HandlePotentialNotificationEvent(AyaEvent.Modified, dbObject, SnapshotOfOriginalDBObj); - return dbObject; - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - //DELETE - // - internal async Task DeleteAsync(long id) - { - using (var transaction = await ct.Database.BeginTransactionAsync()) - { - try - { - PMTemplate dbObject = await ct.PMTemplate.SingleOrDefaultAsync(z => z.Id == id); - if (dbObject == null) - { - AddError(ApiErrorCode.NOT_FOUND); - return false; - } - ValidateCanDelete(dbObject); - if (HasErrors) - return false; - if (HasErrors) - return false; - ct.PMTemplate.Remove(dbObject); - await ct.SaveChangesAsync(); - - //Log event - await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct); - await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct); - await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags); - await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct); - await transaction.CommitAsync(); - await HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject); - } - catch - { - //Just re-throw for now, let exception handler deal, but in future may want to deal with this more here - throw; - } - return true; - } - } - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //SEARCH - // - private async Task SearchIndexAsync(PMTemplate obj, bool isNew) - { - var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType); - DigestSearchText(obj, SearchParams); - if (isNew) - await Search.ProcessNewObjectKeywordsAsync(SearchParams); - else - await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams); - } - - public async Task GetSearchResultSummary(long id) - { - var obj = await ct.PMTemplate.SingleOrDefaultAsync(z => z.Id == id); - var SearchParams = new Search.SearchIndexProcessObjectParameters(); - DigestSearchText(obj, SearchParams); - return SearchParams; - } - - public void DigestSearchText(PMTemplate obj, Search.SearchIndexProcessObjectParameters searchParams) - { - if (obj != null) - searchParams.AddText(obj.Notes) - .AddText(obj.Name) - .AddText(obj.Wiki) - .AddText(obj.Tags) - .AddCustomFields(obj.CustomFields); - } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //VALIDATION - // - - private async Task ValidateAsync(PMTemplate proposedObj, PMTemplate currentObj) - { - - bool isNew = currentObj == null; - - //Name required - if (string.IsNullOrWhiteSpace(proposedObj.Name)) - AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name"); - - - //If name is otherwise OK, check that name is unique - if (!PropertyHasErrors("Name")) - { - //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false - if (await ct.PMTemplate.AnyAsync(z => z.Name == proposedObj.Name && z.Id != proposedObj.Id)) - { - AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name"); - } - } - - - //Any form customizations to validate? - var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.PMTemplate.ToString()); - if (FormCustomization != null) - { - //Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required - - //validate users choices for required non custom fields - RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj); - - //validate custom fields - CustomFieldsValidator.Validate(this, FormCustomization, proposedObj.CustomFields); - } - - } - - private void ValidateCanDelete(PMTemplate inObj) - { - //whatever needs to be check to delete this object - } - - - - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - // NOTIFICATION PROCESSING - // - public async Task HandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null) - { - ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger(); - if (ServerBootConfig.SEEDING) return; - log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{this.BizType}, AyaEvent:{ayaEvent}]"); - - bool isNew = currentObj == null; - - - //STANDARD EVENTS FOR ALL OBJECTS - await NotifyEventHelper.ProcessStandardObjectEvents(ayaEvent, proposedObj, ct); - - //SPECIFIC EVENTS FOR THIS OBJECT - - }//end of process notifications - - - - - ///////////////////////////////////////////////////////////////////// - - }//eoc - - -}//eons - diff --git a/server/AyaNova/biz/QuoteTemplateBiz.cs b/server/AyaNova/biz/QuoteTemplateBiz.cs deleted file mode 100644 index 9b21c3cb..00000000 --- a/server/AyaNova/biz/QuoteTemplateBiz.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; - -using AyaNova.Util; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Models; - -namespace AyaNova.Biz -{ - - internal class QuoteTemplateBiz : BizObject, ISearchAbleObject - { - - internal QuoteTemplateBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles) - { - ct = dbcontext; - UserId = currentUserId; - UserTranslationId = userTranslationId; - CurrentUserRoles = UserRoles; - BizType = AyaType.QuoteTemplate; - } - - internal static QuoteTemplateBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) - { - - if (httpContext != null) - return new QuoteTemplateBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); - else//when called internally for internal ops there will be no context so need to set default values for that - return new QuoteTemplateBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin); - } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //EXISTS - internal async Task ExistsAsync(long id) - { - return await ct.QuoteTemplate.AnyAsync(z => z.Id == id); - } - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - //////////////////////////////////////////////////////////////////////////////////////////////// - /// GET - /// - /// - - internal async Task GetAsync(long fetchId, bool logTheGetEvent = true) - { - //This is simple so nothing more here, but often will be copying to a different output object or some other ops - var ret = await ct.QuoteTemplate.SingleOrDefaultAsync(z => z.Id == fetchId); - if (logTheGetEvent && ret != null) - { - //Log - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, fetchId, BizType, AyaEvent.Retrieved), ct); - } - return ret; - } - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //CREATE - - //Called from route and also seeder - internal async Task CreateAsync(QuoteTemplate inObj) - { - await ValidateAsync(inObj, null); - if (HasErrors) - return null; - else - { - //do stuff with QuoteTemplate - QuoteTemplate outObj = inObj; - - outObj.Tags = TagBiz.NormalizeTags(outObj.Tags); - outObj.CustomFields = JsonUtil.CompactJson(outObj.CustomFields); - //Save to db - await ct.QuoteTemplate.AddAsync(outObj); - await ct.SaveChangesAsync(); - //Handle child and associated items: - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); - await SearchIndexAsync(outObj, true); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null); - - return outObj; - } - } - - - - - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //DUPLICATE - // // - - // internal async Task DuplicateAsync(QuoteTemplate dbObject) - // { - - // QuoteTemplate outObj = new QuoteTemplate(); - // CopyObject.Copy(dbObject, outObj, "Wiki"); - // // outObj.Name = Util.StringUtil.NameUniquify(outObj.Name, 255); - // //generate unique name - // string newUniqueName = string.Empty; - // bool NotUnique = true; - // long l = 1; - // do - // { - // newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObject.Name, l++, 255); - // NotUnique = await ct.QuoteTemplate.AnyAsync(z => z.Name == newUniqueName); - // } while (NotUnique); - - // outObj.Name = newUniqueName; - - - // outObj.Id = 0; - // outObj.Concurrency = 0; - - // await ct.QuoteTemplate.AddAsync(outObj); - // await ct.SaveChangesAsync(); - - // //Handle child and associated items: - // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); - // await SearchIndexAsync(outObj, true); - // await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null); - // return outObj; - - // } - - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE PARTASSEMBLYBIZ / some of WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //UPDATE - // - - //put - internal async Task PutAsync(QuoteTemplate dbObject, QuoteTemplate inObj) - { - - //make a snapshot of the original for validation but update the original to preserve workflow - QuoteTemplate SnapshotOfOriginalDBObj = new QuoteTemplate(); - CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); - - //Replace the db object with the PUT object - CopyObject.Copy(inObj, dbObject, "Id"); - - dbObject.Tags = TagBiz.NormalizeTags(dbObject.Tags); - dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields); - - //Set "original" value of concurrency token to input token - //this will allow EF to check it out - ct.Entry(dbObject).OriginalValues["Concurrency"] = inObj.Concurrency; - - - await ValidateAsync(dbObject, SnapshotOfOriginalDBObj); - if (HasErrors) - return false; - - //Log event and save context - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); - await SearchIndexAsync(dbObject, false); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags); - - return true; - } - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //SEARCH - // - private async Task SearchIndexAsync(QuoteTemplate obj, bool isNew) - { - var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType); - DigestSearchText(obj, SearchParams); - if (isNew) - await Search.ProcessNewObjectKeywordsAsync(SearchParams); - else - await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams); - } - - public async Task GetSearchResultSummary(long id) - { - var obj = await ct.QuoteTemplate.SingleOrDefaultAsync(z => z.Id == id); - var SearchParams = new Search.SearchIndexProcessObjectParameters(); - DigestSearchText(obj, SearchParams); - return SearchParams; - } - - public void DigestSearchText(QuoteTemplate obj, Search.SearchIndexProcessObjectParameters searchParams) - { - if (obj != null) - searchParams.AddText(obj.Notes) - .AddText(obj.Name) - .AddText(obj.Wiki) - .AddText(obj.Tags) - .AddCustomFields(obj.CustomFields); - } - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //DELETE - // - internal async Task DeleteAsync(QuoteTemplate dbObject) - { - //Determine if the object can be deleted, do the deletion tentatively - //Probably also in here deal with tags and associated search text etc - - //NOT REQUIRED NOW BUT IF IN FUTURE ValidateCanDelete(dbObject); - if (HasErrors) - return false; - ct.QuoteTemplate.Remove(dbObject); - await ct.SaveChangesAsync(); - - //Log event - await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct); - await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct); - await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags); - await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct); - return true; - } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //VALIDATION - // - - //Can save or update? - private async Task ValidateAsync(QuoteTemplate proposedObj, QuoteTemplate currentObj) - { - - //run validation and biz rules - bool isNew = currentObj == null; - - //Name required - if (string.IsNullOrWhiteSpace(proposedObj.Name)) - AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name"); - - - - //If name is otherwise OK, check that name is unique - if (!PropertyHasErrors("Name")) - { - //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false - if (await ct.QuoteTemplate.AnyAsync(z => z.Name == proposedObj.Name && z.Id != proposedObj.Id)) - { - AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name"); - } - } - - - //Any form customizations to validate? - var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.QuoteTemplate.ToString()); - if (FormCustomization != null) - { - //Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required - - //validate users choices for required non custom fields - RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj); - - //validate custom fields - CustomFieldsValidator.Validate(this, FormCustomization, proposedObj.CustomFields); - } - - } - - - //Can delete? - // private void ValidateCanDelete(QuoteTemplate inObj) - // { - // //whatever needs to be check to delete this object - // } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //JOB / OPERATIONS - // - - - //Other job handlers here... - - - ///////////////////////////////////////////////////////////////////// - - }//eoc - - -}//eons - diff --git a/server/AyaNova/biz/WorkorderTemplateBiz.cs b/server/AyaNova/biz/WorkorderTemplateBiz.cs deleted file mode 100644 index 277743ab..00000000 --- a/server/AyaNova/biz/WorkorderTemplateBiz.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; - -using AyaNova.Util; -using AyaNova.Api.ControllerHelpers; -using AyaNova.Models; - -namespace AyaNova.Biz -{ - - internal class WorkOrderTemplateBiz : BizObject, ISearchAbleObject, INotifiableObject - { - - internal WorkOrderTemplateBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles) - { - ct = dbcontext; - UserId = currentUserId; - UserTranslationId = userTranslationId; - CurrentUserRoles = UserRoles; - BizType = AyaType.WorkOrderTemplate; - } - - internal static WorkOrderTemplateBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) - { - - if (httpContext != null) - return new WorkOrderTemplateBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); - else//when called internally for internal ops there will be no context so need to set default values for that - return new WorkOrderTemplateBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin); - } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //EXISTS - internal async Task ExistsAsync(long id) - { - return await ct.WorkOrderTemplate.AnyAsync(z => z.Id == id); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - /// GET - /// - /// - - internal async Task GetAsync(long fetchId, bool logTheGetEvent = true) - { - //This is simple so nothing more here, but often will be copying to a different output object or some other ops - var ret = await ct.WorkOrderTemplate.SingleOrDefaultAsync(z => z.Id == fetchId); - if (logTheGetEvent && ret != null) - { - //Log - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, fetchId, BizType, AyaEvent.Retrieved), ct); - } - return ret; - } - - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //CREATE - - //Called from route and also seeder - internal async Task CreateAsync(WorkOrderTemplate newObject) - { - await ValidateAsync(newObject, null); - if (HasErrors) - return null; - else - { - //do stuff with WorkOrderTemplate - WorkOrderTemplate outObj = newObject; - - outObj.Tags = TagBiz.NormalizeTags(outObj.Tags); - outObj.CustomFields = JsonUtil.CompactJson(outObj.CustomFields); - //Save to db - await ct.WorkOrderTemplate.AddAsync(outObj); - await ct.SaveChangesAsync(); - //Handle child and associated items: - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); - await SearchIndexAsync(outObj, true); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null); - await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - - return outObj; - } - } - - - - - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //DUPLICATE - // // - - // internal async Task DuplicateAsync(WorkOrderTemplate dbObject) - // { - - // WorkOrderTemplate newObject = new WorkOrderTemplate(); - // CopyObject.Copy(dbObject, newObject, "Wiki"); - // // outObj.Name = Util.StringUtil.NameUniquify(outObj.Name, 255); - // //generate unique name - // string newUniqueName = string.Empty; - // bool NotUnique = true; - // long l = 1; - // do - // { - // newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObject.Name, l++, 255); - // NotUnique = await ct.WorkOrderTemplate.AnyAsync(z => z.Name == newUniqueName); - // } while (NotUnique); - - // newObject.Name = newUniqueName; - - - // newObject.Id = 0; - // newObject.Concurrency = 0; - - // await ct.WorkOrderTemplate.AddAsync(newObject); - // await ct.SaveChangesAsync(); - - // //Handle child and associated items: - // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); - // await SearchIndexAsync(newObject, true); - // await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); - // await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - // return newObject; - - // } - - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE PARTASSEMBLYBIZ / some of WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //UPDATE - // - - //put - internal async Task PutAsync(WorkOrderTemplate dbObject, WorkOrderTemplate inObj) - { - - //make a snapshot of the original for validation but update the original to preserve workflow - WorkOrderTemplate SnapshotOfOriginalDBObj = new WorkOrderTemplate(); - CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); - - //Replace the db object with the PUT object - CopyObject.Copy(inObj, dbObject, "Id"); - - dbObject.Tags = TagBiz.NormalizeTags(dbObject.Tags); - dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields); - - //Set "original" value of concurrency token to input token - //this will allow EF to check it out - ct.Entry(dbObject).OriginalValues["Concurrency"] = inObj.Concurrency; - - - await ValidateAsync(dbObject, SnapshotOfOriginalDBObj); - if (HasErrors) - return false; - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); - await SearchIndexAsync(dbObject, false); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags); - await HandlePotentialNotificationEvent(AyaEvent.Modified, dbObject, SnapshotOfOriginalDBObj); - return true; - } - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //SEARCH - // - private async Task SearchIndexAsync(WorkOrderTemplate obj, bool isNew) - { - var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType); - DigestSearchText(obj, SearchParams); - if (isNew) - await Search.ProcessNewObjectKeywordsAsync(SearchParams); - else - await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams); - } - - public async Task GetSearchResultSummary(long id) - { - var obj = await ct.WorkOrderTemplate.SingleOrDefaultAsync(z => z.Id == id); - var SearchParams = new Search.SearchIndexProcessObjectParameters(); - DigestSearchText(obj, SearchParams); - return SearchParams; - } - - public void DigestSearchText(WorkOrderTemplate obj, Search.SearchIndexProcessObjectParameters searchParams) - { - if (obj != null) - searchParams.AddText(obj.Notes) - .AddText(obj.Name) - .AddText(obj.Wiki) - .AddText(obj.Tags) - .AddCustomFields(obj.CustomFields); - } - - //################################################################################################################################################### - //################################################################################################################################################### - // WARNING! THIS OBJECT IS AN INITIAL TEST VERSION NOT UP TO CURRENT STANDARDS, SEE WORKORDERBIZ FOR HOW THIS SHOULD BE CODED - //################################################################################################################################################### - //################################################################################################################################################### - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //DELETE - // - internal async Task DeleteAsync(WorkOrderTemplate dbObject) - { - //Determine if the object can be deleted, do the deletion tentatively - //Probably also in here deal with tags and associated search text etc - - //NOT REQUIRED NOW BUT IF IN FUTURE ValidateCanDelete(dbObject); - if (HasErrors) - return false; - ct.WorkOrderTemplate.Remove(dbObject); - await ct.SaveChangesAsync(); - - //Log event - await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Name, ct); - await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct); - await TagBiz.ProcessDeleteTagsInRepositoryAsync(ct, dbObject.Tags); - await FileUtil.DeleteAttachmentsForObjectAsync(BizType, dbObject.Id, ct); - await HandlePotentialNotificationEvent(AyaEvent.Deleted, dbObject); - return true; - } - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - //VALIDATION - // - - //Can save or update? - private async Task ValidateAsync(WorkOrderTemplate proposedObj, WorkOrderTemplate currentObj) - { - - //run validation and biz rules - bool isNew = currentObj == null; - - //Name required - if (string.IsNullOrWhiteSpace(proposedObj.Name)) - AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name"); - - //If name is otherwise OK, check that name is unique - if (!PropertyHasErrors("Name")) - { - //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false - if (await ct.WorkOrderTemplate.AnyAsync(z => z.Name == proposedObj.Name && z.Id != proposedObj.Id)) - { - AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name"); - } - } - - - //Any form customizations to validate? - var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderTemplate.ToString()); - if (FormCustomization != null) - { - //Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required - - //validate users choices for required non custom fields - RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj); - - //validate custom fields - CustomFieldsValidator.Validate(this, FormCustomization, proposedObj.CustomFields); - } - - } - - - //Can delete? - // private void ValidateCanDelete(WorkOrderTemplate inObj) - // { - // //whatever needs to be check to delete this object - // } - - - - - - - //////////////////////////////////////////////////////////////////////////////////////////////// - // NOTIFICATION PROCESSING - // - public async Task HandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null) - { - ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger(); - if (ServerBootConfig.SEEDING) return; - log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{this.BizType}, AyaEvent:{ayaEvent}]"); - - bool isNew = currentObj == null; - - - //STANDARD EVENTS FOR ALL OBJECTS - await NotifyEventHelper.ProcessStandardObjectEvents(ayaEvent, proposedObj, ct); - - //SPECIFIC EVENTS FOR THIS OBJECT - - }//end of process notifications - - - ///////////////////////////////////////////////////////////////////// - - }//eoc - - -}//eons - diff --git a/server/AyaNova/models/AyContext.cs b/server/AyaNova/models/AyContext.cs index 6fdea900..eb01ac70 100644 --- a/server/AyaNova/models/AyContext.cs +++ b/server/AyaNova/models/AyContext.cs @@ -54,15 +54,12 @@ namespace AyaNova.Models public virtual DbSet PartAssemblyItem { get; set; } public virtual DbSet PM { get; set; } public virtual DbSet PMItem { get; set; } - public virtual DbSet PMTemplate { get; set; } - public virtual DbSet PMTemplateItem { get; set; } + public virtual DbSet Project { get; set; } public virtual DbSet PurchaseOrder { get; set; } public virtual DbSet PurchaseOrderItem { get; set; } - public virtual DbSet Quote { get; set; } - public virtual DbSet QuoteItem { get; set; } - public virtual DbSet QuoteTemplate { get; set; } - public virtual DbSet QuoteTemplateItem { get; set; } + + public virtual DbSet Unit { get; set; } public virtual DbSet UnitModel { get; set; } public virtual DbSet Vendor { get; set; } @@ -92,9 +89,25 @@ namespace AyaNova.Models public virtual DbSet WorkOrderItemPriority { get; set; } public virtual DbSet WorkOrderItemStatus { get; set; } - //WorkOrderTemplate - public virtual DbSet WorkOrderTemplate { get; set; } - public virtual DbSet WorkOrderTemplateItem { get; set; } + //Quote + public virtual DbSet Quote { get; set; } + public virtual DbSet QuoteItem { get; set; } + public virtual DbSet QuoteState { get; set; } + public virtual DbSet QuoteItemExpense { get; set; } + public virtual DbSet QuoteItemLabor { get; set; } + public virtual DbSet QuoteItemLoan { get; set; } + public virtual DbSet QuoteItemPart { get; set; } + public virtual DbSet QuoteItemScheduledUser { get; set; } + public virtual DbSet QuoteItemTask { get; set; } + public virtual DbSet QuoteItemTravel { get; set; } + public virtual DbSet QuoteItemUnit { get; set; } + public virtual DbSet QuoteItemOutsideService { get; set; } + public virtual DbSet QuoteStatus { get; set; } + public virtual DbSet QuoteItemPriority { get; set; } + public virtual DbSet QuoteItemStatus { get; set; } + + + public virtual DbSet Logo { get; set; } public virtual DbSet Report { get; set; } diff --git a/server/AyaNova/models/PMTemplate.cs b/server/AyaNova/models/PMTemplate.cs deleted file mode 100644 index 44201242..00000000 --- a/server/AyaNova/models/PMTemplate.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class PMTemplate : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public PMTemplate() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.PMTemplate; } - - }//eoc - -}//eons diff --git a/server/AyaNova/models/PMTemplateItem.cs b/server/AyaNova/models/PMTemplateItem.cs deleted file mode 100644 index 37e93523..00000000 --- a/server/AyaNova/models/PMTemplateItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class PMTemplateItem : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public PMTemplateItem() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.PMTemplateItem; } - - }//eoc - -}//eons diff --git a/server/AyaNova/models/Quote.cs b/server/AyaNova/models/Quote.cs index 8b6b648d..fcdb6ad3 100644 --- a/server/AyaNova/models/Quote.cs +++ b/server/AyaNova/models/Quote.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -6,9 +7,7 @@ using AyaNova.Biz; namespace AyaNova.Models { - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - + public class Quote : ICoreBizObjectModel { public long Id { get; set; } @@ -16,37 +15,148 @@ namespace AyaNova.Models [Required] public long Serial { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } + + public string Notes { get; set; }//WAS "SUMMARY" public string Wiki { get; set; } public string CustomFields { get; set; } - public List Tags { get; set; } + public List Tags { get; set; } = new List(); + + [Required] + public long CustomerId { get; set; } + [NotMapped] + public string CustomerViz { get; set; } + + [NotMapped] + public string CustomerTechNotesViz { get; set; } + + public long? ProjectId { get; set; } + [NotMapped] + public string ProjectViz { get; set; } + public string InternalReferenceNumber { get; set; } + public string CustomerReferenceNumber { get; set; } + public string CustomerContactName { get; set; } + + public DateTime CreatedDate { get; set; } = DateTime.UtcNow; + public DateTime? ServiceDate { get; set; } + public DateTime? CompleteByDate { get; set; } + public TimeSpan DurationToCompleted { get; set; } = TimeSpan.Zero; + public string InvoiceNumber { get; set; } + public string CustomerSignature { get; set; } + public string CustomerSignatureName { get; set; } + public DateTime? CustomerSignatureCaptured { get; set; } + public string TechSignature { get; set; } + public string TechSignatureName { get; set; } + public DateTime? TechSignatureCaptured { get; set; } + public bool Onsite { get; set; } + public long? ContractId { get; set; } + [NotMapped] + public string ContractViz { get; set; } + + //redundant field to speed up list queries + //(added after status system already coded) + public long? LastStatusId { get; set; } - //workaround for notification + //POSTAL ADDRESS / "BILLING ADDRESS" + public string PostAddress { get; set; } + public string PostCity { get; set; } + public string PostRegion { get; set; } + public string PostCountry { get; set; } + public string PostCode { get; set; } + + //PHYSICAL ADDRESS / "SERVICE ADDRESS" + public string Address { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string Country { get; set; } + public decimal? Latitude { get; set; } + public decimal? Longitude { get; set; } + + public List Items { get; set; } = new List(); + public List States { get; set; } = new List(); + + + //UTILITY FIELDS + [NotMapped] + public bool IsLockedAtServer { get; set; } = false;//signal to client that it came from the server in a locked state + [NotMapped] + public string AlertViz { get; set; } = null; + [NotMapped] + public string FromQuoteViz { get; set; } + [NotMapped] + public string FromPMViz { get; set; } + [NotMapped] + public string FromCSRViz { get; set; } + + [NotMapped] + public bool IsCompleteRecord { get; set; } = true;//indicates if some items were removed due to user role / type restrictions (i.e. woitems they are not scheduled on) + + [NotMapped] + public bool UserIsRestrictedType { get; set; } + [NotMapped] + public bool UserIsTechRestricted { get; set; } + [NotMapped] + public bool UserIsSubContractorFull { get; set; } + [NotMapped] + public bool UserIsSubContractorRestricted { get; set; } + [NotMapped] + public bool UserCanViewPartCosts { get; set; } + [NotMapped] + public bool UserCanViewLaborOrTravelRateCosts { get; set; } + [NotMapped] + public bool UserCanViewLoanerCosts { get; set; } + + [NotMapped, JsonIgnore] + public AyaType AyaType { get => AyaType.WorkOrder; } + + //workaround for notification [NotMapped, JsonIgnore] public string Name { get; set; } - /* - - todo: Consider adding latitude / longitude to wo, quote, pm objects - can copy over from the unit or customer or set themselves - and can always hide - means wo could be scheduled for ad-hoc locations and serviced that way, i.e. a truck parked on the side of the highway etc - */ - //dependents - public List QuoteItems { get; set; } - - public Quote() - { - Tags = new List(); - QuoteItems = new List(); - } - - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.Quote; } }//eoc }//eons + + +/* +QUOTE FIELDS +CREATE TABLE [dbo].[AWORKORDERQUOTE]( + [AID] [uniqueidentifier] NOT NULL, + [AWORKORDERID] [uniqueidentifier] NOT NULL, + [ACREATOR] [uniqueidentifier] NOT NULL, + [AMODIFIER] [uniqueidentifier] NOT NULL, + [ACREATED] [datetime] NOT NULL, + [AMODIFIED] [datetime] NOT NULL, + [AQUOTENUMBER] [int] IDENTITY(1,1) NOT NULL, + [AQUOTESTATUSTYPE] [smallint] NULL, + [APREPAREDBYID] [uniqueidentifier] NULL, + [AQUOTEREQUESTDATE] [datetime] NULL, + [AINTRODUCTION] [nvarchar](255) NULL, + [AVALIDUNTILDATE] [datetime] NULL, + [ADATESUBMITTED] [datetime] NULL, + [ADATEAPPROVED] [datetime] NULL, +PRIMARY KEY NONCLUSTERED + + + +QUOTE DOESN'T NEED THESE FIELDS + +CREATE TABLE [dbo].[AWORKORDERSERVICE]( + [AID] [uniqueidentifier] NOT NULL, + [AWORKORDERID] [uniqueidentifier] NOT NULL, + [ACREATOR] [uniqueidentifier] NOT NULL, + [AMODIFIER] [uniqueidentifier] NOT NULL, + [ACREATED] [datetime] NOT NULL, + [AMODIFIED] [datetime] NOT NULL, + [AWORKORDERSTATUSID] [uniqueidentifier] NULL,//## Replaced by workorderstate collection + [ASERVICEDATE] [datetime] NULL, + [AINVOICENUMBER] [nvarchar](255) NULL, + [ASERVICENUMBER] [int] IDENTITY(1,1) NOT NULL,//## replaced by Serial field + [AQUOTEWORKORDERID] [uniqueidentifier] NULL, + [ACLIENTREQUESTID] [uniqueidentifier] NULL,//# now FromCSRId + [APREVENTIVEMAINTENANCEID] [uniqueidentifier] NULL, + [ACLOSEBYDATE] [datetime] NULL,//## Now CompleteByDate + [ASIGNATURE] [ntext] NULL,//# now customersignature (more sig types coming) + [ASIGNED] [datetime] NULL,//# now CustomerSignatureCaptured +*/ \ No newline at end of file diff --git a/server/AyaNova/models/QuoteTemplate.cs b/server/AyaNova/models/QuoteTemplate.cs deleted file mode 100644 index 39c866b1..00000000 --- a/server/AyaNova/models/QuoteTemplate.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class QuoteTemplate : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public QuoteTemplate() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.QuoteTemplate; } - - }//eoc - -}//eons diff --git a/server/AyaNova/models/QuoteTemplateItem.cs b/server/AyaNova/models/QuoteTemplateItem.cs deleted file mode 100644 index ef3ec7a8..00000000 --- a/server/AyaNova/models/QuoteTemplateItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class QuoteTemplateItem : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public QuoteTemplateItem() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.QuoteTemplateItem; } - - }//eoc - -}//eons diff --git a/server/AyaNova/models/WorkOrderTemplate.cs b/server/AyaNova/models/WorkOrderTemplate.cs deleted file mode 100644 index df12076c..00000000 --- a/server/AyaNova/models/WorkOrderTemplate.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class WorkOrderTemplate : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public WorkOrderTemplate() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.WorkOrderTemplate; } - - }//eoc - -}//eons diff --git a/server/AyaNova/models/WorkOrderTemplateItem.cs b/server/AyaNova/models/WorkOrderTemplateItem.cs deleted file mode 100644 index cc6ed6de..00000000 --- a/server/AyaNova/models/WorkOrderTemplateItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using AyaNova.Biz; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; - -namespace AyaNova.Models -{ - //NOTE: Any non required field (nullable in DB) sb nullable here, i.e. decimal? not decimal, - //otherwise the server will call it an invalid record if the field isn't sent from client - - public class WorkOrderTemplateItem : ICoreBizObjectModel - { - public long Id { get; set; } - public uint Concurrency { get; set; } - - [Required] - public string Name { get; set; } - public bool Active { get; set; } - public string Notes { get; set; } - public string Wiki { get; set; } - public string CustomFields { get; set; } - public List Tags { get; set; } - - - public WorkOrderTemplateItem() - { - Tags = new List(); - } - - [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.WorkOrderTemplateItem; } - - }//eoc - -}//eons diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index 540d1405..c5a03547 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -896,30 +896,28 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); //---------- - //WORKORDERTEMPLATE - await ExecQueryAsync("CREATE TABLE aworkordertemplate (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - await ExecQueryAsync("ALTER TABLE acustomer ADD column defaultservicetemplateid BIGINT NULL REFERENCES aworkordertemplate"); + - //WORKORDERTEMPLATEITEM - await ExecQueryAsync("CREATE TABLE aworkordertemplateitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); + /* + ██████╗ ██╗ ██╗ ██████╗ ████████╗███████╗ + ██╔═══██╗██║ ██║██╔═══██╗╚══██╔══╝██╔════╝ + ██║ ██║██║ ██║██║ ██║ ██║ █████╗ + ██║▄▄ ██║██║ ██║██║ ██║ ██║ ██╔══╝ + ╚██████╔╝╚██████╔╝╚██████╔╝ ██║ ███████╗ + ╚══▀▀═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ + */ - //QUOTE - await ExecQueryAsync("CREATE TABLE aquote (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, serial BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - //QUOTEITEM - await ExecQueryAsync("CREATE TABLE aquoteitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, quoteid BIGINT NOT NULL REFERENCES aquote (id), name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - //QUOTETEMPLATE - await ExecQueryAsync("CREATE TABLE aquotetemplate (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); + // //QUOTE + // await ExecQueryAsync("CREATE TABLE aquote (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, serial BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, active BOOL NOT NULL, " + // + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); + + // //QUOTEITEM + // await ExecQueryAsync("CREATE TABLE aquoteitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, quoteid BIGINT NOT NULL REFERENCES aquote (id), name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " + // + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); + - //QUOTETEMPLATEITEM - await ExecQueryAsync("CREATE TABLE aquotetemplateitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); //PM await ExecQueryAsync("CREATE TABLE apm (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, serial BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, active BOOL NOT NULL, " @@ -928,15 +926,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); //PMITEM await ExecQueryAsync("CREATE TABLE apmitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, pmid BIGINT NOT NULL REFERENCES apm (id), name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - - //PMTEMPLATE - await ExecQueryAsync("CREATE TABLE apmtemplate (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - - //PMTEMPLATEITEM - await ExecQueryAsync("CREATE TABLE apmtemplateitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL UNIQUE, active BOOL NOT NULL, " - + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY )"); - + //CUSTOMERSERVICEREQUEST await ExecQueryAsync("CREATE TABLE acustomerservicerequest (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name TEXT NOT NULL, " + "notes TEXT, wiki TEXT, customfields TEXT, tags VARCHAR(255) ARRAY, "