diff --git a/docs/8.0/ayanova/docs/adm-import-warehouse.md b/docs/8.0/ayanova/docs/adm-import-warehouse.md new file mode 100644 index 00000000..54f56ef4 --- /dev/null +++ b/docs/8.0/ayanova/docs/adm-import-warehouse.md @@ -0,0 +1,78 @@ +# Warehouse 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 + +## JSON file format + +The .json file must contain an array of Warehouse objects, so even a single object must be within [] square brackets in the import file. + +```JSON +[ + { + "Name": "Van 12", + "Active": true, + "Notes": "Nam tenetur voluptatem voluptas excepturi.", + "Wiki": null, + "Tags": [ + "zone4", + "zone5", + "zone9", + "van" + ] + }, + { + "Name": "East side", + "Active": true, + "Notes": "Laborum sit ipsam ipsum quo nihil id.", + "Wiki": null, + "Tags": [ + "violet", + "east", + "zone5", + "zone9" + ] + }, + { + "Name": "Gateway", + "Active": true, + "Notes": "Sunt numquam quo nulla eum voluptates.", + "Wiki": null, + "Tags": [ + "indigo", + "orange", + "xanthic", + "zone2", + "gateway" + ] + } +] +``` + +## 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 +Van 12,true,Nam tenetur voluptatem voluptas excepturi.,,"zone4,zone5,zone9,van" +East side,true,Laborum sit ipsam ipsum quo nihil id.,,"violet,east,zone5,zone9" +Gateway,true,Sunt numquam quo nulla eum voluptates.,,"indigo,orange,xanthic,zone2,gateway" +``` diff --git a/docs/8.0/ayanova/docs/adm-import.md b/docs/8.0/ayanova/docs/adm-import.md index 35a174a5..be04e98b 100644 --- a/docs/8.0/ayanova/docs/adm-import.md +++ b/docs/8.0/ayanova/docs/adm-import.md @@ -171,6 +171,7 @@ Each object type listed below links to a page showing the specific format requir - ##### [Customers](adm-import-customer.md) - ##### [Head offices](adm-import-headoffice.md) - ##### [Parts](adm-import-part.md) +- ##### [Part assemblies](adm-import-part-assembly.md) ## Import form diff --git a/docs/8.0/ayanova/docs/appendix-os-credits.md b/docs/8.0/ayanova/docs/appendix-os-credits.md index f931b4f7..2a386c8c 100644 --- a/docs/8.0/ayanova/docs/appendix-os-credits.md +++ b/docs/8.0/ayanova/docs/appendix-os-credits.md @@ -50,6 +50,7 @@ We gratefully acknowledge the following open source tools and libraries that wer - [Marked](https://github.com/markedjs/marked) - [Monaco Editor](https://github.com/Microsoft/monaco-editor) - [NProgress](https://github.com/rstacruz/nprogress) +- [Papa Parse](https://www.papaparse.com/) - [register-service-worker](https://github.com/yyx990803/register-service-worker#readme) - [example logo](https://pixabay.com/users/openclipart-vectors-30363/) - [typeface-roboto](https://github.com/KyleAMathews/typefaces/tree/master/packages/roboto) diff --git a/docs/8.0/ayanova/mkdocs.yml b/docs/8.0/ayanova/mkdocs.yml index da7c3a22..b6e5b798 100644 --- a/docs/8.0/ayanova/mkdocs.yml +++ b/docs/8.0/ayanova/mkdocs.yml @@ -178,6 +178,6 @@ nav: - 'API upload routes': 'api-upload-routes.md' - 'API Data types': 'ay-start-data-types.md' - Appendix: - - 'Data types': 'ay-start-data-types.md' + - 'Data types': 'ay-start-data-types.md' - 'Open source credits': 'appendix-os-credits.md' - 'License agreement': 'license.md' diff --git a/server/AyaNova/biz/PartAssemblyBiz.cs b/server/AyaNova/biz/PartAssemblyBiz.cs index e658541d..3a343bfb 100644 --- a/server/AyaNova/biz/PartAssemblyBiz.cs +++ b/server/AyaNova/biz/PartAssemblyBiz.cs @@ -456,7 +456,7 @@ namespace AyaNova.Biz //update this record with any data provided //load existing record var Target = await GetAsync((long)existingId); - var Source = j.ToObject(jsset); + var Source = j.ToObject(jsset); var propertiesToUpdate = j.Properties().Select(p => p.Name).ToList(); propertiesToUpdate.Remove("Name"); propertiesToUpdate.Remove("Items"); diff --git a/server/AyaNova/biz/PartWarehouseBiz.cs b/server/AyaNova/biz/PartWarehouseBiz.cs index b686e0ac..083fbd8f 100644 --- a/server/AyaNova/biz/PartWarehouseBiz.cs +++ b/server/AyaNova/biz/PartWarehouseBiz.cs @@ -161,8 +161,8 @@ namespace AyaNova.Biz await ValidateCanDeleteAsync(dbObject); if (HasErrors) return false; - { - var IDList = await ct.Review.AsNoTracking().Where(x => x.AType == AyaType.PartWarehouse&& x.ObjectId == id).Select(x => x.Id).ToListAsync(); + { + var IDList = await ct.Review.AsNoTracking().Where(x => x.AType == AyaType.PartWarehouse && x.ObjectId == id).Select(x => x.Id).ToListAsync(); if (IDList.Count() > 0) { ReviewBiz b = new ReviewBiz(ct, UserId, UserTranslationId, CurrentUserRoles); @@ -297,7 +297,7 @@ namespace AyaNova.Biz var batchResults = await ct.PartWarehouse.AsNoTracking().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 (PartWarehouse w in orderedList) { if (!ReportRenderManager.KeepGoing(jobId)) return null; @@ -306,7 +306,7 @@ namespace AyaNova.Biz jo["CustomFields"] = JObject.Parse((string)jo["CustomFields"]); ReportData.Add(jo); } - orderedList=null; + orderedList = null; } return ReportData; } @@ -330,24 +330,53 @@ 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.PartWarehouse.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; @@ -355,7 +384,6 @@ namespace AyaNova.Biz - //////////////////////////////////////////////////////////////////////////////////////////////// //JOB / OPERATIONS // @@ -449,7 +477,7 @@ namespace AyaNova.Biz public async Task HandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null) { ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger(); - if(ServerBootConfig.SEEDING || ServerBootConfig.MIGRATING) return; + if (ServerBootConfig.SEEDING || ServerBootConfig.MIGRATING) return; log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{this.BizType}, AyaEvent:{ayaEvent}]"); bool isNew = currentObj == null;