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/reports/rad-reorder-gap.asp
<%@ Language="VBScript" %>
<%
Option Explicit

Const DB_DSN = "MySQL_castironradcen"

' Helper: format VBScript Date as ISO yyyy-mm-dd for HTML5 date inputs
Function FormatDateISO(d)
    Dim y, m, dd
    y  = Year(d)
    m  = Month(d)
    dd = Day(d)
    FormatDateISO = y & "-" & Right("0" & m, 2) & "-" & Right("0" & dd, 2)
End Function

' Helper: Null to empty string
Function Nz(val)
    If IsNull(val) Then
        Nz = ""
    Else
        Nz = val
    End If
End Function

Dim conn, rs1, rs2
Dim startDate2, endDate2, minGapDays, maxGapDays, hasRun
Dim today, defaultStart2, defaultEnd2, defaultMaxGap

today         = Date()
defaultStart2 = FormatDateISO(DateSerial(Year(today), 1, 1)) ' start of this year
defaultEnd2   = FormatDateISO(today)                          ' today
defaultMaxGap = 365                                           ' default max gap in days

' ---- Read & validate request values (SQL-injection safe for these simple types) ----
Dim rawStart2, rawEnd2, rawMinGap, rawMaxGap
rawStart2 = Trim(Request("start_date_2"))
rawEnd2   = Trim(Request("end_date_2"))
rawMinGap = Trim(Request("min_gap_days"))
rawMaxGap = Trim(Request("max_gap_days"))

' HTML5 date input will submit yyyy-mm-dd; validate strictly with RegExp
Dim re
Set re = New RegExp
re.Pattern = "^\d{4}-\d{2}-\d{2}$"
re.IgnoreCase = False
re.Global = False

If rawStart2 = "" Then
    startDate2 = defaultStart2
ElseIf re.Test(rawStart2) Then
    startDate2 = rawStart2
Else
    startDate2 = defaultStart2
End If

If rawEnd2 = "" Then
    endDate2 = defaultEnd2
ElseIf re.Test(rawEnd2) Then
    endDate2 = rawEnd2
Else
    endDate2 = defaultEnd2
End If

Set re = Nothing

' Min gap (days)
If rawMinGap = "" Then
    minGapDays = 5
Else
    On Error Resume Next
    minGapDays = CLng(rawMinGap)
    If Err.Number <> 0 Or minGapDays < 0 Then minGapDays = 5
    Err.Clear
    On Error GoTo 0
End If

' Max gap (days)
If rawMaxGap = "" Then
    maxGapDays = defaultMaxGap
Else
    On Error Resume Next
    maxGapDays = CLng(rawMaxGap)
    If Err.Number <> 0 Or maxGapDays < 0 Then maxGapDays = defaultMaxGap
    Err.Clear
    On Error GoTo 0
End If

hasRun = (Request("run") <> "")

