soil-report.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. require_once __DIR__.'/../../config/database.php';
  3. require_once __DIR__.'/../../lib/auth.php';
  4. require_once __DIR__.'/../../lib/validation.php';
  5. require_once __DIR__.'/../../lib/soil_calculations.php';
  6. if (session_status() === PHP_SESSION_NONE) {
  7. session_start();
  8. }
  9. requireLogin();
  10. $client_id = (int)($_GET['cid'] ?? 0);
  11. $record_id = (int)($_GET['rid'] ?? 0);
  12. $rand_id = (float)($_GET['rand'] ?? 0);
  13. if (!$record_id || !$rand_id) {
  14. http_response_code(400);
  15. die('Invalid request parameters');
  16. }
  17. try {
  18. $pdo = getDBConnection();
  19. $stmt = $pdo->prepare("SELECT * FROM soil_records WHERE id = ? AND rand = ?");
  20. $stmt->execute([$record_id, $rand_id]);
  21. $row = $stmt->fetch(PDO::FETCH_ASSOC);
  22. if (!$row) {
  23. http_response_code(404);
  24. die('Soil record not found');
  25. }
  26. $client = htmlspecialchars($row['client_name'] ?? '', ENT_QUOTES, 'UTF-8');
  27. $address = htmlspecialchars($row['site_address'] ?? '', ENT_QUOTES, 'UTF-8');
  28. $state = htmlspecialchars($row['state_postcode'] ?? '', ENT_QUOTES, 'UTF-8');
  29. $email = htmlspecialchars($row['email'] ?? '', ENT_QUOTES, 'UTF-8');
  30. $labNo = htmlspecialchars($row['lab_no'] ?? '', ENT_QUOTES, 'UTF-8');
  31. $sampleDate = htmlspecialchars($row['date_sampled'] ?? '', ENT_QUOTES, 'UTF-8');
  32. $sample = htmlspecialchars($row['site_id'] ?? '', ENT_QUOTES, 'UTF-8');
  33. $crop = htmlspecialchars($row['sample_id'] ?? '', ENT_QUOTES, 'UTF-8');
  34. } catch (PDOException $e) {
  35. error_log("Database error in soil-report.php: " . $e->getMessage());
  36. die('Database error occurred');
  37. }
  38. $today = date('jS F Y');
  39. $pageTitle = 'Soil Report - ' . ($client ?: 'Crop Monitoring');
  40. $siteName = 'Crop Management Platform';
  41. $activeItem = 'Soil Report';
  42. include __DIR__.'/../../layouts/header.php';
  43. include __DIR__.'/../../layouts/navbar.php';
  44. ?>
  45. <div id="layoutSidenav">
  46. <div id="layoutSidenav_nav">
  47. <?php include __DIR__.'/../../layouts/sidebar.php'; ?>
  48. </div>
  49. <div id="layoutSidenav_content">
  50. <main>
  51. <div class="container">
  52. <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js" crossorigin="anonymous"></script>
  53. <style>
  54. @media print { @page { size: A4 portrait; margin: 0.5cm; } }
  55. </style>
  56. </head>
  57. <body>
  58. <div class="container">
  59. <div class="row">
  60. <div class="col-md-3">
  61. <img class="img-fluid" src="/client-assets/images/crop-monitor.png" alt="Crop Monitor">
  62. </div>
  63. <div class="col-md-9">
  64. <h4 class="mt-2">Soil Analysis for <?php echo $client; ?></h4>
  65. <p><strong>Sample:</strong> <?php echo $sample; ?> | <strong>Date:</strong> <?php echo $sampleDate; ?></p>
  66. </div>
  67. </div>
  68. <!-- display client metadata -->
  69. <div class="row">
  70. <div class="col-md-12">
  71. <table class="table table-sm table-borderless">
  72. <tr><th>Address</th><td><?php echo $address; ?></td><th>State/Postcode</th><td><?php echo $state; ?></td></tr>
  73. <tr><th>Email</th><td><?php echo $email; ?></td><th>Lab Number</th><td><?php echo $labNo; ?></td></tr>
  74. <tr><th>Crop</th><td><?php echo $crop; ?></td><th>Test Date</th><td><?php echo $sampleDate; ?></td></tr>
  75. </table>
  76. </div>
  77. </div>
  78. <!-- Graph Button -->
  79. <div class="d-print-none">
  80. <div class="row p-2">
  81. <div class="col">
  82. <a href="/dashboard/crop-analysis/soil-test-data/soil-report-pdf.php?rid=<?= (int)$record_id ?>&rand=<?= (float)$rand_id ?>"
  83. class="btn btn-success btn-sm" target="_blank">
  84. <i class="fas fa-file-pdf me-1"></i>View PDF Report
  85. </a>
  86. </div>
  87. <div class="col">
  88. <div class="form-status-holder"></div>
  89. </div>
  90. </div>
  91. </div>
  92. <!-- GRAPH BANNER -->
  93. <div class="row">
  94. <div class="col-md-12 text-center fw-bold h4">Soil Analysis Summary</div>
  95. </div>
  96. <!-- Element Required Module -->
  97. <div class="element-required-module">
  98. <div class="alert alert-secondary" role="alert">
  99. <div class="text-center h5">Total kilograms per hectare of each element needed to balance soil in this test</div>
  100. </div>
  101. <div class="card-group">
  102. <?php
  103. echo soilAnalysisReportCalcs('Ca', 'BS_ca_ppm', 'ca_ppm_min', 'ca_ppm_max', 'Calcium', 'kg', 'col', $record_id, $rand_id);
  104. echo soilAnalysisReportCalcs('Mg', 'BS_mg_ppm', 'mg_ppm_min', 'mg_ppm_max', 'Magnesium', 'kg', 'col', $record_id, $rand_id);
  105. echo soilAnalysisReportCalcs('K', 'BS_k_ppm', 'k_ppm_min', 'k_ppm_max', 'Potasium', 'kg', 'col', $record_id, $rand_id);
  106. echo soilAnalysisReportCalcs('Na', 'BS_na_ppm', 'na_ppm_min', 'na_ppm_max', 'Sodium', 'kg', 'col', $record_id, $rand_id);
  107. echo soilAnalysisReportCalcs('P', 'p_colwell', '', '', 'Phosphate', 'kg', 'col', $record_id, $rand_id);
  108. echo soilAnalysisReportCalcs('S', 's_morgan', '', '', 'Sulfur', 'kg', 'col', $record_id, $rand_id);
  109. echo soilAnalysisReportCalcs('Mn', 'mn_dtpa', '', '', 'Manganese', 'kg', 'col', $record_id, $rand_id);
  110. echo soilAnalysisReportCalcs('Fe', 'fe_dtpa', '', '', 'Iron', 'kg', 'col', $record_id, $rand_id);
  111. echo soilAnalysisReportCalcs('Zn', 'zn_dtpa', '', '', 'Zinc', 'kg', 'col', $record_id, $rand_id);
  112. echo soilAnalysisReportCalcs('Cu', 'cu_dtpa', '', '', 'Copper', 'kg', 'col', $record_id, $rand_id);
  113. echo soilAnalysisReportCalcs('AmN', 'NH3_N', '', '', 'AmNitrogen', 'kg', 'col', $record_id, $rand_id);
  114. echo soilAnalysisReportCalcs('B', 'b_cacl2', '', '', 'Boron', 'kg', 'col', $record_id, $rand_id);
  115. echo soilAnalysisReportCalcs('NN', 'NO3_N', '', '', 'NNitrogen', 'kg', 'col', $record_id, $rand_id);
  116. ?>
  117. <form class="report-form" method="post">
  118. <input class="" hidden type="text" name="id" id="id" value="<?= (int)getCurrentUserId() ?>">
  119. <!-- Overview Module -->
  120. <div class="overview-module py-2">
  121. <div class="alert alert-secondary" role="alert">
  122. <div class="text-center h5">Overview</div>
  123. </div>
  124. <textarea id="overview" name="overview" >This is some text within a card body.</textarea>
  125. </div>
  126. <!-- Overview Module -->
  127. <div class="overview-module py-2">
  128. <div class="alert alert-secondary" role="alert">
  129. <div class="text-center h5">Ideal Soil Balancing Program for One Season of a FIVE YEAR Plan</div>
  130. </div>
  131. <div class="card">
  132. <div class="card-body">
  133. <?php
  134. for ($year = 1; $year <= 5; $year++) {
  135. echo soilProgramCalcs('Ca', 'BS_ca_ppm', 'ca_ppm_min', 'ca_ppm_max', 'Calcium', 'kg', $record_id, $rand_id);
  136. }
  137. ?>
  138. </div>
  139. </div>
  140. </div>
  141. <hr>
  142. <div class="row pt-4">
  143. <p style="font-style: italic; font-size: 9px;">Any recommendations provided by Cropmonitor are advice only, We are not paid consultants and we are not covered to accept responsibiliy for any of our suggestions. As no control can be exercised over storage, handling, mixing application or use, or weather, plant or soil conditions before, during or after application (all of which may affect the preformance of our program), no responsibility for, or liability for any failure in performance, losses, damage or injuries consequential or otherwise, arisiing form such storage mixng application or use will be accepted under any circumstances whatsoever. The buyer assumes all responsibility for the use of any of our products.</p>
  144. </div>
  145. </form>
  146. </div>
  147. <script type="text/javascript">
  148. $(document).ready(function(){
  149. var timeoutId;
  150. $('form textarea, form input').on('input propertychange change', function() {
  151. console.log('Textarea Change');
  152. clearTimeout(timeoutId);
  153. timeoutId = setTimeout(function() {
  154. // Runs 1 second (1000 ms) after the last change
  155. saveToDB();
  156. }, 1000);
  157. });
  158. function saveToDB() {
  159. console.log('Saving to the db');
  160. form = $('.report-form');
  161. $.ajax({
  162. url: "/dashboard/crop-analysis/updatecomment.php?rid=<?= (int)$record_id ?>&rand=<?= (float)$rand_id ?>",
  163. type: "POST",
  164. data: form.serialize(), // serializes the form's elements.
  165. beforeSend: function(xhr) {
  166. // Let them know we are saving
  167. $('.form-status-holder').html('Saving...');
  168. },
  169. success: function(data) {
  170. var jqObj = jQuery(data); // You can get data returned from your ajax call here. ex. jqObj.find('.returned-data').html()
  171. // Now show them we saved and when we did
  172. var d = new Date();
  173. $('.form-status-holder').html('Saved! Last: ' + d.toLocaleTimeString());
  174. },
  175. });
  176. }
  177. // This is just so we don't go anywhere
  178. // and still save if you submit the form
  179. $('.report-form').submit(function(e) {
  180. saveToDB();
  181. e.preventDefault();
  182. });
  183. });
  184. </script>
  185. </div>
  186. <!--
  187. <script src="https://cloud.tinymce.com/stable/tinymce.min.js?apiKey=xcotawi18mg1imp8im144buq68h9g3ndd3c9c8215w8qu3ld"></script>
  188. <script>
  189. tinymce.init({
  190. selector: 'textarea',
  191. menubar: false,
  192. toolbar: 'bold italic | alignleft aligncenter alignright alignjustify | bullist numlist | removeformat',
  193. plugins: 'autosave',
  194. autosave_interval: '20s'
  195. });
  196. </script>
  197. -->
  198. <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  199. <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
  200. <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  201. <script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
  202. <script type="text/javascript">
  203. addEventListener("load", function() {
  204. setTimeout(hideURLbar, 0);
  205. }, false);
  206. function hideURLbar(){
  207. window.scrollTo(0,1);
  208. }
  209. </script>
  210. <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
  211. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js"></script>
  212. <script src="https://cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.1.0/jquery.magnific-popup.js"></script>
  213. <script>
  214. //https://github.com/eKoopmans/html2pdf.js
  215. $('.downloadPDF').click(function () {
  216. var element = document.getElementById('content'); //document.createElement("body");
  217. element.classList.remove('screen');
  218. element.classList.add('print');
  219. var opt = {
  220. margin: 3,
  221. filename: 'soil-analysis.pdf',
  222. image: { type: 'jpeg', quality: 1.0 },
  223. html2canvas: { scale: 2, letterRendering: true, windowWidth: 1024 }, //, windowWidth: 1024
  224. jsPDF: { orientation: 'portrait', unit: 'mm', format: 'a4', putOnlyUsedFonts: true, floatPrecision: 'smart', }
  225. };
  226. html2pdf()
  227. .from(element)
  228. .toPdf()
  229. .set(opt)
  230. .save()
  231. .then(function(){
  232. element.classList.remove('print');
  233. element.classList.add('screen');
  234. });
  235. });
  236. </script>
  237. </body>
  238. </html>