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_USE_URLS": "http://*:7575;",
|
||||
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
||||
"AYANOVA_SERVER_TEST_MODE": "true",
|
||||
"AYANOVA_SERVER_TEST_MODE": "false",
|
||||
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
||||
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
||||
"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:
|
||||
|
||||
- [Customers](adm-import-customer.md)
|
||||
- [Head offices](adm-import-headoffice.md)
|
||||
|
||||
## 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>();
|
||||
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<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)
|
||||
long existingId = await ct.HeadOffice.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 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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user