Soil Analysis Report
prepare('SELECT * FROM soil_records WHERE id = ? AND rand = ?'); $stmt->execute([$record_id, $rand_id]); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!$row) { http_response_code(404); die('Soil record not found'); } // Load specification ranges for this soil type $spec = []; if (!empty($row['soil_type'])) { $stmtSpec = $pdo->prepare('SELECT * FROM soil_specifications WHERE soil_type = ? LIMIT 1'); $stmtSpec->execute([$row['soil_type']]); $spec = $stmtSpec->fetch(PDO::FETCH_ASSOC) ?: []; } // Load saved report comments (JSON blob in reports table) $savedComments = []; $stmtRpt = $pdo->prepare( 'SELECT comment FROM reports WHERE record_id = ? AND modx_user_id = ? ORDER BY id DESC LIMIT 1' ); $stmtRpt->execute([$record_id, $userId]); $savedRow = $stmtRpt->fetchColumn(); if ($savedRow) { $decoded = json_decode($savedRow, true); if (is_array($decoded)) { $savedComments = $decoded; } } } catch (PDOException $e) { error_log('DB error in soil-report.php: ' . $e->getMessage()); die('Database error occurred'); } // ── Escaped display vars ──────────────────────────────────────────────────── $client = htmlspecialchars($row['client_name'] ?? '', ENT_QUOTES, 'UTF-8'); $address = htmlspecialchars($row['site_address'] ?? '', ENT_QUOTES, 'UTF-8'); $state = htmlspecialchars($row['state_postcode'] ?? '', ENT_QUOTES, 'UTF-8'); $email = htmlspecialchars($row['email'] ?? '', ENT_QUOTES, 'UTF-8'); $labNo = htmlspecialchars($row['lab_no'] ?? '', ENT_QUOTES, 'UTF-8'); $sampleDate = htmlspecialchars($row['date_sampled'] ?? '', ENT_QUOTES, 'UTF-8'); $sample = htmlspecialchars($row['site_id'] ?? '', ENT_QUOTES, 'UTF-8'); $cropName = htmlspecialchars($row['sample_id'] ?? '', ENT_QUOTES, 'UTF-8'); $soilType = htmlspecialchars($row['soil_type'] ?? '', ENT_QUOTES, 'UTF-8'); $batchNo = htmlspecialchars($row['batch_no'] ?? '', ENT_QUOTES, 'UTF-8'); $today = date('jS F Y'); $pageTitle = 'Soil Report' . ($client !== '' ? ' — ' . $client : ''); $siteName = 'Crop Monitor'; // ── Five-year plan element definitions ───────────────────────────────────── // [label, soil_records column, min column (record), max column (record), unit] // When min/max are empty the spec column of the same name provides the target. $planElements = [ ['Calcium', 'BS_ca_ppm', 'ca_ppm_min', 'ca_ppm_max', 'kg/ha'], ['Magnesium', 'BS_mg_ppm', 'mg_ppm_min', 'mg_ppm_max', 'kg/ha'], ['Potassium', 'BS_k_ppm', 'k_ppm_min', 'k_ppm_max', 'kg/ha'], ['Sodium', 'BS_na_ppm', 'na_ppm_min', 'na_ppm_max', 'kg/ha'], ['Phosphate', 'p_colwell', '', '', 'kg/ha'], ['Sulfur', 's_morgan', '', '', 'kg/ha'], ['Boron', 'b_cacl2', '', '', 'kg/ha'], ['Manganese', 'mn_dtpa', '', '', 'kg/ha'], ['Zinc', 'zn_dtpa', '', '', 'kg/ha'], ['Copper', 'cu_dtpa', '', '', 'kg/ha'], ]; /** * Calculate total kg/ha deficit for one element, given soil row + spec row. * Returns 0 if already at or above target. */ function calcDeficit(array $row, array $spec, string $col, string $minCol, string $maxCol): float { global $acHa; $value = (float)($row[$col] ?? 0); if ($maxCol !== '') { $maxVal = (float)($row[$maxCol] ?? 0); } else { $maxVal = (float)($spec[$col] ?? 0); } $deficit = ($maxVal - $value) * $acHa; return $deficit > 0 ? round($deficit, 2) : 0.0; } // Parse and render markdown text from AI-generated report sections function formatReportText(string $text): string { if (trim($text) === '') { return '
No content saved.
'; } $parsedown = new Parsedown(); $parsedown->setSafeMode(true); return $parsedown->text($text); } include __DIR__ . '/../../../layouts/header.php'; ?>