This commit is contained in:
2022-03-28 23:11:09 +00:00
parent 4c6e8102c4
commit 83a3ad689c
3 changed files with 197 additions and 15 deletions

View File

@@ -0,0 +1,109 @@
# Task group import / update specifications
Names of fields listed here are the exact case and spelling required to be recognized by AyaNova for [importing / updating](adm-import.md).
Any field in the import file that is not listed on this page will be removed before sending to the server for import.
## Required fields
- Name
## Key field used to match to existing records
- Name
## Fields directly importable / updateable
- Name (import only)
- Active
- Notes
- Items
## JSON file format
The .json file must contain an array of one or more Task group objects.
```JSON
[
{
"Name": "Aerostat monitor standard refurb",
"Active": true,
"Notes": "Alias maxime deserunt corrupti voluptatem a voluptatem eligendi.",
"Items": [
{
"Sequence": 1,
"Task": "Power down unit"
},
{
"Sequence": 2,
"Task": "Open seals"
},
{
"Sequence": 3,
"Task": "Replace central core"
},
{
"Sequence": 4,
"Task": "Test point B and verify +.25"
},
{
"Sequence": 5,
"Task": "Replace seals"
},
{
"Sequence": 6,
"Task": "Confirm power up"
}
]
},
{
"Name": "Clean and inspect Class 7C",
"Active": true,
"Notes": "Facilis omnis dolor tempora dolores suscipit maxime ut et eum aperiam dolor.",
"Items": [
{
"Sequence": 1,
"Task": "Open unit"
},
{
"Sequence": 2,
"Task": "Test tinclavic seals"
},
{
"Task": "Inspect triple-bonded polysium for cracks"
},
{
"Sequence": 4,
"Task": "Verify thickness of zybanium shield"
},
{
"Sequence": 5,
"Task": "Close unit"
},
{
"Sequence": 6,
"Task": "Clean unit and confirm power up"
}
]
}
]
```
## CSV file format
The first row of the .csv file must contain column headers that match the field names listed above.
CSV doesn't cleanly map on to structured elements with sub collections well so the Items column here which contains the Tasks for this Task group has a special format we've adopted:
The Items column **must** be:
- surrounded in double "quotes"
- contain the Tasks separated by commas
- each Task text must _not_ have a comma or a quotation mark in it or the csv will not be valid
- Sequence numbers are not importable from csv but will be automatically assigned in the order presented so the first item will be sequence 1, second sequence 2 etc
```
Name,Active,Notes,Items
Aerostat monitor standard refurb,true,Alias maxime deserunt corrupti voluptatem a voluptatem eligendi.,"Power down unit, Open seals, Replace central core, Test point B and verify +.25"
Clean and inspect Class 7C,true,Facilis omnis dolor tempora dolores suscipit maxime ut et eum aperiam dolor.,"Open unit, Test tinclavic seals, Inspect triple-bonded polysium for cracks, Verify thickness of zybanium shield,Close unit, Clean unit and confirm power up"
```

View File

@@ -175,6 +175,7 @@ Each object type listed below links to a page showing the specific format requir
- ##### [Part warhouses](adm-import-part-warehouse.md)
- ##### [Projects](adm-import-projects.md)
- ##### [Service rates](adm-import-service-rate.md)
- ##### [Task group](adm-import-task-group.md)
- ##### [Travel rates](adm-import-travel-rate.md)
## Import form

View File

@@ -298,7 +298,7 @@ namespace AyaNova.Biz
var batchResults = await ct.TaskGroup.AsNoTracking().Include(z => z.Items).Where(z => batch.Contains(z.Id)).ToArrayAsync();
//order the results back into original
var orderedList = from id in batch join z in batchResults on id equals z.Id select z;
batchResults=null;
batchResults = null;
foreach (TaskGroup w in orderedList)
{
if (!ReportRenderManager.KeepGoing(jobId)) return null;
@@ -307,7 +307,7 @@ namespace AyaNova.Biz
jo["CustomFields"] = JObject.Parse((string)jo["CustomFields"]);
ReportData.Add(jo);
}
orderedList=null;
orderedList = null;
}
return ReportData;
}
@@ -325,35 +325,107 @@ namespace AyaNova.Biz
return await GetReportData(dataListSelectedRequest, jobId);
}
public async Task<List<string>> ImportData(AyImportData importData)
{
List<string> ImportResult = new List<string>();
string ImportTag = $"imported-{FileUtil.GetSafeDateFileName()}";
List<string> ImportResult = new List<string>();
string ImportTag = ImportUtil.GetImportTag();
//ignore these fields
var jsset = JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = new AyaNova.Util.JsonUtil.ShouldSerializeContractResolver(new string[] { "Concurrency", "Id", "CustomFields" }) });
foreach (JObject j in importData.Data)
{
var w = j.ToObject<TaskGroup>(jsset);
// if (j["CustomFields"] != null)
// w.CustomFields = j["CustomFields"].ToString();
// w.Tags.Add(ImportTag);//so user can find them all and revert later if necessary
var res = await CreateAsync(w);
if (res == null)
try
{
ImportResult.Add($"* {w.Name} - {this.GetErrorsAsString()}");
this.ClearErrors();
//Compile Items collection if specified
var ImportTaskGroupItems = new List<TaskGroupItem>();
if (j["Items"] != null)
{
//hydrate from collection
foreach (JToken t in j["Items"])
{
ImportTaskGroupItems.Add(new TaskGroupItem() { TaskGroupId = 0, Sequence = (int)t["Sequence"], Task = (string)t["Task"] });
}
j["Items"] = null;//strip it out so it doesn't get automatically converted into parsed object later
}
long existingId = await ct.TaskGroup.AsNoTracking().Where(z => z.Name == (string)j["Name"]).Select(x => x.Id).FirstOrDefaultAsync();
if (existingId == 0)
{
if (importData.DoImport)
{
//import this record
var Target = j.ToObject<TaskGroup>(jsset);
if (Target.Items == null)
Target.Items = new List<TaskGroupItem>();
if (j["Items"] != null)
foreach (TaskGroupItem tgi in ImportTaskGroupItems)
Target.Items.Add(tgi);
var res = await CreateAsync(Target);
if (res == null)
{
ImportResult.Add($"❌ {Target.Name}\r\n{this.GetErrorsAsString()}");
this.ClearErrors();
}
else
{
ImportResult.Add($"✔️ {Target.Name}");
}
}
}
else
{
if (importData.DoUpdate)
{
//update this record with any data provided
//load existing record
var Target = await GetAsync((long)existingId);
var Source = j.ToObject<TaskGroup>(jsset);
var propertiesToUpdate = j.Properties().Select(p => p.Name).ToList();
propertiesToUpdate.Remove("Name");
propertiesToUpdate.Remove("Items");
ImportUtil.Update(Source, Target, propertiesToUpdate);
if (j["Items"] != null)
{
Target.Items.Clear();
foreach (TaskGroupItem tgi in ImportTaskGroupItems)
Target.Items.Add(tgi);
}
var res = await PutAsync(Target);
if (res == null)
{
ImportResult.Add($"❌ {Target.Name} - {this.GetErrorsAsString()}");
this.ClearErrors();
}
else
{
ImportResult.Add($"✔️ {Target.Name}");
}
}
}
}
else
catch (Exception ex)
{
ImportResult.Add($"{w.Name} - ok");
ImportResult.Add($"❌ Exception processing import\n record:{j.ToString()}\nError:{ex.Message}\nSource:{ex.Source}\nStack:{ex.StackTrace.ToString()}");
}
}
return ImportResult;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//JOB / OPERATIONS
//