From ff686516943a5dbd2d518c05e7b8310bfb2aadfc Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Mon, 28 Mar 2022 21:29:08 +0000 Subject: [PATCH] --- .../ayanova/docs/adm-import-travel-rate.md | 95 +++++++++++++++++++ docs/8.0/ayanova/docs/adm-import.md | 2 + server/AyaNova/biz/TravelRateBiz.cs | 53 ++++++++--- 3 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 docs/8.0/ayanova/docs/adm-import-travel-rate.md diff --git a/docs/8.0/ayanova/docs/adm-import-travel-rate.md b/docs/8.0/ayanova/docs/adm-import-travel-rate.md new file mode 100644 index 00000000..f4257c02 --- /dev/null +++ b/docs/8.0/ayanova/docs/adm-import-travel-rate.md @@ -0,0 +1,95 @@ +# Travel rate 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 +- Wiki +- Tags +- AccountNumber +- Cost +- Charge +- Unit +- ContractOnly + +## JSON file format + +The .json file must contain an array of one or more Travel rate objects. + +```JSON +[ + { + "Name": "On-site service rate", + "Active": true, + "Notes": "Ullam et aliquid reiciendis iure voluptatem minus doloremque doloribus ipsum ut.", + "Wiki": null, + "Tags": [ + "blue", + "brown", + "mauve", + "quince", + "zone6" + ], + "AccountNumber": "55753867", + "Cost": 25.410000000000000000, + "Charge": 39.390000000000000000, + "Unit": "hour", + "ContractOnly": false + }, + { + "Name": "Shop rate", + "Active": true, + "Notes": "Possimus maiores reprehenderit aut tempora in eos dolor.", + "Wiki": null, + "Tags": [ + "blue", + "green", + "silver", + "zone0" + ], + "AccountNumber": "71071010", + "Cost": 12.490000000000000000, + "Charge": 19.360000000000000000, + "Unit": "hour", + "ContractOnly": true + }, + { + "Name": "Day rate", + "Active": true, + "Notes": "Dolores quo et ipsum ut.", + "Wiki": null, + "Tags": [ + "silver" + ], + "AccountNumber": "50669139", + "Cost": 300.000000000000000000, + "Charge": 500.000000000000000000, + "Unit": "day", + "ContractOnly": false + } +] +``` + +## CSV file format + +The first row of the .csv file must contain column headers that match the field names listed above. + +``` +Name,Active,Notes,Wiki,Tags,AccountNumber,Cost,Charge,Unit,ContractOnly +On-site service rate,true,Ullam et aliquid reiciendis iure voluptatem minus doloremque doloribus ipsum ut.,,"blue,brown,mauve,quince,zone6",55753867,25.41,39.39,hour,false +Shop rate,true,Possimus maiores reprehenderit aut tempora in eos dolor.,,"blue,green,silver,zone0",71071010,12.49,19.36,hour,true +Day rate,true,Dolores quo et ipsum ut.,,silver,50669139,300,500,day,false +``` diff --git a/docs/8.0/ayanova/docs/adm-import.md b/docs/8.0/ayanova/docs/adm-import.md index 9b7c9b13..8875a5dd 100644 --- a/docs/8.0/ayanova/docs/adm-import.md +++ b/docs/8.0/ayanova/docs/adm-import.md @@ -174,6 +174,8 @@ Each object type listed below links to a page showing the specific format requir - ##### [Part assemblies](adm-import-part-assembly.md) - ##### [Part warhouses](adm-import-part-warehouse.md) - ##### [Projects](adm-import-projects.md) +- ##### [Service rates](adm-import-service-rate.md) +- ##### [Travel rates](adm-import-travel-rate.md) ## Import form diff --git a/server/AyaNova/biz/TravelRateBiz.cs b/server/AyaNova/biz/TravelRateBiz.cs index 0822472c..e578b1cc 100644 --- a/server/AyaNova/biz/TravelRateBiz.cs +++ b/server/AyaNova/biz/TravelRateBiz.cs @@ -343,32 +343,59 @@ namespace AyaNova.Biz public async Task> ImportData(AyImportData importData) { List ImportResult = new List(); - string ImportTag = $"imported-{FileUtil.GetSafeDateFileName()}"; - + 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(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) + long existingId = await ct.TravelRate.AsNoTracking().Where(z => z.Name == (string)j["Name"]).Select(x => x.Id).FirstOrDefaultAsync(); + if (existingId == 0) { - ImportResult.Add($"* {w.Name} - {this.GetErrorsAsString()}"); - this.ClearErrors(); + if (importData.DoImport) + { + //import this record + var Target = j.ToObject(jsset); + Target.Tags.Add(ImportTag); + var res = await CreateAsync(Target); + if (res == null) + { + ImportResult.Add($"❌ {Target.Name}\r\n{this.GetErrorsAsString()}"); + this.ClearErrors(); + } + else + { + ImportResult.Add($"✔️ {Target.Name}"); + } + } } else { - ImportResult.Add($"{w.Name} - ok"); + if (importData.DoUpdate) + { + //update this record with any data provided + //load existing record + var Target = await GetAsync((long)existingId); + var Source = j.ToObject(jsset); + var propertiesToUpdate = j.Properties().Select(p => p.Name).ToList(); + propertiesToUpdate.Remove("Name"); + ImportUtil.Update(Source, Target, propertiesToUpdate); + var res = await PutAsync(Target); + if (res == null) + { + ImportResult.Add($"❌ {Target.Name} - {this.GetErrorsAsString()}"); + this.ClearErrors(); + } + else + { + ImportResult.Add($"✔️ {Target.Name}"); + } + } } } return ImportResult; } - - //////////////////////////////////////////////////////////////////////////////////////////////// //JOB / OPERATIONS //