HIX & AntiGravity apps gallery

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

facturas.prg

Code: Select all | Expand

function Main()
    
local cAction := Upost( "action" ) local cId := Upost( "id" ) local cClientId := Upost( "client_id" ) local cDate := Upost( "date" ) local cStatus := Upost( "status" ) local cLinesData := Upost( "lines_data" ) // Format: PROD_ID,QTY;PROD_ID,QTY // Search Parameter (Post) local cSearch := Upost( "search" ) local cTmpDir := "c:/hix/testdir" local cDbFact := cTmpDir + "/facturas_v2.dbf" local cDbLines := cTmpDir + "/facturas_lines.dbf" local cDbCli := cTmpDir + "/clientes_v2.dbf" local cDbProd := cTmpDir + "/productos.dbf" local cMessage := "" local cTotal := "0.00" // Ensure Directory Exists if ! IsDirectory( cTmpDir ) DirMake( cTmpDir ) endif // 1. Initialize Databases InitDatabases( cDbFact, cDbLines, cDbCli, cDbProd ) // 2. Open Databases Shared if !OpenDatabases() return "Error opening databases." endif // 3. Seed Data if Empty SeedData() set deleted on set date format to "yyyy-mm-dd" do case case cAction == "save" if !Empty(cClientId) select facturas if Empty( cId ) // New Invoice append blank if !NetErr() cId := GenerateID() replace id with cId replace client_id with cClientId replace date with CToD( cDate ) replace status with cStatus // Save Lines & Calculate Total cTotal := SaveLines( cId, cLinesData, .T. ) replace total with Val( cTotal ) commit unlock cMessage := "Invoice saved successfully." else cMessage := "Error: Could not create invoice (Lock failed)." endif else // Update existing go top locate for AllTrim(id) == AllTrim(cId) if found() if Rlock() replace client_id with cClientId replace date with CToD( cDate ) replace status with cStatus // Note: Stock logic implies checking status change, simplfied here // Save Lines & Calculate Total cTotal := SaveLines( cId, cLinesData, .F. ) replace total with Val( cTotal ) commit unlock cMessage := "Invoice updated successfully." endif endif endif // Handle Stock Deduction if Paid if cStatus == "Paid" UpdateStock( cId ) endif endif cId := "" cClientId := "" cDate := "" cTotal := "" cStatus := "" cSearch := "" case cAction == "delete" if ! Empty( cId ) // Delete Lines first select lines go top do while ! Eof() if lines->invoice_id == cId if Rlock() delete unlock endif endif skip enddo // Delete Header select facturas go top locate for AllTrim(id) == AllTrim(cId) if found() .and. Rlock() delete unlock commit cMessage := "Invoice deleted successfully." endif endif cId := "" cSearch := "" case cAction == "edit" select facturas go top locate for AllTrim(id) == AllTrim(cId) if found() cClientId := facturas->client_id cDate := DToC( facturas->date ) cTotal := Str( facturas->total ) cStatus := facturas->status endif case cAction == "cancel" cId := "" cSearch := "" endcase RenderView( cId, cClientId, cDate, cTotal, cStatus, cMessage, cSearch ) CloseDatabases() return "" // -------------------------------------------------------------------------------- // Database Helpers // -------------------------------------------------------------------------------- function InitDatabases( cDbFact, cDbLines, cDbCli, cDbProd ) if ! File( cDbFact ) DbCreate( cDbFact, { ; { "ID", "C", 8, 0 }, ; { "CLIENT_ID", "C", 8, 0 }, ; { "DATE", "D", 8, 0 }, ; { "TOTAL", "N", 12, 2 }, ; { "STATUS", "C", 10, 0 } ; } ) endif
if ! File( cDbLines ) DbCreate( cDbLines, { ; { "INVOICE_ID","C", 8, 0 }, ; { "PROD_ID", "C", 8, 0 }, ; { "QTY", "N", 10, 2 }, ; { "PRICE", "N", 10, 2 }, ; { "TOTAL", "N", 12, 2 } ; } ) endif if ! File( cDbCli ) DbCreate( cDbCli, { ; { "ID", "C", 8, 0 }, ; { "NAME", "C", 50, 0 } ; } ) endif if ! File( cDbProd ) DbCreate( cDbProd, { ; { "ID", "C", 8, 0 }, ; { "NAME", "C", 50, 0 }, ; { "PRICE", "N", 10, 2 }, ; { "STOCK", "N", 10, 2 } ; } ) endif return nil function OpenDatabases() if Select("facturas") == 0 use ("c:/hix/testdir/facturas_v2.dbf") shared new alias "facturas" else select facturas endif if Select("lines") == 0 use ("c:/hix/testdir/facturas_lines.dbf") shared new alias "lines" else select lines endif if Select("clients") == 0 use ("c:/hix/testdir/clientes.dbf") shared new alias "clients" else select clients endif if Select("products") == 0 use ("c:/hix/testdir/productos.dbf") shared new alias "products" else select products endif return .T. function CloseDatabases() close all return nil function SeedData() select clients if RecCount() == 0 append blank replace id with "C1", name with "Acme Corp" append blank replace id with "C2", name with "Globex Inc." append blank replace id with "C3", name with "Wayne Ent." commit endif
select products if RecCount() == 0 append blank replace id with "P1", name with "Widget A", price with 10.00, stock with 100 append blank replace id with "P2", name with "Widget B", price with 25.50, stock with 50 append blank replace id with "P3", name with "Premium X", price with 99.99, stock with 10 commit endif return nil // -------------------------------------------------------------------------------- // Logic Helpers // -------------------------------------------------------------------------------- function SaveLines( cInvoiceId, cData, lNew ) local aItems := hb_ATokens( cData, ";" ) local aParts local cItem local nGrandTotal := 0 local nPrice := 0 local nQty := 0 local nRowTotal := 0
select lines // If not new, delete old lines first if !lNew go top do while !Eof() if lines->invoice_id == cInvoiceId if Rlock() delete unlock endif endif skip enddo endif // Add new lines for each cItem in aItems if !Empty(cItem) aParts := hb_ATokens( cItem, "," ) // PROD_ID,QTY if Len(aParts) >= 2 nQty := Val( aParts[2] ) // Lookup Price select products go top locate for id == aParts[1] if found() nPrice := products->price else nPrice := 0 endif nRowTotal := nQty * nPrice nGrandTotal += nRowTotal select lines append blank if !NetErr() replace invoice_id with cInvoiceId replace prod_id with aParts[1] replace qty with nQty replace price with nPrice replace total with nRowTotal unlock endif endif endif next return AllTrim( Str( nGrandTotal ) ) function UpdateStock( cInvoiceId ) // Simple implementation: Iterate lines and subtract stock // Real implementation should check if stock was already deducted select lines go top do while ! Eof() if lines->invoice_id == cInvoiceId select products go top locate for id == lines->prod_id if found() .and. Rlock() replace stock with stock - lines->qty unlock endif select lines endif skip enddo return nil function GenerateID() local cChars := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" local cNewId := "" local i for i := 1 to 8 cNewId += SubStr( cChars, Int( hb_Random() * Len(cChars) ) + 1, 1 ) next return cNewId // -------------------------------------------------------------------------------- // View Renderer // -------------------------------------------------------------------------------- function RenderView( cId, cClientId, cDate, cTotal, cStatus, cMessage, cSearch ) local cHtml := MemoRead( "c:/hix/facturas.view" )
// 1. Build Client Options local cClientOpts := "<option value=''>Select Client</option>" local cSelected := "" // 2. Build Product Data for JS local cProdScript := "var products = {" // 3. Build Invoice Rows vars local cRows := "" local cCliName := "" local lMatch := .T. local cFullData := "" local cStatusColor := "" // MESSAGE VAR local cMsgHtml := "" local cLineScript := "var existingLines = [];" // LOGIC START select clients go top do while ! Eof() cSelected := iif( AllTrim(clients->id) == AllTrim(cClientId), "selected", "" ) cClientOpts += [<option value="] + AllTrim(clients->id) + ["] + cSelected + [>] + AllTrim(clients->name) + [</option>] skip enddo select products go top do while ! Eof() cProdScript += ["] + AllTrim(products->id) + [": {name: "] + AllTrim(products->name) + [", price: ] + AllTrim(Str(products->price)) + [},] skip enddo cProdScript += "};" select facturas go top do while ! Eof() lMatch := .T. // Lookup Client Name select clients go top locate for id == facturas->client_id if found() cCliName := AllTrim( clients->name ) else cCliName := facturas->client_id endif select facturas // Search Filter if !Empty( cSearch ) cFullData := Upper(cCliName + " " + DToC(facturas->date) + " " + Str(facturas->total) + " " + facturas->status) if ! ( Upper(AllTrim(cSearch)) $ cFullData ) lMatch := .F. endif endif if lMatch cRows += [<tr>] cRows += [<td>] + AllTrim(facturas->id) + [</td>] cRows += [<td>] + cCliName + [</td>] cRows += [<td>] + DToC( facturas->date ) + [</td>] cRows += [<td>] + AllTrim( Str( facturas->total ) ) + [</td>] cRows += [<td>] + AllTrim( facturas->status ) + [</td>] cRows += [<td class="actions-cell">] cRows += [<form method="POST" action="facturas.prg" style="display:inline;">] cRows += [<input type="hidden" name="action" value="edit">] cRows += [<input type="hidden" name="id" value="] + AllTrim(facturas->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-edit"><i class="fa-solid fa-pen"></i></button>] cRows += [</form> ] cRows += [<form method="POST" action="facturas.prg" style="display:inline;" onsubmit="return confirm('Delete invoice?')">] cRows += [<input type="hidden" name="action" value="delete">] cRows += [<input type="hidden" name="id" value="] + AllTrim(facturas->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-danger"><i class="fa-solid fa-trash"></i></button>] cRows += [</form>] cRows += [<form method="POST" action="factura_pdf.prg" target="_blank" style="display:inline; margin-left: 4px;">] cRows += [<input type="hidden" name="id" value="] + AllTrim(facturas->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-secondary" title="Download PDF"><i class="fa-solid fa-file-pdf"></i></button>] cRows += [</form></td></tr>] endif skip enddo if !Empty( cId ) select lines go top do while ! Eof() if lines->invoice_id == cId cLineScript += [existingLines.push({prod_id: "] + AllTrim(lines->prod_id) + [", qty: ] + AllTrim(Str(lines->qty)) + [});] endif skip enddo endif // Replacements cHtml := StrTran( cHtml, "{{CLIENT_OPTIONS}}", cClientOpts ) cHtml := StrTran( cHtml, "{{PRODUCT_DATA}}", cProdScript ) cHtml := StrTran( cHtml, "{{EXISTING_LINES}}", cLineScript ) cHtml := StrTran( cHtml, "{{INVOICE_ROWS}}", cRows ) // Standard Fields cHtml := StrTran( cHtml, "{{VAL_ID}}", iif( Empty(cId), "", cId ) ) cHtml := StrTran( cHtml, "{{VAL_DATE}}", iif( Empty(cDate), Date(), cDate ) ) cHtml := StrTran( cHtml, "{{VAL_TOTAL}}", iif( Empty(cTotal), "", AllTrim(cTotal) ) ) cHtml := StrTran( cHtml, "{{SEL_PAID}}", iif( cStatus == "Paid", "selected", "" ) ) cHtml := StrTran( cHtml, "{{SEL_PENDING}}", iif( cStatus == "Pending", "selected", "" ) ) cHtml := StrTran( cHtml, "{{SEL_CANCELLED}}", iif( cStatus == "Cancelled", "selected", "" ) ) // Message & Search if !Empty( cMessage ) if Left( cMessage, 5 ) == "Error" cMsgHtml := [<div class="alert alert-danger">] + cMessage + [</div>] else cMsgHtml := [<div class="alert alert-success">] + cMessage + [</div>] endif endif cHtml := StrTran( cHtml, "{{MESSAGE}}", cMsgHtml ) cHtml := StrTran( cHtml, "{{VAL_SEARCH}}", iif( Empty(cSearch), "", cSearch ) ) if !Empty(cId) cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "Edit Invoice: " + cId ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", [<a href="facturas.prg" class="btn btn-sm" style="background:#475569;margin-left:5px;">Cancel</a>] ) else cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "New Invoice" ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", "" ) endif UWrite( cHtml ) return ""

