341 lines
22 KiB
Plaintext
341 lines
22 KiB
Plaintext
WORKORDER
|
|
|
|
Workorder form fleshed out in case https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3850
|
|
Submitting entire wo or just parts at a time??
|
|
If each part has it's own concurrency then can submit whole and bits that aren't different would have same concurrency so no issues
|
|
test this idea
|
|
|
|
|
|
CONCURRENCY decision / research - updating, in bits seperately, entirely at once? [## DECIDED, BITS MAKES MOST SENSE AND DIRTY TRACKING AT CLIENT ##]
|
|
Considering we are looking at a system where some users won't see or even get the data for some parts of the workorder then it's important that they be able to just save their piece of it separately
|
|
So this strongly leans towards seperately saved and not entirely at all.
|
|
concurrency issue reduction
|
|
Things that might require an entire workorder graph be updated at once:
|
|
Major header changes?
|
|
Customer, Contract because pricing and policies might change?
|
|
|
|
Anything that affects balances and totals (are there new features happening showing dollar amounts billable right on workorder?)
|
|
in v7 not an issue because need to preview report to see totals
|
|
in v8 some talk of seeing totals, so need to determine if that's still a thing, if not then this whole class of concurrency issues dissappears
|
|
This would be entirely resolved with a "view" showing a type of "invoice" summary kind of thing where you open that tab and it fetches and calcs and displays
|
|
however this would be little difference from a report and a little worse because the end user can't edit it to calculate how they would like it to so...
|
|
|
|
ENTIRE GRAPH AFFECTING CHANGES
|
|
One idea to support this is if a change is made at header that affects all children then change their concurrency values so updates will fail
|
|
This is a good idea, need a clean way to support it but this makes sense
|
|
|
|
Dirty tracking at every level and object would save having to send entire workorder, just dirty bits
|
|
i.e. have non-mapped dirty fields for every woitemrecord
|
|
client uses them to track changes and what needs to be saved
|
|
upon save client goes through graph looking for dirty records and saves them each but is senstive to the best order to do it and takes into account if save would lock or unlock
|
|
Header fields - dirty
|
|
a woitem - dirty?
|
|
awoitemlabor - dirty?
|
|
If something is changed that affects entire graph then that can be checked for at the client and trigger a full save regardless
|
|
WorkorderStatus change would always be the first thing saved as it might be required to UNLOCK the workorder
|
|
Client needs entire status list cached on hand to know if a status change affects lock status and if it's going from unlocked to locked then it would need to save the entire workorder graph and let the server handle it
|
|
or save bottom up before locking with the status / header change
|
|
Actually isn't this just handled at the server as a biz rule? (no because if header saved first then it's locked potentially and sub items can't be save subsequently in a graph walking save)
|
|
New items are always dirty so a new labor record added would be dirty and saved individually
|
|
At the server upon item being saved there would always need to be a quick check of the entire workorder to see if it's LOCKED status or not
|
|
if locked then bumps back with error that wo is now locked (of course they could just change the status in the header and resave I guess)
|
|
|
|
|
|
UI stuff
|
|
<!-- grid with edit form below in each collection section. Edit form Has controls to navigate to other collection items so no need to go up and click on table if don't want to or it's huge -->
|
|
<!-- Want to support the case that when it's a single woitem workorder then user can just scroll down and enter shit and doesn't need to open or go anywhere to enter things all the way down
|
|
so a single workorderitem workorder would have all fields exposed and if any grandchildren those are entered in a single form too until the user has more than one
|
|
|
|
in v7 it's three clicks to go to a grandchild items specific field from the top header, woitem click -> left nav button row selection of area click -> grid row column click
|
|
in v8 it would be one more click then if it was a multi record grandchild but if it was a single record all the way down then all would be exposed and visible at hand could go directly to the field in question
|
|
so in this concept every level exposes an edit form below a grid of one or more items, but grid doesn't show if there is one item so it's very clean.
|
|
if there is no record at that collection then just a click to add button as unobtrusive but clearly marked as possible (if user has selected to hide that section then doesn't even show and some users don't see at all)
|
|
if multiple at that level then a grid to select the active row to edit below it showing as much data as possible in each row to help user see at a glance while editing a sibling item
|
|
When select in grid it highlights that row very well so that user knows for sure which row they are editing (plus it will live update I bet so clear to see)
|
|
This gives the user as much as possible at hand immediately to view and edit and the option of adding and selecting more items
|
|
It also ensures a clean interface more like a piece of paper with only stuff added showing
|
|
|
|
So every level and collection including woitem and down is shown as a control with 4 major states (may have sub states or alternates):
|
|
HIDDEN, EMPTY, SINGLE, MULTIPLE
|
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
Customized to not show at all or not allowed: is just not visible at all, doesn't render doesn't affect anything
|
|
None entered: it's exposed as a clean and not too intrusive "Section title" control affordance with a title so "Scheduled users +" taking up very little vertical space
|
|
but distinct enough and large enough to quickly find visually on the page (this is always visible)
|
|
1 entered: it's exposed as a edit form below the Title control (no grid)
|
|
More than 1 entered: it's exposed as a grid below the title control which is used to select a row and an edit form below the grid that is displayed ONLY when a row is selected in the grid
|
|
so if they just open the form and haven't picked a row yet then no edit form shows to save vertical space and be cleaner
|
|
|
|
Visually each section is separated by a distinctive title and whitespace around it, no lines or boxes or other ugly shit. It should look as much as possible like a clean sheet of paper and be minimalist.
|
|
Roles and rights
|
|
some controls may have an alternative format for differing roles and rights users, so if it's a subcontractor then they may see an alternate view
|
|
|
|
|
|
e.g.
|
|
# single all the way down:
|
|
WOHEADER
|
|
singlewoitem record form with all fields showing for edit here
|
|
schedusers is just an add button until there is one then it's an exposed form until there's two then it's a grid only with click to open and edit each record
|
|
|
|
# two all the way down
|
|
WOHEADER
|
|
woitemgrid, click to select second item (first automatically selected when opened?), after click it shows immediately below the woitemheader fields and below that the grandchild collections as grids or add button or whole form if one
|
|
schedusers shows as a grid, click on it to open the form below it, not popup??
|
|
Showing the form below the grid of all the other items is actually a handy affordance because you can see what was entered and refer to it in the companion same group items
|
|
so if you forgot if you entered a particular user or not in the midst of entry you can see it just above
|
|
|
|
|
|
|
|
|
|
|
|
USAGE NOTES:
|
|
v-if should always be as high up as possible for performance, so don't let a component decide to render, make the parent do the v-if!!
|
|
e.g. don't let a GzWoItemParts component check if it should display, instead do it in here
|
|
-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########### PLANNING BELOW HERE, OUTDATED NOW ########################################
|
|
Lot's to go in here but for now this is holding my planning and thoughts until can set in stone:
|
|
|
|
|
|
## Copied over from client todo while testing / planning, probably outdated if you're reading this after May 2020
|
|
|
|
todo: PLANNING WORKORDER considerations:
|
|
QUESTIONS:
|
|
Why do I need to make a wo first before I can update it? (i.e. why did I make a CREATE route?)
|
|
still no idea after lot's of planning, answer is probably not needed at all
|
|
|
|
How can I avoid concurrency issues?
|
|
concurrency check each record in graph, not entire workorder from top
|
|
|
|
How to minimize data sent, make fast saves?
|
|
I'm leaning towards the tons of routes option, need to test it out
|
|
|
|
PATCH, send all changes in graph in one go
|
|
most efficient, sends all changes in one go
|
|
if any part fails it all fails
|
|
requires second copy of wo for diffing
|
|
UPDATE (PATCH): Send only changes in whole graph from client with an OP (for "operation") flag at each level indicating to change that part or not, a flag?
|
|
WO (OP flag=no change, no concurrency token, basically empty but for the fields that hold the descendants that are changed)
|
|
woitem 0 (OP flag="Delete" and concurrency token, no other data with it, just the id and flag and ctoken)
|
|
woitem 1 (OP flag ="update", all fields as in a "put" operation, nothing left out, assumed all are changed)
|
|
woitem2 (OP flag="no OP", just a placeholder for children with changes)
|
|
labor 2 (OP flag = "update" with all data)
|
|
labor 3 (OP flag="delete" with concurrency token and nothing else)
|
|
labor 4 (OP flag="Add", with all PUT data)
|
|
issues with patch:
|
|
how to post a whole object leaving blank when so many fields will be required?
|
|
maybe we don't make them required at the object field annotation level but only at the db level and as a biz rule?
|
|
how to synchronize objects and id's?
|
|
i.e. reverse patch back again
|
|
for example, you add two woitems, save, you have two now that are not id'd and don't know which is which
|
|
server has to return something identifying which is which and assigned ID, plus it might add data back or change data due to rules or whatever
|
|
Maybe server sends back entire saved objects?
|
|
issues:
|
|
how to update client end with update back from server when saved (server will add id and may change fields or even add things)
|
|
|
|
* TONS OF ROUTES: Update individual portions as seperate objects to their own routes sequentially
|
|
i.e. client traverses and diffs virgin copy and edited copy of wo
|
|
determines what's different, only sends an update for each object to it's own route as appropriate
|
|
on successful update fixes up the edited copy of that object
|
|
on all updates done, the edited copy becomes the virgin copy (or do we need 3 objects at one point in case of fail?)
|
|
|
|
requires second copy of wo for diffing
|
|
goes over workorder, looks for changes, sends update for each object individually and patches up local from result
|
|
so if a workorderitempart has changed then it sends only that for update individually
|
|
Example routes:
|
|
Post: Workorder/1/WorkOrderItem/2/Labor/4 {updated object}
|
|
WorkOrder/{woid} <-entire workorder, get for all, post for entire, put to update entire (not likely to use but?)
|
|
WorkOrder/{woid}/WorkOrderItems <- all workorderitems, post to add new, put to update all as a collection
|
|
WorkOrder/{woid}/WorkOrderItems/{woitemid} <- CRUD single woitemid
|
|
WorkOrder/{woid}/WorkOrderItems/{woitemid}/Labors <- entire labor collection CRUD ops over all collection (also ADD new labor here (POST))
|
|
WorkOrder/{woid}/WorkOrderItems/{woitemid}/Labors/{laborid} <- Crud on individual item
|
|
|
|
This way is pretty solid, will result in a lot of routes but a lot of the code can be shared in the biz object, so for example if updating a labor or a collection of labor most code the same
|
|
Efficiency:
|
|
Since there is a route for every bit of the workorder the client can pick how high up to update based on diff check
|
|
so if only one single bit of a header has changed then only update that bit (or will it need the collection to not remove it? No because collection route is where you remove an item)
|
|
or if only a deeply nested labor has changed, just PUTS it to that exact route and udpates concurrency token on result
|
|
since the workorder is not really influenced as a whole by updates to portions this could work and be a bit less problematic than JSONPATCH which really seems to be a bit of a stretch
|
|
|
|
|
|
NOTE: can put part of the route in the controller, so for example if every route in that controller needs to identify a workorder then this kind of thing is possible, not sure if helpful or not yet:
|
|
[Route("api/campus/{campusId:int}/building")]
|
|
public class BuildingController : Controller {
|
|
//...
|
|
|
|
[HttpGet]
|
|
[Route("{buildingId:int}")] // Matches GET api/campus/123/building/456
|
|
public IActionResult GetBuilding ([FromRoute]int campusId, [FromRoute]int buildingId) {
|
|
//... validate campus id along with building id
|
|
}
|
|
}
|
|
|
|
issues:
|
|
very chatty, could be slow
|
|
|
|
PUT, update entire workorder on every save
|
|
Very easy to code, basically send it all and see what happens
|
|
Very clean, no need to worry about bits and pieces being tracked etc
|
|
issues:
|
|
not very efficient, needs to send entire graph on every save even if user just changed one character
|
|
|
|
|
|
How to support undo?
|
|
How to show what's dirty on form?
|
|
|
|
|
|
|
|
BUSINESS RULES (v7)
|
|
In reality there are almost no business rules in v7 workorder graph.
|
|
Only serious one is woitempart requires serial if serialized
|
|
Rest are all related to length of fields, required fields, date order etc and only a few of those to boot
|
|
Looks like this is not an issue regarding v7 stuff at all
|
|
|
|
|
|
DEPENDENCIES
|
|
Workorder is not dependent on it's children for anything
|
|
WoItem is not dependent on any of it's children
|
|
In fact nothing in any part of the wo is dependent on anything else during normal ops
|
|
|
|
CONCURRENCY
|
|
If the client updates part of the wo graph, only that exact record really needs dependency checking.
|
|
There *is* however business rules that might take hold but that's all at the server and not related to concurrency directly
|
|
For example, on any change to the wo graph the server has to see if the wo is still editable and hasn't been locked or user's rights changed
|
|
But that's not strictly concurrency related in the sense that another user change the *same* record being updated
|
|
So, for v8 as long as it can handle a portional update to part of the graph and uses the concurrency of that exact record to check then it sidesteps a lot of multi-user scenarios
|
|
This was only an issue in v7 due to it using only the wo header itself as the source of concurrency checking which would *always* involve the whole graph in any change anywhere
|
|
|
|
for example:
|
|
WOHEADER (concurrency id, dirty flag at client)
|
|
WOITEM (concurrency id, dirty flag at client)
|
|
woitempart (concurrencyid dirty flag at client)
|
|
woitemlabor (concurrencyid, dirty flag at client)
|
|
WOITEM (concurrency id, dirty flag at client)
|
|
woitemscheduser (own concurrency, dirty flag etc)
|
|
woitempart (concurrencyid dirty flag at client)
|
|
woitemlabor (concurrencyid, dirty flag at client)
|
|
|
|
ROUTES
|
|
In light of dependencies and concurrency it is ideal if the server can handle updates to any portion of the graph independently
|
|
But, do we really want CRUD routes for every descendant of the workorder graph? (maybe, just not sure)
|
|
|
|
|
|
|
|
TEST
|
|
Do a practical test of a mocked wo, woitem, woitemlabor or whatever, see how it would be updated, fetched concurrency checking etc
|
|
QUESTIONS:
|
|
How to do CRUD efficiently with a workorder and client?
|
|
|
|
|
|
PROPOSAL TO TEST:
|
|
Create enough of a graph to test, 3 layers two grandhild collections should be sufficient:
|
|
WO
|
|
WOITEMS
|
|
WOITEMLABORS
|
|
WOITEMPARTS
|
|
|
|
CREATE (POST):
|
|
CreateFromxxxx routes (NO TEST REQUIRED)
|
|
POST accepts NEW workorder full graph (test)
|
|
RETRIEVE (GET):
|
|
Get(id) - simple get, just confirm entire graph comes across
|
|
GetByRelative(ayatype, id) (no test required)
|
|
|
|
UPDATE (PUT?)
|
|
Test code tons of routes method detailed above
|
|
|
|
SERVER
|
|
Server accepts graph at single WO POST route (since it's not a put)
|
|
UI
|
|
ui manufactures the return object with the OP fields by doing dirty tracking on changes
|
|
DELETE
|
|
Not much here except handling delete will be more intensive and sophisticated when have real data but for now if the graph deletes then that's enough
|
|
Test how to delete graph without ref. integrity errors
|
|
|
|
|
|
UI
|
|
Only send the bits that are altered to save bandwidth
|
|
All updates are technically a PATCH operation
|
|
Because it starts with a wo object provided by the server?
|
|
or is this even necessary now?
|
|
think Patch
|
|
CONCURRENCY:
|
|
if any part of the patch fails the whole patch fails
|
|
|
|
idea: UI reflects tentativeness state of object:
|
|
The UI doesn't imply something is done by changing it fully until the save is completed.
|
|
This serves two purposes:
|
|
1) user knows at a glance what isn't saved yet and will know it's waiting for save clearly, hopefully leading them to save more often,
|
|
2) client doesn't need to track invisible shit behind the scenes, can more easily do patch updates right off UI source
|
|
|
|
e.g.:
|
|
if deleted a row in parts, that row doesn't disappear but rather shows crossed out, maybe grayed out but still there until save to indicate it's tentative status
|
|
if added a row, shows green or something or bold or asterisk, (can style with css based on state) until saved
|
|
problems:
|
|
how to handle regular fields that are changed (that's a lot of field data to track for changes)?
|
|
Maybe client keeps a virgin copy of the original wo for comparison
|
|
periodically does a compare and flags differences on updates?
|
|
(this would also help to serve as an Undo maybe?)
|
|
|
|
|
|
|
|
A biz object for each one?
|
|
probably need the parent for biz rules and shit so likely best to keep in one file
|
|
Controller - all in root controller or seperate controllers?
|
|
likely follows biz object decision
|
|
case 1714 re-rises the question about concurrency and mutiple editors of a workorder
|
|
Look into how independent changes can be from each other, i.e. is it safe to have two users editing two different woitems on a workorder?
|
|
This might make people happier.
|
|
Like, what exactly affects what else on a workorder. Do you save the whole wo to the route at once even though you just added a woitem or..?
|
|
If I code it to send the whole wo on a change to even a grandchild then that's heavy traffic for a minor change
|
|
- actually no, it's not really that heavy, even a fairly fat workorder will be way under 100kb, most probably under 1kb
|
|
should really only send the minimum data required to fulfil the change.
|
|
Maybe need two copies of wo at client so can tell what has changed and then only send that bit.
|
|
But then need routes to handle that?
|
|
Or can the wo route just accept a blank header with items hanging off it that have changed only? (like a patch?)
|
|
|
|
Use foreign keys!!
|
|
Consider UI in this as well, will need to decide at least what is visible when
|
|
Workorder UI good ideas here: https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3475
|
|
How to add items, like new woitem?
|
|
send to server get back new object?
|
|
lots of biz rules and stuff need to happen, want to minimize load at client
|
|
but lots of data back and forth is not ideal
|
|
maybe request a woitem and get it back?
|
|
what exactly needs to be processed in the wo when items are added / removed?
|
|
math / totalling?
|
|
simple calcs sb client doable
|
|
this will drive what has to happen.
|
|
Need to go over all wo features and factor them into this decision properly
|
|
The whole idea of a completed section of a wo and stuff, is that dropped due to TTM or still viable?
|
|
maybe can pick out the best new features of that which can be integrated into existing design rather than re-inventing the wheel
|
|
Here is an overview: https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3412
|
|
How best to be able to service LoanUnits on a workorder?
|
|
Just make them Units with extra properties exposed if type of loaner?
|
|
This seems simplest, but what will it effect?
|
|
Hard to make them serviceable if they are an alternate table of source for what's being repaired as that breaks a lot of other code or adds exceptions
|
|
Customer is then who exactly because it's fundamental to a lot of wo functionality?
|
|
from a biz perspective isn't it like you are your own customer when you service your own equipment that you loan out?
|
|
Does Serial field need to be numeric, could it be text instead?
|
|
prompted by case 3428 saying that it's hard to deal with constant conversion to text for UI etc
|
|
plus, I'm thinking it opens door to textual scheme like appending -A or whatever to a wo.
|
|
or, is that a display issue?
|
|
Calling something "serial" implies it's unique but it isn't, maybe I should call it "number" instead or "ID" or something?
|
|
INFO: did a test workorder with ALL fields filled out heavily and one woitem, exported from db entire graph based on detailed report so every line was every item repeated
|
|
still only 84kb and it's a lot bigger than any typical wo in v8 would be as it will be far more efficient without having to repeat lines flatly
|
|
so I think size of object is a non-issue really from a practical standpoint.
|
|
|
|
|