Jump to content

portabletelly

Members
  • Posts

    51
  • Joined

  • Last visited

Profile Information

  • Gender
    Not Telling

portabletelly's Achievements

Member

Member (2/5)

0

Reputation

  1. In the end I just went with tcpdf was quite simple and very fast to generate. PDF generation is much faster then my current PSA tool. Filesize is also small on the pdfs generated.
  2. Just doing some research on Coverting HTML content quotes into PDF. Allot of what I read and watched is pointing to using composer then a tool like dompdf. For the guru's out there what would you recommend to turn a page like the below with a customers name quote number and 10 to 20 line items and then some totals into a pdf document. I eventually want to have some type of cron job run a task and email pdfs out. Most quotes will be a single page but project quotes will go over to 2 pages. I don't really want to muck around installing composer but before I go too far down the garden path with this section I thought I'd get some feedback on the best way/path to go for php pdf generation for things like quotes and invoices. Option 1. mPDF Options 2. jsPDF Options 3. Puppeteer Option 4. Dompdf This is basic example of the data to go on the quote.
  3. @mac_gyver champion this fixed it JS; echo <<<'JS' <script> function openEditQuantityPopup(quoteItemId, quoteId) { const width = 400; const height = 200; console.log("Opening popup for quoteItemId:", quoteItemId, "quoteId:", quoteId); const left = (window.innerWidth - width) / 2; const top = (window.innerHeight - height) / 2; window.open( `Quotes/Edit_Quote_Quantity.php?quote_item_id=${quoteItemId}&quote_id=${quoteId}`, "EditQuoteQuantity", `width=${width},height=${height},top=${top},left=${left},resizable=no,scrollbars=no` ); } </script> JS;
  4. Further to this I added the console.log the quoteItemId value inside the openEditQuantityPopup() and got this result. inspect shows correct value however popup is defiantly wrong item.
  5. <?php function renderQuoteTopButtons() { echo <<<HTML <div style="margin-bottom: 20px;"> <button onclick="startNewQuote()">๐Ÿ“ New Quote</button> <button onclick="loadTemplateQuote()">๐Ÿ“„ Quote from Template</button> <button onclick="cloneQuote()">๐Ÿ“‹ Clone Quote</button> </div> HTML; } function renderNewQuoteFormWithClientSearch() { echo <<<HTML <div id="newQuoteForm" style="display: block; margin-top: 20px;"> <h3>New Quote Details</h3> <form method="POST" action="Quotes.php?action=create_quote"> <label for="clientSearch">Search Customer:</label><br> <input type="text" id="clientSearch" name="clientSearch" oninput="getSuggestions(this.value)" autocomplete="off" required> <input type="hidden" name="selectedCustomerId" id="selectedCustomerId"> <div id="suggestions"></div><br> <label for="quoteTitle">Quote Title:</label><br> <input type="text" id="quoteTitle" name="quoteTitle" required><br><br> <label for="quoteDate">Quote Date:</label><br> <input type="date" id="quoteDate" name="quoteDate" required><br><br> <label for="quoteNotes">Notes (Optional):</label><br> <textarea id="quoteNotes" name="quoteNotes" rows="4" cols="50"></textarea><br><br> <button type="submit">Create Quote</button> </form> </div> HTML; // JavaScript for showing the form and handling customer selection echo <<<JS <script> function startNewQuote() { document.getElementById('newQuoteForm').style.display = 'block'; } function getSuggestions(query) { if (query.length === 0) { document.getElementById("suggestions").innerHTML = ""; return; } var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("suggestions").innerHTML = this.responseText; } }; xhttp.open("GET", "Functions/get_customer_suggestions.php?q=" + encodeURIComponent(query), true); xhttp.send(); } function selectSuggestion(id, name) { document.getElementById("clientSearch").value = name; document.getElementById("selectedCustomerId").value = id; document.getElementById("suggestions").innerHTML = ""; } </script> JS; } function renderEditQuoteForm($pdo, $quoteId) { // Fetch quote and customer data $stmt = $pdo->prepare("SELECT q.*, c.CompanyName FROM Quote q JOIN Customer c ON q.CustomerID = c.CustomerID WHERE q.QuoteID = ?"); $stmt->execute([$quoteId]); $quote = $stmt->fetch(PDO::FETCH_ASSOC); if (!$quote) { echo "<p>โŒ Quote not found.</p>"; return; } // ๐Ÿ’ฐ Calculate total profit and margin $totalProfit = $quote['QuoteEXTotal'] - $quote['QuoteOurBuytotalEx']; $profitMargin = $quote['QuoteEXTotal'] > 0 ? round(($totalProfit / $quote['QuoteEXTotal']) * 100, 2) : 0; // Fetch contacts for dropdown $contacts = $pdo->prepare("SELECT ContactID, FirstName, LastName FROM Contact WHERE CustomerID = ?"); $contacts->execute([$quote['CustomerID']]); // Fetch sales people $techs = $pdo->query("SELECT TechnicianID, FirstName, LastName FROM Technician")->fetchAll(PDO::FETCH_ASSOC); // Fetch statuses $statuses = $pdo->query("SELECT QuoteStatusID, StatusDescription FROM QuoteStatus")->fetchAll(PDO::FETCH_ASSOC); echo "<br><br>"; echo "<form method='POST' action='Quotes.php?action=update_quote&id={$quoteId}'>"; // ๐ŸŒŸ Header layout (3 columns) echo <<<HTML <br><br> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"> <!-- Customer name (left) --> <div style="flex: 1; text-align: left;"> <strong>Customer:</strong> {$quote['CompanyName']} </div> <!-- Quote Title (center-left) --> <div style="flex: 1; text-align: center;"> <span>{$quote['QuoteTitle']}</span> <button type="button" onclick="openQuoteTitlePopup({$quote['QuoteID']})" style="border: none; background: none; cursor: pointer;">โœ๏ธ</button> </div> <!-- Contact (center-right) --> <div style="flex: 1; text-align: center;"> <label><strong>Contact:</strong></label> <span> HTML; // Close heredoc to insert PHP logic $contactName = ''; $contactStmt = $pdo->prepare("SELECT FirstName, LastName FROM Contact WHERE ContactID = ?"); $contactStmt->execute([$quote['QuotecontactID']]); if ($contactRow = $contactStmt->fetch(PDO::FETCH_ASSOC)) { $contactName = htmlspecialchars($contactRow['FirstName'] . ' ' . $contactRow['LastName']); } echo $contactName ?: "<em>No Contact Selected</em>"; echo " <button type='button' onclick='openContactEditPopup({$quoteId})' title='Edit Contact' style='margin-left: 6px; font-size: 14px; border: none; background: none; cursor: pointer;'>๐Ÿ‘ค</button>"; echo "</span><br><label><strong>Sales Person:</strong></label> <span>"; // Insert PHP logic for Sales Person $salesPersonName = ''; $salesStmt = $pdo->prepare("SELECT FirstName, LastName FROM Technician WHERE TechnicianID = ?"); $salesStmt->execute([$quote['SalesPerson']]); if ($salesRow = $salesStmt->fetch(PDO::FETCH_ASSOC)) { $salesPersonName = htmlspecialchars($salesRow['FirstName'] . ' ' . $salesRow['LastName']); } echo $salesPersonName ?: "<em>Not Assigned</em>"; echo " <button type='button' onclick='openSalesPersonEditPopup({$quoteId})' title='Edit Sales Person' style='margin-left: 6px; font-size: 14px; border: none; background: none; cursor: pointer;'>๐Ÿ‘ค</button>"; echo "</span>"; // Resume heredoc echo <<<HTML </span> HTML; $escapedNotes = htmlspecialchars($quote['Notes']); // Close previous heredoc and resume HTML echo <<<HTML </select> </div> <!-- Quote ID and Date Created (right) --> <div style="flex: 1; text-align: right;"> <strong>Quote #{$quote['QuoteID']}</strong><br> <small> <strong>Date Created:</strong> {$quote['DateCreated']} <button type="button" onclick="openDateEditPopup({$quote['QuoteID']})" style="border: none; background: none; cursor: pointer;"> ๐Ÿ“… </button> </small> <div style="margin-top: 6px;"> <small> <strong>Quote Expiry Date:</strong> {$quote['QuoteExpireyDate']} <button type="button" onclick="openExpiryEditPopup({$quote['QuoteID']})" style="border: none; background: none; cursor: pointer;"> ๐Ÿ“… </button> </small> </div> <div style="margin-top: 8px;"> <label style="font-size: 13px;"><strong>Quote Notes:</strong></label> <button type="button" onclick="openNotesPopup({$quote['QuoteID']})" title="View & Edit Notes" style="border: none; background: none; cursor: pointer;">๐Ÿ”</button> </div> <!-- Hidden field to keep existing notes in form --> <input type="hidden" name="Notes" value="{$escapedNotes}"> HTML; // โœ… Determine current status text $currentStatusText = ''; foreach ($statuses as $status) { if ($status['QuoteStatusID'] == $quote['StatusID']) { $currentStatusText = htmlspecialchars($status['StatusDescription']); break; } } // โœ… Output status row echo <<<HTML <div style="margin-top: 8px;"> <label style="font-size: 13px;"><strong>Status:</strong></label> <span style="margin-left: 6px; font-weight: bold;">{$currentStatusText}</span> <button type="button" onclick="openStatusEditPopup({$quote['QuoteID']})" title="Edit Status" style="border: none; background: none; cursor: pointer;">โœ๏ธ</button> </div> </div> </div> HTML; // ๐Ÿ” Quote Notes with popup button //$escapedNotes = htmlspecialchars($quote['Notes']); //echo <<<HTML //<div style="margin-bottom: 10px;"> // <label><strong>Quote Notes:</strong></label> // <button type="button" onclick="openNotesPopup({$quote['QuoteID']})" title="View & Edit Notes" style="margin-left: 8px; font-size: 16px;">๐Ÿ”</button> //</div> //<!-- Hidden field to keep existing notes in form --> //<input type="hidden" name="Notes" value="{$escapedNotes}"> //HTML; // echo "</select><br><br>"; // ๐Ÿงพ Quote Items Header and Add Button echo <<<HTML <hr style="margin: 20px 0;"> <div style="display: flex; justify-content: space-between; align-items: center;"> <h4 style="margin: 0;">Quote Items</h4> <button type="button" onclick="openAddItemPopup({$quote['QuoteID']})" title="Add Item" style="font-size: 16px; cursor: pointer;"> โž• Add Item </button> </div> <table border="1" cellpadding="6" cellspacing="0" width="100%" style="margin-top: 10px; text-align: left;"> <thead> <tr> <th>Product Name</th> <th>Description</th> <th>Quantity</th> <th>WS Ex Per Unit</th> <th>Sell Ex Per Unit</th> <th>Sell Tot Ex</th> <th>Sell Tot Inc</th> <th>GST</th> <th>Del</th> </tr> </thead> <tbody> HTML; // Fetch quote items // Fetch quote items $itemsStmt = $pdo->prepare(" SELECT qi.quote_item_id, qi.product_id, qi.service_id, qi.WSExPerUnit, qi.SellExPerUnit, qi.SellTotalEx, qi.SellTotalInc, qi.quantity, qi.discount, qi.GSTAmount, qi.custom_description, qi.is_custom_item, p.product_name, p.description FROM QuoteItems qi LEFT JOIN Products p ON qi.product_id = p.product_id WHERE qi.quote_id = ? "); $itemsStmt->execute([$quoteId]); $quoteItems = $itemsStmt->fetchAll(PDO::FETCH_ASSOC); // Loop if (count($quoteItems) > 0) { echo "<!-- Entering quoteItems loop -->"; foreach ($quoteItems as $item) { echo "<!-- Looping item: quote_item_id = {$item['quote_item_id']} -->"; echo "<!-- DEBUG quote_item_id: {$item['quote_item_id']} -->"; // ๐Ÿ” Debug line $isCustom = $item['is_custom_item'] ?? 0; $productName = $isCustom ? 'Custom Item' : ($item['product_name'] ?? 'โ€”'); $description = $isCustom ? ($item['custom_description'] ?? 'โ€”') : ($item['description'] ?? 'โ€”'); echo "<tr>"; echo "<td>" . htmlspecialchars($productName) . "</td>"; echo "<td>" . htmlspecialchars($description) . "</td>"; // Quantity with ๐Ÿ›  button $quoteItemId = (int)$item['quote_item_id']; echo "<td>" . htmlspecialchars($item['quantity']) . ""; echo "<button type=\"button\" onclick=\"openEditQuantityPopup(" . (int)$item['quote_item_id'] . ", " . (int)$quoteId . ")\" title=\"Edit Quantity\" style=\"border: none; background: none; cursor: pointer; font-size: 14px;\"> ๐Ÿ›  </button>"; echo "</td>"; echo "<td>" . number_format((float)$item['WSExPerUnit'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellExPerUnit'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellTotalEx'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellTotalInc'], 2) . "</td>"; echo "<td>" . number_format((float)$item['GSTAmount'], 2) . "</td>"; // Delete button echo "<td style='text-align: center;'> <form method='POST' action='Quotes.php?action=edit_quote&id=" . (int)$quoteId . "' onsubmit=\"return confirm('Are you sure you want to delete this item?');\" style='display:inline;'> <input type='hidden' name='delete_item_id' value='" . (int)$item['quote_item_id'] . "'> <button type='submit' style='border:none; background:none; color:red; font-size:16px;'>โŒ</button> </form> </td>"; echo "</tr>"; } } else { echo "<tr><td colspan='9' style='text-align:center;'><em>No items added yet.</em></td></tr>"; } // Resume heredoc echo <<<HTML </tbody> </table> HTML; // ๐Ÿ’ฐ Totals (read-only) echo "<br><label>Ex. Total:</label> {$quote['QuoteEXTotal']}<br>"; echo "<label>Tax Total:</label> {$quote['QuoteTaxTotal']}<br>"; echo "<label>Inc. Total:</label> {$quote['QuoteIncTotal']}<br>"; echo "<label>Our Buy Total (Ex):</label> {$quote['QuoteOurBuytotalEx']}<br><br>"; //echo "<button type='button' onclick='openUpdateTotalsPopup({$quoteId})'>๐Ÿ“Š Update Totals</button>"; echo "<button type=\"button\" onclick=\"openUpdateTotalsPopup({$quoteId})\">๐Ÿ“Š Update Totals</button>"; echo "<br><br><label><strong>Total Profit (Ex GST):</strong></label> \$" . number_format($totalProfit, 2) . "<br>"; echo "<label><strong>Profit Margin:</strong></label> {$profitMargin}%<br><br>"; echo "</form>"; echo <<<JS <script> function openNotesPopup(quoteId) { const width = 800; const height = 400; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; const screenHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Quote_Notes.php?id=" + quoteId, "QuoteNotes", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=yes,scrollbars=yes" ); } function openQuoteTitlePopup(quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; const screenHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_Title.php?id=" + quoteId, "EditQuoteTitle", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openDateEditPopup(quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; const screenHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_Date.php?id=" + quoteId, "EditQuoteDate", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openStatusEditPopup(quoteId) { const width = 400; const height = 250; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_Status.php?id=" + quoteId, "EditQuoteStatus", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openExpiryEditPopup(quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_Expiry.php?id=" + quoteId, "EditQuoteExpiry", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openContactEditPopup(quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_Contact.php?id=" + quoteId, "EditQuoteContact", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openSalesPersonEditPopup(quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Edit_Quote_SalesPerson.php?id=" + quoteId, "EditQuoteSalesPerson", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openAddItemPopup(quoteId) { const width = 600; const height = 400; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( "Quotes/Add_Quote_Item.php?quoteId=" + quoteId, "AddQuoteItem", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } function openUpdateTotalsPopup(quoteId) { const width = 400; const height = 200; const left = (window.innerWidth - width) / 2; const top = (window.innerHeight - height) / 2; window.open( `Quotes/Update_Quote_Totals.php?quoteId=${quoteId}`, 'UpdateQuoteTotals', `width=${width},height=${height},top=${top},left=${left},resizable=no,scrollbars=no` ); } function openEditQuantityPopup(quoteItemId, quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( `Quotes/Edit_Quote_Quantity.php?quote_item_id=${quoteItemId}&quote_id=${quoteId}`, "EditQuoteQuantity", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } </script> JS; } ?> This is the full Quote_Functions.php code and this is the Quotes.php below that calls the functions. <?php //ini_set('display_errors', 1); //ini_set('display_startup_errors', 1); //error_reporting(E_ALL); session_start(); // Check if the user is logged in if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { header("Location: /login.php"); exit(); } // Include necessary files include 'Functions/Common_Functions.php'; include 'Functions/Quote_Functions.php'; include 'Functions/db_con.php'; include 'Functions/Button_Quotes.php'; // Left menu buttons // โœ… Handle Quote Creation BEFORE output // โœ… Handle Quote Creation Before Output if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['action']) && $_GET['action'] === 'create_quote') { $customerId = $_POST['selectedCustomerId'] ?? null; $quoteTitle = $_POST['quoteTitle'] ?? ''; $quoteDate = $_POST['quoteDate'] ?? ''; $quoteNotes = $_POST['quoteNotes'] ?? ''; if ($customerId && $quoteTitle && $quoteDate) { $stmt = $pdo->prepare("INSERT INTO Quote (CustomerID, QuoteTitle, Notes, DateCreated, StatusID, QuoteEXTotal, QuoteIncTotal, QuoteTaxTotal, QuoteOurBuytotalEx) VALUES (?, ?, ?, ?, ?, 0.00, 0.00, 0.00, 0.00)"); $stmt->execute([$customerId, $quoteTitle, $quoteNotes, $quoteDate, 1]); $newQuoteId = $pdo->lastInsertId(); header("Location: Quotes.php?action=edit_quote&id=" . $newQuoteId); exit(); } else { echo "โŒ Missing required data."; exit(); } } // โœ… Display main menu func_header(); menu_items(); // โœ… Begin layout echo "<div class='main-container'>"; // โœ… Left-side menu echo "<div class='side-menu'>"; echo "<h4 style='color: white; text-align: center;'>Quotes</h4>"; renderQuotesButtons(); echo "</div>"; // โœ… Right-side content echo "<div class='right-content'>"; // โœ… Routing by action if (isset($_GET['action'])) { switch ($_GET['action']) { case 'new_quote': echo "<h2 style='text-align: left;'>Create New Quote</h2>"; renderQuoteTopButtons(); renderNewQuoteFormWithClientSearch(); break; case 'all_quotes': echo "<h2 style='text-align: left;'>All Quotes</h2>"; break; case 'pending_quotes': echo "<h2 style='text-align: left;'>Pending Quotes</h2>"; break; case 'approved_quotes': echo "<h2 style='text-align: left;'>Approved Quotes</h2>"; break; case 'rejected_quotes': echo "<h2 style='text-align: left;'>Rejected Quotes</h2>"; break; case 'expired_quotes': echo "<h2 style='text-align: left;'>Expired Quotes</h2>"; break; case 'draft_quotes': echo "<h2 style='text-align: left;'>Draft Quotes</h2>"; break; case 'converted_quotes': echo "<h2 style='text-align: left;'>Converted Quotes</h2>"; break; case 'search_quotes': echo "<h2 style='text-align: left;'>Search Quotes</h2>"; break; case 'customer_quotes': echo "<h2 style='text-align: left;'>Customer Quotes</h2>"; break; case 'quote_reports': echo "<h2 style='text-align: left;'>Quote Reports</h2>"; break; case 'quote_settings': echo "<h2 style='text-align: left;'>Quote Settings</h2>"; echo ' <table border="1"> <tr><th>Feature</th><th>Action</th></tr> <tr> <td>Import/Update Products</td> <td><button id="importProducts">Import</button> <span id="syncStatus"></span></td> </tr> <tr> <td>Sync Contacts</td> <td><button id="syncContacts">Sync</button> <span id="syncContactsStatus"></span></td> </tr> <tr> <td>Update Vendors</td> <td><button id="manageVendors">Manage</button></td> </tr> </table> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function () { $("#importProducts").click(function () { $("#syncStatus").text("Importing..."); $.post("Functions/Product_Functions.php", { sync_products: true }, function (response) { $("#syncStatus").text(response); }).fail(function () { $("#syncStatus").text("Error importing products."); }); }); $("#syncContacts").click(function () { $("#syncContactsStatus").text("Syncing contacts..."); $.post("Functions/Syncro_Contact_Sync.php", { sync_contacts: true }, function (response) { $("#syncContactsStatus").text(response); }).fail(function () { $("#syncContactsStatus").text("โŒ Error syncing contacts."); }); }); $("#manageVendors").click(function () { window.open("Vendors/Manage_Vendors.php", "ManageVendors", "width=600,height=400"); }); }); </script>'; break; case 'edit_quote': $quoteId = $_GET['id'] ?? null; // ๐Ÿ‘‡ Handle delete quote item if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_item_id'])) { $itemIdToDelete = $_POST['delete_item_id']; $deleteStmt = $pdo->prepare("DELETE FROM QuoteItems WHERE quote_item_id = ?"); $deleteStmt->execute([$itemIdToDelete]); } if ($quoteId) { renderEditQuoteForm($pdo, $quoteId); } else { echo "<p>โŒ Quote ID is missing.</p>"; } break; default: echo "<h2>Quotes Dashboard</h2><p>Welcome to the Quotes Dashboard. Choose an option from the left menu.</p>"; break; } } else { echo "<h2>Quotes Dashboard</h2><p>Welcome to the Quotes Dashboard. Choose an option from the left menu.</p>"; } echo "</div>"; // End right-content echo "</div>"; // End main-container ?>
  6. Ok here goes hope i can explain this correctly. Im building an internal quoting system THE PROBLEM: . These buttons 1, 2, and 3 when code is inspected all have the correct quote_item_id However when you click on any change quantity the javascript brings up the popup with the very last line items quote_item_id every time. THE CODE: This bit of code is whats doing the work // Loop if (count($quoteItems) > 0) { echo "<!-- Entering quoteItems loop -->"; foreach ($quoteItems as $item) { echo "<!-- Looping item: quote_item_id = {$item['quote_item_id']} -->"; echo "<!-- DEBUG quote_item_id: {$item['quote_item_id']} -->"; // ๐Ÿ” Debug line $isCustom = $item['is_custom_item'] ?? 0; $productName = $isCustom ? 'Custom Item' : ($item['product_name'] ?? 'โ€”'); $description = $isCustom ? ($item['custom_description'] ?? 'โ€”') : ($item['description'] ?? 'โ€”'); echo "<tr>"; echo "<td>" . htmlspecialchars($productName) . "</td>"; echo "<td>" . htmlspecialchars($description) . "</td>"; // Quantity with ๐Ÿ›  button $quoteItemId = (int)$item['quote_item_id']; echo "<td>" . htmlspecialchars($item['quantity']) . ""; echo "<button type=\"button\" onclick=\"openEditQuantityPopup(" . (int)$item['quote_item_id'] . ", " . (int)$quoteId . ")\" title=\"Edit Quantity\" style=\"border: none; background: none; cursor: pointer; font-size: 14px;\"> ๐Ÿ›  </button>"; echo "</td>"; echo "<td>" . number_format((float)$item['WSExPerUnit'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellExPerUnit'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellTotalEx'], 2) . "</td>"; echo "<td>" . number_format((float)$item['SellTotalInc'], 2) . "</td>"; echo "<td>" . number_format((float)$item['GSTAmount'], 2) . "</td>"; // Delete button echo "<td style='text-align: center;'> <form method='POST' action='Quotes.php?action=edit_quote&id=" . (int)$quoteId . "' onsubmit=\"return confirm('Are you sure you want to delete this item?');\" style='display:inline;'> <input type='hidden' name='delete_item_id' value='" . (int)$item['quote_item_id'] . "'> <button type='submit' style='border:none; background:none; color:red; font-size:16px;'>โŒ</button> </form> </td>"; echo "</tr>"; } } else { echo "<tr><td colspan='9' style='text-align:center;'><em>No items added yet.</em></td></tr>"; } And this is the javascript calling the popup window function openEditQuantityPopup(quoteItemId, quoteId) { const width = 400; const height = 200; const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const screenWidth = window.innerWidth || document.documentElement.clientWidth || screen.width; const screenHeight = window.innerHeight || document.documentElement.clientHeight || screen.height; const left = dualScreenLeft + (screenWidth - width) / 2; const top = dualScreenTop + (screenHeight - height) / 2; window.open( `Quotes/Edit_Quote_Quantity.php?quote_item_id=${quoteItemId}&quote_id=${quoteId}`, "EditQuoteQuantity", "width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",resizable=no,scrollbars=no" ); } and this is the Edit_Quote_Quantity.php that run when button is clicked <?php var_dump($_GET); include '../Functions/db_con.php'; $quoteItemId = $_GET['quote_item_id'] ?? null; $quoteId = $_GET['quote_id'] ?? null; if (!$quoteItemId || !$quoteId) { echo "Missing parameters."; exit; } // Get current quantity $stmt = $pdo->prepare("SELECT quantity FROM QuoteItems WHERE quote_item_id = ?"); $stmt->execute([$quoteItemId]); $item = $stmt->fetch(PDO::FETCH_ASSOC); $currentQty = $item['quantity'] ?? 1; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $newQty = (int)$_POST['quantity']; // Update quantity $update = $pdo->prepare("UPDATE QuoteItems SET quantity = ? WHERE quote_item_id = ?"); $update->execute([$newQty, $quoteItemId]); echo "<script>window.opener.location.reload(); window.close();</script>"; exit; } ?> <!DOCTYPE html> <html> <head> <title>Edit Quantity</title> </head> <body style="font-family: Arial; padding: 20px;"> <h3>Edit Quantity</h3> <form method="POST"> <label>New Quantity:</label><br> <input type="number" name="quantity" value="<?= htmlspecialchars($currentQty) ?>" min="1" required><br><br> <button type="submit">Update</button> </form> </body> </html> The process actually works however it always changes the quantity to the last line item called up in the foreach loop. Been racking my brains for a day on this one trying to work it out.
  7. When I click on my All Renewals button it filters all the renewals in the database and puts a button on the end called view details. Then PHP pulls all the details from the database and display the renewal details like below. I then proceed to click update Notes and I get a Text box when it should be showing the current notes in the database "Maintenance contract for firewall support" as well as adding new notes. Both are not working and I spent a whole day on it trying to work it out. This is my Renewals.php file <?php session_start(); include 'Functions/Common_Functions.php'; // Includes menu_items function include 'Functions/functions_renewals.php'; // Includes all renewal button functions include 'Functions/db_con.php'; // Database connection // Display main menu func_header(); menu_items(); // Start the main container echo "<div class='main-container'>"; // Left-side menu echo "<div class='side-menu'>"; echo "<h4 style='color: white; text-align: center;'>Renewals</h4>"; renderRenewalButtons(); echo "</div>"; // Right-side content echo "<div class='right-content'>"; echo "<h2>All Renewals</h2>"; if (isset($_GET['filter']) && $_GET['filter'] === 'allrenewals') { $query = "SELECT * FROM Renewals"; $result = $pdo->query($query); echo "<table class='table table-bordered'>"; echo "<tr> <th>Company Name</th> <th>Service Name</th> <th>Renewal Date</th> <th>Status</th> <th>Notes</th> <th>Action</th> </tr>"; while ($row = $result->fetch(PDO::FETCH_ASSOC)) { echo "<tr>"; echo "<td>" . htmlspecialchars($row['Customer_ID']) . "</td>"; // Replace with actual company name if available echo "<td>" . htmlspecialchars($row['Service_Name']) . "</td>"; echo "<td>" . htmlspecialchars($row['Renewal_Date']) . "</td>"; echo "<td>" . htmlspecialchars($row['Status']) . "</td>"; echo "<td>" . htmlspecialchars($row['Notes']) . "</td>"; echo "<td><button class='view-details-btn' data-id='" . $row['Renewals_ID'] . "'>View Details</button></td>"; echo "</tr>"; } echo "</table>"; } echo "<div id='renewal-details' style='display:none; padding: 20px; border: 1px solid #ddd; margin-top: 20px;'></div>"; echo "</div>"; // End right-side content echo "</div>"; // End main container ?> <!-- โœ… Update Notes Modal --> <div id="updateNotesModal" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); background:white; padding:20px; border-radius:8px; box-shadow: 0px 4px 6px rgba(0,0,0,0.2);"> <h3>Update Notes</h3> <p id="currentNotesText"></p> <textarea id="newNotesInput" rows="4" style="width:100%;"></textarea> <br><br> <button id="confirmUpdateNotes">Save Notes</button> <button onclick="closeNotesModal()">Cancel</button> </div> <script> document.addEventListener("DOMContentLoaded", function() { console.log("โœ… DOM fully loaded and parsed."); // Attach event listeners to all "View Details" buttons document.querySelectorAll(".view-details-btn").forEach(button => { button.addEventListener("click", function() { let renewalId = this.getAttribute("data-id"); console.log("๐Ÿ”„ Fetching details for Renewal ID:", renewalId); fetch("get_renewal_details.php?renewal_id=" + renewalId) .then(response => response.text()) .then(data => { document.getElementById("renewal-details").innerHTML = data; document.getElementById("renewal-details").style.display = "block"; console.log("โœ… Renewal details loaded."); // โœ… Reattach event listeners after loading new content setTimeout(attachButtonEvents, 500); }) .catch(error => console.error("โŒ Error fetching renewal details:", error)); }); }); }); // โœ… Function to reattach events to dynamically loaded buttons function attachButtonEvents() { console.log("๐Ÿ”„ Reattaching event listeners..."); // Attach "Change Status" button event document.querySelectorAll(".change-status-btn").forEach(button => { button.addEventListener("click", function() { console.log("โœ… Change Status button clicked."); openStatusModal(this); }); }); // Attach "Delete" button event document.querySelectorAll(".delete-btn").forEach(button => { button.addEventListener("click", function() { console.log("โœ… Delete button clicked."); deleteRenewal(this); }); }); // Attach "Update Notes" button event document.querySelectorAll(".update-notes-btn").forEach(button => { button.addEventListener("click", function() { console.log("โœ… Update Notes button clicked."); openNotesModal(this); }); });; } // โœ… Open Change Status Modal function openStatusModal(button) { let currentStatus = button.getAttribute("data-current-status"); let renewalId = button.getAttribute("data-id"); console.log("๐Ÿ“ข Opening modal for Renewal ID:", renewalId, "Current Status:", currentStatus); document.getElementById("currentStatusText").innerText = currentStatus; document.getElementById("confirmChangeStatus").setAttribute("data-id", renewalId); document.getElementById("changeStatusModal").style.display = "block"; } // โœ… Close Modal function closeStatusModal() { document.getElementById("changeStatusModal").style.display = "none"; } // โœ… Handle Changing Status (Auto-Refresh) document.addEventListener("click", function(event) { if (event.target.id === "confirmChangeStatus") { let renewalId = event.target.getAttribute("data-id"); let newStatus = document.getElementById("statusDropdown").value; console.log("โณ Sending status change request..."); fetch("change_status.php?renewal_id=" + renewalId + "&new_status=" + newStatus, { method: "GET" }) .then(response => response.text()) .then(data => { alert("โœ… Status Updated: " + data); closeStatusModal(); // โœ… Auto-refresh after status update setTimeout(() => { location.reload(); }, 1000); // Refresh after 1 second }) .catch(error => { alert("โŒ Error updating status: " + error); }); } }); // โœ… Delete function function deleteRenewal(button) { let renewalId = button.getAttribute("data-id"); if (confirm("โš ๏ธ Are you sure you want to delete this renewal?")) { console.log("โณ Deleting renewal..."); fetch("delete_renewal.php?renewal_id=" + renewalId, { method: "GET" }) .then(response => response.text()) .then(data => { alert("โœ… Server Response: " + data); document.getElementById("renewal-details").innerHTML = "<p style='color: green;'>Renewal successfully deleted.</p>"; }) .catch(error => { alert("โŒ Error deleting renewal: " + error); }); } } // โœ… Open Update Notes Modal function openNotesModal(button) { let renewalId = button.getAttribute("data-id"); let currentNotes = button.getAttribute("data-notes") || "No previous notes."; console.log("๐Ÿ“ข Opening Notes Modal for Renewal ID:", renewalId); document.getElementById("currentNotesText").innerText = "Current Notes: " + currentNotes; document.getElementById("newNotesInput").value = ""; // Clear previous input document.getElementById("confirmUpdateNotes").setAttribute("data-id", renewalId); document.getElementById("updateNotesModal").style.display = "block"; } // โœ… Close Notes Modal function closeNotesModal() { document.getElementById("updateNotesModal").style.display = "none"; } // โœ… Handle Updating Notes (Auto-Refresh) document.addEventListener("click", function(event) { if (event.target.id === "confirmUpdateNotes") { let renewalId = event.target.getAttribute("data-id"); let newNotes = document.getElementById("newNotesInput").value.trim(); if (!newNotes) { alert("โŒ Please enter new notes."); return; } console.log("โณ Sending notes update request..."); fetch("update_notes.php?renewal_id=" + renewalId + "&new_notes=" + encodeURIComponent(newNotes), { method: "GET" }) .then(response => response.text()) .then(data => { alert("โœ… Notes Updated: " + data); closeNotesModal(); // โœ… Auto-refresh after updating notes setTimeout(() => { location.reload(); }, 1000); // Refresh after 1 second }) .catch(error => { alert("โŒ Error updating notes: " + error); }); } }); </script> This is my get_renewal_details.php file <?php include 'Functions/db_con.php'; // Database connection if (!isset($_GET['renewal_id'])) { die("<p style='color: red;'>Error: No Renewal ID received.</p>"); } $renewal_id = intval($_GET['renewal_id']); // Fetch renewal details with JOINs for status name and customer name $stmt = $pdo->prepare(" SELECT r.*, rs.RenewalsStatusName, c.CompanyName FROM Renewals r LEFT JOIN RenewalsStatus rs ON r.Status = rs.RenewalsStatusID LEFT JOIN Customer c ON r.Customer_ID = c.CustomerID WHERE r.Renewals_ID = ? "); $stmt->execute([$renewal_id]); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!$row) { die("<p style='color: red;'>Error: No details found for Renewal ID: $renewal_id</p>"); } // Display renewal details echo "<h3>Renewal Details</h3>"; echo "<p><strong>Customer:</strong> " . htmlspecialchars($row['CompanyName'] ?? 'Unknown') . "</p>"; echo "<p><strong>Service Name:</strong> " . htmlspecialchars($row['Service_Name']) . "</p>"; echo "<p><strong>Service Type:</strong> " . htmlspecialchars($row['Service_Type']) . "</p>"; echo "<p><strong>Vendor:</strong> " . htmlspecialchars($row['Vendor']) . "</p>"; echo "<p><strong>Contract ID:</strong> " . htmlspecialchars($row['Contract_ID']) . "</p>"; echo "<p><strong>Start Date:</strong> " . htmlspecialchars($row['Start_Date']) . "</p>"; echo "<p><strong>End Date:</strong> " . htmlspecialchars($row['End_Date']) . "</p>"; echo "<p><strong>Renewal Date:</strong> " . htmlspecialchars($row['Renewal_Date']) . "</p>"; echo "<p><strong>Status:</strong> " . htmlspecialchars($row['RenewalsStatusName']) . "</p>"; echo "<p><strong>Recurrence:</strong> " . htmlspecialchars($row['Recurrence']) . "</p>"; echo "<p><strong>Amount:</strong> $" . number_format($row['Amount'], 2) . "</p>"; echo "<p><strong>Alert Days Before:</strong> " . htmlspecialchars($row['Alert_Days_Before']) . " days</p>"; echo "<p><strong>Last Alert Sent:</strong> " . ($row['Last_Alert_Sent'] ? htmlspecialchars($row['Last_Alert_Sent']) : "N/A") . "</p>"; echo "<p><strong>Notes:</strong> " . nl2br(htmlspecialchars($row['Notes'])) . "</p>"; // Buttons echo "<div style='display: flex; justify-content: center; gap: 10px; margin-top: 20px;'> <button class='change-status-btn' data-id='" . (int) $renewal_id . "' data-current-status='" . htmlspecialchars($row['RenewalsStatusName'] ?? '', ENT_QUOTES, 'UTF-8') . "' style='background-color: blue; color: white; padding: 10px; border: none; cursor: pointer;'>Change Status</button> <button class='update-notes-btn' data-id='" . $renewal_id . "' data-notes='" . htmlspecialchars($row['Notes'] ?? '', ENT_QUOTES) . "' style='background-color: green; color: white; padding: 10px; border: none; cursor: pointer;'> Update Notes </button> <p>DEBUG Notes: " . htmlspecialchars($row['Notes'] ?? 'NO NOTES', ENT_QUOTES) . "</p> <!-- Debugging --> <button class='delete-btn' data-id='" . (int) $renewal_id . "' style='background-color: red; color: white; padding: 10px; border: none; cursor: pointer;'>Delete</button> </div>"; // Status Change Modal echo "<div id='changeStatusModal' style='display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border: 1px solid #ddd; box-shadow: 0px 0px 10px rgba(0,0,0,0.3); z-index: 1000;'> <h3>Change Renewal Status</h3> <p>Current Status: <span id='currentStatusText'></span></p> <label for='statusDropdown'>Select New Status:</label> <select id='statusDropdown'> <option value='1'>Active</option> <option value='2'>Pending</option> <option value='3'>Expired</option> <option value='4'>Renewed</option> <option value='5'>Cancelled</option> </select> <br><br> <button id='confirmChangeStatus' style='background-color: blue; color: white; padding: 10px; border: none; cursor: pointer;'>Change Status</button> <button onclick='closeStatusModal()' style='background-color: gray; color: white; padding: 10px; border: none; cursor: pointer;'>Close</button> </div>"; // Notes Modal echo "<div id='updateNotesModal' style='display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border: 1px solid #ddd; box-shadow: 0px 0px 10px rgba(0,0,0,0.3); z-index: 1000; width: 400px;'> <h3>Update Renewal Notes</h3> <label for='existingNotes'><strong>Current Notes:</strong></label> <textarea id='existingNotes' readonly style='width: 100%; height: 100px; margin-bottom: 10px; background-color: #f0f0f0;'></textarea> <label for='newNotes'><strong>New Notes:</strong></label> <textarea id='newNotes' style='width: 100%; height: 100px;'></textarea> <br><br> <button id='confirmUpdateNotes' style='background-color: green; color: white; padding: 10px; border: none; cursor: pointer;'>Update</button> <button id='clearNotes' style='background-color: red; color: white; padding: 10px; border: none; cursor: pointer;'>Clear Notes</button> <button onclick='closeNotesModal()' style='background-color: gray; color: white; padding: 10px; border: none; cursor: pointer;'>Close</button> </div>"; ?> <script> document.addEventListener("DOMContentLoaded", function() { console.log("โœ… DOM fully loaded and parsed."); // โœ… Open Change Status Modal document.querySelectorAll(".change-status-btn").forEach(button => { button.addEventListener("click", function() { let renewalId = this.getAttribute("data-id"); let currentStatus = this.getAttribute("data-current-status"); document.getElementById("currentStatusText").innerText = currentStatus; document.getElementById("confirmChangeStatus").setAttribute("data-id", renewalId); document.getElementById("changeStatusModal").style.display = "block"; }); }); // โœ… Change Status Action document.getElementById("confirmChangeStatus").addEventListener("click", function() { let renewalId = this.getAttribute("data-id"); let newStatus = document.getElementById("statusDropdown").value; fetch("change_status.php?renewal_id=" + renewalId + "&new_status=" + newStatus, { method: "GET" }) .then(response => response.text()) .then(data => { alert("โœ… Status Updated: " + data); closeStatusModal(); setTimeout(() => { location.reload(); }, 1000); }) .catch(error => { alert("โŒ Error updating status: " + error); }); }); function closeStatusModal() { document.getElementById("changeStatusModal").style.display = "none"; } // โœ… Open Update Notes Modal document.querySelectorAll(".update-notes-btn").forEach(button => { button.addEventListener("click", function () { let renewalId = this.getAttribute("data-id"); let existingNotes = this.getAttribute("data-notes") || ""; console.log("๐Ÿ“ Opening Update Notes modal..."); console.log("๐Ÿ“Œ Renewal ID:", renewalId); console.log("๐Ÿ“Œ Existing Notes Data:", existingNotes); // Debugging // โœ… Ensure "Current Notes" field is found let existingNotesField = document.getElementById("existingNotes"); let newNotesField = document.getElementById("newNotes"); if (!existingNotesField || !newNotesField) { console.error("โŒ ERROR: Notes text fields not found in the modal."); return; } // โœ… Directly Assign Notes Value existingNotesField.value = existingNotes; console.log("โœ… Assigned Existing Notes to Text Field:", existingNotesField.value); // โœ… Clear the "New Notes" field newNotesField.value = ""; // โœ… Store the renewal ID inside the update button document.getElementById("confirmUpdateNotes").setAttribute("data-id", renewalId); // โœ… Show the modal document.getElementById("updateNotesModal").style.display = "block"; }); }); // โœ… Save Notes Button (Using POST) document.getElementById("confirmUpdateNotes").addEventListener("click", function () { let renewalId = this.getAttribute("data-id"); let newNotes = document.getElementById("newNotes").value.trim(); console.log("๐Ÿ” Checking new notes input:", newNotes); if (!renewalId) { alert("โŒ Missing renewal ID."); return; } if (!newNotes || newNotes.length === 0) { alert("โŒ Please enter new notes."); return; } console.log("๐Ÿ›  Sending POST request with:", { renewal_id: renewalId, new_notes: newNotes }); fetch("update_notes.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "renewal_id=" + encodeURIComponent(renewalId) + "&new_notes=" + encodeURIComponent(newNotes) }) .then(response => response.text()) .then(data => { console.log("โœ… Server response:", data); alert("โœ… Notes Updated: " + data); closeNotesModal(); setTimeout(() => { location.reload(); }, 1000); }) .catch(error => { alert("โŒ Error updating notes: " + error); }); }); function closeNotesModal() { document.getElementById("updateNotesModal").style.display = "none"; } }); </script> and this is my update_notes.php file <?php include 'Functions/db_con.php'; // Database connection if (!isset($_GET['renewal_id']) || !isset($_GET['new_notes'])) { die("Error: Missing renewal ID or new notes."); } $renewal_id = intval($_GET['renewal_id']); $new_notes = trim($_GET['new_notes']); $stmt = $pdo->prepare("UPDATE Renewals SET Notes = ? WHERE Renewals_ID = ?"); if ($stmt->execute([$new_notes, $renewal_id])) { echo "Notes updated successfully."; } else { echo "Error updating notes."; } ?> This is the section of code i think has the issue // โœ… Save Notes Button (Using POST) document.getElementById("confirmUpdateNotes").addEventListener("click", function () { let renewalId = this.getAttribute("data-id"); let newNotes = document.getElementById("newNotes").value.trim(); console.log("๐Ÿ” Checking new notes input:", newNotes); if (!renewalId) { alert("โŒ Missing renewal ID."); return; } if (!newNotes || newNotes.length === 0) { alert("โŒ Please enter new notes."); return; } and this is what comes up when i click update notes So two issues. 1. Current Notes data is not being pulled into text box. 2. not able to update notes in the database Pressing F12 show the following when clicking on update Please go easy on me on by no means a coder.
  8. Ok ill try and explain this as best i can. I have client.php which includes a file called 'Functions/Common_Functions.php'; on this clients.php page it has a form, the form is a mixture of html and script. include 'Functions/Common_Functions.php'; func_header(); header_client_search(); func_endheader(); func_TopMenu(); menu_items(); ?> <br><br> <form method="post" action=<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>> <?php if (isset($_GET['error'])) { ?> <p class="error"><?php echo $_GET['error']; ?></p> <?php } client_search(); client_search_script(); // $clientSearch = ($_POST['clientSearch']); ?> <input type="submit" value="Search"> </form> <?php // Check if the form is submitted if ($_SERVER["REQUEST_METHOD"] == "POST") { // Process form data if needed echo "formposted"; echo $clientSearch; $clientSearch = isset($_POST['clientSearch']) ? $_POST['clientSearch'] : ''; echo "Form posted with clientSearch value: " . htmlspecialchars($clientSearch); echo $clientSearch; } The two functions client_search(); and client_Search_script(); go out and query mysql clients table so as you start typing a clients name the options get smaller "suggestive text". This part is working well. However when I submit the form for the life of me I cannot get the clients name captured on submit. This is the script code located in common_functions.php function header_client_search(){ echo "<style>"; echo " #suggestions {"; echo " position: absolute;"; echo " max-height: 200px;"; echo " overflow-y: auto;"; echo " border: 1px solid #ccc;"; echo " background-color: #fff;"; echo "}"; echo ".suggestion {"; echo " padding: 8px;"; echo " cursor: pointer;"; echo " background-color: #cccccc;"; echo "}"; echo ".suggestion:hover {"; // echo " background-color: #f2f2f2;"; echo " background-color: #cccccc;"; echo " }"; echo "</style>"; } function client_search(){ echo "<h1 color=#00000>Client Search</h1>"; echo "<label for='clientSearch'>Search Clients:</label>"; echo "<input type='text' id='clientSearch' oninput='getSuggestions(this.value)'>"; echo "<div id='suggestions'></div>"; } function client_search_script(){ echo "<script>"; echo "function getSuggestions(query) {"; echo "if (query.length === 0) {"; echo "document.getElementById('suggestions').innerHTML = '';"; echo "return;"; echo " }"; //echo "// Make an asynchronous request to fetch suggestions"; echo "var xhttp = new XMLHttpRequest();"; echo "xhttp.onreadystatechange = function() {"; echo "if (this.readyState == 4 && this.status == 200) {"; echo "document.getElementById('suggestions').innerHTML = this.responseText;"; echo "}"; echo "};"; echo "xhttp.open('GET', 'get_suggestions.php?q=' + query, true);"; echo "xhttp.send();"; echo "}"; echo "function selectSuggestion(value) {"; echo "document.getElementById('clientSearch').value = value;"; echo "document.getElementById('suggestions').innerHTML = '';"; echo " }"; echo "</script>"; } and incase you need it this is the get_suggestions.php file <?php // Include your database connection logic here include('Functions/db_con.php'); // Get the search query from the URL parameter $q = $_GET['q']; // Prepare and execute the query to fetch client names based on the search query $query = "SELECT DISTINCT CompanyName FROM Customer WHERE CompanyName LIKE :query"; $stmt = $pdo->prepare($query); $stmt->bindValue(':query', '%' . $q . '%', PDO::PARAM_STR); $stmt->execute(); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); // Output the suggestions as a list foreach ($results as $row) { echo '<div class="suggestion" onclick="selectSuggestion(\'' . $row['CompanyName'] . '\')">' . $row['CompanyName'] . '</div>'; } ?> What I have tried to do is muck around with $clientSearch = isset($_POST['clientSearch']) ? $_POST['clientSearch'] : ''; echo "Form posted with clientSearch value: " . htmlspecialchars($clientSearch); and these $clientSearch = document.getElementById('clientSearch'); echo $clientSearch; but I can never get the customer name back after submitting form I just get client search value: blank like in the picture below. Where am I going wrong?
  9. Please ignore above post about additional pages I jumped the gun I had to change the collum syncroID to be unique in mysql in order for this to work. Seems to work well.
  10. Hmm, am I doing something wrong here. It appears that the following code just add new duplicate entries into the database. Clearing out the customer table, 9 pages of records are created on first run then an additional 9 pages total 18 pages on second run. <?php function Get_Customer() { set_time_limit(300); $customers = []; $totalPages = getTotalPages(); $page = 1; while ($page <= $totalPages) { $returnedCustomers = Customers($page); $customers = array_merge($customers, $returnedCustomers); $page++; } include('db_con.php'); //**************https://forums.phpfreaks.com/topic/317537-curl-rate-limits-and-time-outs-limit-rate-under-a-certain-amount-for-get-requests/ ************************* //updated syncroid //updated SQL query with duplicate key update $query = "INSERT INTO Customer (SyncroID, CompanyName, Address, City, State, Postcode) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE SyncroID = VALUES(SyncroID), CompanyName = VALUES(CompanyName), Address = VALUES(Address), City = VALUES(City), State = VALUES(State), Postcode = VALUES(Postcode)"; echo $query; try { $pdo->beginTransaction(); $stmt = $pdo->prepare($query); foreach ($customers as $customer) { if (!empty($customer['business_name'])) { //udpated Customer ID for where clause $stmt->execute([$customer['id'], $customer['business_name'], $customer['address'], $customer['city'], $customer['state'], $customer['zip']]); } } $pdo->commit(); } catch (\Throwable $e){ $pdo->rollback(); throw $e; } //******************************end of gizmola code *************************** return $customers; } function Customers($page = 1) { $url = "https://xxxxxxxxxxxxxxxxxxxxxmsp.com/api/v1/customers?sort=business_name&page=" . $page; $cURL = curl_init(); curl_setopt($cURL, CURLOPT_URL, $url); curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true); curl_setopt($cURL, CURLOPT_HTTPGET, true); curl_setopt($cURL, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", "Accept: application/json", "Authorization: xxxxxxxxxxxxxxxxxxxxxxxx" ]); $result = curl_exec($cURL); $data = json_decode($result, true); $customers = $data["customers"]; curl_close($cURL); return $customers; } function getTotalPages() { $url = "https://xxxxxxxxxxxxxxxxmsp.com/api/v1/customers"; $cURL = curl_init(); curl_setopt($cURL, CURLOPT_URL, $url); curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true); curl_setopt($cURL, CURLOPT_HTTPGET, true); curl_setopt($cURL, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", "Accept: application/json", "Authorization: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]); $result = curl_exec($cURL); $data = json_decode($result, true); $totalPages = $data["meta"]["total_pages"]; curl_close($cURL); return $totalPages; } // Get_Customer(); // test /* echo "<br>"; echo $custname; echo " "; echo $customer["address"]; echo " "; echo $customer["city"]; echo ","; echo $customer["state"]; echo " "; echo $customer["zip"]; echo "<b>Customer ID:</b> "; echo " "; echo $customer["id"]; echo "<br>"; echo $query; echo "<br>"; */ //INSERT INTO `Customer` (`SyncroID`, `PrimaryContactID`, `CompanyName`, `Address`, `City`, `State`, `Postcode`, `Country`, `AccountStatus`, `UserName`, `Password_Hash`, `Password_Salt`, `Notes`, `BillingContactID`) //VALUES ('12321', NULL, 'test', NULL, NULL, 'QLD', NULL, 'Australia', 4, NULL, NULL, NULL, NULL, NULL); The $query variable returns INSERT INTO Customer (SyncroID, CompanyName, Address, City, State, Postcode) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE SyncroID = VALUES(SyncroID), CompanyName = VALUES(CompanyName), Address = VALUES(Address), City = VALUES(City), State = VALUES(State), Postcode = VALUES(Postcode) my primary key on the customer table is Customer_ID but I don't want duplicate entries based on Syncro_ID either.
  11. So im trying to run a SQL query to insert data into a customer table. But I only want to insert date if the ID does not already exist. This code here works //************************************start of gizmola coe ************************* $query = "INSERT INTO Customer (SyncroID, CompanyName) VALUES (?, ?)"; try { $pdo->beginTransaction(); $stmt = $pdo->prepare($query); foreach ($customers as $customer) { if (!empty($customer['business_name'])) { $stmt->execute([$customer['id'], $customer['business_name']]); } } $pdo->commit(); } catch (\Throwable $e){ $pdo->rollback(); throw $e; } //******************************end of gizmola code *************************** However when I try to add the where clause in it just bails out on the below code, im pretty sure my where statement has bad syntax and then im not sure the execute is done right? //**************https://forums.phpfreaks.com/topic/317537-curl-rate-limits-and-time-outs-limit-rate-under-a-certain-amount-for-get-requests/ ************************* //updated syncroid $query = "INSERT INTO Customer (SyncroID, CompanyName, Address, City, State, Postcode) VALUES (?, ?, ?, ?, ?, ?) WHERE (SyncroID) != VALUES (?)"; try { $pdo->beginTransaction(); $stmt = $pdo->prepare($query); foreach ($customers as $customer) { if (!empty($customer['business_name'])) { //udpated Customer ID for where clause $stmt->execute([$customer['id'], $customer['business_name'], $customer['address'], $customer['city'], $customer['state'], $customer['zip'], [$customer['id']]); } } $pdo->commit(); } catch (\Throwable $e){ $pdo->rollback(); throw $e; } //******************************end of gizmola code ***************************
  12. Just circling back to this. Finally got it working with gizmola's code thank you. This was the end result. Now i have to rewrite this code to add all the other fields in. Then after that is successful if the ID already exists in mysql then only update row if there's something different. I don't fully understand why this is faster and works though. Is it because it prepares the query outside of the for loop rather than inside the for loop and that's why it doesn't time out? <?php function Get_Customer() { set_time_limit(300); $customers = []; $totalPages = getTotalPages(); $page = 1; while ($page <= $totalPages) { $returnedCustomers = Customers($page); $customers = array_merge($customers, $returnedCustomers); $page++; } include('db_con.php'); //************************************start of gizmola coe ************************* $query = "INSERT INTO Customer (SyncroID, CompanyName) VALUES (?, ?)"; try { $pdo->beginTransaction(); $stmt = $pdo->prepare($query); foreach ($customers as $customer) { if (!empty($customer['business_name'])) { $stmt->execute([$customer['id'], $customer['business_name']]); } } $pdo->commit(); } catch (\Throwable $e){ $pdo->rollback(); throw $e; } //******************************end of gizmola code *************************** return $customers; } function Customers($page = 1) { $url = "https://xxxxxxxxxxxxxxxxxxxxxxxxxxmsp.com/api/v1/customers?sort=business_name&page=" . $page; $cURL = curl_init(); curl_setopt($cURL, CURLOPT_URL, $url); curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true); curl_setopt($cURL, CURLOPT_HTTPGET, true); curl_setopt($cURL, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", "Accept: application/json", "Authorization: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]); $result = curl_exec($cURL); $data = json_decode($result, true); $customers = $data["customers"]; curl_close($cURL); return $customers; } function getTotalPages() { $url = "https://xxxxxxxxxxxxxxxmsp.com/api/v1/customers"; $cURL = curl_init(); curl_setopt($cURL, CURLOPT_URL, $url); curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true); curl_setopt($cURL, CURLOPT_HTTPGET, true); curl_setopt($cURL, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", "Accept: application/json", "Authorization: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]); $result = curl_exec($cURL); $data = json_decode($result, true); $totalPages = $data["meta"]["total_pages"]; curl_close($cURL); return $totalPages; }
  13. Barand yes your right the other 50% will go into a different table.
  14. Thanks ill give that go . In Reply to gizmol the data below is additional data that I'll need to insert later after i can successfully insert just the ID and business name. I know that I'm currently not using but i hope to add it in later ill just comment it out for now. $customer["id"]; $customer["firstname"]; $customer["lastname"]; $customer["fullname"]; $customer["business_name"]; $customer["email"]; $customer["phone"]; $customer["mobile"]; $customer["address"]; $customer["city"]; $customer["state"]; $customer["zip"]; $customer["business_and_full_name"]; $customer["business_then_name"];
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.