facturas.view

Code: Select all | Expand

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Invoices Management</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <style>
        body { background-color: #0f172a; color: #e0f2fe; font-family: 'Inter', sans-serif; }
        .container-fluid { max-width: 1400px; padding: 20px; }
        .card { background-color: #1e293b; border: 1px solid #3b82f6; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.2); }
        .card-header { background-color: #1d4ed8; color: #e0f2fe; border-bottom: 1px solid #1e40af; border-radius: 12px 12px 0 0 !important; padding: 1rem 1.5rem; }
        
/* Navbar Standardization */ .navbar { background-color: #172554; border-bottom: 1px solid #1e3a8a; padding-top: 0.75rem; padding-bottom: 0.75rem; min-height: 70px; } .navbar-brand { font-weight: 600; color: #bae6fd !important; font-size: 1.25rem; } .nav-link { color: #bfdbfe; margin-right: 15px; font-weight: 500; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight: 600; } .form-label { color: #bfdbfe; font-weight: 500; font-size: 0.875rem; } .form-control, .form-select { background-color: #0f172a; border: 1px solid #3b82f6; color: #e0f2fe; border-radius: 8px; padding: 0.625rem 1rem; } .form-control:focus, .form-select:focus { background-color: #172554; border-color: #60a5fa; box-shadow: 0 0 0 2px rgba(96,165,250,0.3); color: #e0f2fe; } .btn-primary { background-color: #3b82f6; border: none; padding: 0.625rem 1.25rem; font-weight: 500; } .btn-primary:hover { background-color: #2563eb; } .btn-secondary { background-color: #1e40af; border: none; color: #e0f2fe; } .btn-secondary:hover { background-color: #1e3a8a; } .table { color: #0c4a6e; margin-bottom: 0; } .table thead th { background-color: #1e3a8a; border-bottom: none; color: #fff; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; padding: 1rem; } .table tbody tr:nth-of-type(odd) { background-color: #e0f2fe; color: #0c4a6e; } .table tbody tr:nth-of-type(even) { background-color: #bae6fd; color: #0c4a6e; } .table td { border-bottom: 1px solid #7dd3fc; padding: 1rem; vertical-align: middle; border-top: none; } .table tr:last-child td { border-bottom: none; } .actions-cell { white-space: nowrap; width: 1%; } .btn-edit { color: #0f172a; border: none; background: transparent; padding: 0.25rem 0.5rem; } .btn-edit:hover { color: #3b82f6; } .nav-link { color: #bae6fd; margin-right: 15px; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight:600; } .total-box { font-size: 1.5rem; font-weight: 600; text-align: right; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #1e40af; color: #60a5fa; } </style> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark mb-4"> <div class="container"> <a class="navbar-brand" href="#"><i class="fa-solid fa-file-invoice me-2"></i>HIX Invoices</a> <div class="collapse navbar-collapse"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"><a class="nav-link active" href="facturas.prg">Invoices</a></li> <li class="nav-item"><a class="nav-link" href="clientes.prg">Clients</a></li> <li class="nav-item"><a class="nav-link" href="productos.prg">Products</a></li> </ul> <form class="d-flex" action="facturas.prg" method="POST"> <button class="btn btn-outline-success me-2" type="button" id="btnNew"><i class="fa-solid fa-plus me-1"></i>New</button> <input type="hidden" name="action" value="search"> <input class="form-control me-2" type="search" name="search" placeholder="Search invoices..." value="{{VAL_SEARCH}}"> <button class="btn btn-outline-light me-2" type="submit">Search</button> {{CANCEL_BUTTON}} <a href="facturas_list_pdf.prg" target="_blank" class="btn btn-outline-info" title="Generar Listado PDF"><i class="fa-solid fa-file-pdf"></i></a> </form> </div> </div> </nav> <div class="container"> <div class="row"> <!-- Left Side: Invoice Editor --> <div class="col-md-5 mb-4" id="invoiceFormCard" style="display:none;"> <div class="card h-100"> <div class="card-header"> <h5 class="mb-0"><i class="fa-solid fa-file-invoice me-2"></i>{{FORM_TITLE}}</h5> </div> <div class="card-body"> {{MESSAGE}} <form method="POST" action="facturas.prg" onsubmit="prepareSubmit()"> <input type="hidden" name="action" value="save"> <input type="hidden" name="id" value="{{VAL_ID}}"> <input type="hidden" name="lines_data" id="lines_data"> <div class="mb-3"> <label class="form-label">Client</label> <select name="client_id" class="form-select" required> {{CLIENT_OPTIONS}} </select> </div> <div class="row mb-3"> <div class="col-md-6"> <label class="form-label">Date</label> <input type="date" name="date" class="form-control" value="{{VAL_DATE}}" required> </div> <div class="col-md-6"> <label class="form-label">Status</label> <select name="status" class="form-select"> <option value="Pending" {{SEL_PENDING}}>Pending</option> <option value="Paid" {{SEL_PAID}}>Paid</option> <option value="Cancelled" {{SEL_CANCELLED}}>Cancelled</option> </select> </div> </div> <h6 class="border-bottom border-secondary pb-2 mb-3 mt-4">Itens</h6> <div class="table-responsive mb-3"> <table class="table table-sm" id="linesTable"> <thead> <tr> <th style="width: 45%;">Product</th> <th style="width: 20%;">Qty</th> <th style="width: 25%;">Price</th> <th style="width: 10%;"></th> </tr> </thead> <tbody id="linesBody"> <!-- JS Rows --> </tbody> </table> </div> <button type="button" class="btn btn-sm btn-secondary mb-3" onclick="addLine()"> <i class="fa-solid fa-plus me-1"></i> Add Item </button> <div class="total-box"> Total: $<span id="displayTotal">0.00</span> </div> <div class="d-grid gap-2 d-md-flex justify-content-md-end mt-4"> <button type="submit" class="btn btn-primary"><i class="fa-solid fa-save me-2"></i>Save Invoice</button> </div> </form> </div> </div> </div> <!-- Right Side: List --> <div class="col-md-7" id="invoiceListColumn"> <div class="card"> <div class="card-header d-flex justify-content-between align-items-center"> <h5 class="mb-0"><i class="fa-solid fa-list me-2"></i>Existing Invoices</h5> </div> <div class="card-body p-0"> <div class="table-responsive"> <table class="table table-hover"> <thead> <tr> <th>ID</th> <th>Client</th> <th>Date</th> <th>Total</th> <th>Status</th> <th>Actions</th> </tr> </thead> <tbody> {{INVOICE_ROWS}} </tbody> </table> </div> </div> </div> </div> </div> </div> <script> // Data injected from PRG {{PRODUCT_DATA}} // Format: var products = {"P1": {name: "Widget", price: 10}, ...}; {{EXISTING_LINES}} // Format: var existingLines = [{prod_id: "P1", qty: 2}, ...]; function renderLines() { const tbody = document.getElementById('linesBody'); tbody.innerHTML = ''; existingLines.forEach((line, index) => { addLineRow(line.prod_id, line.qty, index); }); if(existingLines.length === 0) { // Add one empty row by default if new and register it existingLines.push({prod_id: "", qty: 1}); addLineRow("", 1, 0); } calculateTotal(); } function addLine() { addLineRow("", 1, existingLines.length); existingLines.push({prod_id: "", qty: 1}); } function addLineRow(prodId, qty, index) { const body = document.getElementById('linesBody'); const tr = document.createElement('tr'); // Build Options let opts = '<option value="">Select...</option>'; for (const [key, val] of Object.entries(products)) { const sel = (key === prodId) ? 'selected' : ''; opts += `<option value="${key}" ${sel}>${val.name}</option>`; } tr.innerHTML = ` <td> <select class="form-select form-select-sm" onchange="updateLine(${index}, 'prod_id', this.value); calculateTotal();"> ${opts} </select> </td> <td> <input type="number" class="form-control form-control-sm" value="${qty}" min="1" step="0.01" onchange="updateLine(${index}, 'qty', this.value); calculateTotal();"> </td> <td id="price_${index}" class="text-end pe-3 pt-2"> ${getProductPrice(prodId, qty)} </td> <td> <button type="button" class="btn btn-sm btn-outline-danger border-0" onclick="removeLine(${index})"><i class="fa-solid fa-times"></i></button> </td> `; body.appendChild(tr); } function getProductPrice(id, qty) { if(!id || !products[id]) return "0.00"; return (products[id].price * qty).toFixed(2); } function updateLine(index, field, value) { if(existingLines[index]) { existingLines[index][field] = value; // Update specific row price display const rowPrice = document.getElementById(`price_${index}`); if(rowPrice) { rowPrice.innerText = getProductPrice(existingLines[index].prod_id, existingLines[index].qty); } } } function removeLine(index) { existingLines.splice(index, 1); renderLines(); // Re-render to update indices } function calculateTotal() { let total = 0; existingLines.forEach(line => { if(line.prod_id && products[line.prod_id]) { total += products[line.prod_id].price * line.qty; } }); document.getElementById('displayTotal').innerText = total.toFixed(2); } function prepareSubmit() { // Serialize lines to format: ID,QTY;ID,QTY let data = ""; existingLines.forEach(line => { if(line.prod_id) { data += `${line.prod_id},${line.qty};`; } }); document.getElementById('lines_data').value = data; } // Initialize renderLines(); </script> <script> document.addEventListener('DOMContentLoaded', function() { var formCard = document.getElementById('invoiceFormCard'); var btnNew = document.getElementById('btnNew'); var inputId = document.querySelector('input[name="id"]'); var listCol = document.getElementById('invoiceListColumn'); function updateLayout() { if (formCard.style.display === "none") { listCol.classList.remove('col-md-7'); listCol.classList.add('col-12'); } else { listCol.classList.remove('col-12'); listCol.classList.add('col-md-7'); } } if (inputId && inputId.value.trim() !== "") { formCard.style.display = "block"; updateLayout(); } else { // Ensure initial state updateLayout(); } if (btnNew) { btnNew.addEventListener('click', function(e) { e.preventDefault(); if (formCard.style.display === "none") { formCard.style.display = "block"; } else { formCard.style.display = "none"; } updateLayout(); }); } }); </script> </body> </html>

factura_pdf.prg

Code: Select all | Expand

function Main()
    local cId := Upost("id")
    local cTmpDir := "c:/hix/testdir"
    local cPdfFile := ""
    local cContent := ""
    local cBase64 := ""
    
// DB Vars local cClientId := "" local cDate := "" local cStatus := "" local nTotal := 0 local cCliName := "" local cCliAddr := "" local cCliCity := "" local cCliZip := "" local cCliVat := "" local cCliPhone := "" // Init Logic cPdfFile := cTmpDir + "/invoice_" + cId + "_" + AllTrim(Str(Int(hb_Random() * 100000))) + ".pdf" if Empty(cId) UWrite("Error: No Invoice ID provided.") return "" endif // Open Databases if !OpenDatabases() UWrite("Error opening databases.") return "" endif // Find Invoice select facturas locate for AllTrim(id) == AllTrim(cId) if !found() UWrite("Error: Invoice not found.") close all return "" endif cClientId := facturas->client_id cDate := DToC(facturas->date) cStatus := facturas->status nTotal := facturas->total // Find Client select clients locate for AllTrim(id) == AllTrim(cClientId) if found() cCliName := AllTrim(clients->name) cCliAddr := AllTrim(clients->address) cCliCity := AllTrim(clients->city) cCliZip := AllTrim(clients->zip) cCliVat := AllTrim(clients->vat_id) cCliPhone := AllTrim(clients->phone) endif // GENERATE PDF GeneratePDF( cPdfFile, cId, cDate, cStatus, nTotal, cCliName, cCliAddr, cCliCity, cCliZip, cCliVat, cCliPhone ) close all // READ AND OUTPUT if File(cPdfFile) cContent := MemoRead(cPdfFile) cBase64 := hb_base64Encode(cContent) UWrite( '<!DOCTYPE html>' ) UWrite( '<html><head><title>Factura ' + cId + '</title></head>' ) UWrite( '<body style="margin:0;padding:0;overflow:hidden;">' ) UWrite( '<iframe src="data:application/pdf;base64,' + cBase64 + '" width="100%" height="100%" style="border:none;height:100vh;"></iframe>' ) UWrite( '</body></html>' ) else UWrite("Error: PDF Generation failed.") endif return "" function GeneratePDF( cFile, cId, cDate, cStatus, nTotal, cName, cAddr, cCity, cZip, cVat, cPhone ) local oPdf, oPage, oFont, oFontBold local nY := 750 local nRow := 0 local cProdName := "" local nLPrice := 0
oPdf := HPDF_New() HPDF_SetCompressionMode( oPdf, "HPDF_COMP_ALL" ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) oFont := HPDF_GetFont( oPdf, "Helvetica", "CP1252" ) oFontBold := HPDF_GetFont( oPdf, "Helvetica-Bold", "CP1252" ) // HEADER HPDF_Page_SetFontAndSize( oPage, oFontBold, 24 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, "INVOICE" ) HPDF_Page_EndText( oPage ) HPDF_Page_SetFontAndSize( oPage, oFont, 12 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 400, nY, "Invoice #: " + cId ) HPDF_Page_TextOut( oPage, 400, nY - 15, "Date: " + cDate ) HPDF_Page_TextOut( oPage, 400, nY - 30, "Status: " + cStatus ) HPDF_Page_EndText( oPage ) nY -= 80 // CLIENT INFO HPDF_Page_SetFontAndSize( oPage, oFontBold, 14 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, "Bill To:" ) HPDF_Page_EndText( oPage ) nY -= 20 HPDF_Page_SetFontAndSize( oPage, oFont, 12 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, cName ) nY -= 15 if !Empty(cVat); HPDF_Page_TextOut( oPage, 50, nY, "VAT ID: " + cVat ); nY -= 15; endif if !Empty(cAddr); HPDF_Page_TextOut( oPage, 50, nY, cAddr ); nY -= 15; endif if !Empty(cCity); HPDF_Page_TextOut( oPage, 50, nY, AllTrim(cCity) + " " + AllTrim(cZip) ); nY -= 15; endif if !Empty(cPhone); HPDF_Page_TextOut( oPage, 50, nY, "Phone: " + cPhone ); nY -= 15; endif HPDF_Page_EndText( oPage ) nY -= 40 // TABLE HEADER HPDF_Page_SetLineWidth( oPage, 1 ) HPDF_Page_Rectangle( oPage, 50, nY, 500, 25 ) HPDF_Page_Stroke( oPage ) HPDF_Page_SetFontAndSize( oPage, oFontBold, 11 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 60, nY + 8, "Product" ) HPDF_Page_TextOut( oPage, 300, nY + 8, "Qty" ) HPDF_Page_TextOut( oPage, 380, nY + 8, "Price" ) HPDF_Page_TextOut( oPage, 480, nY + 8, "Total" ) HPDF_Page_EndText( oPage ) nY -= 5 // ITEMS select lines go top HPDF_Page_SetFontAndSize( oPage, oFont, 11 ) do while !Eof() if lines->invoice_id == cId cProdName := "Unknown" nLPrice := lines->price select products locate for id == lines->prod_id if found(); cProdName := AllTrim(products->name); endif select lines nY -= 20 HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 60, nY, cProdName ) HPDF_Page_TextOut( oPage, 300, nY, AllTrim(Str(lines->qty)) ) HPDF_Page_TextOut( oPage, 380, nY, AllTrim(Str(nLPrice)) ) HPDF_Page_TextOut( oPage, 480, nY, AllTrim(Str(lines->total)) ) HPDF_Page_EndText( oPage ) endif skip enddo // GRAND TOTAL nY -= 40 HPDF_Page_SetFontAndSize( oPage, oFontBold, 14 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 350, nY, "Grand Total: " + AllTrim(Str(nTotal)) ) HPDF_Page_EndText( oPage ) HPDF_SaveToFile( oPdf, cFile ) HPDF_Free( oPdf ) return nil function OpenDatabases() local cTmpDir := "c:/hix/testdir" if Select("facturas") == 0; use (cTmpDir+"/facturas_v2.dbf") shared new alias "facturas"; endif if Select("lines") == 0; use (cTmpDir+"/facturas_lines.dbf") shared new alias "lines"; endif if Select("clients") == 0; use (cTmpDir+"/clientes_v2.dbf") shared new alias "clients"; endif if Select("products") == 0; use (cTmpDir+"/productos.dbf") shared new alias "products"; endif return .T.

facturas_list_pdf.prg

Code: Select all | Expand

function Main()
    local cTmpDir := "c:/hix/testdir"
    local cPdfFile := cTmpDir + "/invoices_list_" + AllTrim(Str(Int(hb_Random() * 100000))) + ".pdf"
    local cContent, cBase64

// Open Databases
if !OpenDatabases()
UWrite("Error opening databases.")
return ""
endif

// GENERATE PDF
GeneratePDF( cPdfFile )

close all

// READ AND OUTPUT
if File(cPdfFile)
cContent := MemoRead(cPdfFile)
cBase64  := hb_base64Encode(cContent)
    
UWrite( '<!DOCTYPE html>' )
UWrite( '<html><head><title>Listado de Facturas</title></head>' )
UWrite( '<body style="margin:0;padding:0;overflow:hidden;">' )
UWrite( '<iframe src="data:application/pdf;base64,' + cBase64 + '" width="100%" height="100%" style="border:none;height:100vh;"></iframe>' )
UWrite( '</body></html>' )
else
UWrite("Error: PDF Generation failed.")
endif

return ""

function GeneratePDF( cFile )
    local oPdf, oPage, oFont, oFontBold
    local nY := 750
    local nRow := 0
    local cCliName := ""
    local cCliId := ""
    
HPDF_SetCompressionMode( oPdf, "HPDF_COMP_ALL" ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) set deleted on oFont := HPDF_GetFont( oPdf, "Helvetica", "CP1252" ) oFontBold := HPDF_GetFont( oPdf, "Helvetica-Bold", "CP1252" ) // HEADER HPDF_Page_SetFontAndSize( oPage, oFontBold, 18 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, "LISTADO DE FACTURAS" ) HPDF_Page_EndText( oPage ) nY -= 30 // TABLE HEADER HPDF_Page_SetLineWidth( oPage, 1 ) HPDF_Page_Rectangle( oPage, 50, nY, 500, 20 ) HPDF_Page_Stroke( oPage ) HPDF_Page_SetFontAndSize( oPage, oFontBold, 10 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 55, nY + 6, "ID" ) HPDF_Page_TextOut( oPage, 120, nY + 6, "Date" ) HPDF_Page_TextOut( oPage, 200, nY + 6, "Client" ) HPDF_Page_TextOut( oPage, 380, nY + 6, "Status" ) HPDF_Page_TextOut( oPage, 460, nY + 6, "Total" ) HPDF_Page_EndText( oPage ) nY -= 5 // ITEMS select facturas go top HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) do while !Eof() // Lookup Client Name cCliName := "Unknown" cCliId := facturas->client_id select clients go top locate for AllTrim(clients->id) == AllTrim(cCliId) if found() cCliName := AllTrim(clients->name) endif select facturas nY -= 15 if nY < 50 HPDF_Page_EndText( oPage ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) HPDF_Page_BeginText( oPage ) nY := 750 else HPDF_Page_BeginText( oPage ) endif HPDF_Page_TextOut( oPage, 55, nY, AllTrim(facturas->id) ) HPDF_Page_TextOut( oPage, 120, nY, DToC(facturas->date) ) HPDF_Page_TextOut( oPage, 200, nY, SubStr(cCliName, 1, 30) ) HPDF_Page_TextOut( oPage, 380, nY, AllTrim(facturas->status) ) HPDF_Page_TextOut( oPage, 460, nY, AllTrim(Str(facturas->total)) ) HPDF_Page_EndText( oPage ) skip enddo HPDF_SaveToFile( oPdf, cFile ) HPDF_Free( oPdf ) return nil function OpenDatabases() local cTmpDir := "c:/hix/testdir" if Select("facturas") == 0; use (cTmpDir+"/facturas_v2.dbf") shared new alias "facturas"; endif if Select("clients") == 0; use (cTmpDir+"/clientes_v2.dbf") shared new alias "clients"; endif return .T.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

clientes.prg

Code: Select all | Expand

function Main()
    
local cAction := Upost( "action" ) local cId := Upost( "id" ) local cName := Upost( "name" ) local cVat := Upost( "vat_id" ) local cAddress := Upost( "address" ) local cCity := Upost( "city" ) local cZip := Upost( "zip" ) local cPhone := Upost( "phone" ) local cSearch := Upost( "search" ) local cTmpDir := "c:/hix/testdir" local cDbCli := cTmpDir + "/clientes_v2.dbf" local cMessage := "" // Ensure Directory Exists if ! IsDirectory( cTmpDir ) DirMake( cTmpDir ) endif // Initialize Database if not exists if ! File( cDbCli ) // Migration: If v2 doesn't exist, Create it with new structure DbCreate( cDbCli, { ; { "ID", "C", 8, 0 }, ; { "NAME", "C", 50, 0 }, ; { "VAT_ID", "C", 20, 0 }, ; { "ADDRESS", "C", 100, 0 }, ; { "CITY", "C", 50, 0 }, ; { "ZIP", "C", 10, 0 }, ; { "PHONE", "C", 20, 0 } ; } ) endif // Open Database if Select("clients") == 0 use (cDbCli) shared new alias "clients" else select clients endif do case case cAction == "save" if !Empty(cName) select clients if Empty( cId ) // New Client append blank if !NetErr() cId := GenerateID() replace id with cId replace name with cName replace vat_id with cVat replace address with cAddress replace city with cCity replace zip with cZip replace phone with cPhone commit unlock cMessage := "Client created successfully." else cMessage := "Error: Could not create client (Lock failed)." endif else // Update existing go top locate for AllTrim(id) == AllTrim(cId) if found() if Rlock() replace name with cName replace vat_id with cVat replace address with cAddress replace city with cCity replace zip with cZip replace phone with cPhone commit unlock cMessage := "Client updated successfully." endif endif endif endif // Reset form cId := "" cName := "" cVat := "" cAddress := "" cCity := "" cZip := "" cPhone := "" case cAction == "delete" if ! Empty( cId ) select clients go top locate for AllTrim(id) == AllTrim(cId) if found() .and. Rlock() delete unlock commit cMessage := "Client deleted successfully." endif endif cId := "" cName := "" case cAction == "edit" select clients go top locate for AllTrim(id) == AllTrim(cId) if found() cName := AllTrim(clients->name) cVat := AllTrim(clients->vat_id) cAddress := AllTrim(clients->address) cCity := AllTrim(clients->city) cZip := AllTrim(clients->zip) cPhone := AllTrim(clients->phone) endif case cAction == "cancel" cId := "" cName := "" cVat := "" cAddress := "" cCity := "" cZip := "" cPhone := "" cSearch := "" endcase RenderView( cId, cName, cVat, cAddress, cCity, cZip, cPhone, cMessage, cSearch ) close all return "" function GenerateID() local cChars := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" local cNewId := "C" local i for i := 1 to 7 cNewId += SubStr( cChars, Int( hb_Random() * Len(cChars) ) + 1, 1 ) next return cNewId function RenderView( cId, cName, cVat, cAddress, cCity, cZip, cPhone, cMessage, cSearch ) local cHtml := MemoRead( "c:/hix/clientes.view" ) local cMsgHtml := ""
// Build Rows local cRows := "" local lMatch := .T. local cInfo := "" local cContact := "" select clients go top do while ! Eof() lMatch := .T. if !Empty( cSearch ) if ! ( Upper(AllTrim(cSearch)) $ Upper(clients->name) ) .and. ; ! ( Upper(AllTrim(cSearch)) $ Upper(clients->city) ) lMatch := .F. endif endif if lMatch // Format Info Column cInfo := "" if !Empty(clients->city) cInfo += AllTrim(clients->city) endif if !Empty(clients->vat_id) if !Empty(cInfo); cInfo += "<br>"; endif cInfo += "<small class='text-muted'>VAT: " + AllTrim(clients->vat_id) + "</small>" endif // Format Contact Column cContact := "" if !Empty(clients->phone) cContact += "<i class='fa-solid fa-phone me-1'></i>" + AllTrim(clients->phone) endif cRows += [<tr>] cRows += [<td>] + AllTrim(clients->id) + [</td>] cRows += [<td><strong>] + AllTrim(clients->name) + [</strong></td>] cRows += [<td>] + cInfo + [</td>] cRows += [<td>] + cContact + [</td>] cRows += [<td class="actions-cell text-end">] cRows += [<form method="POST" action="clientes.prg" style="display:inline;">] cRows += [<input type="hidden" name="action" value="edit">] cRows += [<input type="hidden" name="id" value="] + AllTrim(clients->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-edit"><i class="fa-solid fa-pen"></i></button>] cRows += [</form> ] cRows += [<form method="POST" action="clientes.prg" style="display:inline;" onsubmit="return confirm('Delete client?')">] cRows += [<input type="hidden" name="action" value="delete">] cRows += [<input type="hidden" name="id" value="] + AllTrim(clients->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-edit" style="color:#ef4444;"><i class="fa-solid fa-trash"></i></button>] cRows += [</form></td></tr>] endif skip enddo // Standard Fields cHtml := StrTran( cHtml, "{{CLIENT_ROWS}}", cRows ) cHtml := StrTran( cHtml, "{{VAL_ID}}", iif( Empty(cId), "", cId ) ) cHtml := StrTran( cHtml, "{{VAL_NAME}}", iif( Empty(cName), "", cName ) ) cHtml := StrTran( cHtml, "{{VAL_VAT}}", iif( Empty(cVat), "", cVat ) ) cHtml := StrTran( cHtml, "{{VAL_ADDRESS}}", iif( Empty(cAddress), "", cAddress ) ) cHtml := StrTran( cHtml, "{{VAL_CITY}}", iif( Empty(cCity), "", cCity ) ) cHtml := StrTran( cHtml, "{{VAL_ZIP}}", iif( Empty(cZip), "", cZip ) ) cHtml := StrTran( cHtml, "{{VAL_PHONE}}", iif( Empty(cPhone), "", cPhone ) ) // Message & Search if !Empty( cMessage ) if Left( cMessage, 5 ) == "Error" cMsgHtml := [<div class="alert alert-danger" role="alert">] + cMessage + [</div>] else cMsgHtml := [<div class="alert alert-success" role="alert">] + cMessage + [</div>] endif endif cHtml := StrTran( cHtml, "{{MESSAGE}}", cMsgHtml ) cHtml := StrTran( cHtml, "{{VAL_SEARCH}}", iif( Empty(cSearch), "", cSearch ) ) if !Empty(cId) cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "Edit Client: " + cId ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", [<a href="clientes.prg" class="btn btn-sm" style="background:#1e3a8a;margin-left:5px;color:#e0f2fe;">Cancel</a>] ) else cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "New Client" ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", "" ) endif UWrite( cHtml ) return ""

clientes.view

Code: Select all | Expand

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Clients Management</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
    <style>
        :root { --primary-bg: #0f172a; --card-bg: #1e293b; --text-main: #e0f2fe; --accent: #38bdf8; }
        body { background-color: var(--primary-bg); color: var(--text-main); font-family: 'Inter', sans-serif; }
        
/* Navbar Standardization */ .navbar { background-color: #172554; border-bottom: 1px solid #1e3a8a; padding-top: 0.75rem; padding-bottom: 0.75rem; min-height: 70px; } .navbar-brand { font-weight: 600; color: #bae6fd !important; font-size: 1.25rem; } .nav-link { color: #bfdbfe; margin-right: 15px; font-weight: 500; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight: 600; } .card { background-color: var(--card-bg); border: 1px solid #334155; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); margin-bottom: 2rem; } .card-header { background-color: #1e293b; border-bottom: 1px solid #334155; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: #bae6fd; padding: 1rem 1.25rem; } .form-label { font-size: 0.875rem; font-weight: 500; color: #bfdbfe; margin-bottom: 0.5rem; } .form-control, .form-select { background-color: #0f172a; border: 1px solid #334155; color: #e0f2fe; padding: 0.625rem; } .form-control:focus, .form-select:focus { background-color: #172554; border-color: #60a5fa; box-shadow: 0 0 0 2px rgba(96,165,250,0.3); color: #e0f2fe; } .btn-primary { background-color: #3b82f6; border: none; padding: 0.625rem 1.25rem; font-weight: 500; } .btn-primary:hover { background-color: #2563eb; } .table { color: #0c4a6e; margin-bottom: 0; } .table thead th { background-color: #1e3a8a; border-bottom: none; color: #fff; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; padding: 1rem; } .table tbody tr:nth-of-type(odd) { background-color: #e0f2fe; color: #0c4a6e; } .table tbody tr:nth-of-type(even) { background-color: #bae6fd; color: #0c4a6e; } .table td { border-bottom: 1px solid #7dd3fc; padding: 1rem; vertical-align: middle; border-top: none; } .table tr:last-child td { border-bottom: none; } .actions-cell { white-space: nowrap; width: 1%; } .btn-edit { color: #0f172a; border: none; background: transparent; padding: 0.25rem 0.5rem; } .btn-edit:hover { color: #3b82f6; } .nav-link { color: #bae6fd; margin-right: 15px; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight:600; } </style> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark mb-4"> <div class="container"> <a class="navbar-brand" href="#"><i class="fa-solid fa-users me-2"></i>HIX Clients</a> <div class="collapse navbar-collapse"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"><a class="nav-link" href="facturas.prg">Invoices</a></li> <li class="nav-item"><a class="nav-link active" href="clientes.prg">Clients</a></li> <li class="nav-item"><a class="nav-link" href="productos.prg">Products</a></li> </ul> <form class="d-flex" action="clientes.prg" method="POST"> <button class="btn btn-outline-success me-2" type="button" id="btnNew"><i class="fa-solid fa-plus me-1"></i>New</button> <input type="hidden" name="action" value="search"> <input class="form-control me-2" type="search" name="search" placeholder="Search clients..." value="{{VAL_SEARCH}}"> <button class="btn btn-outline-light me-2" type="submit">Search</button> {{CANCEL_BUTTON}} <a href="clientes_pdf.prg" target="_blank" class="btn btn-outline-info" title="Generar Listado PDF"><i class="fa-solid fa-file-pdf"></i></a> </form> </div> </div> </nav> <div class="container"> {{MESSAGE}} <div class="card" id="clientFormCard" style="display:none;"> <div class="card-header">{{FORM_TITLE}}</div> <div class="card-body"> <form method="POST" action="clientes.prg"> <input type="hidden" name="action" value="save"> <input type="hidden" name="id" value="{{VAL_ID}}"> <div class="row g-3"> <div class="col-md-6"> <label class="form-label">Client Name</label> <input type="text" class="form-control" name="name" value="{{VAL_NAME}}" required placeholder="Company or Full Name"> </div> <div class="col-md-6"> <label class="form-label">VAT ID / Tax Number</label> <input type="text" class="form-control" name="vat_id" value="{{VAL_VAT}}" placeholder="e.g. US123456789"> </div> <div class="col-md-12"> <label class="form-label">Address</label> <input type="text" class="form-control" name="address" value="{{VAL_ADDRESS}}" placeholder="Street address, P.O. box"> </div> <div class="col-md-5"> <label class="form-label">City</label> <input type="text" class="form-control" name="city" value="{{VAL_CITY}}" placeholder="City"> </div> <div class="col-md-3"> <label class="form-label">Zip / Postal Code</label> <input type="text" class="form-control" name="zip" value="{{VAL_ZIP}}" placeholder="Zip Code"> </div> <div class="col-md-4"> <label class="form-label">Phone</label> <input type="text" class="form-control" name="phone" value="{{VAL_PHONE}}" placeholder="+1 (555) 000-0000"> </div> <div class="col-12 text-end mt-4"> <button type="submit" class="btn btn-primary"><i class="fa-solid fa-save me-2"></i>Save Client</button> </div> </div> </form> </div> </div> <div class="card"> <div class="card-header"><i class="fa-solid fa-list me-2"></i> Client Directory</div> <div class="table-responsive"> <table class="table table-hover align-middle"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Info</th> <th>Contact</th> <th class="text-end">Actions</th> </tr> </thead> <tbody> {{CLIENT_ROWS}} </tbody> </table> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { var formCard = document.getElementById('clientFormCard'); var btnNew = document.getElementById('btnNew'); var inputId = document.querySelector('input[name="id"]'); // Show form automatically if we are in Edit mode (ID is present) or if there is an error message (usually implies we want to retry save) // Checking {{VAL_ID}} via the input value if (inputId && inputId.value.trim() !== "") { formCard.style.display = "block"; } btnNew.addEventListener('click', function(e) { e.preventDefault(); // Toggle visibility if (formCard.style.display === "none") { formCard.style.display = "block"; // Focus on name field var nameInput = document.querySelector('input[name="name"]'); if(nameInput) nameInput.focus(); } else { formCard.style.display = "none"; } }); }); </script> </body> </html>

clientes_pdf.prg

Code: Select all | Expand

function Main()
    local cTmpDir := "c:/hix/testdir"
    local cPdfFile := cTmpDir + "/clients_list_" + AllTrim(Str(Int(hb_Random() * 100000))) + ".pdf"
    local cContent, cBase64

// Open Databases
if !OpenDatabases()
UWrite("Error opening databases.")
return ""
endif

// GENERATE PDF
GeneratePDF( cPdfFile )

close all

// READ AND OUTPUT
if File(cPdfFile)
cContent := MemoRead(cPdfFile)
cBase64  := hb_base64Encode(cContent)
    
UWrite( '<!DOCTYPE html>' )
UWrite( '<html><head><title>Listado de Clientes</title></head>' )
UWrite( '<body style="margin:0;padding:0;overflow:hidden;">' )
UWrite( '<iframe src="data:application/pdf;base64,' + cBase64 + '" width="100%" height="100%" style="border:none;height:100vh;"></iframe>' )
UWrite( '</body></html>' )
else
UWrite("Error: PDF Generation failed.")
endif

return ""

function GeneratePDF( cFile )
    local oPdf, oPage, oFont, oFontBold
    local nY := 750
    local nRow := 0
    
oPdf := HPDF_New() HPDF_SetCompressionMode( oPdf, "HPDF_COMP_ALL" ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) oFont := HPDF_GetFont( oPdf, "Helvetica", "CP1252" ) oFontBold := HPDF_GetFont( oPdf, "Helvetica-Bold", "CP1252" ) // HEADER HPDF_Page_SetFontAndSize( oPage, oFontBold, 18 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, "LISTADO DE CLIENTES" ) HPDF_Page_EndText( oPage ) nY -= 30 // TABLE HEADER HPDF_Page_SetLineWidth( oPage, 1 ) HPDF_Page_Rectangle( oPage, 50, nY, 500, 20 ) HPDF_Page_Stroke( oPage ) HPDF_Page_SetFontAndSize( oPage, oFontBold, 10 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 55, nY + 6, "ID" ) HPDF_Page_TextOut( oPage, 110, nY + 6, "Name" ) HPDF_Page_TextOut( oPage, 250, nY + 6, "City" ) HPDF_Page_TextOut( oPage, 350, nY + 6, "Phone" ) HPDF_Page_TextOut( oPage, 450, nY + 6, "VAT ID" ) HPDF_Page_EndText( oPage ) nY -= 5 // ITEMS select clients go top HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) do while !Eof() nY -= 15 if nY < 50 HPDF_Page_EndText( oPage ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) HPDF_Page_BeginText( oPage ) nY := 750 else HPDF_Page_BeginText( oPage ) endif HPDF_Page_TextOut( oPage, 55, nY, AllTrim(clients->id) ) HPDF_Page_TextOut( oPage, 110, nY, SubStr(AllTrim(clients->name), 1, 25) ) HPDF_Page_TextOut( oPage, 250, nY, SubStr(AllTrim(clients->city), 1, 15) ) HPDF_Page_TextOut( oPage, 350, nY, AllTrim(clients->phone) ) HPDF_Page_TextOut( oPage, 450, nY, AllTrim(clients->vat_id) ) HPDF_Page_EndText( oPage ) skip enddo HPDF_SaveToFile( oPdf, cFile ) HPDF_Free( oPdf ) return nil function OpenDatabases() local cTmpDir := "c:/hix/testdir" if Select("clients") == 0; use (cTmpDir+"/clientes_v2.dbf") shared new alias "clients"; endif return .T.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

productos.prg

Code: Select all | Expand

function Main()
    
local cAction := Upost( "action" ) local cId := Upost( "id" ) local cName := Upost( "name" ) local cPrice := Upost( "price" ) local cStock := Upost( "stock" ) local cSearch := Upost( "search" ) local cTmpDir := "c:/hix/testdir" local cDbProd := cTmpDir + "/productos.dbf" local cMessage := "" // Ensure Directory Exists if ! IsDirectory( cTmpDir ) DirMake( cTmpDir ) endif // Initialize Database if not exists if ! File( cDbProd ) DbCreate( cDbProd, { ; { "ID", "C", 8, 0 }, ; { "NAME", "C", 50, 0 }, ; { "PRICE", "N", 10, 2 }, ; { "STOCK", "N", 10, 2 } ; } ) endif // Open Database if Select("products") == 0 use (cDbProd) shared new alias "products" else select products endif do case case cAction == "save" if !Empty(cName) select products if Empty( cId ) // New Product append blank if !NetErr() cId := GenerateID() replace id with cId replace name with cName replace price with Val(cPrice) replace stock with Val(cStock) commit unlock cMessage := "Product created successfully." else cMessage := "Error: Could not create product (Lock failed)." endif else // Update existing go top locate for AllTrim(id) == AllTrim(cId) if found() if Rlock() replace name with cName replace price with Val(cPrice) replace stock with Val(cStock) commit unlock cMessage := "Product updated successfully." endif endif endif endif cId := "" cName := "" cPrice := "" cStock := "" case cAction == "delete" if ! Empty( cId ) select products go top locate for AllTrim(id) == AllTrim(cId) if found() .and. Rlock() delete unlock commit cMessage := "Product deleted successfully." endif endif cId := "" cName := "" cPrice := "" cStock := "" case cAction == "edit" select products go top locate for AllTrim(id) == AllTrim(cId) if found() cName := AllTrim(products->name) cPrice := AllTrim(Str(products->price)) cStock := AllTrim(Str(products->stock)) endif case cAction == "cancel" cId := "" cName := "" cPrice := "" cStock := "" cSearch := "" endcase RenderView( cId, cName, cPrice, cStock, cMessage, cSearch ) close all return "" function GenerateID() local cChars := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" local cNewId := "P" local i for i := 1 to 7 cNewId += SubStr( cChars, Int( hb_Random() * Len(cChars) ) + 1, 1 ) next return cNewId function RenderView( cId, cName, cPrice, cStock, cMessage, cSearch ) local cHtml := MemoRead( "c:/hix/productos.view" ) local cMsgHtml := ""
// Build Rows local cRows := "" local lMatch := .T. select products go top do while ! Eof() lMatch := .T. if !Empty( cSearch ) if ! ( Upper(AllTrim(cSearch)) $ Upper(products->name) ) lMatch := .F. endif endif if lMatch cRows += [<tr>] cRows += [<td>] + AllTrim(products->id) + [</td>] cRows += [<td>] + AllTrim(products->name) + [</td>] cRows += [<td>] + AllTrim(Str(products->price)) + [</td>] cRows += [<td>] + AllTrim(Str(products->stock)) + [</td>] cRows += [<td class="actions-cell">] cRows += [<form method="POST" action="productos.prg" style="display:inline;">] cRows += [<input type="hidden" name="action" value="edit">] cRows += [<input type="hidden" name="id" value="] + AllTrim(products->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-edit"><i class="fa-solid fa-pen"></i></button>] cRows += [</form> ] cRows += [<form method="POST" action="productos.prg" style="display:inline;" onsubmit="return confirm('Delete product?')">] cRows += [<input type="hidden" name="action" value="delete">] cRows += [<input type="hidden" name="id" value="] + AllTrim(products->id) + [">] cRows += [<button type="submit" class="btn btn-sm btn-danger"><i class="fa-solid fa-trash"></i></button>] cRows += [</form></td></tr>] endif skip enddo // Standard Fields cHtml := StrTran( cHtml, "{{PRODUCT_ROWS}}", cRows ) cHtml := StrTran( cHtml, "{{VAL_ID}}", iif( Empty(cId), "", cId ) ) cHtml := StrTran( cHtml, "{{VAL_NAME}}", iif( Empty(cName), "", cName ) ) cHtml := StrTran( cHtml, "{{VAL_PRICE}}", iif( Empty(cPrice), "", cPrice ) ) cHtml := StrTran( cHtml, "{{VAL_STOCK}}", iif( Empty(cStock), "", cStock ) ) // Message & Search if !Empty( cMessage ) if Left( cMessage, 5 ) == "Error" cMsgHtml := [<div class="alert alert-danger" role="alert">] + cMessage + [</div>] else cMsgHtml := [<div class="alert alert-success" role="alert">] + cMessage + [</div>] endif endif cHtml := StrTran( cHtml, "{{MESSAGE}}", cMsgHtml ) cHtml := StrTran( cHtml, "{{VAL_SEARCH}}", iif( Empty(cSearch), "", cSearch ) ) if !Empty(cId) cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "Edit Product: " + cId ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", [<a href="productos.prg" class="btn btn-sm" style="background:#1e3a8a;margin-left:5px;color:#e0f2fe;">Cancel</a>] ) else cHtml := StrTran( cHtml, "{{FORM_TITLE}}", "New Product" ) cHtml := StrTran( cHtml, "{{CANCEL_BUTTON}}", "" ) endif UWrite( cHtml ) return ""

productos.view

Code: Select all | Expand

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Products Management</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <style>
        body { background-color: #0f172a; color: #e0f2fe; font-family: 'Inter', sans-serif; }
        .container-fluid { max-width: 1400px; padding: 20px; }
        .card { background-color: #1e293b; border: 1px solid #3b82f6; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.2); }
        .card-header { background-color: #1d4ed8; color: #e0f2fe; border-bottom: 1px solid #1e40af; border-radius: 12px 12px 0 0 !important; padding: 1rem 1.5rem; }
        
/* Navbar Standardization */ .navbar { background-color: #172554; border-bottom: 1px solid #1e3a8a; padding-top: 0.75rem; padding-bottom: 0.75rem; min-height: 70px; } .navbar-brand { font-weight: 600; color: #bae6fd !important; font-size: 1.25rem; } .nav-link { color: #bfdbfe; margin-right: 15px; font-weight: 500; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight: 600; } .form-label { color: #bfdbfe; font-weight: 500; font-size: 0.875rem; } .form-control, .form-select { background-color: #0f172a; border: 1px solid #3b82f6; color: #e0f2fe; border-radius: 8px; padding: 0.625rem 1rem; } .form-control:focus, .form-select:focus { background-color: #172554; border-color: #60a5fa; box-shadow: 0 0 0 2px rgba(96,165,250,0.3); color: #e0f2fe; } .btn-primary { background-color: #3b82f6; border: none; padding: 0.625rem 1.25rem; font-weight: 500; } .btn-primary:hover { background-color: #2563eb; } .table { color: #0c4a6e; margin-bottom: 0; } .table thead th { background-color: #1e3a8a; border-bottom: none; color: #fff; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; padding: 1rem; } .table tbody tr:nth-of-type(odd) { background-color: #e0f2fe; color: #0c4a6e; } .table tbody tr:nth-of-type(even) { background-color: #bae6fd; color: #0c4a6e; } .table td { border-bottom: 1px solid #7dd3fc; padding: 1rem; vertical-align: middle; border-top: none; } .table tr:last-child td { border-bottom: none; } .actions-cell { white-space: nowrap; width: 1%; } .btn-edit { color: #0f172a; border: none; background: transparent; padding: 0.25rem 0.5rem; } .btn-edit:hover { color: #3b82f6; } .nav-link { color: #bae6fd; margin-right: 15px; } .nav-link:hover, .nav-link.active { color: #e0f2fe; font-weight:600; } </style> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark mb-4"> <div class="container"> <a class="navbar-brand" href="#"><i class="fa-solid fa-boxes-stacked me-2"></i>HIX Products</a> <div class="collapse navbar-collapse"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"><a class="nav-link" href="facturas.prg">Invoices</a></li> <li class="nav-item"><a class="nav-link" href="clientes.prg">Clients</a></li> <li class="nav-item"><a class="nav-link active" href="productos.prg">Products</a></li> </ul> <form class="d-flex" action="productos.prg" method="POST"> <button class="btn btn-outline-success me-2" type="button" id="btnNew"><i class="fa-solid fa-plus me-1"></i>New</button> <input type="hidden" name="action" value="search"> <input class="form-control me-2" type="search" name="search" placeholder="Search products..." value="{{VAL_SEARCH}}"> <button class="btn btn-outline-light me-2" type="submit">Search</button> {{CANCEL_BUTTON}} <a href="productos_pdf.prg" target="_blank" class="btn btn-outline-info" title="Generar Listado PDF"><i class="fa-solid fa-file-pdf"></i></a> </form> </div> </div> </nav> <div class="container"> <div class="row"> <!-- Left Side: Form --> <div class="col-md-4 mb-4" id="productFormCard" style="display:none;"> <div class="card h-100"> <div class="card-header"> <h5 class="mb-0"><i class="fa-solid fa-box-open me-2"></i>{{FORM_TITLE}}</h5> </div> <div class="card-body"> {{MESSAGE}} <form method="POST" action="productos.prg"> <input type="hidden" name="action" value="save"> <input type="hidden" name="id" value="{{VAL_ID}}"> <div class="mb-3"> <label class="form-label">Product Name</label> <input type="text" name="name" class="form-control" value="{{VAL_NAME}}" required placeholder="Enter product name"> </div> <div class="row"> <div class="col-md-6 mb-3"> <label class="form-label">Price</label> <input type="number" step="0.01" name="price" class="form-control" value="{{VAL_PRICE}}" required> </div> <div class="col-md-6 mb-3"> <label class="form-label">Stock</label> <input type="number" step="0.01" name="stock" class="form-control" value="{{VAL_STOCK}}" required> </div> </div> <div class="d-grid gap-2 d-md-flex justify-content-md-end mt-4"> <button type="submit" class="btn btn-primary"><i class="fa-solid fa-save me-2"></i>Save Product</button> </div> </form> </div> </div> </div> <!-- Right Side: List --> <div class="col-md-8" id="productListColumn"> <div class="card"> <div class="card-header d-flex justify-content-between align-items-center"> <h5 class="mb-0"><i class="fa-solid fa-boxes me-2"></i>Inventory</h5> </div> <div class="card-body p-0"> <div class="table-responsive"> <table class="table table-hover"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Price</th> <th>Stock</th> <th>Actions</th> </tr> </thead> <tbody> {{PRODUCT_ROWS}} </tbody> </table> </div> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { var formCard = document.getElementById('productFormCard'); var btnNew = document.getElementById('btnNew'); var inputId = document.querySelector('input[name="id"]'); var listCol = document.getElementById('productListColumn'); function updateLayout() { if (formCard.style.display === "none") { listCol.classList.remove('col-md-8'); listCol.classList.add('col-12'); } else { listCol.classList.remove('col-12'); listCol.classList.add('col-md-8'); } } if (inputId && inputId.value.trim() !== "") { formCard.style.display = "block"; updateLayout(); } else { updateLayout(); } if (btnNew) { btnNew.addEventListener('click', function(e) { e.preventDefault(); if (formCard.style.display === "none") { formCard.style.display = "block"; } else { formCard.style.display = "none"; } updateLayout(); }); } }); </script> </body> </html>

productos_pdf.prg

Code: Select all | Expand

function Main()
    local cTmpDir := "c:/hix/testdir"
    local cPdfFile := cTmpDir + "/products_list_" + AllTrim(Str(Int(hb_Random() * 100000))) + ".pdf"
    local cContent, cBase64

// Open Databases
if !OpenDatabases()
UWrite("Error opening databases.")
return ""
endif

// GENERATE PDF
GeneratePDF( cPdfFile )

close all

// READ AND OUTPUT
if File(cPdfFile)
cContent := MemoRead(cPdfFile)
cBase64  := hb_base64Encode(cContent)
    
UWrite( '<!DOCTYPE html>' )
UWrite( '<html><head><title>Listado de Productos</title></head>' )
UWrite( '<body style="margin:0;padding:0;overflow:hidden;">' )
UWrite( '<iframe src="data:application/pdf;base64,' + cBase64 + '" width="100%" height="100%" style="border:none;height:100vh;"></iframe>' )
UWrite( '</body></html>' )
else
UWrite("Error: PDF Generation failed.")
endif

return ""

function GeneratePDF( cFile )
    local oPdf, oPage, oFont, oFontBold
    local nY := 750
    local nRow := 0
    
oPdf := HPDF_New() HPDF_SetCompressionMode( oPdf, "HPDF_COMP_ALL" ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) oFont := HPDF_GetFont( oPdf, "Helvetica", "CP1252" ) oFontBold := HPDF_GetFont( oPdf, "Helvetica-Bold", "CP1252" ) // HEADER HPDF_Page_SetFontAndSize( oPage, oFontBold, 18 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 50, nY, "LISTADO DE PRODUCTOS" ) HPDF_Page_EndText( oPage ) nY -= 30 // TABLE HEADER HPDF_Page_SetLineWidth( oPage, 1 ) HPDF_Page_Rectangle( oPage, 50, nY, 500, 20 ) HPDF_Page_Stroke( oPage ) HPDF_Page_SetFontAndSize( oPage, oFontBold, 10 ) HPDF_Page_BeginText( oPage ) HPDF_Page_TextOut( oPage, 55, nY + 6, "ID" ) HPDF_Page_TextOut( oPage, 120, nY + 6, "Name" ) HPDF_Page_TextOut( oPage, 350, nY + 6, "Price" ) HPDF_Page_TextOut( oPage, 450, nY + 6, "Stock" ) HPDF_Page_EndText( oPage ) nY -= 5 // ITEMS select products go top HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) do while !Eof() nY -= 15 if nY < 50 HPDF_Page_EndText( oPage ) oPage := HPDF_AddPage( oPdf ) HPDF_Page_SetSize( oPage, "HPDF_PAGE_SIZE_A4", "HPDF_PAGE_PORTRAIT" ) HPDF_Page_SetFontAndSize( oPage, oFont, 10 ) HPDF_Page_BeginText( oPage ) nY := 750 else HPDF_Page_BeginText( oPage ) endif HPDF_Page_TextOut( oPage, 55, nY, AllTrim(products->id) ) HPDF_Page_TextOut( oPage, 120, nY, SubStr(AllTrim(products->name), 1, 40) ) HPDF_Page_TextOut( oPage, 350, nY, AllTrim(Str(products->price)) ) HPDF_Page_TextOut( oPage, 450, nY, AllTrim(Str(products->stock)) ) HPDF_Page_EndText( oPage ) skip enddo HPDF_SaveToFile( oPdf, cFile ) HPDF_Free( oPdf ) return nil function OpenDatabases() local cTmpDir := "c:/hix/testdir" if Select("products") == 0; use (cTmpDir+"/productos.dbf") shared new alias "products"; endif return .T.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Adolfredo Martinez
Posts: 141
Joined: Fri Feb 15, 2019 1:37 pm
Location: Aracataca-Colombia

Re: HIX & AntiGravity apps gallery

Post by Adolfredo Martinez »

Hola a todos

Excelente

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

https://ai.fivetechsoft.com/facturas.prg

Implementado al 100% con HIX y Antigravity :wink: :!:

regards, saludos

Antonio Linares
www.fivetechsoft.com
Adolfredo Martinez
Posts: 141
Joined: Fri Feb 15, 2019 1:37 pm
Location: Aracataca-Colombia

Re: HIX & AntiGravity apps gallery

Post by Adolfredo Martinez »

Hola Antonio.

Lo estuve probando, todo se ven bien excelente, solo que en la parte de New Invoice, al salvar sale un error asi:

System Error

error DBFCDX/EG_UNLOCKED(38) 1022
Descripcion Lock required

Pero el resto todo bien

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

Corregido 👍🏻

Gracias por el feedback 🙏🏻🤗

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

regards, saludos

Antonio Linares
www.fivetechsoft.com
FiveWiDi
Posts: 1467
Joined: Mon Oct 10, 2005 2:38 pm

Re: HIX & AntiGravity apps gallery

Post by FiveWiDi »

Antonio,

Llevo desde anteayer jugando con Antigravity, creo que me he comido el límite de uso de Gemini3, es posible?
Le he pedido lo mismo con modificaciones muchas veces. También le he pedido modificaciones sobre lo que ha creado. Es un no parar.
Con que que facilidad se obtienen resultados.
Estoy usando Gemini 3 Pro High.

Un Saludo
Carlos G.

FiveWin 25.12 + Harbour 3.2.0dev (r2502110321), BCC 7.7 Windows 11 Home

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

Carlos,

No se exactamente cual es su límite, pues yo uso una cuenta Pro obtenida con email de estudiante (oferta que terminó el 9 de diciembre). Le he preguntado a Grok:

Google Antigravity es una plataforma de desarrollo agentic (IDE con agentes IA autónomos) lanzada por Google junto con el modelo Gemini 3 (noviembre 2025). Es gratuita en su versión pública preview y permite usar Gemini 3 Pro con límites de uso generosos diseñados para que la mayoría de usuarios no los alcancen.Los límites se reinician cada 5 horas.
Google indica que solo una pequeña fracción de usuarios "power users" (con tareas muy intensas y complejas) llega a agotarlos.
Usuarios con suscripciones Google AI Pro o Ultra tienen límites más altos en Antigravity (así como en otras herramientas como Gemini CLI o Code Assist).

No se publican números exactos de prompts o tokens por ventana (varían según la complejidad de las tareas agenticas), pero en la práctica, sesiones normales duran horas sin problemas, mientras que usos intensos pueden agotar la cuota en 1-2 horas.Para detalles actualizados o descargar Antigravity, visita el sitio oficial: antigravity.google. Si tienes una suscripción paga, los límites son notablemente más amplios.

regards, saludos

Antonio Linares
www.fivetechsoft.com
gvaronas
Posts: 2
Joined: Fri Nov 12, 2021 2:47 pm

Re: HIX & AntiGravity apps gallery

Post by gvaronas »

Saludos y gracias por la galeria de ejemplos.

En el modpro, al parecer falta el archivo:
views/body.view

Salu2,
GVARONAS

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

gvaronas wrote: Mon Dec 22, 2025 8:54 pm

Saludos y gracias por la galeria de ejemplos.

En el modpro, al parecer falta el archivo:
views/body.view

Salu2,
GVARONAS

views/body.view

Code: Select all | Expand

<body>
	<div id="main" class="container-fluid" style="padding:0px;overflow-x:hidden">
		<div class="row">
			<div class="col-md-12">
				{{View("menu")}}
			</div>
		</div>
		<div id="body">
		   {{View("code")}}
			<div id="right">
         	<div id="splitter"></div>
         	<div id="output"></div>
      	</div> 
        <div id="chat-splitter"></div>
        <div id="chat-panel-container">
            {{View("chat")}}
        </div>
		</div>
	</div>
	<script>
      var editor_width, right_margin_left, cResult;

  editor_width = sessionStorage.getItem( 'editor-width' );
  if( editor_width )
     $( "#editor" ).css( "width", editor_width );

  right_margin_left = sessionStorage.getItem( 'right-margin-left' );
  if( right_margin_left )
      $( "#right" ).css( "margin-left", right_margin_left );

	cResult = sessionStorage.getItem( 'result' );
	if( cResult )
	   $('#output').html( cResult );	 

  $('#splitter').mousedown( function(e) {
      e.preventDefault();
      $(document).mousemove( function(e) {
         var x = e.pageX;
         e.preventDefault();
         if( x > 300 && x < ( $(window).width() - 300 ) )
         {
            $( "#editor" ).css( "width", x );
            $( "#right" ).css( "margin-left", x ); 
	sessionStorage.setItem( 'modpro_code', editor.getValue() );
            sessionStorage.setItem( 'editor-width', $( "#editor" ).css( "width" ) );
            sessionStorage.setItem( 'right-margin-left', $( "#right" ).css( "margin-left" ) );   
         }
      } ) } );
 
   $(document).mouseup( function() {
      $(document).unbind('mousemove'); } );
</script>
</body>
</html>
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

https://ai.fivetechsoft.com/facturas_mysql.prg

100% coded with HIX + Antigravity

Full mysql support :wink: :!:

regards, saludos

Antonio Linares
www.fivetechsoft.com
csincuir
Posts: 483
Joined: Sat Feb 03, 2007 6:36 am
Location: Guatemala
Contact:

Re: HIX & AntiGravity apps gallery

Post by csincuir »

Hola a todos, Feliz Navidad!

Antonio, y que utilizaste para trabajar Mysql?

Saludos cordiales.

Carlos

User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: HIX & AntiGravity apps gallery

Post by Antonio Linares »

Carlos,

Le dí el código que usabamos en mod_harbour y además le pedí a Charly que construyese HIX con la función PTRTOSTR()
necesaria para convertir punteros a cadenas, y Antigravity hizo el resto :wink:

La idea es proporcionaros todo el código para que podais usarlo, pero como te digo, es preciso una actualización de HIX.

Espectacular como Antigravity portó toda la app que usaba DBFs a mysql :!: :o

regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply