HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/circ.itp/wc-orders.asp
<%@ LANGUAGE="VBScript" %>
<%
Option Explicit
Response.Buffer = True

' ==========================
' Cookie-based Authentication
' ==========================
Const ADMIN_USERNAME = "woo"
Const ADMIN_PASSWORD = "woowoo#42"
Const COOKIE_NAME   = "auth_token"
Const COOKIE_DAYS   = 7

Dim isAuthenticated, enteredUser, enteredPassword, rememberMe, storedToken, expectedToken

Function SimpleHash(str)
  Dim i,h: h=0
  For i=1 To Len(str)
    h=(h+Asc(Mid(str,i,1))*i) Mod 99999
  Next
  SimpleHash=CStr(h)
End Function
expectedToken = SimpleHash("secure-salt-" & ADMIN_PASSWORD)

If Request("logout")="1" Then
  Response.Cookies(COOKIE_NAME).Expires = DateAdd("d",-1,Now())
  Response.AddHeader "Set-Cookie", COOKIE_NAME & "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Strict"
  Response.Redirect Request.ServerVariables("SCRIPT_NAME")
End If

storedToken = Request.Cookies(COOKIE_NAME)
If storedToken = expectedToken Then isAuthenticated=True Else isAuthenticated=False

If Not isAuthenticated Then
  enteredUser     = Trim(Request.Form("username"))
  enteredPassword = Trim(Request.Form("password"))
  rememberMe      = (Request.Form("remember")="1")
  If enteredUser="" Then enteredUser=ADMIN_USERNAME
  If enteredPassword<>"" Then
    If enteredUser=ADMIN_USERNAME And enteredPassword=ADMIN_PASSWORD Then
      Response.Cookies(COOKIE_NAME)=expectedToken
      If rememberMe Then Response.Cookies(COOKIE_NAME).Expires=DateAdd("d",COOKIE_DAYS,Now())
      On Error Resume Next
      Response.Cookies(COOKIE_NAME).Secure=True
      Response.Cookies(COOKIE_NAME).HttpOnly=True
      On Error GoTo 0
      Response.AddHeader "Set-Cookie", COOKIE_NAME & "=" & expectedToken & "; Path=/; Secure; HttpOnly; SameSite=Strict"
      Response.Redirect Request.ServerVariables("SCRIPT_NAME")
    Else
      Session("AuthError")="Invalid username or password."
    End If
  End If
End If

If Not isAuthenticated Then
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Required</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light d-flex justify-content-center align-items-center vh-100">
<div class="card shadow-sm p-4" style="max-width:400px;">
  <h3 class="text-center mb-3">Restricted Access</h3>
  <% If Session("AuthError")<>"" Then %>
    <div class="alert alert-danger py-2"><%=Session("AuthError")%></div>
    <% Session("AuthError")="" %>
  <% End If %>
  <form method="post" action="">
    <div class="mb-3">
      <label class="form-label">Username</label>
      <input type="text" name="username" value="<%=ADMIN_USERNAME%>" class="form-control" required>
    </div>
    <div class="mb-3">
      <label class="form-label">Password</label>
      <input type="password" name="password" class="form-control" required>
    </div>
    <div class="form-check mb-3">
      <input class="form-check-input" type="checkbox" name="remember" value="1" id="remember">
      <label class="form-check-label" for="remember">Remember me for 7 days</label>
    </div>
    <button type="submit" class="btn btn-primary w-100">Access Dashboard</button>
  </form>
</div>
</body>
</html>
<%
Response.End
End If
%>

<%
' ==========================
' Helper Functions
' ==========================
Function IIf(cond,t,f): If cond Then IIf=t Else IIf=f End If: End Function

Function CleanNumeric(val, decimals)
  On Error Resume Next
  If IsNull(val) Or val="" Then val=0
  If IsEmpty(decimals) Or Not IsNumeric(decimals) Then decimals=2
  CleanNumeric = Replace(FormatNumber(CDbl(val),decimals,-1,0,-1),",","")
  On Error GoTo 0
End Function

