Compare commits
68 Commits
Author | SHA1 | Date | |
---|---|---|---|
fb92fa0d1c | |||
67e5cb6bb4 | |||
da82c232e3 | |||
752b538780 | |||
178ba1ea5b | |||
c2e4f9d861 | |||
6d6b5b1b7a | |||
fcf6b2af51 | |||
24feeba58e | |||
a98a81776d | |||
e05bb5a8f7 | |||
6faa5104c8 | |||
efb4d6833f | |||
0a9a83a5a6 | |||
fe2bd98589 | |||
ffbb45894a | |||
67014e20f5 | |||
84f27db16e | |||
d756f08b4c | |||
77532fee9f | |||
5d2789a806 | |||
dea4f102f5 | |||
39ee3263a7 | |||
619cb5e92c | |||
5399fd66df | |||
5d02370f56 | |||
e4087adc77 | |||
4761166472 | |||
9d691dfed1 | |||
d616fd3dfc | |||
3f66676914 | |||
aa18393102 | |||
0b0ec8f767 | |||
aef8c7c446 | |||
f1707c432f | |||
cfba86cf75 | |||
da808362c3 | |||
847ff75845 | |||
6d903c3e9b | |||
6eb36b2b4f | |||
7f3b87ae38 | |||
90f285a0d1 | |||
546ce131e4 | |||
d8c2ecb88b | |||
2d588026e2 | |||
1a9d5af5f6 | |||
8771e47b28 | |||
4102ed628e | |||
1cc36422a4 | |||
fedd363075 | |||
f04cc239d5 | |||
8a770a1762 | |||
b99191b7b1 | |||
9be9eb3145 | |||
641e09f833 | |||
8c5a0aed95 | |||
59f9ef4743 | |||
8bb5c6f581 | |||
7149086ce2 | |||
55f00da9d0 | |||
3d7bf186e7 | |||
8f8f857bf0 | |||
b7bedf182c | |||
be22d631bc | |||
7dda21dd77 | |||
c79e0d062c | |||
32138bef80 | |||
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>
|
||||
|
178
FarmmapsDownloadCL/DownloadCLApplication.cs
Normal file
178
FarmmapsDownloadCL/DownloadCLApplication.cs
Normal file
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
FarmmapsDownloadCL/DownloadCLInput.json
Normal file
5
FarmmapsDownloadCL/DownloadCLInput.json
Normal file
@ -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\
|
||||
}
|
27
FarmmapsDownloadCL/DownloadCLService.cs
Normal file
27
FarmmapsDownloadCL/DownloadCLService.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
24
FarmmapsDownloadCL/FarmmapsDownloadCL.csproj
Normal file
24
FarmmapsDownloadCL/FarmmapsDownloadCL.csproj
Normal file
@ -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>
|
169
FarmmapsDownloadCL/Models/CodelistsClasses.cs
Normal file
169
FarmmapsDownloadCL/Models/CodelistsClasses.cs
Normal file
@ -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; }
|
||||
|
||||
}
|
||||
}
|
12
FarmmapsDownloadCL/Models/DownloadCLInput.cs
Normal file
12
FarmmapsDownloadCL/Models/DownloadCLInput.cs
Normal file
@ -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; }
|
||||
|
||||
}
|
||||
}
|
21
FarmmapsDownloadCL/Program.cs
Normal file
21
FarmmapsDownloadCL/Program.cs
Normal file
@ -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>
|
||||
|
20
FarmmapsKPI/FarmmapsKPI.csproj
Normal file
20
FarmmapsKPI/FarmmapsKPI.csproj
Normal file
@ -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>
|
895
FarmmapsKPI/KPIApplication.cs
Normal file
895
FarmmapsKPI/KPIApplication.cs
Normal file
@ -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);
|
||||
crpOperationItemCodes.Add(crpOperationItem.Code);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("reading OperationItemCodes from KPIinput json");
|
||||
for (int i = 0; i < input.OperationItemCodes.Length; i++)
|
||||
{
|
||||
codeOperation = input.OperationItemCodes[i];
|
||||
crpOperationItem = await _farmmapsApiService.GetItemAsync(codeOperation);
|
||||
crpOperationItems.Add(crpOperationItem);
|
||||
crpOperationItemCodes.Add(crpOperationItem.Code);
|
||||
}
|
||||
_settings.OperationItemCodes = crpOperationItemCodes.ToArray();
|
||||
SaveSettings(settingsfile);
|
||||
}
|
||||
|
||||
// Inspect the children and grandchildren. If all is well, cropfield will have:
|
||||
// one crprec, with 0-many operations as children. And the Data of an operation will have specification of how much fertilizer / cropprotection agent was applied
|
||||
// one edicrop.characteristic (with yield in the data)
|
||||
cropfieldChildren = await _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code);
|
||||
crprecChildren = await _farmmapsApiService.GetItemChildrenAsync(crprecItem.Code);
|
||||
|
||||
//Check total operations
|
||||
int nOperationsInput = input.DataOperations.Length;
|
||||
int nOperationsCropfield = crprecChildren.Count;
|
||||
if (nOperationsInput != nOperationsCropfield)
|
||||
{
|
||||
_logger.LogWarning(String.Format($"1. run {run}: nOperationsInput != nOperationsCropfield?!"));
|
||||
//throw new Exception(String.Format($"run {run}: nOperationsInput != nOperationsCropfield?!"));
|
||||
}
|
||||
|
||||
|
||||
//Check totalNfertiliser input and Cropfield,
|
||||
//for (int o = 0; o < crprecChildren.Count; o++)
|
||||
//{
|
||||
// dynamic data = JObject.Parse(crprecChildren[o].Data.ToString());
|
||||
// totalNferiliserCropfield = totalNferiliserCropfield + (double)data.n;
|
||||
//}
|
||||
//if (totalNferiliserInput != totalNferiliserCropfield)
|
||||
//{
|
||||
// _logger.LogWarning(String.Format($"2. run {run}: totalNferiliserInput != totalNferiliserCropfield?!"));
|
||||
// //throw new Exception(String.Format($"run {run}: totalNferiliserInput != totalNferiliserCropfield?!"));
|
||||
//}
|
||||
|
||||
//Now get the KPIs for this cropfield, mounted with operations & cropyield
|
||||
List<Item> KPIItems = await _generalService.GetKpiItemsForCropField(cropfieldItem, 3);
|
||||
_logger.LogInformation($"GetKpiItemsForCropField('{cropfieldItem.Code}')");
|
||||
//Pesticide KPI's D1 and E1 are retreived from API's of CTBG and CLM and may take a bit longer to retrieve
|
||||
targetKPIitemsCount = 8; //if we know we should be getting 8 KPI items (A1,B1,B2,C1,D1,E1,F1,F2)
|
||||
trycnt = 0;
|
||||
bool boolAquaticLife = false;
|
||||
_logger.LogInformation($"Firing calls GetKpiItemsForCropField() until we have {targetKPIitemsCount} KPIitems, but don't keep firing forever, stop after {maxtries} calls");
|
||||
_logger.LogInformation($"Before we start:");
|
||||
//_logger.LogInformation($"* KPIItems.Count = {KPIItems.Count}");
|
||||
_logger.LogInformation($"* trycnt = {trycnt}");
|
||||
_logger.LogInformation($"* boolAquaticLife = {boolAquaticLife}");
|
||||
//additional criterion for while loop: check if it really contains the E1 mbp elements.
|
||||
//while (trycnt == 0 || ((KPIItems.Count < targetKPIitemsCount || boolAquaticLife == false) & trycnt < maxtries))
|
||||
targetKPIitemsCount = 8; //if we know we should be getting 8 KPI items (A1,B1,B2,C1,D1,E1,F1,F2)
|
||||
while (trycnt == 0 || (KPIItems.Count < targetKPIitemsCount & trycnt < maxtries))
|
||||
{
|
||||
_logger.LogInformation($"Call nr {trycnt + 1}");
|
||||
KPIItems = await _generalService.GetKpiItemsForCropField(cropfieldItem, 30); //number after comma is how many seconds per try, should be between 30 seconds and 5 minutes
|
||||
_logger.LogInformation($"Found {KPIItems.Count} KPI items");
|
||||
//boolAquaticLife = GetBoolAquaticLife(KPIItems);
|
||||
trycnt ++;
|
||||
}
|
||||
if (KPIItems.Count < targetKPIitemsCount) {
|
||||
_logger.LogWarning($"Found {KPIItems.Count} KPIItems while you were aiming for {targetKPIitemsCount} KPIItems");
|
||||
}
|
||||
|
||||
//Download KPI's into a json output file for this specific cropfield (with unique cropfieldItem.Code)
|
||||
string KPIItemPathJson = Path.Combine(downloadFolder, $"KPIItems_{cropfieldItem.Code}.json");
|
||||
var count = 0;
|
||||
foreach (Item item in KPIItems)
|
||||
{
|
||||
//Console.WriteLine($"KPI item #{count}: {item.Name}");
|
||||
File.AppendAllText(KPIItemPathJson, item.Data + Environment.NewLine);
|
||||
count++;
|
||||
}
|
||||
_logger.LogInformation($"Downloaded file {KPIItemPathJson}");
|
||||
_logger.LogInformation($"");
|
||||
|
||||
|
||||
//Remove duplicate KPI items
|
||||
List<Item> KPIItemsClean = new List<Item>();
|
||||
Item itemi;
|
||||
string id, idNext;
|
||||
double value, valueNext;
|
||||
int DuplicateCounter;
|
||||
value = 0;
|
||||
id = "";
|
||||
DuplicateCounter = 1;
|
||||
for (int i = 0; i < KPIItems.Count; i++)
|
||||
{
|
||||
itemi = KPIItems[i];
|
||||
idNext = JsonConvert.DeserializeObject<KPIOutput>(itemi.Data.ToString()).id;
|
||||
valueNext = Convert.ToDouble(JsonConvert.DeserializeObject<KPIOutput>(itemi.Data.ToString()).value);
|
||||
if (idNext != null)
|
||||
{
|
||||
if (id != idNext)
|
||||
{
|
||||
KPIItemsClean.Add(itemi);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueNext >= value)
|
||||
{
|
||||
//Remove the previous element from this list with same id but wrong value (valueNext > value) or duplicate value (valueNext == value). Presumes list is always sorted by kpiid, e.g. we may havce "
|
||||
KPIItemsClean.RemoveAt(i - DuplicateCounter); //added a duplicate counter to deal with calculations where there is more 1 duplicate.
|
||||
KPIItemsClean.Add(itemi);
|
||||
DuplicateCounter = DuplicateCounter + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Previous element was correct and already added so do nothing here
|
||||
}
|
||||
}
|
||||
id = idNext;
|
||||
value = valueNext;
|
||||
}
|
||||
}
|
||||
|
||||
////Order again from A zo Z.
|
||||
//List<Item> KPIItemsCleanSorted = new List<Item>();
|
||||
//for (int i = KPIItemsClean.Count - 1; i >= 0; i--)
|
||||
//{
|
||||
// KPIItemsCleanSorted.Add(KPIItemsClean[i]);
|
||||
//}
|
||||
|
||||
//Write to the csv file that collects all KPI's for all the crop fields
|
||||
List<string> dataList;
|
||||
foreach (Item item in KPIItemsClean)
|
||||
{
|
||||
kpio = JsonConvert.DeserializeObject<KPIOutput>(item.Data.ToString());
|
||||
if (kpio.id != null)
|
||||
{
|
||||
KPIelementsOfBalance kPIelementsOfBalance = kpio.data.values;
|
||||
if (kpio.id == "A1") //TtD
|
||||
{
|
||||
//Make a new dataList = new line to be written
|
||||
//Fill the datalist with this kpi
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity, // in KPI output quantity is what we call KPIvariable in headerlist of csv file
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
foreach (string elementName in kpio.A1elements)
|
||||
{
|
||||
// get A1element from the element called values
|
||||
// TtD 20240311: note elements of A1 are in the data structure elements of kpio.data and not as below for B1, B2, etc as kpio.data.values
|
||||
string elementValue = (string)kpio.data.GetType().GetProperty(elementName).GetValue(kpio.data, null);
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
elementName, // specific output variable name for A1 element
|
||||
elementValue, // specific output value name for A1 element
|
||||
kpio.unit,
|
||||
"",
|
||||
""
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
else if (kpio.id == "B1")
|
||||
{
|
||||
//Make a new dataList = new line to be written
|
||||
//Fill the datalist with this kpi
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity, // in KPI output quantity is what we call KPIvariable in headerlist of csv file
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
foreach (string elementName in kpio.B1elements)
|
||||
{
|
||||
// get B1element from the element called values
|
||||
string elementValue = (string)kPIelementsOfBalance.GetType().GetProperty(elementName).GetValue(kPIelementsOfBalance, null);
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
elementName, // specific output variable name for B1 element
|
||||
elementValue, // specific output value name for B1 element
|
||||
kpio.unit,
|
||||
"",
|
||||
""
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
//Check if totalNferiliserInput is equal to what comes out of the KPI calculation
|
||||
//if (elementName == "nFertilizerNKgHa")
|
||||
//{
|
||||
// if (totalNferiliserInput != Convert.ToDouble(elementValue))
|
||||
// {
|
||||
// _logger.LogWarning(String.Format($"3. run {run}: totalNferiliserInput != nFertilizerNKgHa"));
|
||||
// //throw new Exception(String.Format($"run {run}: totalNferiliserInput != nFertilizerNKgHa"));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
else if (kpio.id == "B2")
|
||||
{
|
||||
//Make a new dataList = new line to be written
|
||||
dataList = new List<string>
|
||||
{
|
||||
//Fill the datalist with this kpi
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity, // in KPI output quantity is what we call KPIvariable in headerlist of csv file
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
foreach (string elementName in kpio.B2elements)
|
||||
{
|
||||
// get B1element from the element called values
|
||||
string elementValue = (string)kPIelementsOfBalance.GetType().GetProperty(elementName).GetValue(kPIelementsOfBalance, null);
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
elementName, // specific output variable name for B2 element
|
||||
elementValue, // specific output value name for B2 element
|
||||
kpio.unit,
|
||||
"",
|
||||
""
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
|
||||
else if (kpio.id == "C1") //TtD
|
||||
{
|
||||
//Make a new dataList = new line to be written
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity, // in KPI output quantity is what we call KPIvariable in headerlist of csv file
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
foreach (string elementName in kpio.C1elements)
|
||||
{
|
||||
// get C1element from the element called values
|
||||
string elementValue = (string)kPIelementsOfBalance.GetType().GetProperty(elementName).GetValue(kPIelementsOfBalance, null);
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
elementName, // specific output variable name for C1 element
|
||||
elementValue, // specific output value name for C1 element
|
||||
kpio.unit,
|
||||
"",
|
||||
""
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
else if (kpio.id == "E1")
|
||||
{
|
||||
//for E1, environmentMeasureData is an array of elements with 1 per pesticide. Inside each element there are multiple mbp_KPIvariables to be written
|
||||
foreach (KPIenvironmentMeasureData e in kpio.data.environmentMeasureData)
|
||||
{
|
||||
foreach (string mbp_KPIvariable in mbp_KPIvariables)
|
||||
{
|
||||
if (mbp_KPIvariable == "aquaticLife") { mbp_KPIvalue = e.aquaticLife; } else if (mbp_KPIvariable == "groundWater") { mbp_KPIvalue = e.groundWater; } else if (mbp_KPIvariable == "soilLife") { mbp_KPIvalue = e.soilLife; } else { mbp_KPIvalue = ""; }
|
||||
//Make a new dataList = new line to be written
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id, //"E1"
|
||||
kpio.quantity, // "mbp"
|
||||
"", // not here the value
|
||||
"", // not here KPIunit for this indicator
|
||||
"", // not here KPItargetvalue for this indicator
|
||||
"", // not here KPIthresholdValue for this indicator
|
||||
e.productCode,
|
||||
e.productName,
|
||||
e.quantity,
|
||||
e.unitCode,
|
||||
e.date,
|
||||
mbp_KPIvariable,
|
||||
mbp_KPIvalue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (kpio.id == "G1") //TtD
|
||||
{
|
||||
//Make a new dataList = new line to be written
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity, // in KPI output quantity is what we call KPIvariable in headerlist of csv file
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
foreach (string elementName in kpio.G1elements)
|
||||
{
|
||||
// get G1element from the element called values
|
||||
string elementValue = (string)kPIelementsOfBalance.GetType().GetProperty(elementName).GetValue(kPIelementsOfBalance, null);
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
elementName, // specific output variable name for G1 element
|
||||
elementValue, // specific output value name for G1 element
|
||||
kpio.unit,
|
||||
"",
|
||||
""
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Any other KPI, (D1, F1, and F2), with just 1 record to write
|
||||
dataList = new List<string>
|
||||
{
|
||||
run.ToString(),
|
||||
kpio.parentName,
|
||||
cropfieldItem.Code,
|
||||
kpio.data.area,
|
||||
kpio.data.cropTypeCode,
|
||||
kpio.data.cropTypeName,
|
||||
kpio.id,
|
||||
kpio.quantity,
|
||||
kpio.value,
|
||||
kpio.unit,
|
||||
kpio.targetValue,
|
||||
kpio.thresholdValue
|
||||
};
|
||||
//Write the datalist to a line to the streamwrieter sw for the output csv file
|
||||
sw.WriteLine(string.Join(",", dataList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////Total N applied from input
|
||||
//double totalNapplied = 0.0;
|
||||
//double operationNapplied;
|
||||
//for (int i = 0; i < crpOperationItemCodes.Count; i++)
|
||||
//{
|
||||
// codeOperation = crpOperationItemCodes[i];
|
||||
// crpOperationItem = await _farmmapsApiService.GetItemAsync(codeOperation);
|
||||
// dynamic data = JObject.Parse(crpOperationItem.Data.ToString(Formatting.None));
|
||||
// if (data.n != null)
|
||||
// {
|
||||
// operationNapplied = crpOperationItem.Data.GetValue("n").ToObject<double>();
|
||||
// totalNapplied = totalNapplied + operationNapplied;
|
||||
// }
|
||||
//}
|
||||
////Also add totalNapplied to the csv
|
||||
//dataList = new List<string> { };
|
||||
//dataList.Add(kpioPrevious.parentName);
|
||||
//dataList.Add(cropfieldItem.Code);
|
||||
//try { dataList.Add(kpioPrevious.data.area); } catch { dataList.Add(""); };
|
||||
//try { dataList.Add(kpioPrevious.data.cropTypeCode); } catch { dataList.Add(""); };
|
||||
//try { dataList.Add(kpioPrevious.data.cropTypeName); } catch { dataList.Add(""); };
|
||||
//dataList.Add("");
|
||||
//dataList.Add("totalNapplied");
|
||||
//dataList.Add(totalNapplied.ToString());
|
||||
//dataList.Add("kg/ha");
|
||||
//dataList.Add("");
|
||||
//dataList.Add("");
|
||||
//sw.WriteLine(string.Join(",", dataList));
|
||||
|
||||
//Clean up. Only newly created fields
|
||||
//Look up instruction in Swagger / api / v1 / items /{ code}
|
||||
if (useExistingCropfieldWithChildren == false && input.DeleteNewlyCreatedAfterCalc == true)
|
||||
{
|
||||
// Tested and found that if I delete the parent (cropfieldItem) then
|
||||
// automatically deletes children (crprecItem, cropfieldCharacteristicItem, KPIcontainer)
|
||||
// and automatically deletes grand children (crprecItem: operations, KPIcontainer: KPI items)
|
||||
await _farmmapsApiService.DeleteItemAsync(cropfieldItem.Code);
|
||||
//Do we need to wait here for the task to be completed? Or does it continue in the background?
|
||||
//await Task.Delay(60000); // wait 60 secs for task to be completed
|
||||
//Before the GetItem you will see cropfieldItem, crprecItem etc exist (with data).
|
||||
//After the GetItem these cropfieldItem, crprecItem etc are null which means they have been succesfully deleted.
|
||||
//// Check if below works, i.e. is item really deleted?
|
||||
//cropfieldItem = await _farmmapsApiService.GetItemAsync(cropfieldItem.Code);
|
||||
//// Check if croprecording has also been deleted. If not also delete it
|
||||
//crprecItem = await _farmmapsApiService.GetItemAsync(crprecItem.Code);
|
||||
//// Check if 1 operation has also been deleted. If not also delete it
|
||||
//crpOperationItem = await _farmmapsApiService.GetItemAsync(crpOperationItemCodes[0]);
|
||||
//// Check if 1 cropfieldCharacteristicItem has also been deleted. If not also delete it
|
||||
//cropfieldCharacteristicItem = await _farmmapsApiService.GetItemAsync(cropfieldCharacteristicItem.Code);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions to save previously created cropfields
|
||||
private void LoadSettings(string file)
|
||||
{
|
||||
if (File.Exists(file))
|
||||
{
|
||||
var jsonText = File.ReadAllText(file);
|
||||
_settings = JsonConvert.DeserializeObject<Settings>(jsonText);
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings = new Settings();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveSettings(string file)
|
||||
{
|
||||
if (_settings == null)
|
||||
return;
|
||||
|
||||
var json = JsonConvert.SerializeObject(_settings);
|
||||
File.WriteAllText(file, json);
|
||||
}
|
||||
private void SaveInfo(string file)
|
||||
{
|
||||
if (_settings == null)
|
||||
return;
|
||||
|
||||
var json = JsonConvert.SerializeObject(_settings);
|
||||
File.WriteAllText(file, json);
|
||||
|
||||
}
|
||||
private string strTime(TimeSpan ts)
|
||||
{
|
||||
return String.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds);
|
||||
}
|
||||
|
||||
private bool GetBoolAquaticLife(List<Item> KPIItems)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (Item item in KPIItems)
|
||||
{
|
||||
KPIOutput kpio = JsonConvert.DeserializeObject<KPIOutput>(item.Data.ToString());
|
||||
if (kpio.id == "E1")
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (KPIenvironmentMeasureData e in kpio.data.environmentMeasureData)
|
||||
{
|
||||
if (e.aquaticLife != null)
|
||||
{
|
||||
found = true;
|
||||
_logger.LogInformation($"Found e.aquaticLife = {e.aquaticLife}");
|
||||
_logger.LogInformation("");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning($"NOT Found e.aquaticLife");
|
||||
_logger.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
891
FarmmapsKPI/KPIInput.json
Normal file
891
FarmmapsKPI/KPIInput.json
Normal file
@ -0,0 +1,891 @@
|
||||
[
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_Potato_ZeroFertilizer_Consumption_Sand",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
"productionPurposeCode": "003", //From codelist CL251. For testing, see case with consumption & starch potato
|
||||
"productionPurposeName": "consumption" //From codelist CL251
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [], //leaving the operations empty means no fertilizer is applied
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
//PO20231029: not different yields from different parts of fields?
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\Downloads\
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_Potato_ZeroFertilizer_Consumption_Clay",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "7", //From codelist CL405. Can no longer be omitted
|
||||
"soilName": "Clay", //From codelist CL405
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
"productionPurposeCode": "003", //From codelist CL251. For testing, see case with consumption & starch potato
|
||||
"productionPurposeName": "consumption" //From codelist CL251
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [], //leaving the operations empty means no fertilizer is applied
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
//PO20231029: not different yields from different parts of fields?
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\Downloads\
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_Potato_ZeroFertilizer_Starch_Sand",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
"productionPurposeCode": "002", //From codelist CL251. For testing, see case with consumption & starch potato
|
||||
"productionPurposeName": "starch" //From codelist CL251
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [], //leaving the operations empty means no fertilizer is applied
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
//PO20231029: not different yields from different parts of fields?
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\Downloads\
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "aardappelveld_test_Potato_cattlemanure144kgnha_plusUrea92kgNha",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "5", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Loam", //From codelist CL405.
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
//"rootDepthMax": 45, //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
//"emergenceDate": "2022-05-16T00:00:00", //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
"productionPurposeCode": "003", //From codelist CL251. Can be omitted if unknown
|
||||
"productionPurposeName": "consumption" //From codelist CL251. Can be omitted if unknown
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [
|
||||
{
|
||||
//"area": "0.08", //if leave empty then write code to fill in value from geometry (operation applied to whole field). Fill in different value if operation applied to part of the field (e.g. in case of variable rate application, VRA)
|
||||
"contractor": false,
|
||||
"designator": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"from": "2022-05-23T11:34:00",
|
||||
"method": "70400", //refers to codelist CL127 with operation methods
|
||||
"n": "92", //refers to codelist CL022 with fertilizer types & npk contents
|
||||
"name": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"product": "7360", //refers to codelist CL022 with fertilizer types
|
||||
//"type": "MAN", //indicates wether the fertilization is anorganic (MAN) or organic (MOR)
|
||||
"quantity": "200",
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "7", // refers to codelist CL018 consisting of main catergorie of operations. Code 7 stands for fertilization
|
||||
"to": "2022-05-23T12:34:00",
|
||||
"unit": "kg/ha",
|
||||
"unitCode": "KGMHAR"
|
||||
},
|
||||
{
|
||||
"k": "201.6",
|
||||
"n": "144",
|
||||
"p": "60.8",
|
||||
"to": "2022-04-19T09:19:00",
|
||||
//"area": "0.08", //if leave empty then write code to fill in value from geometry (operation applied to whole field). Fill in different value if operation applied to part of the field (e.g. in case of variable rate application, VRA)
|
||||
"from": "2022-04-19T08:19:00",
|
||||
"name": "Injecteren", //refers to codelist CL127 with operation methods
|
||||
"unit": "kg/ha",
|
||||
"method": "70700", //refers to codelist CL127 with operation methods
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "7", // refers to codelist CL018 consisting of main catergorie of operations. Code 7 stands for fertilization
|
||||
"product": "2329", //refers to codelist CL022 with fertilizer types
|
||||
//"type": "MAN",//indicates wether the fertilization is anorganic (MAN) or organic (MOR)
|
||||
"quantity": "32000",
|
||||
"unitCode": "KGMHAR",
|
||||
"contractor": false,
|
||||
"designator": "Injecteren"
|
||||
}
|
||||
],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "aardappelveld_test_Potato_Urea92kgNha",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "5", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Loam", //From codelist CL405.
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
//"rootDepthMax": 45, //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
//"emergenceDate": "2022-05-16T00:00:00", //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
"productionPurposeCode": "003", //From codelist CL251. Can be omitted if unknown
|
||||
"productionPurposeName": "consumption" //From codelist CL251. Can be omitted if unknown
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [
|
||||
{
|
||||
//"area": "0.08", //if leave empty then write code to fill in value from geometry (operation applied to whole field). Fill in different value if operation applied to part of the field (e.g. in case of variable rate application, VRA)
|
||||
"contractor": false,
|
||||
"designator": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"from": "2022-05-23T11:34:00",
|
||||
"method": "70400", //refers to codelist CL127 with operation methods
|
||||
"n": "92",
|
||||
"name": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"product": "7360", //refers to codelist CL022 with fertilizer types
|
||||
"quantity": "200",
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "7", // refers to codelist CL018 consisting of main catergorie of operations. Code 7 stands for fertilization
|
||||
"to": "2022-05-23T12:34:00",
|
||||
"unit": "kg/ha",
|
||||
"unitCode": "KGMHAR"
|
||||
}
|
||||
],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "aardappelveld_test_Potato_Urea92kgNha_ZuidLimburg",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "5", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Loam", //From codelist CL405.
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
//"rootDepthMax": 45, //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
//"emergenceDate": "2022-05-16T00:00:00", //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
"productionPurposeCode": "003", //From codelist CL251. Can be omitted if unknown
|
||||
"productionPurposeName": "consumption" //From codelist CL251. Can be omitted if unknown
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [
|
||||
{
|
||||
//"area": "0.08", //if leave empty then write code to fill in value from geometry (operation applied to whole field). Fill in different value if operation applied to part of the field (e.g. in case of variable rate application, VRA)
|
||||
"contractor": false,
|
||||
"designator": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"from": "2022-05-23T11:34:00",
|
||||
"method": "70400", //refers to codelist CL127 with operation methods
|
||||
"n": "92",
|
||||
"name": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "7", // refers to codelist CL018 consisting of main catergorie of operations. Code 7 stands for fertilization
|
||||
"product": "7360", //refers to codelist CL022 with fertilizer types
|
||||
"quantity": "200",
|
||||
"to": "2022-05-23T12:34:00",
|
||||
"unit": "kg/ha",
|
||||
"unitCode": "KGMHAR"
|
||||
}
|
||||
],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.900,
|
||||
50.800
|
||||
],
|
||||
[
|
||||
5.901,
|
||||
50.800
|
||||
],
|
||||
[
|
||||
5.901,
|
||||
50.801
|
||||
],
|
||||
[
|
||||
5.900,
|
||||
50.801
|
||||
],
|
||||
[
|
||||
5.900,
|
||||
50.800
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "caseQuoteNnotProvidedInDataOperations",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
//"rootDepthMax": 45, //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
//"emergenceDate": "2022-05-16T00:00:00", //not needed for KPI calculation, but shown here to know this is a possible property
|
||||
"productionPurposeCode": "003", //From codelist CL251. Can be omitted if unknown
|
||||
"productionPurposeName": "consumption" //From codelist CL251. Can be omitted if unknown
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [
|
||||
{
|
||||
//"area": "0.08", //if leave empty then write code to fill in value from geometry (operation applied to whole field). Fill in different value if operation applied to part of the field (e.g. in case of variable rate application, VRA)
|
||||
"contractor": false,
|
||||
"designator": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
"from": "2022-05-23T11:34:00",
|
||||
"method": "70400", //refers to codelist CL127 with operation methods
|
||||
//"n": "92",
|
||||
"name": "Kunstmest strooien", //refers to codelist CL127 with operation methods
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "7", // refers to codelist CL018 consisting of main catergorie of operations. Code 7 stands for fertilization
|
||||
"product": "7360", //refers to codelist CL022 with fertilizer types
|
||||
"quantity": "200",
|
||||
"to": "2022-05-23T12:34:00",
|
||||
"unit": "kg/ha",
|
||||
"unitCode": "KGMHAR"
|
||||
}
|
||||
],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "examplePesticide_11767N",
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
"dataCropfield": {
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"final": true, //always true
|
||||
"cropTypeCode": "1010101", //From codelist CL263
|
||||
"cropTypeName": "Potato", //From codelist CL263
|
||||
"productionPurposeCode": "003", //From codelist CL251. Can be omitted if unknown
|
||||
"productionPurposeName": "consumption" //From codelist CL251. Can be omitted if unknown
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [
|
||||
{
|
||||
"to": "2022-07-13T17:27:00",
|
||||
"from": "2022-07-13T16:27:00",
|
||||
"name": "Volveld spuiten (3/3)", //refers to codelist CL127 with operation methods
|
||||
"method": "80200", //refers to codelist CL127 with operation methods
|
||||
//"status": "3", // refers to codelist CL256. where 3 stand for completed. The status does not matter and is not used in the KPI calculations
|
||||
"operationCode": "8", // refers to codelist CL018 consisting of main catergorie of operations. Code 8 stands for crop protection
|
||||
"products": [
|
||||
{
|
||||
"product": "11767 N", //CTBG code, lookup via CTBG API. Important: with space N",
|
||||
"quantity": "1.25",
|
||||
"unitCode": "LTRHAR"
|
||||
//"designator": "Amistar"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619",
|
||||
"label": "cropyield",
|
||||
"value": "48.01"
|
||||
}
|
||||
],
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\Downloads\
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "doperwt_heleJaar",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"final": true, //always true
|
||||
"cropTypeCode": "1030101", //From codelist CL263
|
||||
"cropTypeName": "Garden pea" //From codelist CL263
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "9.58" //CBS: https://www.cbs.nl/nl-nl/cijfers/detail/37738, 2022: 40.4 Mkg / 4216 ha = 40400 / 4216
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
//"StartDate": "2022-04-15", //PO20231108: StartDate & EndDate important for legumes, where Nitrogen fixation depends on number of days from start to end. More days = more N fixation
|
||||
//"EndDate": "2022-07-30", // if StartDate & EndDate left empty then whole year from cropYear
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "doperwt_groeiperiode",
|
||||
"CropfieldItemCode": "",
|
||||
"dataCropfield": {
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"final": true, //always true
|
||||
"cropTypeCode": "1030101", //From codelist CL263
|
||||
"cropTypeName": "Garden pea" //From codelist CL263
|
||||
},
|
||||
"CropRecordingItemCode": "",
|
||||
"OperationItemCodes": [],
|
||||
"dataOperations": [],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "9.58" //CBS: https://www.cbs.nl/nl-nl/cijfers/detail/37738, 2022: 40.4 Mkg / 4216 ha = 40400 / 4216
|
||||
}
|
||||
],
|
||||
//"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\
|
||||
"CropYear": 2022,
|
||||
"StartDate": "2022-04-15", //PO20231108: StartDate & EndDate important for legumes, where Nitrogen fixation depends on number of days from start to end. More days = more N fixation
|
||||
"EndDate": "2022-07-30", // if StartDate & EndDate left empty then whole year from cropYear
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_WinterWheat_DefaultStrawRemainsInField",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"cropTypeCode": "1020101", //From codelist CL263
|
||||
"cropTypeName": "Winter wheat" //From codelist CL263
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [], //leaving the operations empty means no fertilizer is applied
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
//PO20231029: not different yields from different parts of fields?
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "10.0"
|
||||
}
|
||||
],
|
||||
//"DownloadFolder": "Downloads", //"C:\\hugoschrererdir\\kpidir\\", // "Downloads", -> if you just put "Downloads" the program will download to somewhere in ..\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\Downloads\
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_WinterWheat_StrawRemovedFromField",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"cropTypeCode": "1020101", //From codelist CL263
|
||||
"cropTypeName": "Winter wheat" //From codelist CL263
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [], //leaving the operations empty means no fertilizer is applied
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
//PO20231029: not different yields from different parts of fields?
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "10.0"
|
||||
},
|
||||
{
|
||||
"code": "fm009", //TODO: which codelist?
|
||||
"label": "strawyield",
|
||||
"value": "6.8"
|
||||
}
|
||||
],
|
||||
"CropYear": 2022,
|
||||
//geometryJson = polygon of location of the cropfield, coordinates in LON,LAT (LON: decimal degrees East, LAT: decimal degrees North)
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"useExistingCropfieldWithChildren": false,
|
||||
"deleteNewlyCreatedAfterCalc": true,
|
||||
"fieldName": "test_WinterWheat_greenmanure",
|
||||
//Note when you run the FarmmapsKPI project, somewhere to your C:\git\FarmMapsApiClient_KB34_MAST\FarmmapsKPI\bin\Debug\netcoreapp3.1\ directory, files named like this are written:
|
||||
//'Settings_aardappelveld_test_Potato_ZeroFertilizer.json', where 'aardappelveld_test_Potato_ZeroFertilizer.json' is your fieldName (see below)
|
||||
//1 useExistingCropfieldWithChildren = false -> create new
|
||||
//2 useExistingCropfieldWithChildren = true && CropfieldItemCode = "" or absent -> read fieldName (see below) -> read all codes from settings json file
|
||||
//3 useExistingCropfieldWithChildren = true && CropfieldItemCode like "deb48a74c5b54299bb852f17288010e9" in KPIinput -> if you have in your account already an existing cropfield then use that
|
||||
"CropfieldItemCode": "", // could contain for example this: "abae97f89f3c4ac08953b1b8bea9f076" if this is an exisiting CropfieldItemCode in your account.
|
||||
//And then if useExistingCropfieldWithChildren = true, this would be used.
|
||||
"dataCropfield": {
|
||||
//"area": 4.22, //Leave empty, KPI app will calculate it from geometry
|
||||
"final": true, //always true
|
||||
"soilCode": "1", //From codelist CL405. Can be no longer be omitted
|
||||
"soilName": "Sand",
|
||||
"cropTypeCode": "1020101", //From codelist CL263
|
||||
"cropTypeName": "Winter wheat" //From codelist CL263
|
||||
},
|
||||
"CropRecordingItemCode": "", // could contain for example this: "314aa1b6480b493ba28a5f55039a01d4" if this is the CropRecordingItemCode of the provided CropfieldItemCode. And then if useExistingCropfieldWithChildren = true, this would be used
|
||||
"OperationItemCodes": [], // could contain for example this: ["4d1a6f28ea3f414180663baa4b08c60f"] or ["4d1a6f28ea3f414180663baa4b08c60f","21e08386f0454ad79acfebf78649d59b"] if these are the operations of the provided CropRecordingItemCode. And then if useExistingCropfieldWithChildren = true, these would be used
|
||||
"dataOperations": [],
|
||||
"CropfieldCharacteristicItemCode": "",
|
||||
"DataCropfieldCharacteristics": [
|
||||
{
|
||||
"code": "860619", //From codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
"label": "cropyield",
|
||||
"value": "10"
|
||||
},
|
||||
{
|
||||
"code": "501505", //From codelist CL265. 501505 refers to green manure after main crop.
|
||||
"label": "cropgreenmanureaftercultivation",
|
||||
"value": "1040102", // Code is from CL263. You can put any CL263 crop here. However, the KPI app only works with a limited selection of greenmanure crops, see CL104 for the names.
|
||||
//"cropHeight": 100, //optional input. Height of greemmanure in cm.
|
||||
//"plantingDate": "2022-08-01T12:34:00" // optional input. Plantingsdate of greenmanure. required layout "2022-07-23T12:34:00".
|
||||
}
|
||||
],
|
||||
"CropYear": 2022,
|
||||
"geometryJson": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
],
|
||||
[
|
||||
5.598645994070678,
|
||||
52.571540800206236
|
||||
],
|
||||
[
|
||||
5.599381743127071,
|
||||
52.57012773140724
|
||||
],
|
||||
[
|
||||
5.595408698222548,
|
||||
52.56968054825188
|
||||
],
|
||||
[
|
||||
5.5945257993548765,
|
||||
52.57080744107003
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
27
FarmmapsKPI/KPIService.cs
Normal file
27
FarmmapsKPI/KPIService.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using FarmmapsApi.Models;
|
||||
using FarmmapsApi.Services;
|
||||
using FarmmapsKPI.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static FarmmapsApi.Extensions;
|
||||
using static FarmmapsApiSamples.Constants;
|
||||
|
||||
namespace FarmmapsKPI
|
||||
{
|
||||
public class KPIService
|
||||
{
|
||||
private readonly ILogger<KPIService> _logger;
|
||||
private readonly FarmmapsApiService _farmmapsApiService;
|
||||
private readonly GeneralService _generalService;
|
||||
|
||||
public KPIService(ILogger<KPIService> logger, FarmmapsApiService farmmapsApiService,
|
||||
GeneralService generalService)
|
||||
{
|
||||
_logger = logger;
|
||||
_farmmapsApiService = farmmapsApiService;
|
||||
_generalService = generalService;
|
||||
}
|
||||
}
|
||||
}
|
28
FarmmapsKPI/KPIdefinitions.csv
Normal file
28
FarmmapsKPI/KPIdefinitions.csv
Normal file
@ -0,0 +1,28 @@
|
||||
KPIid,KPIvariable,Description,Calculated,KPItargetvalue,KPIthresholdValue
|
||||
A1,yield,observed yield,User input,target value as in benchmark value for same crop in same region. E.g. cropyield target is from Central Bureau of Statistics (CBS) for same crop in region in which the cropfield (geometry) is located.,No threshold for this KPI.
|
||||
A1,strawYield,straw yield; value 0 or not filled in = straw remains in field; value > 0 means straw was exported,User input,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,nitrogen,Nitrogen surplus = N artifical fertilizer + N manure+ N atmospheric deposition + N fixation by crop + N from seed potatoes - N removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yield and fertilizer/manure applications.,The target value depends on the soil type. To calculate the threshold and target values data from CBS and RIVM are used. The same calculation method is also used in biodiversiteitsmonitoring akkerbouw (https://www.bo-akkerbouw.nl/kennis-en-innovatie/pps-biodiversiteitsmonitor-akkerbouw).,The threshold value depends on soil type and groundwater levels. To calculate the threshold and target values data from CBS and RIVM are used. The same calculation method is also used in biodiversiteitsmonitoring akkerbouw (https://www.bo-akkerbouw.nl/kennis-en-innovatie/pps-biodiversiteitsmonitor-akkerbouw).
|
||||
B1,nHarvestedKgHa, N removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yield.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,nHarvestedStrawKgHa, N removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yieldStraw.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,nFixationNKgHa, N fixated by crop (legumes only). ,Calculated KPI internal model & parameters and from user input: planting date,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,nDepositionNKgHa, N deposition,Based on RIVM maps. Value depens on location,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,nFertilizerNKgHa, N from artifical fertilizers and manure.,KPI internal model & parameters and from user input: fertilizer/manure applications.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B1,sowPlantingNKgHa, N from seed potatoes (potatoes only). ,Calculated KPI internal model & parameters and from user input: amount of planted seed potatoes,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B2,phosphate,Phosphate surplus = P fertilizer + P from seed potatoes - P removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yield and fertilizer applications ,The phosphate target value is set at 20 kg/ha ,No threshold for this KPI.
|
||||
B2,pHarvestedKgHa, P2O5 removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yield,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B2,pHarvestedStrawKgHa, P2O5 removal through harvested product. ,Calculated KPI internal model & parameters and from user input: yieldStraw,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B2,pFertillizerPKgHa, P2O5 from artifical fertilizers and manure.,Calculated KPI internal model & parameters and from user input: fertilizer/manure applications.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
B2,sowPlantingPKgHa, P2O5 from seeds potatoes (potatoes only). ,Calculated KPI internal model & parameters and from user input: amount of planted seed potatoes,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
C1,effective organic matter supply,"Organic matter supply = Organic matter from manure + Crop residues to soil + organic matter from green manure. ""Effective"" means netto, after correction for carbon respiration by soil microbial activity",Calculated KPI internal model & parameters and from user input: yield and manure applications.,The target value for this KPI is the amount of EOM that companies with ‘ Goede Landbouwpraktijk’ supply (2500 kg EOM/ha/year). ,The threshold value is 2000 kg EOM/ha/year. This value comes from van Doorn et al. (2022) which states that on average 2000 kg of EOM/ha degrades on Dutch agricultural land. This is the also the threshold value from biodiversiteitsmonitoring akkerbouw (https://www.bo-akkerbouw.nl/kennis-en-innovatie/pps-biodiversiteitsmonitor-akkerbouw)
|
||||
C1,fertilizerEom,"Effective organic matter added through fertilizer (animal manure, compost, etc). ",Calculated KPI internal model & parameters and from user input: manure applications.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
C1,greenManureEom,Effective organic matter added through green manure (also called cover crop). ,Calculated KPI internal model & parameters and from user input: cover crop.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
C1,cropLeftoversEom,Effective organic matter added through crop residues of main product and (when relevant) straw.,Calculated KPI internal model & parameters.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
D1,pesticides,"kg/ha of active ingredient. Sum over kg a.i. of the different crop protection agents applied, with concentration (kg a.i. / kg or litre) of crop protection agents ",Retrieved from CTBG,The target value fort his KPI is to reduce pesticide use to 50% of the amount used in the Netherlands during 2020. Data for 2020 is obtained from CBS statline ,No threshold for this KPI.
|
||||
E1,mpb,"milieubelastingspunten. For each pesticide applied show 3 sub-mbp's: aquaticLife, groundWater, soilLife",Retrieved from CTBG,"0 applications with exceedances of either the target MBP or risks. MBP's consist of three categories (groundwater, soil life, and aquatic life). An value of <100 in either or these categories counts as exceedance. Each application of pesticides cannot have more then one exceedance for MBP. Risks consist of two categories (natural enemies and pollinators), a value of B or C in either category counts as exceedance. Each application of pesticides cannot have more then one exceedance for risks. Values and methodology come from Environmental Yardstick for Pesticides (https://www.milieumeetlat.nl/). The same calculation method is also used in biodiversiteitsmonitoring akkerbouw (https://www.bo-akkerbouw.nl/kennis-en-innovatie/pps-biodiversiteitsmonitor-akkerbouw).","0 applications with exceedances of either the target MBP or risks. MBP's consist of three categories (groundwater, soil life, and aquatic life). An value of <10 in either or these categories counts as exceedance. Each application of pesticides cannot have more then one exceedance for MBP. Risks consist of two categories (natural enemies and pollinators), a value of B or C in either category counts as exceedance. Each application of pesticides cannot have more then one exceedance for risks. Values and methodology come from Environmental Yardstick for Pesticides (https://www.milieumeetlat.nl/). The same calculation method is also used in biodiversiteitsmonitoring akkerbouw (https://www.bo-akkerbouw.nl/kennis-en-innovatie/pps-biodiversiteitsmonitor-akkerbouw)."
|
||||
F1,greenness,time of year that the field was covered. ,Based on NDVI data from AgroDataCube.,Target value is 75%.,Threshold value is 25%.
|
||||
F2,rotationindex,index of diversity of crops over time. ,Calculated in AgroDataCube,Target value is 75%.,Threshold value is 25%.
|
||||
G1,ammonia emissions,"ammonia emissions from crop residues, green manure, artificial fertilizers and organic fertilizers.",Calculated KPI internal model & parameters and from user input: fertilizer/manure applications.,There is not target value yet for this KPI. Currently has a dummy value of 9999.,There is not target value yet for this KPI. Currently has a dummy value of 9999.
|
||||
G1,Manure,ammonia emissions from manure.,Calculated KPI internal model & parameters and from user input: manure applications.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
G1,GreenManure,ammonia emissions from green manure (also called cover crop). ,Calculated KPI internal model & parameters.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
G1,CropResidues,ammonia emissions from crop residues. ,Calculated KPI internal model & parameters.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
||||
G1,ArtificialFertilize,ammonia emissions from artificial fertilizers ,Calculated KPI internal model & parameters and from user input: artificial fertilizer applications.,there are no target values for individual compenets of KPI's,there are no threshold values for individual compenets of KPI's
|
|
26
FarmmapsKPI/Models/KPIInput.cs
Normal file
26
FarmmapsKPI/Models/KPIInput.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace FarmmapsKPI.Models
|
||||
{
|
||||
public class KPIInput
|
||||
{
|
||||
public bool UseExistingCropfieldWithChildren { get; set; }
|
||||
public bool DeleteNewlyCreatedAfterCalc { get; set; }
|
||||
public string fieldName { get; set; }
|
||||
public string CropfieldItemCode { get; set; }
|
||||
public JObject DataCropfield { get; set; }
|
||||
public string CropRecordingItemCode { get; set; }
|
||||
public JObject DataCropRecording { get; set; }
|
||||
public string[] OperationItemCodes { get; set; }
|
||||
public JObject[] DataOperations { get; set; }
|
||||
public string CropfieldCharacteristicItemCode { get; set; }
|
||||
public JObject[] DataCropfieldCharacteristics { get; set; }
|
||||
public string DownloadFolder { get; set; }
|
||||
public int CropYear { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public JObject GeometryJson { get; set; }
|
||||
|
||||
}
|
||||
}
|
79
FarmmapsKPI/Models/KPIoutput.cs
Normal file
79
FarmmapsKPI/Models/KPIoutput.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace FarmmapsKPI.Models
|
||||
{
|
||||
public class KPIOutput
|
||||
{
|
||||
public string id { get; set; }
|
||||
public KPIOutputData data { get; set; }
|
||||
public string type { get; set; }
|
||||
public string unit { get; set; }
|
||||
public string value { get; set; }
|
||||
public string duration { get; set; }
|
||||
public string quantity { get; set; }
|
||||
public string parentName { get; set; }
|
||||
public string targetValue { get; set; }
|
||||
public string thresholdValue { get; set; }
|
||||
|
||||
public List<string> A1elements; //TtD
|
||||
public List<string> B1elements;
|
||||
public List<string> B2elements;
|
||||
public List<string> C1elements;
|
||||
public List<string> G1elements; //TtD
|
||||
public KPIOutput()
|
||||
{
|
||||
this.A1elements = new List<string>() { "yield", "strawYield" }; //TtD
|
||||
this.B1elements = new List<string>() { "nHarvestedKgHa", "nHarvestedStrawKgHa", "nFixationNKgHa", "nDepositionNKgHa","nFertilizerNKgHa","sowPlantingNKgHa" }; //TtD
|
||||
this.B2elements = new List<string>() { "pHarvestedKgHa", "pHarvestedStrawKgHa", "pFertillizerPKgHa", "sowPlantingPKgHa" }; //TtD
|
||||
this.C1elements = new List<string>() { "fertilizerEom", "greenManureEom", "cropLeftoversEom" }; //TtD to do rename
|
||||
this.G1elements = new List<string>() { "Manure", "GreenManure", "CropResidues", "ArtificialFertilize" }; //TtD
|
||||
}
|
||||
}
|
||||
public class KPIOutputData
|
||||
{
|
||||
public string area { get; set; }
|
||||
public string cropTypeCode { get; set; }
|
||||
public string cropTypeName { get; set; }
|
||||
public string yield { get; set; }
|
||||
public string strawYield { get; set; }
|
||||
|
||||
public KPIelementsOfBalance values { get; set; }
|
||||
public KPIenvironmentMeasureData[] environmentMeasureData { get; set; }
|
||||
|
||||
}
|
||||
public class KPIenvironmentMeasureData
|
||||
{
|
||||
public string date { get; set; }
|
||||
public string productCode { get; set; }
|
||||
public string productName { get; set; }
|
||||
public string quantity { get; set; }
|
||||
public string unitCode { get; set; }
|
||||
public string soilLife { get; set; }
|
||||
public string aquaticLife { get; set; }
|
||||
public string groundWater { get; set; }
|
||||
}
|
||||
public class KPIelementsOfBalance
|
||||
{
|
||||
public string yield { get; set; } //TtD
|
||||
public string strawYield { get; set; } //TtD
|
||||
public string nHarvestedKgHa { get; set; } //TtD
|
||||
public string nHarvestedStrawKgHa { get; set; } //TtD
|
||||
public string nFixationNKgHa { get; set; }
|
||||
public string nDepositionNKgHa { get; set; }
|
||||
public string nFertilizerNKgHa { get; set; }
|
||||
public string sowPlantingNKgHa { get; set; }
|
||||
public string pHarvestedKgHa { get; set; } //TtD
|
||||
public string pHarvestedStrawKgHa { get; set; } //TtD
|
||||
public string pFertillizerPKgHa { get; set; } //TtD
|
||||
public string sowPlantingPKgHa { get; set; } //TtD
|
||||
public string fertilizerEom { get; set; } //TtD
|
||||
public string greenManureEom { get; set; } //TtD
|
||||
public string cropLeftoversEom { get; set; } //TtD tamara: rename
|
||||
public string Manure { get; set; } //TtD
|
||||
public string GreenManure { get; set; } //TtD
|
||||
public string CropResidues { get; set; } //TtD
|
||||
public string ArtificialFertilize { get; set; } //TtD
|
||||
}
|
||||
}
|
11
FarmmapsKPI/Models/Settings.cs
Normal file
11
FarmmapsKPI/Models/Settings.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace FarmmapsKPI
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public string CropfieldItemCode { get; set; }
|
||||
public string CropRecordingItemCode { get; set; }
|
||||
public string[] OperationItemCodes { get; set; }
|
||||
public string CropfieldCharacteristicItemCode { get; set; }
|
||||
|
||||
}
|
||||
}
|
21
FarmmapsKPI/Program.cs
Normal file
21
FarmmapsKPI/Program.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Threading.Tasks;
|
||||
using FarmmapsApi;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FarmmapsKPI
|
||||
{
|
||||
class Program : FarmmapsProgram<KPIApplication>
|
||||
{
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
await new Program().Start(args);
|
||||
}
|
||||
|
||||
protected override void Configure(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddLogging()
|
||||
.AddTransient<KPIService>();
|
||||
}
|
||||
}
|
||||
}
|
66
FarmmapsKPI/TODO.txt
Normal file
66
FarmmapsKPI/TODO.txt
Normal file
@ -0,0 +1,66 @@
|
||||
TODO.txt
|
||||
|
||||
###################################################################################################
|
||||
# 1. DONE
|
||||
###################################################################################################
|
||||
Laat de farmmapsKPI zelf maar uitzoeken wat de n-p gehaltes zijn:
|
||||
a. We willen als input opgeven we hebben 400 kg/ha urea gegeven, of 32000 kg/ha runderdrijfmest.
|
||||
Daarvoor wel de juiste gewas code opgeven -> zie onder, FarmmapsEditeeltList 263 gewassen
|
||||
Daarvoor wel de juiste meststof code opgeven -> zie onder, FarmmapsEditeeltList 022 meststoffen
|
||||
b. Check of de operation data een element “n” bevat. Zoniet of als waarde 0, dan
|
||||
i. Zoek onder de motorkap op: de omreken factor (bijv 200 kg/ha urea met 46% n -> 200*0.46 = 92 kg N/ha)
|
||||
ii. Voeg die 92 toe aan de operation data ("n": 92)
|
||||
c. Reken N surplus uit (KPI item id b1)
|
||||
GEPARKEERD:
|
||||
Want voor veel meststoffen is geen content bekend -> automatisch opzoeken zal in veel gevallen niet goed werken
|
||||
Laat de gebruiker zelf maar de codelist CL022 raadplegen en omrekenen.
|
||||
|
||||
Nieuw project: FarmmapsEditeeltLists DONE
|
||||
a. Why? Because
|
||||
i. This is (1) so that we can at any time retrieve the most recent up-to-date list
|
||||
ii. so that you can look up crops and fertilizer types and fill in KPIinput.json correctly
|
||||
b. Download full list of items from vnd.farmmaps.itemtype.codelist.cl263 DONE
|
||||
c. Write them to a csv file DONE
|
||||
d. In any case following lists: 127 operations DONE; 022 meststoffen (fertilizer products) DONE; 263 gewassen DONE; 405 soilcode DONE
|
||||
in which list the productionPurposeCode 251 DONE
|
||||
|
||||
Testing:
|
||||
Effect of soiltype (e.g. different N concents in crop depending on soiltype? (CL405))
|
||||
DONE (using KPIinput.json): same N balance, different target & threshold
|
||||
Effect of location (e.g. different atmospheric N deposition).
|
||||
DONE (using KPIinput.json): slightly different N balance
|
||||
|
||||
"DataCropfieldCharacteristic": {
|
||||
"code": "860619", //PO20231004: so what does this code mean? Can we see the code list somewhere? COMPLETED code comes from codelist CL265. 860619 refers to cropyield in ton/ha
|
||||
productionPurposeCode: different result depending on starch or consumption potato (different N contents in tubers)?
|
||||
nContentFactor seems not to be adjusted by productionPurposeCode. Tamara check with Francisco
|
||||
idem for pContentFactor
|
||||
DONE (using KPIinput.json): surprisingly no effect?, format of the productionPurposeCode was wrong i.e was '002' instead of '2'. Format has been adjusted.
|
||||
dataOperations: "operationCode": "7" & "8": DONE
|
||||
a. which codelist? What does it mean? this refers to CL018 (bewerkinghoofdcaterogie), which contains information about the caterogie of the crop operations.
|
||||
7 stands for fertilization while 8 refers to crop protection
|
||||
b. using KPIinput.json: does it have an effect on KPI outcomes? YES
|
||||
dataOperations: "status": "3": DONE
|
||||
a. which codelist? What does it mean? this refers to CL256 (statusBewerking), which contains information about a crop operation has been planned, completed, cancelled etc. 3 refers to completed
|
||||
b. using KPIinput.json: does it have an effect on KPI outcomes? NO, even without the status the crop operations is included in the KPI calculation.
|
||||
As the status has no effect on the KPI calculations I have changed the lines about the status in the KPIinput.json file to comment
|
||||
|
||||
KPIelementsOfBalance: Tamara
|
||||
a. define elements for C1 organic matter supply
|
||||
b. for nitrogen B1 rename disposal to nHarvestedNKgHa COMPLETED
|
||||
c. for phosporous B2 rename disposal to pHarvestedPKgHa COMPLETED
|
||||
d. for phosporous B2 rename from pFertilizerNKgHa to pFertilizerPKgHa COMPLETED
|
||||
e. idem sowPlantingNKgHa COMPLETED
|
||||
f. add straw for N & P in output COMPLETED
|
||||
g. add 2 examples in KPIinput.json: straw yes/no removed. Bijv. nStrawLeftInField EN nStrawRemoved COMPLETED
|
||||
h. add amount of removed straw in A1 COMPLETED
|
||||
i. update KPIdefinitions.csv COMPLETED
|
||||
|
||||
###################################################################################################
|
||||
# 2. Pending
|
||||
###################################################################################################
|
||||
Testing:
|
||||
|
||||
KPIelementsOfBalance: Tamara
|
||||
j. for C1 rename 'cropLeftoversEom' to 'cropResiduesEom' GEPARKEERD
|
||||
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,7 @@
|
||||
##### NOT PRODUCTION READY CODE, JUST AN EXAMPLE
|
||||
|
||||
Put your clientId and clientSecret or your Farmmaps-account data (username and password) in a newly created appsettings.secrets.json file inside the root of the Secrets project.
|
||||
Clone the git repository to a local drive. DON'T clone to a network drive like "My Documents". Latter may cause authentication problems.
|
||||
|
||||
**appsettings.secrets.json**
|
||||
```
|
||||
|
@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,11 +2,11 @@
|
||||
//There are three farmmaps environments, uncomment the environemnt you want to use with this sample client
|
||||
|
||||
//test environment
|
||||
"Authority": "https://accounts.test.farmmaps.eu/",
|
||||
"Endpoint": "https://test.farmmaps.eu/",
|
||||
"BasePath": "api/v1",
|
||||
"DiscoveryEndpointUrl": "https://accounts.test.farmmaps.eu/.well-known/openid-configuration",
|
||||
"GrantClientId": "farmmapstesteu",
|
||||
//"Authority": "https://accounts.test.farmmaps.eu/",
|
||||
//"Endpoint": "https://test.farmmaps.eu/",
|
||||
//"BasePath": "api/v1",
|
||||
//"DiscoveryEndpointUrl": "https://accounts.test.farmmaps.eu/.well-known/openid-configuration",
|
||||
//"GrantClientId": "farmmapstesteu",
|
||||
|
||||
////acceptance environment
|
||||
//"Authority": "https://accounts.acc.farmmaps.eu/",
|
||||
@ -16,11 +16,11 @@
|
||||
//"GrantClientId": "farmmapsacceu",
|
||||
|
||||
////production environment
|
||||
//"authority": "https://accounts.farmmaps.eu/",
|
||||
//"endpoint": "https://farmmaps.eu/",
|
||||
//"basepath": "api/v1",
|
||||
//"discoveryendpointurl": "https://accounts.farmmaps.eu/.well-known/openid-configuration",
|
||||
//"GrantClientId": "farmmaps",
|
||||
"authority": "https://accounts.farmmaps.eu/",
|
||||
"endpoint": "https://farmmaps.eu/",
|
||||
"basepath": "api/v1",
|
||||
"discoveryendpointurl": "https://accounts.farmmaps.eu/.well-known/openid-configuration",
|
||||
"GrantClientId": "farmmaps",
|
||||
|
||||
//overige info
|
||||
"RedirectUri": "http://example.nl/api",
|
||||
|
Loading…
Reference in New Issue
Block a user