/**
* Import Script für Biohof Sonnenacker Datensatz
* Importiert deutsche Bio-Farm-Daten in LiteFarm
*/
import dotenv from "dotenv";
import { LiteFarmClient } from "./litefarm-client.js";
// Load environment variables
dotenv.config();
// Biohof Sonnenacker Datensatz
const BIOHOF_DATA = {
"FarmDetails": {
"FarmName": "Biohof Sonnenacker (DE)",
"Location": "Nordrhein-Westfalen, Deutschland",
"Certification": "EU-Ökologischer Landbau (DE-ÖKO-XXX)",
"TotalArea_ha": 63.0,
"ReportingPeriod": "2023-2025 (3 Anbaujahre)",
"Target": "Nachhaltige Ertragssteigerung bei Reduzierung der externen Betriebsmittel"
},
"FieldsAndCrops": [
{
"FieldID": "F-01",
"FieldName": "Acker West",
"Area_ha": 6.0,
"SoilType": "Löss-Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Winterweizen (Bio-Sorte 'Mulan')",
"WaterSupply": {
"Rainfall_mm": 550,
"Irrigation_m3_ha": 0,
"Comment": "Ausreichend Niederschlag"
},
"Fertilization": [
{"Date": "2023-03-15", "Type": "Rindermist (fest)", "Quantity_t_ha": 20, "N_total_kg_ha": 80},
{"Date": "2023-04-20", "Type": "Vinasse", "Quantity_l_ha": 300, "N_total_kg_ha": 15}
],
"Observations": [
{
"Date": "2023-05-10",
"Type": "Schädlingsbefall",
"Indicator": "starke Vergilbung untere Blätter, klebrige Stellen, vereinzelt **Blattläuse** an Ährenbeginn",
"Severity_Index_0_10": 7.5,
"ProblemScenario": "**Mittelschwerer Blattlausbefall** aufgrund warmer, trockener Phase im Mai. Ertragseinbuße erwartet.",
"ActionTaken": "Förderung von Nützlingen (Blühstreifen), keine direkte Behandlung (Bio-Auflage)"
}
],
"Yield_t_ha": 3.5,
"HarvestQuality_Index_0_10": 6.8
},
{
"Year": 2024,
"Crop": "Kartoffeln (Bio-Sorte 'Gunda')",
"WaterSupply": {
"Rainfall_mm": 380,
"Irrigation_m3_ha": 1200,
"Comment": "**Dürre-Jahr**, hohe Bewässerungsnotwendigkeit"
},
"Fertilization": [
{"Date": "2024-03-25", "Type": "Kompost", "Quantity_t_ha": 25, "N_total_kg_ha": 75}
],
"Observations": [],
"Yield_t_ha": 28.0,
"HarvestQuality_Index_0_10": 8.5
}
]
},
{
"FieldID": "F-02",
"FieldName": "Mittelstück",
"Area_ha": 5.5,
"SoilType": "Sandiger Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Hafer (Bio-Sorte 'Poseidon')",
"WaterSupply": {
"Rainfall_mm": 600,
"Irrigation_m3_ha": 0,
"Comment": "Normales Jahr"
},
"Fertilization": [
{"Date": "2023-04-05", "Type": "Gründüngung (abgemulcht)", "Quantity_t_ha": 5, "N_total_kg_ha": 30}
],
"Observations": [],
"Yield_t_ha": 4.2,
"HarvestQuality_Index_0_10": 8.0
},
{
"Year": 2024,
"Crop": "Dinkel (Bio-Sorte 'Frankenkorn')",
"WaterSupply": {
"Rainfall_mm": 400,
"Irrigation_m3_ha": 0,
"Comment": "Trockenes Frühjahr, aber Dinkel widerstandsfähig"
},
"Fertilization": [
{"Date": "2024-03-20", "Type": "Rindermist (fest)", "Quantity_t_ha": 25, "N_total_kg_ha": 100}
],
"Observations": [
{
"Date": "2024-06-01",
"Type": "Wuchsanomalie",
"Indicator": "**Dunkelgrüne, überdimensionierte Blätter**; leichte Einrollung der Spitzen; späte Blüte",
"Severity_Index_0_10": 8.5,
"ProblemScenario": "**Starke Überdüngung mit Stickstoff** im Frühjahr, was zu vegetativem Wachstum statt Kornansatz führte. Massive Ertragsverluste durch **Lagerbildung** (Umknicken).",
"ActionTaken": "Bestandsregulierung nicht möglich. Maßnahmen für Folgejahr planen."
}
],
"Yield_t_ha": 1.9,
"HarvestQuality_Index_0_10": 4.5
}
]
},
{
"FieldID": "F-03",
"FieldName": "Südfeld",
"Area_ha": 10.0,
"SoilType": "Mooriger Sand",
"CropHistory": [
{
"Year": 2023,
"Crop": "Luzerne (mehrjährig)",
"WaterSupply": {"Rainfall_mm": 580, "Irrigation_m3_ha": 0, "Comment": "Normale Bedingungen"},
"Fertilization": [],
"Observations": [],
"Yield_t_ha": 8.5,
"HarvestQuality_Index_0_10": 9.0
},
{
"Year": 2024,
"Crop": "Luzerne (mehrjährig)",
"WaterSupply": {"Rainfall_mm": 450, "Irrigation_m3_ha": 500, "Comment": "Zweite Schnitte bewässert"},
"Fertilization": [],
"Observations": [],
"Yield_t_ha": 7.8,
"HarvestQuality_Index_0_10": 8.5
}
]
},
{
"FieldID": "F-04",
"FieldName": "Kleeblatt",
"Area_ha": 4.5,
"SoilType": "Schluff-Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Ackerbohnen",
"WaterSupply": {"Rainfall_mm": 560, "Irrigation_m3_ha": 0, "Comment": "Normale Bedingungen"},
"Fertilization": [],
"Observations": [
{
"Date": "2023-07-01",
"Type": "Schädlingsbefall",
"Indicator": "Zusammengekräuselte Triebe, schwarze Massen an Triebspitzen",
"Severity_Index_0_10": 9.0,
"ProblemScenario": "**Totalbefall durch Schwarze Bohnenlaus** (Aphis fabae). Trotz Bio-Regulierung starke Schädigung. Ernte nahezu Totalausfall.",
"ActionTaken": "Abbruch der Kultur, Flächenmulchung"
}
],
"Yield_t_ha": 0.5,
"HarvestQuality_Index_0_10": 2.0
},
{
"Year": 2024,
"Crop": "Körnermais (Bio-Sorte 'Karmona')",
"WaterSupply": {"Rainfall_mm": 420, "Irrigation_m3_ha": 800, "Comment": "Gezielte Tröpfchenbewässerung"},
"Fertilization": [
{"Date": "2024-05-10", "Type": "Hühnertrockenkot", "Quantity_t_ha": 3.0, "N_total_kg_ha": 90}
],
"Observations": [],
"Yield_t_ha": 7.5,
"HarvestQuality_Index_0_10": 7.5
}
]
},
{
"FieldID": "F-05",
"FieldName": "Nordhang",
"Area_ha": 3.0,
"SoilType": "Flachgründiger Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Sommergerste",
"WaterSupply": {"Rainfall_mm": 540, "Irrigation_m3_ha": 0, "Comment": "Normale Bedingungen"},
"Fertilization": [
{"Date": "2023-04-10", "Type": "Gründüngung", "Quantity_t_ha": 4, "N_total_kg_ha": 25}
],
"Observations": [],
"Yield_t_ha": 3.8,
"HarvestQuality_Index_0_10": 8.2
},
{
"Year": 2024,
"Crop": "Rotklee-Gras-Gemenge",
"WaterSupply": {"Rainfall_mm": 450, "Irrigation_m3_ha": 0, "Comment": "Trockenheit hemmt Klee-Wachstum"},
"Fertilization": [],
"Observations": [],
"Yield_t_ha": 6.5,
"HarvestQuality_Index_0_10": 7.0
}
]
},
{
"FieldID": "F-06",
"FieldName": "Teichwiese",
"Area_ha": 7.0,
"SoilType": "Aue-Boden",
"CropHistory": [
{
"Year": 2023,
"Crop": "Dauergrünland (Heu)",
"WaterSupply": {"Rainfall_mm": 610, "Irrigation_m3_ha": 0, "Comment": "Gute Grasernte"},
"Fertilization": [
{"Date": "2023-05-01", "Type": "Gülle (Rind)", "Quantity_t_ha": 15, "N_total_kg_ha": 55}
],
"Observations": [],
"Yield_t_ha": 9.0,
"HarvestQuality_Index_0_10": 9.0
},
{
"Year": 2024,
"Crop": "Dauergrünland (Heu)",
"WaterSupply": {"Rainfall_mm": 440, "Irrigation_m3_ha": 0, "Comment": "Erster Schnitt gut, zweiter durch Trockenheit schlecht"},
"Fertilization": [
{"Date": "2024-05-05", "Type": "Gülle (Rind)", "Quantity_t_ha": 15, "N_total_kg_ha": 55}
],
"Observations": [],
"Yield_t_ha": 6.5,
"HarvestQuality_Index_0_10": 7.0
}
]
},
{
"FieldID": "F-07",
"FieldName": "Hofnähe",
"Area_ha": 2.0,
"SoilType": "Humoser Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Speisekürbisse",
"WaterSupply": {"Rainfall_mm": 550, "Irrigation_m3_ha": 300, "Comment": "Spezielle Bewässerung nötig"},
"Fertilization": [
{"Date": "2023-04-25", "Type": "Kompost", "Quantity_t_ha": 30, "N_total_kg_ha": 90}
],
"Observations": [
{
"Date": "2023-08-15",
"Type": "Pilzkrankheit",
"Indicator": "Weiße, mehlige Flecken auf Blattober- und -unterseite",
"Severity_Index_0_10": 6.0,
"ProblemScenario": "**Echter Mehltau-Befall** durch feucht-warme Witterung. Ertrag leicht gemindert, Lagerfähigkeit betroffen.",
"ActionTaken": "Behandlung mit Netzschwefel (zugelassenes Bio-Pflanzenschutzmittel)"
}
],
"Yield_t_ha": 25.0,
"HarvestQuality_Index_0_10": 7.5
},
{
"Year": 2024,
"Crop": "Möhren",
"WaterSupply": {"Rainfall_mm": 400, "Irrigation_m3_ha": 1000, "Comment": "Hohe Bewässerung für gerade Wurzeln"},
"Fertilization": [
{"Date": "2024-04-01", "Type": "Rindermist (alt)", "Quantity_t_ha": 20, "N_total_kg_ha": 70}
],
"Observations": [],
"Yield_t_ha": 45.0,
"HarvestQuality_Index_0_10": 8.5
}
]
},
{
"FieldID": "F-08",
"FieldName": "Obstwiese",
"Area_ha": 5.0,
"SoilType": "Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Äpfel (Hochstamm-Mischkultur)",
"WaterSupply": {"Rainfall_mm": 570, "Irrigation_m3_ha": 0, "Comment": "Gute Witterung"},
"Fertilization": [
{"Date": "2023-03-01", "Type": "Kompost", "Quantity_t_ha": 10, "N_total_kg_ha": 30}
],
"Observations": [],
"Yield_t_ha": 15.0,
"HarvestQuality_Index_0_10": 9.0
},
{
"Year": 2024,
"Crop": "Äpfel (Hochstamm-Mischkultur)",
"WaterSupply": {"Rainfall_mm": 450, "Irrigation_m3_ha": 0, "Comment": "**Spätfrost** im April"},
"Fertilization": [
{"Date": "2024-03-05", "Type": "Kompost", "Quantity_t_ha": 10, "N_total_kg_ha": 30}
],
"Observations": [
{
"Date": "2024-04-25",
"Type": "Witterungsschaden",
"Indicator": "Geschwärzte, abgestorbene Blüten",
"Severity_Index_0_10": 9.5,
"ProblemScenario": "**Fast kompletter Ausfall der Apfelernte** durch Spätfrost während der Blüte.",
"ActionTaken": "Keine, Frostschutz nicht praktikabel bei Hochstämmen"
}
],
"Yield_t_ha": 1.0,
"HarvestQuality_Index_0_10": 3.0
}
]
},
{
"FieldID": "F-09",
"FieldName": "Ostfeld",
"Area_ha": 12.0,
"SoilType": "Tiefgründiger Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Winterroggen",
"WaterSupply": {"Rainfall_mm": 590, "Irrigation_m3_ha": 0, "Comment": "Sehr gutes Roggen-Jahr"},
"Fertilization": [
{"Date": "2023-03-20", "Type": "Vinasse", "Quantity_l_ha": 400, "N_total_kg_ha": 20}
],
"Observations": [],
"Yield_t_ha": 5.0,
"HarvestQuality_Index_0_10": 9.2
},
{
"Year": 2024,
"Crop": "Öllein (Flachs)",
"WaterSupply": {"Rainfall_mm": 410, "Irrigation_m3_ha": 0, "Comment": "Verträgt Trockenheit gut"},
"Fertilization": [
{"Date": "2024-04-15", "Type": "Gründüngung (vorherige Frucht)", "Quantity_t_ha": 0, "N_total_kg_ha": 0}
],
"Observations": [],
"Yield_t_ha": 1.5,
"HarvestQuality_Index_0_10": 8.0
}
]
},
{
"FieldID": "F-10",
"FieldName": "Eckstück",
"Area_ha": 2.5,
"SoilType": "Sand",
"CropHistory": [
{
"Year": 2023,
"Crop": "Sommerdinkel",
"WaterSupply": {"Rainfall_mm": 520, "Irrigation_m3_ha": 0, "Comment": "Normale Bedingungen"},
"Fertilization": [
{"Date": "2023-04-01", "Type": "Rindermist (fest)", "Quantity_t_ha": 15, "N_total_kg_ha": 60}
],
"Observations": [],
"Yield_t_ha": 3.0,
"HarvestQuality_Index_0_10": 7.5
},
{
"Year": 2024,
"Crop": "Linsen (als Untersaat)",
"WaterSupply": {"Rainfall_mm": 430, "Irrigation_m3_ha": 0, "Comment": "Frühe Ernte"},
"Fertilization": [],
"Observations": [],
"Yield_t_ha": 0.8,
"HarvestQuality_Index_0_10": 7.8
}
]
},
{
"FieldID": "F-11",
"FieldName": "Pappelallee",
"Area_ha": 8.0,
"SoilType": "Lehm",
"CropHistory": [
{
"Year": 2023,
"Crop": "Silomais (f. Biogas)",
"WaterSupply": {"Rainfall_mm": 570, "Irrigation_m3_ha": 0, "Comment": "Gutes Wachstum"},
"Fertilization": [
{"Date": "2023-05-15", "Type": "Gärrest (aus Biogasanlage)", "Quantity_t_ha": 35, "N_total_kg_ha": 120}
],
"Observations": [],
"Yield_t_ha": 40.0,
"HarvestQuality_Index_0_10": 8.5
},
{
"Year": 2024,
"Crop": "Winterweizen (Bio-Sorte 'Spindel')",
"WaterSupply": {"Rainfall_mm": 450, "Irrigation_m3_ha": 0, "Comment": "Trockenheit reduziert Kornfüllung"},
"Fertilization": [
{"Date": "2024-03-22", "Type": "Vinasse", "Quantity_l_ha": 350, "N_total_kg_ha": 18}
],
"Observations": [
{
"Date": "2024-07-05",
"Type": "Nährstoffmangel",
"Indicator": "**Helle, gelbliche Flecken** an den jüngeren Blättern, unterdurchschnittliche Bestockung",
"Severity_Index_0_10": 5.0,
"ProblemScenario": "**Schwefelmangel**, bedingt durch unzureichende organische Düngung (kein Schwefel im Vinasse/Gärrest). Mittlere Ertragseinbuße.",
"ActionTaken": "Keine Korrektur mehr möglich."
}
],
"Yield_t_ha": 3.2,
"HarvestQuality_Index_0_10": 6.5
}
]
},
{
"FieldID": "F-12",
"FieldName": "Waldrand",
"Area_ha": 7.0,
"SoilType": "Lehm mit hohem Humusgehalt",
"CropHistory": [
{
"Year": 2023,
"Crop": "Pausenjahr (Gründüngung)",
"WaterSupply": {"Rainfall_mm": 580, "Irrigation_m3_ha": 0, "Comment": "Normale Bedingungen"},
"Fertilization": [],
"Observations": [],
"Yield_t_ha": 0.0,
"HarvestQuality_Index_0_10": 10.0
},
{
"Year": 2024,
"Crop": "Winterraps",
"WaterSupply": {"Rainfall_mm": 430, "Irrigation_m3_ha": 0, "Comment": "Trockenheit während der Schotenfüllung"},
"Fertilization": [
{"Date": "2024-03-10", "Type": "Gülle (Rind)", "Quantity_t_ha": 20, "N_total_kg_ha": 70}
],
"Observations": [
{
"Date": "2024-05-01",
"Type": "Schädlingsbefall",
"Indicator": "Löcher in Blättern und Knospen; kleine, metallisch-blaue Käfer",
"Severity_Index_0_10": 4.5,
"ProblemScenario": "**Rapsglanzkäfer-Befall** im mittleren Umfang. Durch schnelles Wachstum der Pflanzen gut überstanden.",
"ActionTaken": "Förderung natürlicher Feinde"
}
],
"Yield_t_ha": 2.5,
"HarvestQuality_Index_0_10": 7.5
}
]
}
]
};
interface ImportStats {
farmCreated: boolean;
farmId?: string;
fieldsCreated: number;
fieldErrors: number;
managementPlansCreated: number;
managementPlanErrors: number;
tasksCreated: number;
taskErrors: number;
warnings: string[];
}
class BiohofImporter {
private client: LiteFarmClient;
private stats: ImportStats;
private farmId: string | null = null;
private fieldMapping: Map<string, string> = new Map(); // FieldID -> location_id
private cropMapping: Map<string, string> = new Map(); // Crop name -> crop_id
constructor(email: string, password: string) {
this.client = new LiteFarmClient(email, password);
this.stats = {
farmCreated: false,
fieldsCreated: 0,
fieldErrors: 0,
managementPlansCreated: 0,
managementPlanErrors: 0,
tasksCreated: 0,
taskErrors: 0,
warnings: []
};
}
async run(): Promise<void> {
try {
console.log("\n🚀 Starting Biohof Sonnenacker Import...\n");
// Login
console.log("1️⃣ Logging in...");
await this.client.login();
console.log("✅ Login successful\n");
// Load available crops for mapping
console.log("2️⃣ Loading available crops...");
await this.loadCropMapping();
console.log(`✅ Loaded ${this.cropMapping.size} crops\n`);
// Create farm
console.log("3️⃣ Creating farm...");
await this.createFarm();
console.log(`✅ Farm created with ID: ${this.farmId}\n`);
// Select farm (CRITICAL: Sets farm_id header for all subsequent requests)
console.log("4️⃣ Selecting farm...");
await this.client.selectFarm(this.farmId!);
console.log(`✅ Farm selected: ${this.farmId}\n`);
// Create fields
console.log("5️⃣ Creating fields...");
await this.createFields();
console.log(`✅ Created ${this.stats.fieldsCreated} fields (${this.stats.fieldErrors} errors)\n`);
// Create management plans and tasks
console.log("6️⃣ Creating management plans and tasks...");
await this.createManagementPlansAndTasks();
console.log(`✅ Created ${this.stats.managementPlansCreated} management plans and ${this.stats.tasksCreated} tasks\n`);
// Print summary
this.printSummary();
} catch (error) {
console.error("\n❌ Import failed:", error);
throw error;
}
}
private async loadCropMapping(): Promise<void> {
try {
const crops = await this.client.getCrops();
crops.forEach(crop => {
// Map by common name
this.cropMapping.set(crop.crop_common_name.toLowerCase(), crop.crop_id);
// Also map by genus + species
const scientificName = `${crop.crop_genus} ${crop.crop_specie}`.toLowerCase();
this.cropMapping.set(scientificName, crop.crop_id);
});
} catch (error) {
console.warn("⚠️ Could not load crops, will try to create custom crops");
}
}
private async createFarm(): Promise<void> {
const farmData = {
farm_name: BIOHOF_DATA.FarmDetails.FarmName,
address: BIOHOF_DATA.FarmDetails.Location,
farm_phone_number: "",
};
const farm = await this.client.createFarm(farmData);
this.farmId = farm.farm_id;
this.stats.farmCreated = true;
this.stats.farmId = farm.farm_id;
}
private async createFields(): Promise<void> {
if (!this.farmId) throw new Error("Farm ID not set");
for (const field of BIOHOF_DATA.FieldsAndCrops) {
try {
// Convert hectares to square meters (LiteFarm uses m²)
const area_m2 = field.Area_ha * 10000;
const locationData = {
farm_id: this.farmId,
name: field.FieldName,
notes: `Bodentyp: ${field.SoilType}\nFläche: ${field.Area_ha} ha`,
figure: {
type: "field",
total_area: area_m2
},
organic_status: "Organic", // From certification
};
const location = await this.client.post<any>("/location/field", locationData);
this.fieldMapping.set(field.FieldID, location.location_id);
this.stats.fieldsCreated++;
console.log(` ✓ Created field: ${field.FieldName} (${field.Area_ha} ha)`);
} catch (error) {
this.stats.fieldErrors++;
this.stats.warnings.push(`Failed to create field ${field.FieldName}: ${error}`);
console.error(` ✗ Failed to create field ${field.FieldName}:`, error);
}
}
}
private async createManagementPlansAndTasks(): Promise<void> {
if (!this.farmId) throw new Error("Farm ID not set");
for (const field of BIOHOF_DATA.FieldsAndCrops) {
const locationId = this.fieldMapping.get(field.FieldID);
if (!locationId) {
console.warn(` ⚠️ Skipping ${field.FieldName} - no location ID`);
continue;
}
for (const cropHistory of field.CropHistory) {
try {
// Extract crop name (remove variety info in parentheses)
const cropName = cropHistory.Crop.split('(')[0].trim();
const varietyInfo = cropHistory.Crop.includes('(')
? (cropHistory.Crop.match(/\(([^)]+)\)/)?.[1] || '')
: '';
// Try to find matching crop in LiteFarm database
const cropId = this.findCropId(cropName);
// Build detailed notes for management plan
const mpNotes = this.buildManagementPlanNotes(cropHistory, varietyInfo, field.Area_ha);
// Create management plan (simplified - without crop_variety_id for now)
// Note: In production, would need to handle crop varieties properly
const managementPlanData = {
farm_id: this.farmId,
name: `${cropName} ${cropHistory.Year} - ${field.FieldName}`,
notes: mpNotes,
start_date: `${cropHistory.Year}-01-01`,
};
// For now, store in notes as management plans require crop_variety_id
console.log(` → ${field.FieldName} - ${cropName} ${cropHistory.Year}`);
// Create fertilization tasks
for (const fert of cropHistory.Fertilization) {
await this.createFertilizationTask(locationId, fert, field.Area_ha);
}
// Create irrigation tasks if applicable
if (cropHistory.WaterSupply.Irrigation_m3_ha > 0) {
await this.createIrrigationTask(locationId, cropHistory);
}
// Create observation/scouting tasks
for (const obs of cropHistory.Observations) {
await this.createObservationTask(locationId, obs);
}
this.stats.managementPlansCreated++;
} catch (error) {
this.stats.managementPlanErrors++;
this.stats.warnings.push(`Failed to create plan for ${field.FieldName} - ${cropHistory.Crop}: ${error}`);
console.error(` ✗ Error:`, error);
}
}
}
}
private findCropId(cropName: string): string | null {
const lowerName = cropName.toLowerCase();
return this.cropMapping.get(lowerName) || null;
}
private buildManagementPlanNotes(cropHistory: any, varietyInfo: string, area_ha: number): string {
let notes = '';
if (varietyInfo) {
notes += `Sorte: ${varietyInfo}\n\n`;
}
// Water supply info
notes += `== Wasserversorgung ==\n`;
notes += `Niederschlag: ${cropHistory.WaterSupply.Rainfall_mm} mm\n`;
if (cropHistory.WaterSupply.Irrigation_m3_ha > 0) {
notes += `Bewässerung: ${cropHistory.WaterSupply.Irrigation_m3_ha} m³/ha\n`;
}
notes += `Kommentar: ${cropHistory.WaterSupply.Comment}\n\n`;
// Yield info
notes += `== Ertrag ==\n`;
notes += `Ertrag: ${cropHistory.Yield_t_ha} t/ha (Total: ${(cropHistory.Yield_t_ha * area_ha).toFixed(1)} t)\n`;
notes += `Qualitätsindex: ${cropHistory.HarvestQuality_Index_0_10}/10\n`;
return notes;
}
private async createFertilizationTask(locationId: string, fert: any, area_ha: number): Promise<void> {
try {
const notes = this.buildFertilizationNotes(fert, area_ha);
const taskData = {
farm_id: this.farmId,
due_date: fert.Date,
task_type: 'soil_amendment',
notes: notes,
};
await this.client.post<any>('/task', taskData);
this.stats.tasksCreated++;
console.log(` ✓ Fertilization task: ${fert.Type} (${fert.Date})`);
} catch (error) {
this.stats.taskErrors++;
console.error(` ✗ Failed to create fertilization task:`, error);
}
}
private buildFertilizationNotes(fert: any, area_ha: number): string {
let notes = `== Düngung: ${fert.Type} ==\n`;
notes += `Datum: ${fert.Date}\n`;
if (fert.Quantity_t_ha) {
notes += `Menge: ${fert.Quantity_t_ha} t/ha (Total: ${(fert.Quantity_t_ha * area_ha).toFixed(1)} t)\n`;
} else if (fert.Quantity_l_ha) {
notes += `Menge: ${fert.Quantity_l_ha} l/ha (Total: ${(fert.Quantity_l_ha * area_ha).toFixed(0)} l)\n`;
}
notes += `N-Gehalt: ${fert.N_total_kg_ha} kg N/ha (Total: ${(fert.N_total_kg_ha * area_ha).toFixed(1)} kg N)\n`;
return notes;
}
private async createIrrigationTask(locationId: string, cropHistory: any): Promise<void> {
try {
const notes = `== Bewässerung ==\n`;
const fullNotes = notes +
`Bewässerungsmenge: ${cropHistory.WaterSupply.Irrigation_m3_ha} m³/ha\n` +
`Kommentar: ${cropHistory.WaterSupply.Comment}\n`;
const taskData = {
farm_id: this.farmId,
due_date: `${cropHistory.Year}-06-01`, // Approximate date
task_type: 'irrigation',
notes: fullNotes,
};
await this.client.post<any>('/task', taskData);
this.stats.tasksCreated++;
console.log(` ✓ Irrigation task created`);
} catch (error) {
this.stats.taskErrors++;
console.error(` ✗ Failed to create irrigation task:`, error);
}
}
private async createObservationTask(locationId: string, obs: any): Promise<void> {
try {
const notes = this.buildObservationNotes(obs);
const taskData = {
farm_id: this.farmId,
due_date: obs.Date,
task_type: 'scouting',
notes: notes,
};
await this.client.post<any>('/task', taskData);
this.stats.tasksCreated++;
console.log(` ✓ Observation task: ${obs.Type} (Severity: ${obs.Severity_Index_0_10}/10)`);
} catch (error) {
this.stats.taskErrors++;
console.error(` ✗ Failed to create observation task:`, error);
}
}
private buildObservationNotes(obs: any): string {
let notes = `== Beobachtung: ${obs.Type} ==\n`;
notes += `Datum: ${obs.Date}\n`;
notes += `Schweregrad: ${obs.Severity_Index_0_10}/10\n\n`;
notes += `Indikatoren:\n${obs.Indicator}\n\n`;
notes += `Problem-Szenario:\n${obs.ProblemScenario}\n\n`;
notes += `Maßnahmen:\n${obs.ActionTaken}\n`;
return notes;
}
private printSummary(): void {
console.log("\n" + "=".repeat(60));
console.log("📊 IMPORT SUMMARY");
console.log("=".repeat(60));
console.log(`\n✅ Farm: ${this.stats.farmCreated ? 'Created' : 'Failed'}`);
if (this.stats.farmId) {
console.log(` Farm ID: ${this.stats.farmId}`);
}
console.log(`\n📍 Fields: ${this.stats.fieldsCreated} created, ${this.stats.fieldErrors} failed`);
console.log(`🌾 Management Plans: ${this.stats.managementPlansCreated} created, ${this.stats.managementPlanErrors} failed`);
console.log(`📋 Tasks: ${this.stats.tasksCreated} created, ${this.stats.taskErrors} failed`);
if (this.stats.warnings.length > 0) {
console.log(`\n⚠️ Warnings (${this.stats.warnings.length}):`);
this.stats.warnings.slice(0, 10).forEach(w => console.log(` - ${w}`));
if (this.stats.warnings.length > 10) {
console.log(` ... and ${this.stats.warnings.length - 10} more`);
}
}
console.log("\n" + "=".repeat(60));
console.log("✨ Import completed!");
console.log("=".repeat(60) + "\n");
}
}
// Main execution
async function main() {
if (!process.env.LITEFARM_EMAIL || !process.env.LITEFARM_PASSWORD) {
console.error("❌ Error: LITEFARM_EMAIL and LITEFARM_PASSWORD must be set in .env file");
process.exit(1);
}
const importer = new BiohofImporter(
process.env.LITEFARM_EMAIL,
process.env.LITEFARM_PASSWORD
);
try {
await importer.run();
} catch (error) {
console.error("\n💥 Fatal error during import:", error);
process.exit(1);
}
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
export { BiohofImporter };