Function SortLink(field,label)
  Dim nextDir,arrow,css
  If LCase(Request.QueryString("sort"))=LCase(field) Then
    If UCase(Request.QueryString("dir"))="ASC" Then
      nextDir="DESC":arrow=" &#9650;"
    Else
      nextDir="ASC":arrow=" &#9660;"
    End If
    css="active-sort"
  Else
    nextDir="ASC":arrow="":css=""
  End If
  Dim link
  link="?startDate="&Server.URLEncode(Request.QueryString("startDate"))&_
       "&endDate="&Server.URLEncode(Request.QueryString("endDate"))&_
       "&dateField="&Server.URLEncode(Request.QueryString("dateField"))&_
       "&search="&Server.URLEncode(Request.QueryString("search"))&_
       "&errors="&Server.URLEncode(Request.QueryString("errors"))&_
       "&sort="&field&"&dir="&nextDir
  SortLink="<a href='"&link&"' class='text-decoration-none "&css&"'>"&label&arrow&"</a>"
End Function

' ==========================
' Query / Filter setup
' ==========================
Dim startDate,endDate,searchTerm,sortField,sortDir,dateField,showErrors
Dim pageSize,currentPage,offset,whereClause,totalCount

startDate = Trim(Request.QueryString("startDate"))
endDate   = Trim(Request.QueryString("endDate"))
searchTerm= Trim(Request.QueryString("search"))
sortField = Trim(Request.QueryString("sort"))
sortDir   = Trim(Request.QueryString("dir"))
dateField = Trim(Request.QueryString("dateField"))
showErrors= (Request.QueryString("errors")="1")

If dateField="" Then dateField="DateTimePaid"
If sortField="" Then sortField="DateTimePaid"
If sortDir="" Then sortDir="DESC"

pageSize=50
If IsNumeric(Request.QueryString("page")) Then currentPage=CInt(Request.QueryString("page")) Else currentPage=1
If currentPage<1 Then currentPage=1
offset=(currentPage-1)*pageSize

Dim conn,cmd,rs,sql,totalCmd,totalRS
Set conn=Server.CreateObject("ADODB.Connection")
conn.Open "DSN=MySQL_castironradcen;"

Dim safeStart,safeEnd
safeStart="":safeEnd="":whereClause=""

If IsDate(startDate) Then safeStart=Year(CDate(startDate))&"-"&Right("0"&Month(CDate(startDate)),2)&"-"&Right("0"&Day(CDate(startDate)),2)&" 00:00:00"
If IsDate(endDate)   Then safeEnd  =Year(CDate(endDate))&"-"&Right("0"&Month(CDate(endDate)),2)&"-"&Right("0"&Day(CDate(endDate)),2)&" 23:59:59"

If safeStart<>"" And safeEnd<>"" Then
  whereClause="WHERE "&dateField&" BETWEEN ? AND ?"
ElseIf safeStart<>"" Then
  whereClause="WHERE "&dateField&">=?"
ElseIf safeEnd<>"" Then
  whereClause="WHERE "&dateField&"<=?"
End If
If searchTerm<>"" Then whereClause=whereClause&IIf(whereClause="","WHERE "," AND ")&"(OrderNumber LIKE ?)"
If showErrors Then whereClause=whereClause&IIf(whereClause="","WHERE "," AND ")&"Imported=0"

' ---- Count ----
sql="SELECT COUNT(*) AS TotalCount FROM circ_penn.wc_orders "&whereClause
Set totalCmd=Server.CreateObject("ADODB.Command")
With totalCmd
  .ActiveConnection=conn
  .CommandText=sql
  .CommandType=1
End With
If safeStart<>"" And safeEnd<>"" Then
  totalCmd.Parameters.Append totalCmd.CreateParameter("p1",200,1,19,safeStart)
  totalCmd.Parameters.Append totalCmd.CreateParameter("p2",200,1,19,safeEnd)
ElseIf safeStart<>"" Then
  totalCmd.Parameters.Append totalCmd.CreateParameter("p1",200,1,19,safeStart)
ElseIf safeEnd<>"" Then
  totalCmd.Parameters.Append totalCmd.CreateParameter("p1",200,1,19,safeEnd)
End If
If searchTerm<>"" Then totalCmd.Parameters.Append totalCmd.CreateParameter("p3",200,1,255,"%"&searchTerm&"%")
Set totalRS=totalCmd.Execute()
If Not totalRS.EOF Then totalCount=CLng(totalRS("TotalCount")) Else totalCount=0
totalRS.Close:Set totalRS=Nothing

