soil-report-pdf.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. /**
  3. * soil-report-pdf.php
  4. *
  5. * Printable / PDF-export version of a soil analysis report.
  6. * NOTE: The [[!soilAnalysisReportCalcs?]] and [[!soilProgramCalcs?]] snippet
  7. * sections are pending full PHP migration. They currently render as blank.
  8. */
  9. require_once __DIR__ . '/../../../config/database.php';
  10. require_once __DIR__ . '/../../../lib/auth.php';
  11. require_once __DIR__ . '/../../../lib/csrf.php';
  12. if (session_status() === PHP_SESSION_NONE) {
  13. session_start();
  14. }
  15. requireLogin();
  16. $pdo = getDBConnection();
  17. $userId = getCurrentUserId();
  18. $recordId = (int) ($_GET['rid'] ?? 0);
  19. $randId = (float) ($_GET['rand'] ?? 0);
  20. $row = null;
  21. $today = date('jS F Y');
  22. if ($recordId > 0) {
  23. $stmt = $pdo->prepare(
  24. 'SELECT * FROM soil_records WHERE id = ? AND rand = ? LIMIT 1'
  25. );
  26. $stmt->execute([$recordId, $randId]);
  27. $row = $stmt->fetch();
  28. }
  29. $h = fn($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
  30. ?>
  31. <!doctype html>
  32. <html lang="en">
  33. <head>
  34. <meta charset="UTF-8">
  35. <meta name="viewport" content="width=device-width, initial-scale=1">
  36. <title>Soil Analysis Report | Crop Monitor</title>
  37. <script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
  38. <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
  39. <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.css" crossorigin="anonymous" rel="stylesheet">
  40. <link href="/client-assets/css/dashboard.css" rel="stylesheet">
  41. <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js" crossorigin="anonymous"></script>
  42. <style>
  43. @media print {
  44. @page { size: A4 portrait; margin: 0.5cm; }
  45. .d-print-none { display: none !important; }
  46. }
  47. .title th, .title td { padding: 2px 6px; }
  48. </style>
  49. </head>
  50. <body>
  51. <div class="container" id="content">
  52. <?php if (!$row): ?>
  53. <div class="alert alert-danger mt-4">Record not found or access denied.</div>
  54. <?php else: ?>
  55. <div class="row mb-3">
  56. <div class="col-md-3">
  57. <img class="img-fluid" src="/client-assets/images/crop-monitor.png" alt="Crop Monitor">
  58. </div>
  59. <div class="col-md-9"></div>
  60. </div>
  61. <table class="title w-100 mb-3">
  62. <tbody>
  63. <tr>
  64. <td class="text-end fw-bold">DATE:</td>
  65. <td><?= $h($today) ?></td>
  66. <td></td>
  67. <td class="text-end fw-bold">SAMPLE ID:</td>
  68. <td><?= $h($row['site_id']) ?></td>
  69. </tr>
  70. <tr>
  71. <td class="text-end fw-bold">CLIENT:</td>
  72. <td><?= $h($row['client_name']) ?></td>
  73. <td></td>
  74. <td class="text-end fw-bold">DATE SAMPLED:</td>
  75. <td><?= $h($row['date_sampled']) ?></td>
  76. </tr>
  77. <tr>
  78. <td class="text-end fw-bold">ADDRESS:</td>
  79. <td><?= $h($row['site_address']) ?></td>
  80. <td></td>
  81. <td class="text-end fw-bold">LAB NUMBER:</td>
  82. <td><?= $h($row['lab_no']) ?></td>
  83. </tr>
  84. <tr>
  85. <td></td>
  86. <td><?= $h($row['state_postcode']) ?></td>
  87. <td></td>
  88. <td class="text-end fw-bold">CROP:</td>
  89. <td><?= $h($row['sample_id']) ?></td>
  90. </tr>
  91. <tr>
  92. <td></td>
  93. <td><?= $h($row['email']) ?></td>
  94. <td colspan="3"></td>
  95. </tr>
  96. </tbody>
  97. </table>
  98. <!-- Download button (hidden on print) -->
  99. <div class="d-print-none mb-3">
  100. <button class="btn btn-success btn-sm downloadPDF">
  101. <i class="fas fa-download me-1"></i>Download PDF
  102. </button>
  103. </div>
  104. <div class="row">
  105. <div class="col-md-12 text-center fw-bold h4">Soil Analysis Summary</div>
  106. </div>
  107. <!-- Analysis calculation sections — pending PHP migration of soilAnalysisReportCalcs -->
  108. <div class="row bg-dark text-white p-2 mt-3">
  109. <div class="text-center col-md-12 h5">
  110. Total kilograms per hectare of each element needed to balance soil in this test
  111. </div>
  112. </div>
  113. <div class="row">
  114. <div class="col text-muted fst-italic p-3">
  115. [Soil analysis calculation components pending migration]
  116. </div>
  117. </div>
  118. <hr>
  119. <!-- Report form (auto-saves via AJAX) -->
  120. <form class="report-form" method="post">
  121. <input type="hidden" name="csrf_token" value="<?= $h(generateCsrfToken()) ?>">
  122. <div class="row bg-dark text-white p-2 mt-3">
  123. <div class="text-center col-md-12 h5">Overview</div>
  124. </div>
  125. <div class="row">
  126. <div class="col-md-12 p-0">
  127. <textarea class="form-control rounded-0" rows="5" id="overview" name="overview"></textarea>
  128. </div>
  129. </div>
  130. <hr>
  131. <div class="row bg-dark text-white p-2 mt-3">
  132. <div class="text-center col-md-12 h5">
  133. Ideal Soil Balancing Program for One Season of a FIVE YEAR Plan
  134. </div>
  135. </div>
  136. <div class="col text-muted fst-italic p-3">
  137. [Soil program calculation components pending migration]
  138. </div>
  139. <hr>
  140. <div class="row bg-dark text-white p-2 mt-3">
  141. <div class="text-center col-md-12 h5">
  142. <input type="text" class="text-center form-control-plaintext text-white border-dark bg-dark"
  143. name="header1" id="header1" value="Foliar Program">
  144. </div>
  145. </div>
  146. <div class="row">
  147. <div class="col-md-12 p-0">
  148. <textarea class="form-control rounded-0" rows="5"
  149. id="foliar_Details" name="foliar_Details"></textarea>
  150. </div>
  151. </div>
  152. <div class="row bg-dark text-white p-2 mt-3">
  153. <div class="text-center col-md-12 h5">Microbe Program</div>
  154. </div>
  155. <div class="row">
  156. <div class="col-md-12 p-0">
  157. <textarea class="form-control rounded-0" rows="5"
  158. id="microbe_Program" name="microbe_Program"></textarea>
  159. </div>
  160. </div>
  161. <div class="row mt-2">
  162. <p class="small fst-italic text-muted">
  163. Any recommendations provided by Cropmonitor are advice only. We are not paid
  164. consultants and are not covered to accept responsibility for any of our suggestions.
  165. </p>
  166. </div>
  167. </form>
  168. <?php endif; ?>
  169. </div><!-- /container -->
  170. <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
  171. <script>
  172. $(document).ready(function () {
  173. var timeoutId;
  174. var saveUrl = '/dashboard/crop-analysis/updatecomment.php'
  175. + '?rid=<?= (int) $recordId ?>&rand=<?= (float) $randId ?>';
  176. $('form textarea, form input[name="header1"]').on('input propertychange change', function () {
  177. clearTimeout(timeoutId);
  178. timeoutId = setTimeout(saveToDB, 1000);
  179. });
  180. function saveToDB() {
  181. var form = $('.report-form');
  182. $.ajax({
  183. url: saveUrl,
  184. type: 'POST',
  185. data: form.serialize(),
  186. beforeSend: function () { $('.form-status-holder').html('Saving...'); },
  187. success: function (data) {
  188. var d = new Date();
  189. $('.form-status-holder').html('Saved! Last: ' + d.toLocaleTimeString());
  190. }
  191. });
  192. }
  193. $('.report-form').submit(function (e) {
  194. saveToDB();
  195. e.preventDefault();
  196. });
  197. // PDF download
  198. $('.downloadPDF').click(function () {
  199. var element = document.getElementById('content');
  200. var opt = {
  201. margin: 3,
  202. filename: 'soil-analysis.pdf',
  203. image: { type: 'jpeg', quality: 1.0 },
  204. html2canvas: { scale: 2, letterRendering: true, windowWidth: 1024 },
  205. jsPDF: { orientation: 'portrait', unit: 'mm', format: 'a4' }
  206. };
  207. html2pdf().from(element).set(opt).save();
  208. });
  209. });
  210. </script>
  211. </body>
  212. </html>