Import added headoffice support, tests ok
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -48,7 +48,7 @@
|
|||||||
"AYANOVA_DATA_PATH": "c:\\temp\\ravendata",
|
"AYANOVA_DATA_PATH": "c:\\temp\\ravendata",
|
||||||
"AYANOVA_USE_URLS": "http://*:7575;",
|
"AYANOVA_USE_URLS": "http://*:7575;",
|
||||||
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
||||||
"AYANOVA_SERVER_TEST_MODE": "true",
|
"AYANOVA_SERVER_TEST_MODE": "false",
|
||||||
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
||||||
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
||||||
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
|
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
|
||||||
|
|||||||
171
docs/8.0/ayanova/docs/adm-import-headoffice.md
Normal file
171
docs/8.0/ayanova/docs/adm-import-headoffice.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# Head office import / update specifications
|
||||||
|
|
||||||
|
Names of fields listed here are the exact case and spelling required to be recognized by AyaNova for importing / updating.
|
||||||
|
|
||||||
|
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
|
||||||
|
- WebAddress
|
||||||
|
- TechNotes
|
||||||
|
- AccountNumber
|
||||||
|
- ContractExpires
|
||||||
|
- Phone1
|
||||||
|
- Phone2
|
||||||
|
- Phone3
|
||||||
|
- Phone4
|
||||||
|
- Phone5
|
||||||
|
- EmailAddress
|
||||||
|
- PostAddress
|
||||||
|
- PostCity
|
||||||
|
- PostRegion
|
||||||
|
- PostCountry
|
||||||
|
- PostCode
|
||||||
|
- Address
|
||||||
|
- City
|
||||||
|
- Region
|
||||||
|
- Country
|
||||||
|
- Latitude
|
||||||
|
- Longitude
|
||||||
|
|
||||||
|
## Linked object fields
|
||||||
|
|
||||||
|
The following linked objects are supported for importing (update is not supported for these fields):
|
||||||
|
|
||||||
|
- Contract via "ContractViz" field which must contain the name of an existing Contract
|
||||||
|
|
||||||
|
If the Contract is specified then the ContractExpires field can be used to set the expiry date of the Contract.
|
||||||
|
|
||||||
|
If ContractExpires is omitted then it is set to the import date and time minus 1 minute so that it won't take effect until it's been set to a future date.
|
||||||
|
|
||||||
|
## JSON file format
|
||||||
|
|
||||||
|
The .json file must contain an array of Head office objects, so even a single object must be within [] square brackets in the import file.
|
||||||
|
|
||||||
|
The first Head office record here illustrates importing a Head office with a link to an existing Contract.
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Name": "Goodwin LLC",
|
||||||
|
"Active": true,
|
||||||
|
"Notes": "Triple-buffered mission-critical website",
|
||||||
|
"Wiki": null,
|
||||||
|
"Tags": [
|
||||||
|
"jade",
|
||||||
|
"zone5",
|
||||||
|
"zone7"
|
||||||
|
],
|
||||||
|
"WebAddress": "http://example.info",
|
||||||
|
"AccountNumber": "32906249",
|
||||||
|
"ContractViz": "Bronze",
|
||||||
|
"ContractExpires": "2023-02-01T08:00:00Z",
|
||||||
|
"Phone1": "1-629-420-0186",
|
||||||
|
"Phone2": "1-807-405-5544 x2470",
|
||||||
|
"Phone3": "352-364-6323 x45752",
|
||||||
|
"Phone4": null,
|
||||||
|
"Phone5": null,
|
||||||
|
"EmailAddress": "Heloise_Farrell61@example.com",
|
||||||
|
"PostAddress": "865 Tracey Views",
|
||||||
|
"PostCity": "New Mathew",
|
||||||
|
"PostRegion": "Louisiana",
|
||||||
|
"PostCountry": "Jordan",
|
||||||
|
"PostCode": "74354-4982",
|
||||||
|
"Address": "3400 Tyree Keys",
|
||||||
|
"City": "New Mathew",
|
||||||
|
"Region": "Louisiana",
|
||||||
|
"Country": "Jordan",
|
||||||
|
"Latitude": -56.030700,
|
||||||
|
"Longitude": 169.844400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Bahringer - Stark",
|
||||||
|
"Active": true,
|
||||||
|
"Notes": "Enhanced reciprocal matrix",
|
||||||
|
"Wiki": null,
|
||||||
|
"Tags": [
|
||||||
|
"green",
|
||||||
|
"red",
|
||||||
|
"zone8"
|
||||||
|
],
|
||||||
|
"WebAddress": "http://example.name",
|
||||||
|
"AccountNumber": "71115129",
|
||||||
|
"ContractViz": null,
|
||||||
|
"ContractExpires": null,
|
||||||
|
"Phone1": "530.785.2024 x019",
|
||||||
|
"Phone2": "418-629-2283 x34011",
|
||||||
|
"Phone3": "347.447.3645",
|
||||||
|
"Phone4": null,
|
||||||
|
"Phone5": null,
|
||||||
|
"EmailAddress": "Alysa.Mertz@example.org",
|
||||||
|
"PostAddress": "0511 Deckow Stream",
|
||||||
|
"PostCity": "Lake Cotyhaven",
|
||||||
|
"PostRegion": "Nevada",
|
||||||
|
"PostCountry": "Comoros",
|
||||||
|
"PostCode": "41680",
|
||||||
|
"Address": "2438 Sibyl Neck",
|
||||||
|
"City": "Lake Cotyhaven",
|
||||||
|
"Region": "Nevada",
|
||||||
|
"Country": "Comoros",
|
||||||
|
"Latitude": -51.706500,
|
||||||
|
"Longitude": -22.044300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Beer, Armstrong and Wiegand",
|
||||||
|
"Active": true,
|
||||||
|
"Notes": "Compatible clear-thinking concept",
|
||||||
|
"Wiki": null,
|
||||||
|
"Tags": [
|
||||||
|
"zone3",
|
||||||
|
"zone9"
|
||||||
|
],
|
||||||
|
"WebAddress": "https://example.org",
|
||||||
|
"AccountNumber": "95120864",
|
||||||
|
"ContractViz": null,
|
||||||
|
"ContractExpires": null,
|
||||||
|
"Phone1": "986-530-1111",
|
||||||
|
"Phone2": "1-695-482-1199 x321",
|
||||||
|
"Phone3": "653-466-6627 x117",
|
||||||
|
"Phone4": null,
|
||||||
|
"Phone5": null,
|
||||||
|
"EmailAddress": "Elisa41@example.org",
|
||||||
|
"PostAddress": "15461 Deangelo Tunnel",
|
||||||
|
"PostCity": "Kuvalisland",
|
||||||
|
"PostRegion": "Florida",
|
||||||
|
"PostCountry": "Sri Lanka",
|
||||||
|
"PostCode": "15255-8577",
|
||||||
|
"Address": "4695 Sandra Tunnel",
|
||||||
|
"City": "Kuvalisland",
|
||||||
|
"Region": "Florida",
|
||||||
|
"Country": "Sri Lanka",
|
||||||
|
"Latitude": -19.439100,
|
||||||
|
"Longitude": -112.588800
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSV file format
|
||||||
|
|
||||||
|
The first row of the .csv file must contain column headers that match the field names listed above.
|
||||||
|
|
||||||
|
The first Head office record here illustrates importing a Head office with a link to an existing Contract.
|
||||||
|
|
||||||
|
```
|
||||||
|
Name,Active,Notes,Wiki,Tags,WebAddress,AccountNumber,ContractViz,ContractExpires,Phone1,Phone2,Phone3,Phone4,Phone5,EmailAddress,PostAddress,PostCity,PostRegion,PostCountry,PostCode,Address,City,Region,Country,Latitude,Longitude
|
||||||
|
Goodwin LLC,true,Triple-buffered mission-critical website,,"jade,zone5,zone7",http://example.info,32906249,Bronze,2023-02-01T08:00:00Z,1-629-420-0186,1-807-405-5544 x2470,352-364-6323 x45752,,,Heloise_Farrell61@example.com,865 Tracey Views,New Mathew,Louisiana,Jordan,74354-4982,3400 Tyree Keys,New Mathew,Louisiana,Jordan,-56.0307,169.8444
|
||||||
|
Bahringer - Stark,true,Enhanced reciprocal matrix,,"green,red,zone8",http://example.name,71115129,,,530.785.2024 x019,418-629-2283 x34011,347.447.3645,,,Alysa.Mertz@example.org,0511 Deckow Stream,Lake Cotyhaven,Nevada,Comoros,41680,2438 Sibyl Neck,Lake Cotyhaven,Nevada,Comoros,-51.7065,-22.0443
|
||||||
|
"Beer, Armstrong and Wiegand",true,Compatible clear-thinking concept,,"zone3,zone9",https://example.org,95120864,,,986-530-1111,1-695-482-1199 x321,653-466-6627 x117,,,Elisa41@example.org,15461 Deangelo Tunnel,Kuvalisland,Florida,Sri Lanka,15255-8577,4695 Sandra Tunnel,Kuvalisland,Florida,Sri Lanka,-19.4391,-112.5888
|
||||||
|
```
|
||||||
@@ -165,6 +165,7 @@ Types not listed may be added in future; for needs beyond what is provided with
|
|||||||
Each object type listed below links to a page showing the specific format required for the import file and special notes about importing that specific object:
|
Each object type listed below links to a page showing the specific format required for the import file and special notes about importing that specific object:
|
||||||
|
|
||||||
- [Customers](adm-import-customer.md)
|
- [Customers](adm-import-customer.md)
|
||||||
|
- [Head offices](adm-import-headoffice.md)
|
||||||
|
|
||||||
## Import form
|
## Import form
|
||||||
|
|
||||||
|
|||||||
@@ -343,32 +343,106 @@ namespace AyaNova.Biz
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<List<string>> ImportData(AyImportData importData)
|
public async Task<List<string>> ImportData(AyImportData importData)
|
||||||
{
|
{
|
||||||
List<string> ImportResult = new List<string>();
|
List<string> ImportResult = new List<string>();
|
||||||
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" }) });
|
var jsset = JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = new AyaNova.Util.JsonUtil.ShouldSerializeContractResolver(new string[] { "Concurrency", "Id", "CustomFields" }) });
|
||||||
|
|
||||||
foreach (JObject j in importData.Data)
|
foreach (JObject j in importData.Data)
|
||||||
{
|
{
|
||||||
var w = j.ToObject<HeadOffice>(jsset);
|
long existingId = await ct.HeadOffice.AsNoTracking().Where(z => z.Name == (string)j["Name"]).Select(x => x.Id).FirstOrDefaultAsync();
|
||||||
if (j["CustomFields"] != null)
|
|
||||||
w.CustomFields = j["CustomFields"].ToString();
|
if (existingId == 0)
|
||||||
w.Tags.Add(ImportTag);//so user can find them all and revert later if necessary
|
|
||||||
var res = await CreateAsync(w);
|
|
||||||
if (res == null)
|
|
||||||
{
|
{
|
||||||
ImportResult.Add($"* {w.Name} - {this.GetErrorsAsString()}");
|
if (importData.DoImport)
|
||||||
this.ClearErrors();
|
{
|
||||||
|
//import this record
|
||||||
|
var o = j.ToObject<HeadOffice>(jsset);
|
||||||
|
o.Tags.Add(ImportTag);
|
||||||
|
|
||||||
|
|
||||||
|
if (!JsonUtil.JTokenIsNullOrEmpty(j["ContractViz"]))
|
||||||
|
{
|
||||||
|
o.ContractId = await ct.Contract.AsNoTracking().Where(z => z.Name == (string)j["ContractViz"]).Select(x => x.Id).FirstOrDefaultAsync();
|
||||||
|
if (o.ContractId == 0)
|
||||||
|
AddError(ApiErrorCode.NOT_FOUND, "ContractViz", $"'{(string)j["ContractViz"]}'");
|
||||||
|
|
||||||
|
if (JsonUtil.JTokenIsNullOrEmpty(j["ContractExpires"]))
|
||||||
|
o.ContractExpires = DateTime.UtcNow.Subtract(new TimeSpan(0, 1, 0));//expired one minute ago to be safe, can't guess what the contract should be
|
||||||
|
else
|
||||||
|
o.ContractExpires = (DateTime)j["ContractExpires"];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = await CreateAsync(o);
|
||||||
|
if (res == null)
|
||||||
|
{
|
||||||
|
ImportResult.Add($"❌ {o.Name}\r\n{this.GetErrorsAsString()}");
|
||||||
|
this.ClearErrors();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImportResult.Add($"✔️ {o.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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<HeadOffice>(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;
|
return ImportResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public async Task<List<string>> ImportData(AyImportData importData)
|
||||||
|
// {
|
||||||
|
// List<string> ImportResult = new List<string>();
|
||||||
|
// string ImportTag = $"imported-{FileUtil.GetSafeDateFileName()}";
|
||||||
|
|
||||||
|
// 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<HeadOffice>(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)
|
||||||
|
// {
|
||||||
|
// ImportResult.Add($"* {w.Name} - {this.GetErrorsAsString()}");
|
||||||
|
// this.ClearErrors();
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// ImportResult.Add($"{w.Name} - ok");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return ImportResult;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//JOB / OPERATIONS
|
//JOB / OPERATIONS
|
||||||
|
|||||||
Reference in New Issue
Block a user