Compare commits
68 Commits
Author | SHA1 | Date |
---|---|---|
ttenden | fb92fa0d1c | |
ttenden | 67e5cb6bb4 | |
ttenden | da82c232e3 | |
ttenden | 752b538780 | |
ttenden | 178ba1ea5b | |
ttenden | c2e4f9d861 | |
ttenden | 6d6b5b1b7a | |
Pepijn van Oort | fcf6b2af51 | |
Pepijn van Oort | 24feeba58e | |
ttenden | a98a81776d | |
Pepijn van Oort | e05bb5a8f7 | |
tamara | 6faa5104c8 | |
tamara | efb4d6833f | |
tamara | 0a9a83a5a6 | |
tamara | fe2bd98589 | |
Pepijn van Oort | ffbb45894a | |
tamara | 67014e20f5 | |
tamara | 84f27db16e | |
tamara | d756f08b4c | |
tamara | 77532fee9f | |
tamara | 5d2789a806 | |
Pepijn van Oort | dea4f102f5 | |
Pepijn van Oort | 39ee3263a7 | |
Pepijn van Oort | 619cb5e92c | |
tamara | 5399fd66df | |
tamara | 5d02370f56 | |
Pepijn van Oort | e4087adc77 | |
Pepijn van Oort | 4761166472 | |
Pepijn van Oort | 9d691dfed1 | |
Pepijn van Oort | d616fd3dfc | |
Pepijn van Oort | 3f66676914 | |
Pepijn van Oort | aa18393102 | |
Pepijn van Oort | 0b0ec8f767 | |
Pepijn van Oort | aef8c7c446 | |
Pepijn van Oort | f1707c432f | |
Pepijn van Oort | cfba86cf75 | |
Pepijn van Oort | da808362c3 | |
Pepijn van Oort | 847ff75845 | |
Pepijn van Oort | 6d903c3e9b | |
Pepijn van Oort | 6eb36b2b4f | |
Pepijn van Oort | 7f3b87ae38 | |
Pepijn van Oort | 90f285a0d1 | |
Pepijn van Oort | 546ce131e4 | |
Pepijn van Oort | d8c2ecb88b | |
Pepijn van Oort | 2d588026e2 | |
Pepijn van Oort | 1a9d5af5f6 | |
Pepijn van Oort | 8771e47b28 | |
Pepijn van Oort | 4102ed628e | |
Pepijn van Oort | 1cc36422a4 | |
Pepijn van Oort | fedd363075 | |
Pepijn van Oort | f04cc239d5 | |
Pepijn van Oort | 8a770a1762 | |
Abel Hoeven, van | b99191b7b1 | |
Pepijn van Oort | 9be9eb3145 | |
Abel Hoeven, van | 641e09f833 | |
Abel Hoeven, van | 8c5a0aed95 | |
Abel Hoeven, van | 59f9ef4743 | |
Abel Hoeven, van | 8bb5c6f581 | |
Abel Hoeven, van | 7149086ce2 | |
abel | 55f00da9d0 | |
abel | 3d7bf186e7 | |
abel | 8f8f857bf0 | |
abel | b7bedf182c | |
abel | be22d631bc | |
abel | 7dda21dd77 | |
abel | c79e0d062c | |
abel | 32138bef80 | |
Pepijn van Oort | e66820bd87 |
|
@ -12,7 +12,12 @@ namespace FarmmapsApiSamples
|
|||
public const string SHAPE_ITEMTYPE = "vnd.farmmaps.itemtype.shape";
|
||||
public const string GEOJSON_ITEMTYPE = "vnd.farmmaps.itemtype.geojson";
|
||||
public const string BLIGHT_ITEMTYPE = "vnd.farmmaps.itemtype.blight";
|
||||
public const string CROPREC_ITEMTYPE = "vnd.farmmaps.itemtype.crprec.operation";
|
||||
public const string CROPREC_ITEMTYPE = "vnd.farmmaps.itemtype.crprec";
|
||||
public const string CROPOP_ITEMTYPE = "vnd.farmmaps.itemtype.crprec.operation";
|
||||
public const string CROPCHAR_ITEMTYPE = "vnd.farmmaps.itemtype.edicrop.characteristic";
|
||||
public const string CROPSCHEME_ITEMTYPE = "vnd.farmmaps.itemtype.croppingscheme"; // deze toegevoegd, misschien is het type van de KPI task wel een croppingscheme
|
||||
//public const string KPI_ITEM = "vnd.farmmaps.itemtype.kpi.data"; //PO20231004: originally with .data
|
||||
public const string KPICONTAINER_ITEM = "vnd.farmmaps.itemtype.kpi.data.container"; //PO20231004: originally without .container
|
||||
|
||||
public const string VRANBS_TASK = "vnd.farmmaps.task.vranbs";
|
||||
public const string VRAHERBICIDE_TASK = "vnd.farmmaps.task.vraherbicide";
|
||||
|
@ -24,8 +29,10 @@ namespace FarmmapsApiSamples
|
|||
public const string TASKMAP_TASK = "vnd.farmmaps.task.taskmap";
|
||||
public const string WORKFLOW_TASK = "vnd.farmmaps.task.workflow";
|
||||
public const string BOFEK_TASK = "vnd.farmmaps.task.bofek";
|
||||
public const string CROPREC_TASK = "vnd.farmmaps.task.crprec";
|
||||
public const string SHADOW_TASK = "vnd.farmmaps.task.shadow";
|
||||
public const string AHN_TASK = "vnd.farmmaps.task.ahn";
|
||||
public const string WATBAL_TASK = "vnd.farmmaps.task.watbal";
|
||||
public const string KPI_TASK = "vnd.farmmaps.task.kpi"; // dus nieuwe taak om de KPIs te berekenen
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -46,6 +46,10 @@ namespace FarmmapsApi.Services
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<Configuration> GetConfiguration()
|
||||
{
|
||||
return _configuration;
|
||||
}
|
||||
public async Task AuthenticateAsync()
|
||||
{
|
||||
if (_httpClient.DefaultRequestHeaders.Authorization != null &&
|
||||
|
|
|
@ -22,14 +22,20 @@ namespace FarmmapsApi.Services
|
|||
}
|
||||
|
||||
public async Task<Item> CreateCropfieldItemAsync(string parentItemCode, string name, int year,
|
||||
string fieldGeomJson, string data = "{}") {
|
||||
var currentYear = new DateTime(year, 1, 1);
|
||||
string fieldGeomJson, string data = "{}", DateTime startDate = new DateTime(), DateTime endDate = new DateTime() )
|
||||
{
|
||||
//If user provides no startDate or endDate, then set startDate and endDate to full year provided through 'year'
|
||||
if (startDate == new DateTime() || endDate == new DateTime())
|
||||
{
|
||||
startDate = new DateTime(year, 1, 1);
|
||||
endDate = new DateTime(year, 12, 31);
|
||||
}
|
||||
var cropfieldItemRequest = new ItemRequest() {
|
||||
ParentCode = parentItemCode,
|
||||
ItemType = CROPFIELD_ITEMTYPE,
|
||||
Name = name,
|
||||
DataDate = currentYear,
|
||||
DataEndDate = currentYear.AddYears(1).AddDays(-1),
|
||||
DataDate = startDate,
|
||||
DataEndDate = endDate,
|
||||
Data = JObject.Parse(data),
|
||||
Geometry = JObject.Parse(fieldGeomJson)
|
||||
};
|
||||
|
@ -37,6 +43,55 @@ namespace FarmmapsApi.Services
|
|||
return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest);
|
||||
}
|
||||
|
||||
public async Task<Item> CreateOperationItemAsync(string cropRecordingItemCode, int year,
|
||||
string fieldGeomJson, string data = "{}", DateTime startDate = new DateTime(), DateTime endDate = new DateTime())
|
||||
{
|
||||
//If user provides no startDate or endDate, then set startDate and endDate to full year provided through 'year'
|
||||
if (startDate == new DateTime() || endDate == new DateTime())
|
||||
{
|
||||
startDate = new DateTime(year, 1, 1);
|
||||
endDate = new DateTime(year, 12, 31);
|
||||
}
|
||||
JObject jdata = JObject.Parse(data);
|
||||
string name = string.Format($"CrpRec Operation, {jdata.GetValue("name")}");
|
||||
|
||||
ItemRequest operationItemRequest = new ItemRequest()
|
||||
{
|
||||
ParentCode = cropRecordingItemCode,
|
||||
ItemType = CROPOP_ITEMTYPE,
|
||||
Name = name,
|
||||
DataDate = startDate,
|
||||
DataEndDate = endDate,
|
||||
Data = jdata,
|
||||
Geometry = JObject.Parse(fieldGeomJson)
|
||||
};
|
||||
|
||||
return await _farmmapsApiService.CreateItemAsync(operationItemRequest);
|
||||
}
|
||||
public async Task<Item> CreateCropfieldCharacteristicItemAsync(string cropfieldItemCode, int year,
|
||||
string fieldGeomJson, string data = "{}", DateTime startDate = new DateTime(), DateTime endDate = new DateTime())
|
||||
{
|
||||
//If user provides no startDate or endDate, then set startDate and endDate to full year provided through 'year'
|
||||
if (startDate == new DateTime() || endDate == new DateTime())
|
||||
{
|
||||
startDate = new DateTime(year, 1, 1);
|
||||
endDate = new DateTime(year, 12, 31);
|
||||
}
|
||||
// not sure if here we also need to specify DataDate, DataEndDate & Geometry. Do it just in case
|
||||
string name = "Cropfield characteristic";
|
||||
ItemRequest cropfieldCharactericsticItemRequest = new ItemRequest()
|
||||
{
|
||||
ParentCode = cropfieldItemCode,
|
||||
ItemType = CROPCHAR_ITEMTYPE,
|
||||
Name = name,
|
||||
DataDate = startDate,
|
||||
DataEndDate = endDate,
|
||||
Data = JObject.Parse(data),
|
||||
Geometry = JObject.Parse(fieldGeomJson)
|
||||
};
|
||||
|
||||
return await _farmmapsApiService.CreateItemAsync(cropfieldCharactericsticItemRequest);
|
||||
}
|
||||
public async Task<Item> UploadDataAsync(UserRoot root, string itemType, string filePath, string itemName, string geoJsonString = null)
|
||||
{
|
||||
var startUpload = DateTime.UtcNow.AddSeconds(-3);
|
||||
|
@ -247,6 +302,39 @@ namespace FarmmapsApi.Services
|
|||
return dataItem;
|
||||
}
|
||||
|
||||
public async Task<Item> RunCropRecordingTask(Item cropfieldItem)
|
||||
{
|
||||
var cropRecordingRequest = new TaskRequest { TaskType = CROPREC_TASK };
|
||||
|
||||
string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, cropRecordingRequest);
|
||||
|
||||
await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => {
|
||||
var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
|
||||
_logger.LogInformation($"Waiting on RunCropRecordingTask; status: {itemTaskStatus.State}");
|
||||
if (itemTaskStatus.IsFinished)
|
||||
tokenSource.Cancel();
|
||||
});
|
||||
|
||||
var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
|
||||
if (itemTask.State == ItemTaskState.Error)
|
||||
{
|
||||
_logger.LogError($"Something went wrong with task execution: {itemTask.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
//the CropRecording data is a child of the cropfield
|
||||
var itemName = "Crprec";
|
||||
var cropRecordingItem = await FindChildItemAsync(cropfieldItem.Code,
|
||||
CROPREC_ITEMTYPE, itemName);
|
||||
if (cropRecordingItem == null)
|
||||
{
|
||||
_logger.LogError("Could not find the CropRecording data as a child item under the cropfield");
|
||||
return null;
|
||||
}
|
||||
|
||||
return cropRecordingItem;
|
||||
}
|
||||
|
||||
public async Task<Item> RunBofekTask(Item cropfieldItem) {
|
||||
var taskmapRequest = new TaskRequest { TaskType = BOFEK_TASK };
|
||||
|
||||
|
@ -277,6 +365,51 @@ namespace FarmmapsApi.Services
|
|||
return bofekItem;
|
||||
}
|
||||
|
||||
public async Task<List<Item>> GetKpiItemsForCropField(Item cropfieldItem, int waitsecs = 6)
|
||||
{
|
||||
TaskRequest kpiRequest = new TaskRequest { TaskType = KPI_TASK };
|
||||
kpiRequest.attributes["processAggregateKpi"] = "false";
|
||||
int year = cropfieldItem.DataDate.Value.Year;
|
||||
kpiRequest.attributes["year"] = year.ToString();
|
||||
int ms = waitsecs * 1000;
|
||||
|
||||
string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, kpiRequest);
|
||||
|
||||
await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => {
|
||||
var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
|
||||
_logger.LogInformation($"Waiting on retreiving KPI data; status: {itemTaskStatus.State}");
|
||||
if (itemTaskStatus.IsFinished)
|
||||
tokenSource.Cancel();
|
||||
});
|
||||
|
||||
var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
|
||||
if (itemTask.State == ItemTaskState.Error)
|
||||
{
|
||||
_logger.LogError($"Something went wrong with task execution: {itemTask.Message}");
|
||||
return null;
|
||||
}
|
||||
_logger.LogInformation($"Taking {waitsecs} seconds to look up all KPI items. The longer we wait the more KPI's we get ..." +
|
||||
$"");
|
||||
await Task.Delay(ms); // wait 60000ms = 60 secs for task to be completed
|
||||
|
||||
//After the task is completed we have 1 kpiContainerItem with a code and with no data
|
||||
//Because the data are in the children of this kpiContainerItem. The container will have a list of children each with an "id" aand data,
|
||||
//The ids' are "a1", "b1", "b2", "c1","d1","d3","d5"
|
||||
//with following meanings:
|
||||
//| A1 | Opbrengst | Yield |
|
||||
//| B1 | Stikstofoverschot | Nitrogen surplus |
|
||||
//| B2 | Fosfaatoverschot | Phosphate surplus |
|
||||
//| C1 | Effectieve Organischestof aanvoer| Effective Organic Matter supply |
|
||||
//| D1 | Gebruik bestrijdingsmiddelen | Use of pesticides|
|
||||
//| D3 | Gewasdiversiteit(randdichtheid) | Crop diversity(edge density) |
|
||||
//| D5 | Percentage rustgewassen | Percentage of rest crops |
|
||||
List <Item> kpiContainerItem = await _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code, KPICONTAINER_ITEM);
|
||||
string kpiContainerItemCode = kpiContainerItem[0].Code;
|
||||
List<Item> kpiItems = await _farmmapsApiService.GetItemChildrenAsync(kpiContainerItemCode);
|
||||
|
||||
return kpiItems;
|
||||
}
|
||||
|
||||
public async Task<Item> RunAhnTask(Item cropfieldItem) {
|
||||
var taskmapRequest = new TaskRequest { TaskType = AHN_TASK };
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||

|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30320.27
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33122.133
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FarmmapsNbs", "FarmmapsNbs\FarmmapsNbs.csproj", "{E08EF7E9-F09E-42D8-825C-164E458C78F4}"
|
||||
EndProject
|
||||
|
@ -31,56 +31,122 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Secrets", "Secrets\Secrets.
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FarmmapsCleanUp", "FarmmapsCleanUp\FarmmapsCleanUp.csproj", "{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FarmmapsKPI", "FarmmapsKPI\FarmmapsKPI.csproj", "{14575235-9867-4CE5-A22F-3F9FE002FF42}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FarmmapsDownloadCL", "FarmmapsDownloadCL\FarmmapsDownloadCL.csproj", "{63E69101-D804-4DBC-B2E4-A33771CD5C5F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E08EF7E9-F09E-42D8-825C-164E458C78F4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Debug|x64.Build.0 = Debug|x64
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Release|x64.ActiveCfg = Release|x64
|
||||
{1FA9E50B-F45E-4534-953A-37C783D03C74}.Release|x64.Build.0 = Release|x64
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{731A88CD-9DC4-4969-86F2-2315830A6998}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DFA89D0B-5400-4374-B824-8367B76B4B6E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AAFAB03A-6F5C-4D91-991F-867B7898F981}.Release|x64.Build.0 = Release|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{892E0932-5D11-4A37-979E-CEDB39C2E181}.Release|x64.Build.0 = Release|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{91A58C4A-4A80-4079-B43D-9B851206194F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{32ED9500-AAAB-4030-9C7A-F611A85DF890}.Release|x64.Build.0 = Release|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{772DBDCD-9FAA-40A7-8551-2C1620C4AB67}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Debug|x64.Build.0 = Debug|x64
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Release|x64.ActiveCfg = Release|x64
|
||||
{C4EE5ECA-253A-4B71-9F67-D231AC4517D6}.Release|x64.Build.0 = Release|x64
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5E4387F9-5953-4A9B-BCA5-DF3964EED3CB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Debug|x64.Build.0 = Debug|x64
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Release|x64.ActiveCfg = Release|x64
|
||||
{14575235-9867-4CE5-A22F-3F9FE002FF42}.Release|x64.Build.0 = Release|x64
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Debug|x64.Build.0 = Debug|x64
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Release|x64.ActiveCfg = Release|x64
|
||||
{63E69101-D804-4DBC-B2E4-A33771CD5C5F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[
|
||||
{
|
||||
"UseCreatedCropfield": true,
|
||||
"UseCreatedCropfield": false,
|
||||
"outputFileName": "TestData",
|
||||
"fieldName": "TestField",
|
||||
"DownloadFolder": "Downloads", //"C:\\workdir\\groenmonitor\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_WURtest\FarmmapsDataDownload\bin\Debug\netcoreapp3.1\Downloads\
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using FarmmapsApi;
|
||||
using FarmmapsApi.Models;
|
||||
using FarmmapsApi.Services;
|
||||
using FarmmapsDownloadCL.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static FarmmapsApiSamples.Constants;
|
||||
|
||||
namespace FarmmapsDownloadCL
|
||||
{
|
||||
public class DownloadCLApplication : IApplication
|
||||
{
|
||||
|
||||
private readonly ILogger<DownloadCLApplication> _logger;
|
||||
private readonly FarmmapsApiService _farmmapsApiService;
|
||||
private readonly DownloadCLService _DownloadCLService;
|
||||
private readonly GeneralService _generalService;
|
||||
public readonly Dictionary<string, List<string>> _dictCl;
|
||||
string _itemcode;
|
||||
public DownloadCLApplication(ILogger<DownloadCLApplication> logger, FarmmapsApiService farmmapsApiService,
|
||||
GeneralService generalService, DownloadCLService DownloadCLService)
|
||||
{
|
||||
_logger = logger;
|
||||
_farmmapsApiService = farmmapsApiService;
|
||||
_generalService = generalService;
|
||||
_DownloadCLService = DownloadCLService;
|
||||
CodelistsClasses clc = new CodelistsClasses();
|
||||
_itemcode = clc.itemcode;
|
||||
_dictCl = clc.dictCl;
|
||||
}
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var fieldsInputJson = File.ReadAllText("DownloadCLInput.json");
|
||||
|
||||
|
||||
DownloadCLInput clInput = JsonConvert.DeserializeObject<DownloadCLInput>(fieldsInputJson);
|
||||
|
||||
// !! this call is needed the first time an api is called with a fresh clientid and secret !!
|
||||
await _farmmapsApiService.GetCurrentUserCodeAsync();
|
||||
var roots = await _farmmapsApiService.GetCurrentUserRootsAsync();
|
||||
|
||||
//Where to write the output
|
||||
string downloadFolder = clInput.DownloadFolder;
|
||||
if (string.IsNullOrEmpty(downloadFolder))
|
||||
{
|
||||
downloadFolder = "Downloads";
|
||||
}
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
|
||||
//Get the most recent codelists
|
||||
foreach (string codelist in clInput.codelists)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Process(roots, codelist, downloadFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Process(List<UserRoot> roots, string codelistname, string downloadFolder)
|
||||
{
|
||||
List<Item> codelist;
|
||||
string itemtype;
|
||||
string className;
|
||||
string body;
|
||||
string header;
|
||||
string value;
|
||||
string[] aboutArray = null;
|
||||
string[] headerArray = null;
|
||||
PropertyInfo[] props;
|
||||
PropertyInfo prop;
|
||||
List<string> dataList;
|
||||
string clJson = Path.Combine(downloadFolder, $"{codelistname}.json");
|
||||
string clCsv = Path.Combine(downloadFolder, $"{codelistname}.csv");
|
||||
|
||||
try
|
||||
{
|
||||
itemtype = _dictCl[codelistname][0];
|
||||
className = _dictCl[codelistname][1];
|
||||
codelist = await _farmmapsApiService.GetItemChildrenAsync(_itemcode, itemtype);
|
||||
|
||||
//Write full codelist in json format to clJson.
|
||||
body = JsonConvert.SerializeObject(codelist);
|
||||
File.WriteAllText(clJson, body);
|
||||
_logger.LogInformation($"Downloaded file {clJson}");
|
||||
|
||||
//Write full list in csv format to clCsv.
|
||||
StreamWriter sw = new StreamWriter(clCsv);
|
||||
//Write metadata in top: when downloaded
|
||||
sw.WriteLine($"Editeelt codelist {codelistname} downloaded on {DateTime.Now} with the FarmmapsDownloadCL application");
|
||||
|
||||
//Generic, for any Codelist as long as it is also defined in FarmmapsDownloadCL.Models in
|
||||
string typerequest = "FarmmapsDownloadCL.Models." + className + ", FarmmapsDownloadCL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
|
||||
Type objType = Type.GetType(typerequest);
|
||||
object clitem = Activator.CreateInstance(objType);
|
||||
props = clitem.GetType().GetProperties();
|
||||
|
||||
//Lookup about info and write to top
|
||||
foreach (PropertyInfo pi in props)
|
||||
{
|
||||
if (pi.Name == "about")
|
||||
{
|
||||
aboutArray = (string[])pi.GetValue(clitem);
|
||||
foreach (string about in aboutArray)
|
||||
{
|
||||
//Add quotes
|
||||
value = "\"" + about + "\"";
|
||||
//Write each about to a separate line in the csv file
|
||||
sw.WriteLine(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//Write an empty line
|
||||
sw.WriteLine();
|
||||
|
||||
//Look up the headerArray and write the header comma separated
|
||||
int i = 0;
|
||||
while (headerArray == null)
|
||||
{
|
||||
prop = props[i];
|
||||
if (prop.Name == "headers")
|
||||
{
|
||||
headerArray = (string[])prop.GetValue(clitem);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
header = string.Join(",", headerArray);
|
||||
sw.WriteLine(header);
|
||||
|
||||
//Add quotes because a value for field 'description' could be '21% Cl, 16.5%CaO, 1330 g/l' and without the quotes that
|
||||
//would show up as separate columns. So per definition we will add quotes, except if we have a fieldname in the listNotToQuote, then value for that fieldname will not be given quotes
|
||||
//e.g. not code "3" but code 3.
|
||||
List<string> listNotToQuote = new List<string>() { "code", "n", "p", "k", "quantity", "cropGroupCode", "cultivationGroupCode" };
|
||||
//Loop through all items in the codelist
|
||||
foreach (Item item in codelist)
|
||||
{
|
||||
dataList = new List<string> { };
|
||||
clitem = JsonConvert.DeserializeObject(item.Data.ToString(), objType);
|
||||
|
||||
//Add values of the cLitem to the dataList in the same order as the header
|
||||
foreach (string h in headerArray)
|
||||
{
|
||||
value = (string)clitem.GetType().GetProperty(h).GetValue(clitem, null);
|
||||
if(listNotToQuote.Contains(h) == false)
|
||||
value = "\"" +value + "\"";
|
||||
|
||||
dataList.Add(value);
|
||||
}
|
||||
string dataLine = string.Join(",", dataList);
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
|
||||
sw.Close();
|
||||
_logger.LogInformation($"Downloaded file {clCsv}");
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogWarning($"Missing lookup information on codelist {codelistname}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"codeLists": [ "CL022", "CL127", "CL263", "CL265", "CL405", "CL251", "CL104" ]
|
||||
//"codeLists": [ "CL263", "CL265"]
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_WURtest\FarmmapsDataDownload\bin\Debug\netcoreapp3.1\Downloads\
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using FarmmapsApi.Models;
|
||||
using FarmmapsApi.Services;
|
||||
using FarmmapsDownloadCL.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static FarmmapsApi.Extensions;
|
||||
using static FarmmapsApiSamples.Constants;
|
||||
|
||||
namespace FarmmapsDownloadCL
|
||||
{
|
||||
public class DownloadCLService
|
||||
{
|
||||
private readonly ILogger<DownloadCLService> _logger;
|
||||
private readonly FarmmapsApiService _farmmapsApiService;
|
||||
private readonly GeneralService _generalService;
|
||||
|
||||
public DownloadCLService(ILogger<DownloadCLService> logger, FarmmapsApiService farmmapsApiService,
|
||||
GeneralService generalService)
|
||||
{
|
||||
_logger = logger;
|
||||
_farmmapsApiService = farmmapsApiService;
|
||||
_generalService = generalService;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FarmmapsApi\FarmmapsApi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="DownloadCLInput.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,169 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace FarmmapsDownloadCL.Models
|
||||
{
|
||||
public class CodelistsClasses
|
||||
{
|
||||
public CodelistsClasses()
|
||||
{
|
||||
this.itemcode = "938c0aec4efc46e88783fd029f17309e%3ASYSTEM_DATA";
|
||||
this.dictCl = new Dictionary<string, List<string>>();
|
||||
//Add here once you have defined a new CLxxxitem below
|
||||
//To add a new item, look it up in https://test.farmmaps.eu/swagger/index.html. Download the item you are interested in (like "vnd.farmmaps.itemtype.codelist.cl263")
|
||||
//do this under Items <- get/api/v1/items, use the it field. Depending on the size of the list retrieving the list can take a few minutes.
|
||||
//then below create a new CLxxxitem with fieldnames as you see them in the just downloaded new codelist
|
||||
this.dictCl.Add("CL022", new List<string> { "vnd.farmmaps.itemtype.codelist.cl022", "CL022item" });
|
||||
this.dictCl.Add("CL104", new List<string> { "vnd.farmmaps.itemtype.codelist.cl104", "CL104item" });
|
||||
this.dictCl.Add("CL127", new List<string> { "vnd.farmmaps.itemtype.codelist.cl127", "CL127item" });
|
||||
this.dictCl.Add("CL251", new List<string> { "vnd.farmmaps.itemtype.codelist.cl251", "CL251item" });
|
||||
this.dictCl.Add("CL263", new List<string> { "vnd.farmmaps.itemtype.codelist.cl263", "CL263item" });
|
||||
this.dictCl.Add("CL265", new List<string> { "vnd.farmmaps.itemtype.codelist.cl265", "CL265item" });
|
||||
this.dictCl.Add("CL405", new List<string> { "vnd.farmmaps.itemtype.codelist.cl405", "CL405item" });
|
||||
}
|
||||
public string itemcode;
|
||||
//Define here the codelist names, their item type and the class defining the contents of the data type (and defined in the Models.CodelistsClasses)
|
||||
public Dictionary<string, List<string>> dictCl;
|
||||
}
|
||||
|
||||
public class CL022item
|
||||
{
|
||||
public CL022item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "description", "type", "n", "p", "k", "composition" };
|
||||
this.codelist = "CL022";
|
||||
this.about = new string[] { "EDI-Crop, coderingslijst meststoffen", "type MOR = organische meststof; MAN = anorganische meststof" };
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string k { get; set; }
|
||||
public string n { get; set; }
|
||||
public string p { get; set; }
|
||||
public string code { get; set; }
|
||||
public string type { get; set; }
|
||||
public string composition { get; set; }
|
||||
public string description { get; set; }
|
||||
|
||||
}
|
||||
public class CL104item
|
||||
{
|
||||
public CL104item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "description" };
|
||||
this.codelist = "CL104";
|
||||
this.about = new string[] { "EDI-crop, coderingslijst groenbemesters" };
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string code { get; set; }
|
||||
public string description { get; set; }
|
||||
}
|
||||
public class CL127item
|
||||
{
|
||||
public CL127item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "description", "description_nl", "culturalPracticeLevel1", "culturalPracticeLevel2" };
|
||||
this.codelist = "CL127";
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string code { get; set; }
|
||||
public string description { get; set; }
|
||||
public string description_nl { get; set; }
|
||||
public string culturalPracticeLevel1 { get; set; }
|
||||
public string culturalPracticeLevel2 { get; set; }
|
||||
}
|
||||
public class CL251item
|
||||
{
|
||||
public CL251item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "rvo", "active", "primary", "description", "description_fr", "description_nl" };
|
||||
this.codelist = "CL251";
|
||||
this.about = new string[] { "Codering teeltdoelen (CropProductionPurposeCode)", "primary: 1 = primary; 2 = secondary", "rvo: 1 = yes; 0 = no" };
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string code { get; set; }
|
||||
public string rvo { get; set; }
|
||||
public string active { get; set; }
|
||||
public string primary { get; set; }
|
||||
public string description { get; set; }
|
||||
public string description_nl { get; set; }
|
||||
public string description_fr { get; set; }
|
||||
|
||||
}
|
||||
public class CL263item
|
||||
{
|
||||
public CL263item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "eppoCode", "botanicName", "description", "description_fr", "description_nl", "cropGroupCode", "cropGroupName", "subCropGroupCode", "subCropGroupName", "cultivationGroupCode", "cultivationGroupName" };
|
||||
this.codelist = "CL263";
|
||||
this.about = new string[] { "EDI-Crop, coderingslijst gewassoorten" };
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string code { get; set; }
|
||||
public string eppoCode { get; set; }
|
||||
public string botanicName { get; set; }
|
||||
public string description { get; set; }
|
||||
public string description_nl { get; set; }
|
||||
public string description_fr { get; set; }
|
||||
public string cropGroupCode { get; set; }
|
||||
public string cropGroupName { get; set; }
|
||||
public string subCropGroupCode { get; set; }
|
||||
public string subCropGroupName { get; set; }
|
||||
public string cultivationGroupCode { get; set; }
|
||||
public string cultivationGroupName { get; set; }
|
||||
public string composition { get; set; } //?
|
||||
|
||||
}
|
||||
public class CL265item
|
||||
{
|
||||
public CL265item()
|
||||
{
|
||||
this.headers = new string[] { "Code", "Formaat", "Eenheid", "Waarde" };
|
||||
this.codelist = "CL265";
|
||||
this.about = new string[] { "EDI-Crop CL265: FarmCharacterictics, FieldCharacteristics, CropFieldCharacteristics, TreatmentCharacteristics",
|
||||
"Betreft codelijst eigenschappen teelt en teelthandelingen CL265.Daar waar in kolom 'Waarde' wordt verwezen naar CL.., wordt de codelijst bedoeld die onder het betreffende nummer bekend is.",
|
||||
"In het EDI-Crop bericht wordt de code gebruikt onder resp. CropFieldCharacteristic c.q.TreatmentCharacteristic middels de dataelementen PropertyVariableCode (invullen vanuit CL265) en PropertyVariableValue(voor de waarde)"};
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string Code { get; set; }
|
||||
public string Formaat { get; set; }
|
||||
public string Eenheid { get; set; }
|
||||
public string Waarde { get; set; }
|
||||
}
|
||||
public class CL405item
|
||||
{
|
||||
public CL405item()
|
||||
{
|
||||
this.headers = new string[] { "codelist", "code", "description", "description_fr", "description_nl", "hoofdgroep" };
|
||||
this.codelist = "CL405";
|
||||
this.about = new string[] { };
|
||||
}
|
||||
|
||||
public string[] headers { get; }
|
||||
public string codelist { get; }
|
||||
public string[] about { get; }
|
||||
public string code { get; set; }
|
||||
public string hoofdgroep { get; set; }
|
||||
public string description { get; set; }
|
||||
public string description_fr { get; set; }
|
||||
public string description_nl { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace FarmmapsDownloadCL.Models
|
||||
{
|
||||
public class DownloadCLInput
|
||||
{
|
||||
public string[] codelists { get; set; }
|
||||
public string DownloadFolder { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Threading.Tasks;
|
||||
using FarmmapsApi;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FarmmapsDownloadCL
|
||||
{
|
||||
class Program : FarmmapsProgram<DownloadCLApplication>
|
||||
{
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
await new Program().Start(args);
|
||||
}
|
||||
|
||||
protected override void Configure(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddLogging()
|
||||
.AddTransient<DownloadCLService>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FarmmapsApi\FarmmapsApi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="KPIInput.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,895 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
using FarmmapsApi;
|
||||
using FarmmapsApi.Models;
|
||||
using FarmmapsApi.Services;
|
||||
using FarmmapsKPI.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static FarmmapsApiSamples.Constants;
|
||||
|
||||
namespace FarmmapsKPI
|
||||
{
|
||||
public class KPIApplication : IApplication
|
||||
{
|
||||
//private const string DownloadFolder = "Downloads";
|
||||
private const string SettingsFile = "settings.json";
|
||||
|
||||
private readonly ILogger<KPIApplication> _logger;
|
||||
private readonly FarmmapsApiService _farmmapsApiService;
|
||||
private readonly KPIService _kpiService;
|
||||
private readonly GeneralService _generalService;
|
||||
|
||||
private Settings _settings;
|
||||
|
||||
public KPIApplication(ILogger<KPIApplication> logger, FarmmapsApiService farmmapsApiService,
|
||||
GeneralService generalService, KPIService kpiService)
|
||||
{
|
||||
_logger = logger;
|
||||
_farmmapsApiService = farmmapsApiService;
|
||||
_generalService = generalService;
|
||||
_kpiService = kpiService;
|
||||
}
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
KPIInput input;
|
||||
string fnKPIinput;
|
||||
|
||||
//Console.WriteLine("Type name of input json file. Example: KPIinput.json (in same directory as FarmmapsKPI.exe) or for example like this: C:/temp/KPIinputChemieTmp.json");
|
||||
//fnKPIinput = Console.ReadLine();
|
||||
//if (string.IsNullOrEmpty(fnKPIinput))
|
||||
//{
|
||||
//fnKPIinput = "KPIinput.json";
|
||||
fnKPIinput = "C:\\git\\FarmMapsApiClient_KB34_MAST\\FarmmapsKPI\\KPIinput.json";
|
||||
//}
|
||||
|
||||
var fieldsInputJson = File.ReadAllText(fnKPIinput);
|
||||
|
||||
List<KPIInput> fieldsInputs = JsonConvert.DeserializeObject<List<KPIInput>>(fieldsInputJson);
|
||||
|
||||
// !! this call is needed the first time an api is called with a fresh clientid and secret !!
|
||||
await _farmmapsApiService.GetCurrentUserCodeAsync();
|
||||
var roots = await _farmmapsApiService.GetCurrentUserRootsAsync();
|
||||
|
||||
//Where to write the output
|
||||
string downloadFolder = fieldsInputs[0].DownloadFolder;
|
||||
if (string.IsNullOrEmpty(downloadFolder))
|
||||
{
|
||||
downloadFolder = "Downloads";
|
||||
}
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
|
||||
|
||||
//Write the same info to a single csv file. Note this means existing file will be overwritten!
|
||||
StreamWriter sw;
|
||||
string KPIItemCsv = Path.GetFileNameWithoutExtension(fnKPIinput) + "_Items.csv";
|
||||
string KPIItemPathCsv = Path.Combine(downloadFolder, KPIItemCsv);
|
||||
List<string> headerList = new List<string> { "run","parentName", "cropfieldcode", "area_ha", "cropTypeCode", "cropTypeName", "KPIid", "KPIvariable", "KPIvalue", "KPIunit", "KPItargetvalue", "KPIthresholdValue",
|
||||
"mbp_productCode","mbp_productName","mbp_quantity","mbp_unitCode","mbp_date","mbp_KPIvariable","mbp_KPIvalue"};
|
||||
//Create a new csv file. Means if existing then overwritten !!!
|
||||
sw = new StreamWriter(KPIItemPathCsv);
|
||||
Configuration cf = await _farmmapsApiService.GetConfiguration();
|
||||
string endPoint = cf.Endpoint;
|
||||
sw.WriteLine($"Using FarmmapsKPI application in FarmmapsApSamples.sln. Input file: '{fnKPIinput}'. Download DateTime: '{DateTime.Now}'. Calculations on: '{endPoint}'");
|
||||
sw.WriteLine();
|
||||
sw.WriteLine(string.Join(",", headerList));
|
||||
|
||||
// For each input download all KPI's. Keep track to time, important when doing bulk calculations
|
||||
var watch = System.Diagnostics.Stopwatch.StartNew();
|
||||
TimeSpan tsSofar = new TimeSpan();
|
||||
TimeSpan tsRemaining;
|
||||
TimeSpan tsTotalEstimated;
|
||||
|
||||
//Per default just 1 run per field. For debugging check if when we run multiple times do we get (should be) always the same output?
|
||||
int nrun = 1;
|
||||
for (int run = 1; run <= nrun; run++) {
|
||||
for (int i = 0; i < fieldsInputs.Count; i++)
|
||||
//for (int i = 3; i < 4; i++) // for testing
|
||||
{
|
||||
watch.Restart();
|
||||
input = fieldsInputs[i];
|
||||
_logger.LogInformation(string.Format($"// FarmmapsKPI: Run {run}: Downloading KPI's for field {i + 1} out of {fieldsInputs.Count} to single csv file {KPIItemPathCsv}"));
|
||||
try
|
||||
{
|
||||
await Process(roots, input, sw, run);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
}
|
||||
watch.Stop();
|
||||
tsSofar = tsSofar + watch.Elapsed;
|
||||
tsTotalEstimated = tsSofar / (i + 1) * fieldsInputs.Count;
|
||||
tsRemaining = tsTotalEstimated - tsSofar;
|
||||
_logger.LogInformation(string.Format($"// Time (hh:mm:ss): this field: {strTime(watch.Elapsed)}. Sofar: {strTime(tsSofar)}. Estimated total: {strTime(tsTotalEstimated)}. Remaining: {strTime(tsRemaining)}"));
|
||||
}
|
||||
}
|
||||
//Close the csv file, write message to screen
|
||||
sw.Close();
|
||||
_logger.LogInformation(string.Format($"// FarmmapsKPI:"));
|
||||
_logger.LogInformation($"Done! Written all KPI for all fields in '{fnKPIinput}' to output file '{KPIItemPathCsv}'");
|
||||
}
|
||||
|
||||
private async Task Process(List<UserRoot> roots, KPIInput input, StreamWriter sw, int run)
|
||||
{
|
||||
List<Item> cropfieldChildren;
|
||||
List<Item> crprecChildren;
|
||||
KPIOutput kpio;
|
||||
KPIOutput kpioPrevious = new KPIOutput(); //creates a new empty
|
||||
//If KPI E1 is calculated, write these sub kpi's to output
|
||||
string[] mbp_KPIvariables = new string[] { "aquaticLife", "groundWater", "soilLife" };
|
||||
string mbp_KPIvalue;
|
||||
int targetKPIitemsCount; //if we know we should be getting 8 KPI items (A1,B1,B2,C1,D1,E1,F1,F2)
|
||||
int maxtries = 5; // but don't keep on trying forever; there is a maximum number of tries
|
||||
int trycnt;
|
||||
//double totalNferiliserInput = 0;
|
||||
//double totalNferiliserCropfield = 0;
|
||||
|
||||
string downloadFolder = input.DownloadFolder;
|
||||
if (string.IsNullOrEmpty(downloadFolder)) {
|
||||
downloadFolder = "Downloads";
|
||||
}
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
|
||||
// !!specify if you are using an already created cropfield:
|
||||
bool useExistingCropfieldWithChildren = input.UseExistingCropfieldWithChildren;
|
||||
int cropYear = input.CropYear;
|
||||
string fieldName = input.fieldName;
|
||||
string fieldGeom = input.GeometryJson.ToString(Formatting.None);
|
||||
|
||||
//Settings
|
||||
string settingsfile = $"Settings_{fieldName}.json";
|
||||
LoadSettings(settingsfile);
|
||||
|
||||
var uploadedRoot = roots.SingleOrDefault(r => r.Name == "USER_IN");
|
||||
if (uploadedRoot == null)
|
||||
{
|
||||
_logger.LogError("Could not find a needed root item");
|
||||
return;
|
||||
}
|
||||
|
||||
var myDriveRoot = roots.SingleOrDefault(r => r.Name == "USER_FILES");
|
||||
if (myDriveRoot == null)
|
||||
{
|
||||
_logger.LogError("Could not find a needed root item");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use already created cropfield or create new one, added a Data input, with field specific data for the KPI calculation
|
||||
Item cropfieldItem;
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && input.CropfieldItemCode = "" or absent -> read from settings json
|
||||
//3 useExistingCropfieldWithChildren = true && input.CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> use this one
|
||||
if (useExistingCropfieldWithChildren == false)
|
||||
{
|
||||
_logger.LogInformation($"Creating cropfield with name '{fieldName}'");
|
||||
cropfieldItem = await _generalService.CreateCropfieldItemAsync(myDriveRoot.Code,
|
||||
$"{fieldName}", cropYear, input.GeometryJson.ToString(Formatting.None), input.DataCropfield.ToString(Formatting.None), input.StartDate, input.EndDate);
|
||||
_settings.CropfieldItemCode = cropfieldItem.Code;
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(input.CropfieldItemCode))
|
||||
{
|
||||
_logger.LogInformation("reading CropfieldItemCode from settings file");
|
||||
cropfieldItem = await _farmmapsApiService.GetItemAsync(_settings.CropfieldItemCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("reading CropfieldItemCode from KPIinput json");
|
||||
cropfieldItem = await _farmmapsApiService.GetItemAsync(input.CropfieldItemCode);
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
|
||||
// The cropfieldCharacteristicItem is used to enter crop yields and/or straw yields
|
||||
Item cropfieldCharacteristicItem;
|
||||
string dataCropfieldCharacteristic;
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && input.CropfieldCharacteristicItemCode = "" or absent -> read from settings json
|
||||
//3 useExistingCropfieldWithChildren = true && input.CropfieldCharacteristicItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> use this one
|
||||
if (useExistingCropfieldWithChildren == false)
|
||||
{
|
||||
for (int i = 0; i < input.DataCropfieldCharacteristics.Length; i++)
|
||||
{
|
||||
dataCropfieldCharacteristic = input.DataCropfieldCharacteristics[i].ToString(Formatting.None);
|
||||
dynamic data = JObject.Parse(dataCropfieldCharacteristic);
|
||||
_logger.LogInformation($"CreateCropfieldCharacteristicItemAsync ... for cropfieldCharacteristic {i}: '{data.label}', value '{data.value}'");
|
||||
cropfieldCharacteristicItem = await _generalService.CreateCropfieldCharacteristicItemAsync(cropfieldItem.Code, cropYear, fieldGeom, dataCropfieldCharacteristic);
|
||||
_settings.CropfieldCharacteristicItemCode = cropfieldCharacteristicItem.Code;
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
}
|
||||
else if (string.IsNullOrEmpty(input.CropfieldItemCode))
|
||||
{
|
||||
_logger.LogInformation("reading CropfieldCharacteristicItemCode from settings file");
|
||||
cropfieldCharacteristicItem = await _farmmapsApiService.GetItemAsync(_settings.CropfieldCharacteristicItemCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("reading CropfieldCharacteristicItemCode from KPIinput json");
|
||||
cropfieldCharacteristicItem = await _farmmapsApiService.GetItemAsync(input.CropfieldCharacteristicItemCode);
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
|
||||
// Now we can do a first KPI calculation and get the polygon area from the KPI output (where it is based on geometry)
|
||||
// We need that because for operations, you need to provide the area on which the operation was applied
|
||||
// And if we put that to the crop area, then we neatly get everything on a per ha basis
|
||||
_logger.LogInformation($"Getting polygon area (ha))");
|
||||
List<Item> KPIItemsArea = await _generalService.GetKpiItemsForCropField(cropfieldItem, 3);
|
||||
trycnt = 1;
|
||||
targetKPIitemsCount = 3; // here for the area we need at least 3, but not more than that
|
||||
while (KPIItemsArea.Count < targetKPIitemsCount & trycnt < maxtries)
|
||||
{
|
||||
KPIItemsArea = await _generalService.GetKpiItemsForCropField(cropfieldItem,3);
|
||||
_logger.LogInformation($"Found {KPIItemsArea.Count} KPI items");
|
||||
trycnt++;
|
||||
}
|
||||
kpio = JsonConvert.DeserializeObject<KPIOutput>(KPIItemsArea[0].Data.ToString());
|
||||
string area_ha = kpio.data.area;
|
||||
// turn the area into a JObject for later merging with operation data;
|
||||
string strJarea = JsonConvert.SerializeObject(new { area = area_ha });
|
||||
JObject Jarea = JObject.Parse(strJarea);
|
||||
|
||||
if (useExistingCropfieldWithChildren == false)
|
||||
{
|
||||
//Retreiving BOFEK. A cropfield has 1 soil
|
||||
//Have a look at the cropfieldChildren before and after running this task, see one child (i.e. soil) has been added)
|
||||
//cropfieldChildren = await _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code);
|
||||
_logger.LogInformation("Get BOFEK for field");
|
||||
Item bofekItem = await _generalService.RunBofekTask(cropfieldItem);
|
||||
if (bofekItem == null)
|
||||
{
|
||||
_logger.LogError("Something went wrong while obtaining the BOFEK data");
|
||||
return;
|
||||
}
|
||||
//cropfieldChildren = await _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("For existing cropfield we assume it already has BOFEK soil data");
|
||||
}
|
||||
|
||||
// A cropfield has 1 crop recording and the crop recording has 0:many operations
|
||||
//So first at the crop recording
|
||||
Item crprecItem;
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && input.CropRecordingItemCode = "" or absent -> read from settings json
|
||||
//3 useExistingCropfieldWithChildren = true && input.CropRecordingItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> use this one
|
||||
if (useExistingCropfieldWithChildren == false)
|
||||
{
|
||||
_logger.LogInformation("RunCropRecordingTask ...");
|
||||
crprecItem = await _generalService.RunCropRecordingTask(cropfieldItem);
|
||||
_settings.CropRecordingItemCode = crprecItem.Code;
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(input.CropfieldItemCode))
|
||||
{
|
||||
_logger.LogInformation("reading CropRecordingItemCode from settings file");
|
||||
crprecItem = await _farmmapsApiService.GetItemAsync(_settings.CropRecordingItemCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("reading CropRecordingItemCode from KPIinput json");
|
||||
crprecItem = await _farmmapsApiService.GetItemAsync(input.CropRecordingItemCode);
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
|
||||
// Now add the operations
|
||||
List<Item> crpOperationItems = new List<Item> { };
|
||||
List<string> crpOperationItemCodes = new List<string> { };
|
||||
Item crpOperationItem;
|
||||
string dataOperation;
|
||||
string codeOperation;
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && input.OperationItemCode = "" or absent -> read from settings json
|
||||
//3 useExistingCropfieldWithChildren = true && input.OperationItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> use this one
|
||||
if (useExistingCropfieldWithChildren == false)
|
||||
{
|
||||
for (int i = 0; i < input.DataOperations.Length; i++)
|
||||
{
|
||||
dataOperation = input.DataOperations[i].ToString(Formatting.None);
|
||||
dynamic data = JObject.Parse(dataOperation);
|
||||
_logger.LogInformation($"CreateOperationItemAsync ... for operation {i}: '{data.name}', on date '{data.from}'");
|
||||
// Now check if the operation has a field called area
|
||||
string? opArea = data["area"];
|
||||
if (string.IsNullOrEmpty(opArea))
|
||||
{
|
||||
// if not having field area: add it to dataOperation ...
|
||||
input.DataOperations[i].Merge(Jarea);
|
||||
// ... and update the string
|
||||
dataOperation = input.DataOperations[i].ToString(Formatting.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if yes having field area: compare with polygon area. If not the same, throw warning
|
||||
if (data.area != area_ha)
|
||||
{
|
||||
double differencePercent = 100.0*(Convert.ToDouble(area_ha) / Convert.ToDouble(data.area) - 1.0);
|
||||
_logger.LogWarning($"cropfield has area {area_ha}, but in your KPIinput.json or file like that, you have an operation with area {data.area}" +
|
||||
$" Difference is {area_ha} / {data.area} - 100% = {differencePercent}%." +
|
||||
$" Is that correct? Example if operation was applied in part of field, e.g. in case of variable rate (VRA) application." +
|
||||
$" Or did you accidentally fill in area in the KPIinput json? To use cropfield area, omit field 'area' from json" +
|
||||
$" then the KPI applicataion will fill in area calculated from geometry");
|
||||
}
|
||||
}
|
||||
//Now after optionally adding the area, add the Operation to the crop recording
|
||||
crpOperationItem = await _generalService.CreateOperationItemAsync(crprecItem.Code, cropYear, fieldGeom, dataOperation);
|
||||
crpOperationItems.Add(crpOperationItem);
|
||||
crpOperationItemCodes.Add(crpOperationItem.Code);
|
||||
//Keep track of totalNferiliserInput
|
||||
//totalNferiliserInput = totalNferiliserInput + (double)data.n; / this causes a problem if N content of the fertilizer is missing. As this check is no longer needed I just commented it out
|
||||
}
|
||||
_settings.OperationItemCodes = crpOperationItemCodes.ToArray();
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(input.CropfieldItemCode))
|
||||
{
|
||||
_logger.LogInformation("reading OperationItemCode from settings file");
|
||||
for (int i = 0; i < _settings.OperationItemCodes.Length; i++)
|
||||
{
|
||||
codeOperation = _settings.OperationItemCodes[i];
|
||||
crpOperationItem = await _farmmapsApiService.GetItemAsync(codeOperation);
|
||||
crpOperationItems.Add(crpOperationItem);
|
||||