If hasRun Then
    On Error Resume Next
    Set conn = Server.CreateObject("ADODB.Connection")
    conn.Open "DSN=" & DB_DSN & ";"

    If Err.Number <> 0 Then
        Response.Write "<div class=""alert alert-danger mt-3""><strong>Error opening database connection:</strong> " & _
                       Server.HTMLEncode(Err.Description) & "</div>"
        Response.End
    End If
    On Error GoTo 0

    ' Set MySQL session variables (values already validated)
    conn.Execute "SET @start_date_2 = '" & startDate2 & "'"
    conn.Execute "SET @end_date_2   = '" & endDate2 & "'"
    conn.Execute "SET @min_gap_days = " & CStr(minGapDays)
    conn.Execute "SET @max_gap_days = " & CStr(maxGapDays)

    ' --- customers placing an order for 1 or more rads, no date range ---
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS all_rad_orders"

    conn.Execute _
        "CREATE TEMPORARY TABLE all_rad_orders " & _
        "SELECT " & _
        "  ROW_NUMBER() OVER (PARTITION BY EmailAddress ORDER BY DatePaid) AS RowNo, " & _
        "  OrderNo, DatePaid, EmailAddress, Postcode, " & _
        "  SUM(QtyRads) AS QtyRads " & _
        "FROM ( " & _
        "  SELECT o.OrderNo, EmailAddress, Postcode, DATE(DateTimePaid) AS DatePaid, " & _
        "         IF(AttributeValue = 'Radiator', Qty - QtyRestocked, 0) AS QtyRads " & _
        "  FROM orders o " & _
        "  INNER JOIN orderdetails od ON od.OrderNo = o.OrderNo " & _
        "  LEFT JOIN product_attributes pa ON pa.ProductID = od.ProductID AND pa.AttributeID = 1 " & _
        "  LEFT JOIN order_detail_options odo ON odo.OrderDetailID = od.OrderDetailID AND odo.OptionName = 'Paint Finish' " & _
        "  WHERE PaymentReceived " & _
        "    AND Status <> 'CANCELLED' " & _
        "    AND od.SubproductOrderDetailID IS NULL " & _
        "    AND (o.Exchange = FALSE OR INSTR(o.ExchangeReason, 'Damaged in transit') > 0) " & _
        "  ORDER BY OrderNo " & _
        ") a " & _
        "GROUP BY OrderNo " & _
        "HAVING QtyRads > 0 " & _
        "ORDER BY EmailAddress, RowNo"

    ' --- first order of 1 or more rads ---
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS first_rad_orders"
    conn.Execute _
        "CREATE TEMPORARY TABLE first_rad_orders " & _
        "SELECT * FROM all_rad_orders " & _
        "WHERE RowNo = 1 AND DatePaid BETWEEN @start_date_2 AND @end_date_2 " & _
        "ORDER BY EmailAddress, RowNo"

    ' --- second order of 1 or more rads ---
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS second_rad_orders"
    conn.Execute _
        "CREATE TEMPORARY TABLE second_rad_orders " & _
        "SELECT * FROM all_rad_orders " & _
        "WHERE RowNo = 2 AND DatePaid BETWEEN @start_date_2 AND @end_date_2 " & _
        "ORDER BY EmailAddress, RowNo"

    ' --- join the two to select customers who placed a second order ---
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS first_and_second_rad_orders"
    conn.Execute _
        "CREATE TEMPORARY TABLE first_and_second_rad_orders " & _
        "SELECT " & _
        "  o1.RowNo AS RowNo1, o1.DatePaid AS DateOrder1, o1.OrderNo AS OrderNo1, " & _
        "  o1.EmailAddress AS EmailAddress1, o1.Postcode AS Postcode1, o1.QtyRads AS QtyRads1, " & _
        "  o2.RowNo AS RowNo2, o2.DatePaid AS DateOrder2, o2.OrderNo AS OrderNo2, " & _
        "  o2.EmailAddress AS EmailAddress2, o2.Postcode AS Postcode2, o2.QtyRads AS QtyRads2, " & _
        "  DATEDIFF(o2.DatePaid, o1.DatePaid) AS DateDiffDays " & _
        "FROM first_rad_orders o1 " & _
        "INNER JOIN second_rad_orders o2 ON o1.EmailAddress = o2.EmailAddress"

    ' --- Result 1: all first->second orders with min/max gap ---
    Set rs1 = Server.CreateObject("ADODB.Recordset")
    rs1.Open _
        "SELECT COUNT(*) AS Customers, " & _
        "       ROUND(AVG(DateDiffDays), 0) AS FirstToSecondAverageDays, " & _
        "       MIN(DateDiffDays) AS MinDays, " & _
        "       MAX(DateDiffDays) AS MaxDays " & _
        "FROM first_and_second_rad_orders " & _
        "WHERE DateDiffDays >= @min_gap_days " & _
        "  AND DateDiffDays <= @max_gap_days", _
        conn, 0, 1

    ' --- Result 2: subset where first order had exactly 1 rad, with min/max gap ---
    Set rs2 = Server.CreateObject("ADODB.Recordset")
    rs2.Open _
        "SELECT COUNT(*) AS Customers, " & _
        "       ROUND(AVG(DateDiffDays), 0) AS FirstToSecondAverageDays, " & _
        "       MIN(DateDiffDays) AS MinDays, " & _
        "       MAX(DateDiffDays) AS MaxDays " & _
        "FROM first_and_second_rad_orders " & _
        "WHERE DateDiffDays >= @min_gap_days " & _
        "  AND DateDiffDays <= @max_gap_days " & _
        "  AND QtyRads1 = 1", _
        conn, 0, 1