' ---- Main Query ----
sql="SELECT WooCommerceOrderID,OrderNumber,DateTimeImported,Imported,ImportError,SyncCount,DateTimeLastSynced," & _
    "Subtotal,Discount,Delivery,VATIncluded,GrandTotal,DateTimeOrdered,DateTimePaid,Status,PaymentMethod,LocalMode,ExchangeReason,LastUpdated " & _
    "FROM circ_penn.wc_orders "&whereClause&" ORDER BY "&sortField&" "&sortDir&" LIMIT "&pageSize&" OFFSET "&offset
Set cmd=Server.CreateObject("ADODB.Command")
cmd.ActiveConnection=conn
cmd.CommandType=1
cmd.CommandText=sql
If safeStart<>"" And safeEnd<>"" Then
  cmd.Parameters.Append cmd.CreateParameter("p1",200,1,19,safeStart)
  cmd.Parameters.Append cmd.CreateParameter("p2",200,1,19,safeEnd)
ElseIf safeStart<>"" Then
  cmd.Parameters.Append cmd.CreateParameter("p1",200,1,19,safeStart)
ElseIf safeEnd<>"" Then
  cmd.Parameters.Append cmd.CreateParameter("p1",200,1,19,safeEnd)
End If
If searchTerm<>"" Then cmd.Parameters.Append cmd.CreateParameter("p3",200,1,255,"%"&searchTerm&"%")
Set rs=cmd.Execute()
%>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WooCommerce Orders</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.tick{color:#28a745;font-size:1.1em}
.cross{color:#dc3545;font-size:1.1em}
.error-highlight{background-color:#f8d7da;color:#842029;font-weight:600;padding:4px 8px;border-radius:4px;display:inline-block}
.no-error{color:#6c757d}
.status-default{background-color:#6c757d!important}
th a.active-sort{color:#0d6efd!important;font-weight:600}
th a.active-sort:hover{text-decoration:underline}
</style>
</head>
<body class="bg-light">
<div class="container-fluid my-4">
<div class="text-end mb-3">
  <a href="?logout=1" class="btn btn-sm btn-outline-secondary">Logout</a>
</div>

<h2 class="mb-4 text-center">WooCommerce Orders</h2>

<!-- Filter Form -->
<form class="row g-3 mb-4" method="get">
  <div class="col-md-2">
    <label class="form-label">Filter By</label>
    <select class="form-select" name="dateField">
      <option value="DateTimePaid" <%=IIf(dateField="DateTimePaid","selected","")%>>Paid Date</option>
      <option value="DateTimeOrdered" <%=IIf(dateField="DateTimeOrdered","selected","")%>>Order Date</option>
    </select>
  </div>
  <div class="col-md-2">
    <label class="form-label">Start Date</label>
    <input type="date" class="form-control" name="startDate" value="<%=Server.HTMLEncode(startDate)%>">
  </div>
  <div class="col-md-2">
    <label class="form-label">End Date</label>
    <input type="date" class="form-control" name="endDate" value="<%=Server.HTMLEncode(endDate)%>">
  </div>
  <div class="col-md-3">
    <label class="form-label">Search Order No.</label>
    <input type="text" class="form-control" name="search" value="<%=Server.HTMLEncode(searchTerm)%>">
  </div>
  <div class="col-md-3 align-self-end">
    <div class="form-check mb-2">
      <input class="form-check-input" type="checkbox" value="1" id="errors" name="errors" <%=IIf(showErrors,"checked","")%>>
      <label class="form-check-label" for="errors">Show Import Errors only</label>
    </div>
    <div class="d-flex gap-2">
      <button type="submit" class="btn btn-primary flex-fill">Filter</button>
      <a href="<%=Request.ServerVariables("SCRIPT_NAME")%>" class="btn btn-outline-secondary flex-fill">Reset</a>
    </div>
  </div>
</form>

<div class="table-responsive shadow-sm rounded">
<table class="table table-striped table-bordered align-middle w-100">
<thead class="table-light">
<tr>
  <th><%=SortLink("WooCommerceOrderID","Order ID")%></th>
  <th><%=SortLink("OrderNumber","Order No.")%></th>
  <th><%=SortLink("DateTimeImported","Imported Date")%></th>
  <th><%=SortLink("Imported","Imported")%></th>
  <th><%=SortLink("ImportError","Import Error")%></th>
  <th class="text-center"><%=SortLink("SyncCount","Sync Count")%></th>
  <th><%=SortLink("DateTimeLastSynced","Last Synced")%></th>
  <th class="text-end"><%=SortLink("Subtotal","Subtotal")%></th>
  <th class="text-end"><%=SortLink("Discount","Discount")%></th>
  <th class="text-end"><%=SortLink("Delivery","Delivery")%></th>
  <th class="text-end"><%=SortLink("VATIncluded","VAT")%></th>
  <th class="text-end"><%=SortLink("GrandTotal","Total")%></th>
  <th><%=SortLink("DateTimeOrdered","Ordered")%></th>
  <th><%=SortLink("DateTimePaid","Paid")%></th>
  <th><%=SortLink("Status","Status")%></th>
  <th><%=SortLink("PaymentMethod","Payment Method")%></th>
  <th class="text-center"><%=SortLink("LocalMode","Web Admin")%></th>
  <th><%=SortLink("ExchangeReason","Exchange Reason")%></th>
  <th><%=SortLink("LastUpdated","Last Updated")%></th>
</tr>
</thead>
<tbody>
<%
Dim importedIcon, importErrorValue, importErrorDisplay, localModeDisplay
If Not rs.EOF Then
  Do Until rs.EOF
    importedIcon = IIf(rs("Imported")=1,"<span class='tick'>&#10004;</span>","<span class='cross'>&#10008;</span>")
    importErrorValue = Trim(rs("ImportError")&"")
    importErrorDisplay = IIf(importErrorValue<>"","<span class='error-highlight'>"&Server.HTMLEncode(importErrorValue)&"</span>","<span class='no-error'>–</span>")
    If rs("LocalMode")=1 Then localModeDisplay="<span class='tick'>&#10004;</span>" Else localModeDisplay=""

    Response.Write "<tr>"
    Response.Write "<td>"&rs("WooCommerceOrderID")&"</td>"
    Response.Write "<td><a href='#' data-bs-toggle='modal' data-bs-target='#orderItemsModal' " & _
                   "data-orderid='" & rs("WooCommerceOrderID") & "' " & _
                   "data-ordernumber='" & Server.HTMLEncode(rs("OrderNumber")) & "' " & _
                   "data-subtotal='" & CleanNumeric(rs("Subtotal"),2) & "' " & _
                   "data-discount='" & CleanNumeric(rs("Discount"),2) & "'>" & _
                   rs("OrderNumber") & "</a></td>"
    Response.Write "<td>"&rs("DateTimeImported")&"</td>"
    Response.Write "<td class='text-center'>"&importedIcon&"</td>"
    Response.Write "<td>"&importErrorDisplay&"</td>"
    Response.Write "<td class='text-center'>"&rs("SyncCount")&"</td>"
    Response.Write "<td>"&rs("DateTimeLastSynced")&"</td>"
    Response.Write "<td class='text-end'>£"&FormatNumber(rs("Subtotal"),2)&"</td>"
    Response.Write "<td class='text-end'>£"&FormatNumber(rs("Discount"),2)&"</td>"
    Response.Write "<td class='text-end'>£"&FormatNumber(rs("Delivery"),2)&"</td>"
    Response.Write "<td class='text-end'>£"&FormatNumber(rs("VATIncluded"),2)&"</td>"
    Response.Write "<td class='text-end fw-bold'>£"&FormatNumber(rs("GrandTotal"),2)&"</td>"
    Response.Write "<td>"&rs("DateTimeOrdered")&"</td>"
    Response.Write "<td>"&rs("DateTimePaid")&"</td>"
    Response.Write "<td><span class='badge status-default'>"&rs("Status")&"</span></td>"
    Response.Write "<td>"&rs("PaymentMethod")&"</td>"
    Response.Write "<td class='text-center'>"&localModeDisplay&"</td>"
    Response.Write "<td>"&rs("ExchangeReason")&"</td>"
    Response.Write "<td>"&rs("LastUpdated")&"</td>"
    Response.Write "</tr>"
    rs.MoveNext
  Loop
Else
  Response.Write "<tr><td colspan='19' class='text-center text-muted py-4'>No matching orders found.</td></tr>"
End If
%>
</tbody>
</table>
</div>

<%
Dim totalPages, startRow, endRow
If totalCount > 0 Then
    totalPages = CInt((totalCount + pageSize - 1) / pageSize)
    startRow   = offset + 1
    endRow     = offset + rs.RecordCount
    If endRow = 0 Then endRow = startRow - 1

    Response.Write "<div class='d-flex justify-content-between align-items-center mt-3 flex-wrap gap-2'>"

    ' --- Summary ---
    Response.Write "<div class='text-muted small'>Showing " & startRow & "–" & endRow & " of " & totalCount & " orders</div>"

    ' --- Pagination links ---
    Response.Write "<nav><ul class='pagination pagination-sm mb-0'>"

    Dim qBase, i
    qBase = "startDate=" & Server.URLEncode(startDate) & _
            "&endDate=" & Server.URLEncode(endDate) & _
            "&search=" & Server.URLEncode(searchTerm) & _
            "&errors=" & IIf(showErrors,"1","0") & _
            "&sort=" & Server.URLEncode(sortField) & _
            "&dir=" & Server.URLEncode(sortDir) & _
            "&dateField=" & Server.URLEncode(dateField)

    If currentPage > 1 Then
        Response.Write "<li class='page-item'><a class='page-link' href='?" & qBase & "&page=" & (currentPage-1) & "'>&laquo; Prev</a></li>"
    Else
        Response.Write "<li class='page-item disabled'><span class='page-link'>&laquo; Prev</span></li>"
    End If

    For i = 1 To totalPages
        If i = currentPage Then
            Response.Write "<li class='page-item active'><span class='page-link'>" & i & "</span></li>"
        ElseIf (i=1) Or (i=totalPages) Or (Abs(i-currentPage)<=2) Then
            Response.Write "<li class='page-item'><a class='page-link' href='?" & qBase & "&page=" & i & "'>" & i & "</a></li>"
        ElseIf Abs(i-currentPage)=3 Then
            Response.Write "<li class='page-item disabled'><span class='page-link'>…</span></li>"
        End If
    Next

    If currentPage < totalPages Then
        Response.Write "<li class='page-item'><a class='page-link' href='?" & qBase & "&page=" & (currentPage+1) & "'>Next &raquo;</a></li>"
    Else
        Response.Write "<li class='page-item disabled'><span class='page-link'>Next &raquo;</span></li>"
    End If

    Response.Write "</ul></nav></div>"
End If
%>


<!-- Modal -->
<div class="modal fade" id="orderItemsModal" tabindex="-1" aria-labelledby="orderItemsModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="orderItemsModalLabel">Order Items</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body"><div id="order-items-content" class="text-center text-muted">Loading...</div></div>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',()=>{
  const modal=document.getElementById('orderItemsModal');
  const modalTitle=document.getElementById('orderItemsModalLabel');
  modal.addEventListener('show.bs.modal',e=>{
    const orderId=e.relatedTarget.getAttribute('data-orderid');
    const orderNumber=e.relatedTarget.getAttribute('data-ordernumber');
    const orderSubtotal=parseFloat(e.relatedTarget.getAttribute('data-subtotal'))||0;
    const orderDiscount=parseFloat(e.relatedTarget.getAttribute('data-discount'))||0;
    const orderNet=(orderSubtotal + orderDiscount).toFixed(2);
    modalTitle.innerHTML=
      'Order Items for <strong>#'+orderNumber+'</strong> — '+
      '<span class="text-muted">Subtotal £'+orderSubtotal.toFixed(2)+
      ' + Discount <span class="text-danger">£'+orderDiscount.toFixed(2)+
      '</span> = <strong class="text-success">£'+orderNet+'</strong></span>';
    const content=document.getElementById('order-items-content');
    content.innerHTML='Loading...';
    fetch('wc-order-items.asp?orderid='+encodeURIComponent(orderId))
      .then(r=>r.text())
      .then(html=>content.innerHTML=html)
      .catch(()=>content.innerHTML='<div class="text-danger">Error loading items.</div>');
  });
});
</script>
</body>
</html>
<%
rs.Close:Set rs=Nothing
conn.Close:Set conn=Nothing
%>