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=" ▲"
Else
nextDir="ASC":arrow=" ▼"
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'>✔</span>","<span class='cross'>✘</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'>✔</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) & "'>« Prev</a></li>"
Else
Response.Write "<li class='page-item disabled'><span class='page-link'>« 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 »</a></li>"
Else
Response.Write "<li class='page-item disabled'><span class='page-link'>Next »</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
%>