diff --git a/server/AyaNova/Controllers/WorkOrderController.cs b/server/AyaNova/Controllers/WorkOrderController.cs
index 75089ffa..df8bda2f 100644
--- a/server/AyaNova/Controllers/WorkOrderController.cs
+++ b/server/AyaNova/Controllers/WorkOrderController.cs
@@ -115,59 +115,19 @@ namespace AyaNova.Api.Controllers
- ///
- /// Patch (update) WorkOrder
- ///
- ///
- ///
- ///
- ///
- [HttpPatch("{id}/{concurrencyToken}")]
- public async Task PatchWorkOrder([FromRoute] long id, [FromRoute] uint concurrencyToken, [FromBody]JsonPatchDocument objectPatch)
- {
- //https://dotnetcoretutorials.com/2017/11/29/json-patch-asp-net-core/
- 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
- WorkOrderBiz biz = WorkOrderBiz.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
- {
- //patch and validate
- if (!await biz.PatchAsync(o, objectPatch, concurrencyToken))
- 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 { ConcurrencyToken = o.ConcurrencyToken }, true));
- }
///
/// Post WorkOrder
///
- ///
+ ///
+ ///
+ /// force a workorder number, leave null to autogenerate the next one in sequence (mostly used for import)
/// Automatically filled from route path, no need to specify in body
- ///
- [HttpPost]
- public async Task PostWorkOrder([FromBody] WorkOrder inObj, ApiVersion apiVersion)
+ /// A created workorder ready to fill out
+ [HttpPost("Create")]
+ public async Task PostWorkOrder([FromQuery] long? workorderTemplateId, long? customerId, uint? serial, ApiVersion apiVersion)
{
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
@@ -183,7 +143,7 @@ namespace AyaNova.Api.Controllers
return BadRequest(new ApiErrorResponse(ModelState));
//Create and validate
- WorkOrder o = await biz.CreateAsync(inObj);
+ WorkOrder o = await biz.CreateAsync(workorderTemplateId,customerId, serial);
if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors));
else
diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs
index b775fe31..e8974563 100644
--- a/server/AyaNova/biz/WorkOrderBiz.cs
+++ b/server/AyaNova/biz/WorkOrderBiz.cs
@@ -60,28 +60,34 @@ namespace AyaNova.Biz
//CREATE
//Called from route and also seeder
- internal async Task CreateAsync(WorkOrder inObj)
+ internal async Task CreateAsync(long? workorderTemplateId, long? customerId, uint? serial)
{
- await ValidateAsync(inObj, null);
- if (HasErrors)
- return null;
- else
- {
- //do stuff with WorkOrder
- WorkOrder outObj = inObj;
+ //Create and save to db a new workorder and return it
+ //By default it should generate a unique id as the "name" field
+ //but need to support export to v8 plugin so need to be able to accept name already
- outObj.Tags = TagUtil.NormalizeTags(outObj.Tags);
- outObj.CustomFields = JsonUtil.CompactJson(outObj.CustomFields);
- //Save to db
- await ct.WorkOrder.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 TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null);
+ // await ValidateAsync(inObj, null);
+ // if (HasErrors)
+ // return null;
+ // else
+ // {
+ //do stuff with WorkOrder
+ WorkOrder outObj = new WorkOrder();
+ outObj.Serial = serial ?? ServerBootConfig.WORKORDER_SERIAL.GetNext();
- return outObj;
- }
+
+ outObj.Tags = TagUtil.NormalizeTags(outObj.Tags);
+ outObj.CustomFields = JsonUtil.CompactJson(outObj.CustomFields);
+ //Save to db
+ await ct.WorkOrder.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 TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null);
+
+ return outObj;
+ //}
}
@@ -93,7 +99,7 @@ namespace AyaNova.Biz
internal async Task DuplicateAsync(WorkOrder dbObj)
{
-
+ throw new System.NotImplementedException("STUB: WORKORDER DUPLICATE");
WorkOrder outObj = new WorkOrder();
CopyObject.Copy(dbObj, outObj, "Wiki");
// outObj.Name = Util.StringUtil.NameUniquify(outObj.Name, 255);
@@ -131,7 +137,7 @@ namespace AyaNova.Biz
//put
internal async Task PutAsync(WorkOrder dbObj, WorkOrder inObj)
{
-
+ throw new System.NotImplementedException("STUB: WORKORDER PUT");
//make a snapshot of the original for validation but update the original to preserve workflow
WorkOrder SnapshotOfOriginalDBObj = new WorkOrder();
CopyObject.Copy(dbObj, SnapshotOfOriginalDBObj);
@@ -159,35 +165,6 @@ namespace AyaNova.Biz
return true;
}
- //patch
- internal async Task PatchAsync(WorkOrder dbObj, JsonPatchDocument objectPatch, uint concurrencyToken)
- {
- //Validate Patch is allowed
- if (!ValidateJsonPatch.Validate(this, objectPatch)) return false;
-
- //make a snapshot of the original for validation but update the original to preserve workflow
- WorkOrder SnapshotOfOriginalDBObj = new WorkOrder();
- CopyObject.Copy(dbObj, SnapshotOfOriginalDBObj);
-
- //Do the patching
- objectPatch.ApplyTo(dbObj);
-
- dbObj.Tags = TagUtil.NormalizeTags(dbObj.Tags);
- dbObj.CustomFields = JsonUtil.CompactJson(dbObj.CustomFields);
-
- ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = concurrencyToken;
- await ValidateAsync(dbObj, SnapshotOfOriginalDBObj);
- if (HasErrors)
- return false;
-
- //Log event and save context
- await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct);
- await SearchIndexAsync(dbObj, false);
-
- await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, dbObj.Tags, SnapshotOfOriginalDBObj.Tags);
-
- return true;
- }
private async Task SearchIndexAsync(WorkOrder obj, bool isNew)
@@ -216,6 +193,7 @@ namespace AyaNova.Biz
//
internal async Task DeleteAsync(WorkOrder dbObj)
{
+ throw new System.NotImplementedException("STUB: WORKORDER DELETE");
//Determine if the object can be deleted, do the deletion tentatively
//Probably also in here deal with tags and associated search text etc
diff --git a/server/AyaNova/models/AyContext.cs b/server/AyaNova/models/AyContext.cs
index a2171dfc..fe041a7b 100644
--- a/server/AyaNova/models/AyContext.cs
+++ b/server/AyaNova/models/AyContext.cs
@@ -124,10 +124,10 @@ namespace AyaNova.Models
.HasForeignKey(b => b.UserId)
.OnDelete(DeleteBehavior.NoAction);
- //Workorder
- modelBuilder.Entity()
- .HasOne(p => p.WorkOrder)
- .WithMany(b => b.WorkorderItems);
+ // //Workorder
+ // modelBuilder.Entity()
+ // .HasOne(p => p.WorkOrder)
+ // .WithMany(b => b.WorkorderItems);
//-----------
diff --git a/server/AyaNova/models/WorkOrder.cs b/server/AyaNova/models/WorkOrder.cs
index 0bd74db8..a2e4cd54 100644
--- a/server/AyaNova/models/WorkOrder.cs
+++ b/server/AyaNova/models/WorkOrder.cs
@@ -1,21 +1,20 @@
-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 partial class WorkOrder
{
public long Id { get; set; }
public uint ConcurrencyToken { get; set; }
[Required]
- public string Name { get; set; }
+ public uint Serial { get; set; }
public bool Active { get; set; }
public string Notes { get; set; }
public string Wiki {get;set;}
@@ -30,6 +29,14 @@ namespace AyaNova.Models
Tags = new List();
}
+
+ //Not persisted business properties
+ //NOTE: this could be a common class applied to everything for common biz rule stuff
+ //i.e. specific rights in situations based on rules, like candelete, canedit etc
+ [NotMapped]
+ public bool NonDataBaseExampleColumn { get; set; }//example of how to add a property that is not persisted but is used by both ends dynamically, should come up with a naming scheme so can see them at a glance
+
+
}//eoc
}//eons
diff --git a/server/AyaNova/models/WorkOrderItem.cs b/server/AyaNova/models/WorkOrderItem.cs
index 9a2b4627..5033810e 100644
--- a/server/AyaNova/models/WorkOrderItem.cs
+++ b/server/AyaNova/models/WorkOrderItem.cs
@@ -1,7 +1,6 @@
-using System;
using System.Collections.Generic;
-using AyaNova.Biz;
using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
namespace AyaNova.Models
@@ -23,6 +22,7 @@ namespace AyaNova.Models
public List Tags { get; set; }
//Principle
+ [Required]//this required annotation should cause a cascade delete to happen automatically when wo is deleted, need to test that
public int WorkorderId { get; set; }//fk
public WorkOrder WorkOrder { get; set; }
@@ -33,6 +33,12 @@ namespace AyaNova.Models
Tags = new List();
}
+ //Not persisted business properties
+ //NOTE: this could be a common class applied to everything for common biz rule stuff
+ //i.e. specific rights in situations based on rules, like candelete, canedit etc
+ [NotMapped]
+ public bool NonDataBaseExampleColumn { get; set; }//example of how to add a property that is not persisted but is used by both ends dynamically, should come up with a naming scheme so can see them at a glance
+
}//eoc
}//eons
diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs
index 22bc8b77..f0debf26 100644
--- a/server/AyaNova/util/AySchema.cs
+++ b/server/AyaNova/util/AySchema.cs
@@ -383,13 +383,13 @@ namespace AyaNova.Util
await ExecQueryAsync("CREATE INDEX avendor_tags ON avendor using GIN(tags)");
//WORKORDER
- await ExecQueryAsync("CREATE TABLE aworkorder (id BIGSERIAL PRIMARY KEY, name varchar(255) not null unique, active bool, " +
+ await ExecQueryAsync("CREATE TABLE aworkorder (id BIGSERIAL PRIMARY KEY, serial bigint not null, active bool, " +
"notes text NULL, wiki text null, customfields text NULL, tags varchar(255) ARRAY NULL)");
- await ExecQueryAsync("CREATE UNIQUE INDEX aworkorder_name_id_idx ON aworkorder (id, name);");
+ await ExecQueryAsync("CREATE INDEX aworkorder_number_id_idx ON aworkorder (id, serial);");
await ExecQueryAsync("CREATE INDEX aworkorder_tags ON aworkorder using GIN(tags)");
//WORKORDERITEM
- await ExecQueryAsync("CREATE TABLE aworkorderitem (id BIGSERIAL PRIMARY KEY, name varchar(255) not null unique, active bool, " +
+ await ExecQueryAsync("CREATE TABLE aworkorderitem (id BIGSERIAL PRIMARY KEY, workorderid bigint not null REFERENCES aworkorder (id), name varchar(255) not null unique, active bool, " +
"notes text NULL, wiki text null, customfields text NULL, tags varchar(255) ARRAY NULL)");
await ExecQueryAsync("CREATE UNIQUE INDEX aworkorderitem_name_id_idx ON aworkorderitem (id, name);");
await ExecQueryAsync("CREATE INDEX aworkorderitem_tags ON aworkorderitem using GIN(tags)");
diff --git a/server/AyaNova/util/ServerBootConfig.cs b/server/AyaNova/util/ServerBootConfig.cs
index 4b735cff..209f966b 100644
--- a/server/AyaNova/util/ServerBootConfig.cs
+++ b/server/AyaNova/util/ServerBootConfig.cs
@@ -15,9 +15,9 @@ namespace AyaNova.Util
//AUTOID's
- //Get the highest id number issued previously and start the auto-id at that level
+ //Get the most recent id number issued previously and start the auto-id at that level
internal static AutoId WIDGET_SERIAL { get; set; }
-
+ internal static AutoId WORKORDER_SERIAL { get; set; }
//Diagnostic static values used during development, may not be related to config at all, this is just a convenient class to put them in
#if (DEBUG)
@@ -226,12 +226,22 @@ namespace AyaNova.Util
//query for most recently used serial number
//(note, can't query for highest serial as it can and likely will reset or be changed manually from time to time
// so the algorithm is to keep the most recent sequence going on startup of the server)
- var MostRecentWidget = ct.Widget.AsNoTracking().OrderByDescending(x => x.Id).FirstOrDefault();
- uint MaxWidgetId = 0;
- if (MostRecentWidget != null)
- MaxWidgetId = MostRecentWidget.Serial;
- WIDGET_SERIAL = new AutoId(MaxWidgetId);
+ var serializedObject = ct.Widget.AsNoTracking().OrderByDescending(x => x.Id).FirstOrDefault();
+ WIDGET_SERIAL = new AutoId(serializedObject == null ? 0 : serializedObject.Serial);
+ // var MostRecentWidget = ct.Widget.AsNoTracking().OrderByDescending(x => x.Id).FirstOrDefault();
+ // uint MaxWidgetId = 0;
+ // if (MostRecentWidget != null)
+ // MaxWidgetId = MostRecentWidget.Serial;
+ // WIDGET_SERIAL = new AutoId(MaxWidgetId);
+
+ }
+
+ //Workorder
+ if (WORKORDER_SERIAL == null)
+ {
+ var serializedObject = ct.WorkOrder.AsNoTracking().OrderByDescending(x => x.Id).FirstOrDefault();
+ WORKORDER_SERIAL = new AutoId(serializedObject == null ? 0 : serializedObject.Serial);
}
//OTHER SERIALS HERE IN FUTURE...