End If
%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Time Between First and Second Rad Orders</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="container my-4">
    <h1 class="h3 mb-3">Time Between First and Second Radiator Orders</h1>

    <form method="get"
          action="<%= Server.HTMLEncode(Request.ServerVariables("SCRIPT_NAME")) %>"
          class="row gy-2 gx-3 align-items-end border rounded p-3">
        <div class="col-sm-3">
            <label for="start_date_2" class="form-label">Start date</label>
            <input type="date" name="start_date_2" id="start_date_2"
                   class="form-control"
                   value="<%= Server.HTMLEncode(startDate2) %>" />
        </div>
        <div class="col-sm-3">
            <label for="end_date_2" class="form-label">End date</label>
            <input type="date" name="end_date_2" id="end_date_2"
                   class="form-control"
                   value="<%= Server.HTMLEncode(endDate2) %>" />
        </div>
        <div class="col-sm-2">
            <label for="min_gap_days" class="form-label">Min gap (days)</label>
            <input type="number" name="min_gap_days" id="min_gap_days"
                   class="form-control"
                   value="<%= Server.HTMLEncode(CStr(minGapDays)) %>" />
        </div>
        <div class="col-sm-2">
            <label for="max_gap_days" class="form-label">Max gap (days)</label>
            <input type="number" name="max_gap_days" id="max_gap_days"
                   class="form-control"
                   value="<%= Server.HTMLEncode(CStr(maxGapDays)) %>" />
        </div>
        <div class="col-sm-2 text-sm-end">
            <input type="hidden" name="run" value="1" />
            <button type="submit" class="btn btn-primary w-100">
                Run query
            </button>
        </div>
    </form>

<%
If hasRun Then
    If rs1 Is Nothing Or rs1.EOF Then
%>
    <div class="alert alert-warning mt-3">
        <strong>No data returned</strong> for the selected parameters.
    </div>
<%
    Else
        rs1.MoveFirst
        rs2.MoveFirst
%>
    <table class="table table-bordered table-striped table-sm mt-4">
        <thead class="table-light">
            <tr>
                <th scope="col">Scenario</th>
                <th scope="col" class="text-end">Customers</th>
                <th scope="col" class="text-end">Average gap (days)</th>
                <th scope="col" class="text-end">Min gap (days)</th>
                <th scope="col" class="text-end">Max gap (days)</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>First → second order (any qty of rads)</td>
                <td class="text-end"><%= Nz(rs1("Customers")) %></td>
                <td class="text-end"><%= Nz(rs1("FirstToSecondAverageDays")) %></td>
                <td class="text-end"><%= Nz(rs1("MinDays")) %></td>
                <td class="text-end"><%= Nz(rs1("MaxDays")) %></td>
            </tr>
            <tr>
                <td>First → second order (first order = 1 rad)</td>
                <td class="text-end"><%= Nz(rs2("Customers")) %></td>
                <td class="text-end"><%= Nz(rs2("FirstToSecondAverageDays")) %></td>
                <td class="text-end"><%= Nz(rs2("MinDays")) %></td>
                <td class="text-end"><%= Nz(rs2("MaxDays")) %></td>
            </tr>
        </tbody>
    </table>
<%
    End If

    ' Cleanup
    If Not rs1 Is Nothing Then
        If rs1.State <> 0 Then rs1.Close
        Set rs1 = Nothing
    End If
    If Not rs2 Is Nothing Then
        If rs2.State <> 0 Then rs2.Close
        Set rs2 = Nothing
    End If
    If Not conn Is Nothing Then
        If conn.State <> 0 Then conn.Close
        Set conn = Nothing
    End If
End If
%>
</div>
</body>
</html>