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/clearance-radiator-analysis.asp
<%@ Language="VBScript" CodePage="65001" %>
<%
Option Explicit

Response.Buffer = True
Response.CodePage = 65001
Response.CharSet = "utf-8"

' Security and privacy headers.
Response.Expires = -1
Response.AddHeader "Cache-Control", "private, no-store, no-cache, must-revalidate, max-age=0"
Response.AddHeader "Pragma", "no-cache"
Response.AddHeader "X-Content-Type-Options", "nosniff"
Response.AddHeader "X-Frame-Options", "DENY"
Response.AddHeader "Referrer-Policy", "no-referrer"
Response.AddHeader "Permissions-Policy", "camera=(), microphone=(), geolocation=()"
Response.AddHeader "X-Robots-Tag", "noindex, nofollow, noarchive"
Response.AddHeader "Content-Security-Policy", "default-src 'none'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; script-src 'self' 'unsafe-inline'; form-action 'self'; frame-ancestors 'none'; base-uri 'none'"

' Fail closed unless IIS is serving the page over HTTPS and has authenticated the user.
Dim isHttps, authenticatedUser
isHttps = (LCase(Trim(Request.ServerVariables("HTTPS"))) = "on" Or _
           Trim(Request.ServerVariables("SERVER_PORT_SECURE")) = "1" Or _
           LCase(Trim(Request.ServerVariables("HTTP_X_FORWARDED_PROTO"))) = "https")

If Not isHttps Then
    Response.Status = "403 Forbidden"
    Response.ContentType = "text/plain"
    Response.Write "HTTPS is required for this report."
    Response.End
End If

authenticatedUser = Trim(Request.ServerVariables("AUTH_USER"))
If authenticatedUser = "" Then authenticatedUser = Trim(Request.ServerVariables("LOGON_USER"))

If authenticatedUser = "" Then
    Response.Status = "403 Forbidden"
    Response.ContentType = "text/plain"
    Response.Write "IIS authentication is required for this report."
    Response.End
End If

Const DB_DSN = "MySQL_castironradcen"

Function FormatDateISO(d)
    FormatDateISO = Year(d) & "-" & Right("0" & Month(d), 2) & "-" & Right("0" & Day(d), 2)
End Function

Function FormatDateTimeDisplay(v)
    If IsNull(v) Or Not IsDate(v) Then
        FormatDateTimeDisplay = ""
    Else
        FormatDateTimeDisplay = Right("0" & Day(v), 2) & "/" & _
                                Right("0" & Month(v), 2) & "/" & _
                                Year(v) & " " & _
                                Right("0" & Hour(v), 2) & ":" & _
                                Right("0" & Minute(v), 2)
    End If
End Function

Function FormatDateDisplay(v)
    If IsNull(v) Or Not IsDate(v) Then
        FormatDateDisplay = ""
    Else
        FormatDateDisplay = Right("0" & Day(v), 2) & "/" & _
                            Right("0" & Month(v), 2) & "/" & _
                            Year(v)
    End If
End Function

Function Nz(v)
    If IsNull(v) Then
        Nz = ""
    Else
        Nz = v
    End If
End Function

Function H(v)
    H = Server.HTMLEncode(CStr(Nz(v)))
End Function

Function Money(v)
    If IsNull(v) Or Not IsNumeric(v) Then
        Money = "0.00"
    Else
        Money = FormatNumber(CDbl(v), 2, -1, 0, -1)
    End If
End Function

Function Number0(ByVal v)
    Dim n

    If IsNull(v) Or IsEmpty(v) Then
        Number0 = "0"
        Exit Function
    End If

    On Error Resume Next
    n = CDbl(v)
    If Err.Number <> 0 Then
        Err.Clear
        Number0 = "0"
    Else
        Number0 = FormatNumber(n, 0, -1, 0, -1)
    End If
    On Error GoTo 0
End Function

Function Percent1(numerator, denominator)
    If IsNull(denominator) Or Not IsNumeric(denominator) Or CDbl(denominator) = 0 Then
        Percent1 = "0.0%"
    Else
        Percent1 = FormatNumber((CDbl(numerator) / CDbl(denominator)) * 100, 1, -1, 0, -1) & "%"
    End If
End Function

Function Csv(v)
    Dim s
    If IsNull(v) Then
        s = ""
    Else
        s = CStr(v)
    End If
    s = Replace(s, Chr(34), Chr(34) & Chr(34))
    Csv = """" & s & """"
End Function

Function CsvNumber(ByVal v)
    Dim n

    If IsNull(v) Or IsEmpty(v) Then
        CsvNumber = "0"
        Exit Function
    End If

    On Error Resume Next
    n = CDbl(v)
    If Err.Number <> 0 Then
        Err.Clear
        CsvNumber = "0"
    Else
        CsvNumber = Replace(CStr(n), ",", ".")
    End If
    On Error GoTo 0
End Function

Function CsvMoney(ByVal v)
    Dim n, s

    If IsNull(v) Or IsEmpty(v) Then
        CsvMoney = "0.00"
        Exit Function
    End If

    On Error Resume Next
    n = CDbl(v)
    If Err.Number <> 0 Then
        Err.Clear
        CsvMoney = "0.00"
    Else
        s = FormatNumber(n, 2, -1, 0, 0)
        CsvMoney = Replace(s, ",", ".")
    End If
    On Error GoTo 0
End Function

Function CsvDate(v)
    If IsNull(v) Or Not IsDate(v) Then
        CsvDate = ""
    Else
        CsvDate = FormatDateISO(CDate(v))
    End If
End Function

Function CsvDateTime(v)
    If IsNull(v) Or Not IsDate(v) Then
        CsvDateTime = ""
    Else
        CsvDateTime = FormatDateISO(CDate(v)) & " " & _
                      Right("0" & Hour(v), 2) & ":" & _
                      Right("0" & Minute(v), 2) & ":" & _
                      Right("0" & Second(v), 2)
    End If
End Function

Sub CloseRecordset(ByRef rs)
    If IsObject(rs) Then
        If Not rs Is Nothing Then
            If rs.State <> 0 Then rs.Close
            Set rs = Nothing
        End If
    End If
End Sub

Sub CloseConnection(ByRef conn)
    If IsObject(conn) Then
        If Not conn Is Nothing Then
            If conn.State <> 0 Then conn.Close
            Set conn = Nothing
        End If
    End If
End Sub

Sub DatabaseErrorAndEnd(conn, message)
    Response.ContentType = "text/html"
    Response.Write "<!doctype html><html><head><meta charset=""utf-8""><title>Report error</title>" & _
                   "<link href=""https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"" rel=""stylesheet""></head>" & _
                   "<body><div class=""container my-4""><div class=""alert alert-danger"">" & _
                   "<strong>" & Server.HTMLEncode(message) & "</strong><br>" & Server.HTMLEncode(Err.Description) & _
                   "</div></div></body></html>"
    CloseConnection conn
    Response.End
End Sub

Dim today, defaultStartDate, defaultEndDate
Dim rawStartDate, rawEndDate, startDate, endDate
Dim hasRun, exportReport, scriptName, queryStringBase
Dim re

today = Date()
defaultStartDate = FormatDateISO(DateAdd("yyyy", -3, today))
defaultEndDate = FormatDateISO(today)

rawStartDate = Trim(Request.QueryString("start_date"))
rawEndDate = Trim(Request.QueryString("end_date"))

Set re = New RegExp
re.Pattern = "^\d{4}-\d{2}-\d{2}$"
re.IgnoreCase = False
re.Global = False

If rawStartDate <> "" And re.Test(rawStartDate) Then
    startDate = rawStartDate
Else
    startDate = defaultStartDate
End If

If rawEndDate <> "" And re.Test(rawEndDate) Then
    endDate = rawEndDate
Else
    endDate = defaultEndDate
End If

Set re = Nothing

If startDate > endDate Then
    Dim swapDate
    swapDate = startDate
    startDate = endDate
    endDate = swapDate
End If

exportReport = LCase(Trim(Request.QueryString("export")))
hasRun = (Request.QueryString("run") <> "" Or exportReport <> "")
scriptName = Request.ServerVariables("SCRIPT_NAME")
queryStringBase = "start_date=" & Server.URLEncode(startDate) & _
                  "&end_date=" & Server.URLEncode(endDate) & "&run=1"

Dim conn
Dim rsSummary, rsCustomerSummary, rsTypes, rsProducts, rsCustomers, rsOrders
Set conn = Nothing
Set rsSummary = Nothing
Set rsCustomerSummary = Nothing
Set rsTypes = Nothing
Set rsProducts = Nothing
Set rsCustomers = Nothing
Set rsOrders = Nothing

If hasRun Then
    On Error Resume Next
    Set conn = Server.CreateObject("ADODB.Connection")
    conn.Open "DSN=" & DB_DSN & ";"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error opening database connection."

    conn.Execute "SET @start_date = '" & startDate & "'"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error setting the report start date."

    conn.Execute "SET @end_date = '" & endDate & "'"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error setting the report end date."

    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_lines_base"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_order_line_totals"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_lines"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_all_orders"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_clearance_orders"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_clearance_customer_period"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_clearance_customer_anchor"
    conn.Execute "DROP TEMPORARY TABLE IF EXISTS report_customer_summary"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error preparing temporary report tables."

    ' All chargeable product lines from qualifying paid orders, across all dates.
    ' Original ordered quantities are used; partial refunds/restocks are intentionally ignored.
    ' Subproduct lines and bundle container lines are excluded to avoid double-counting.
    conn.Execute _
        "CREATE TEMPORARY TABLE report_lines_base AS " & _
        "SELECT " & _
        "  o.OrderNo, o.DateTimePaid, DATE(o.DateTimePaid) AS OrderDate, " & _
        "  LOWER(TRIM(o.EmailAddress)) AS EmailKey, o.EmailAddress, " & _
        "  o.FirstName, o.Surname, o.CompanyName, o.CurrencyCode, " & _
        "  o.Subtotal AS OrderSubtotal, o.Discount AS OrderDiscount, " & _
        "  od.OrderDetailID, od.ProductID, od.ProductCode, od.ProductName, od.OptionsList, " & _
        "  od.Qty AS QtyReport, " & _
        "  od.PriceEach, " & _
        "  od.Qty * od.PriceEach AS LineValueBeforeDiscount, " & _
        "  CASE WHEN COALESCE(p.CustomFlag, 0) = 1 " & _
        "         AND EXISTS ( " & _
        "             SELECT 1 FROM productcategories pc " & _
        "             WHERE pc.ProductCode = od.ProductCode " & _
        "               AND pc.Category = 'Clearance' " & _
        "               AND pc.Subcategory = 'Radiators' " & _
        "               AND pc.Main = 1 " & _
        "         ) THEN 1 ELSE 0 END AS IsClearanceRadiator, " & _
        "  CASE " & _
        "    WHEN COALESCE(p.CustomFlag, 0) = 1 " & _
        "         AND EXISTS ( " & _
        "             SELECT 1 FROM productcategories pc2 " & _
        "             WHERE pc2.ProductCode = od.ProductCode " & _
        "               AND pc2.Category = 'Clearance' " & _
        "               AND pc2.Subcategory = 'Radiators' " & _
        "               AND pc2.Main = 1 " & _
        "         ) THEN 'Clearance Radiator' " & _
        "    WHEN TRIM(COALESCE(pa.AttributeValue, '')) IN " & _
        "         ('Radiator','Valve Set','Wall Stay','Pipe Shrouds','Bleed Valve','Touch Up Paint','Inhibitor','Bundle') " & _
        "      THEN TRIM(pa.AttributeValue) " & _
        "    ELSE 'Other / Unclassified' " & _
        "  END AS ProductType " & _
        "FROM orders o " & _
        "INNER JOIN orderdetails od ON od.OrderNo = o.OrderNo " & _
        "LEFT JOIN products p ON p.ProductCode = od.ProductCode " & _
        "LEFT JOIN product_attributes pa ON pa.ProductID = od.ProductID AND pa.AttributeID = 1 " & _
        "WHERE o.Status IN ('COMPLETED', 'PAYMENT RECEIVED') " & _
        "  AND o.PaymentReceived = 1 " & _
        "  AND o.GrandTotal > 0 " & _
        "  AND o.DateTimePaid IS NOT NULL " & _
        "  AND o.DateTimePaid <> '0000-00-00 00:00:00' " & _
        "  AND od.SubproductOrderDetailID IS NULL " & _
        "  AND COALESCE(od.BundlePriceEach, 0) = 0 " & _
        "  AND od.Qty > 0"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error creating the qualifying order-line data."

    conn.Execute "ALTER TABLE report_lines_base ADD INDEX idx_rlb_order (OrderNo), ADD INDEX idx_rlb_email (EmailKey), ADD INDEX idx_rlb_paid (DateTimePaid)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing the qualifying order-line data."

    conn.Execute _
        "CREATE TEMPORARY TABLE report_order_line_totals AS " & _
        "SELECT OrderNo, SUM(LineValueBeforeDiscount) AS IncludedLineTotal " & _
        "FROM report_lines_base GROUP BY OrderNo"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error calculating order-line totals."

    conn.Execute "ALTER TABLE report_order_line_totals ADD PRIMARY KEY (OrderNo)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing order-line totals."

    ' CIRC stores discounts as negative values. Allocate that signed adjustment proportionally across included product lines.
    conn.Execute _
        "CREATE TEMPORARY TABLE report_lines AS " & _
        "SELECT b.*, t.IncludedLineTotal, " & _
        "  CASE WHEN t.IncludedLineTotal <> 0 " & _
        "       THEN b.OrderDiscount * b.LineValueBeforeDiscount / t.IncludedLineTotal " & _
        "       ELSE 0 END AS AllocatedDiscount, " & _
        "  b.LineValueBeforeDiscount + " & _
        "  CASE WHEN t.IncludedLineTotal <> 0 " & _
        "       THEN b.OrderDiscount * b.LineValueBeforeDiscount / t.IncludedLineTotal " & _
        "       ELSE 0 END AS LineRevenue " & _
        "FROM report_lines_base b " & _
        "INNER JOIN report_order_line_totals t ON t.OrderNo = b.OrderNo"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error allocating order discounts."

    conn.Execute "ALTER TABLE report_lines ADD INDEX idx_rl_order (OrderNo), ADD INDEX idx_rl_email (EmailKey), ADD INDEX idx_rl_type (ProductType), ADD INDEX idx_rl_clearance (IsClearanceRadiator)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing the analysed order lines."

    conn.Execute _
        "CREATE TEMPORARY TABLE report_all_orders AS " & _
        "SELECT " & _
        "  OrderNo, MIN(DateTimePaid) AS DateTimePaid, MIN(OrderDate) AS OrderDate, " & _
        "  MIN(EmailKey) AS EmailKey, MIN(EmailAddress) AS EmailAddress, " & _
        "  MIN(FirstName) AS FirstName, MIN(Surname) AS Surname, MIN(CompanyName) AS CompanyName, " & _
        "  MIN(CurrencyCode) AS CurrencyCode, " & _
        "  MAX(OrderSubtotal) AS OrderSubtotal, MAX(OrderDiscount) AS OrderDiscount, " & _
        "  SUM(LineValueBeforeDiscount) AS IncludedLineTotal, " & _
        "  SUM(AllocatedDiscount) AS AllocatedDiscount, " & _
        "  SUM(LineRevenue) AS CalculatedProductRevenue, " & _
        "  MAX(OrderSubtotal) + MAX(OrderDiscount) AS OrderNetProductRevenue " & _
        "FROM report_lines GROUP BY OrderNo"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error creating all-order summaries."

    conn.Execute "ALTER TABLE report_all_orders ADD PRIMARY KEY (OrderNo), ADD INDEX idx_rao_email (EmailKey), ADD INDEX idx_rao_paid (DateTimePaid)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing all-order summaries."

    ' One row per clearance radiator order in the selected period.
    conn.Execute _
        "CREATE TEMPORARY TABLE report_clearance_orders AS " & _
        "SELECT " & _
        "  OrderNo, MIN(DateTimePaid) AS DateTimePaid, MIN(OrderDate) AS OrderDate, " & _
        "  MIN(EmailKey) AS EmailKey, MIN(EmailAddress) AS EmailAddress, " & _
        "  MIN(FirstName) AS FirstName, MIN(Surname) AS Surname, MIN(CompanyName) AS CompanyName, " & _
        "  MIN(CurrencyCode) AS CurrencyCode, " & _
        "  MAX(OrderSubtotal) AS OrderSubtotal, MAX(OrderDiscount) AS OrderDiscount, " & _
        "  SUM(LineValueBeforeDiscount) AS IncludedLineTotal, " & _
        "  SUM(LineRevenue) AS CalculatedProductRevenue, " & _
        "  MAX(OrderSubtotal) + MAX(OrderDiscount) AS OrderNetProductRevenue, " & _
        "  SUM(CASE WHEN IsClearanceRadiator = 1 THEN QtyReport ELSE 0 END) AS ClearanceRadiatorQty, " & _
        "  SUM(CASE WHEN IsClearanceRadiator = 1 THEN LineRevenue ELSE 0 END) AS ClearanceRadiatorRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Radiator' THEN LineRevenue ELSE 0 END) AS OtherRadiatorRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Valve Set' THEN LineRevenue ELSE 0 END) AS ValveSetRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Wall Stay' THEN LineRevenue ELSE 0 END) AS WallStayRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Pipe Shrouds' THEN LineRevenue ELSE 0 END) AS PipeShroudsRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Bleed Valve' THEN LineRevenue ELSE 0 END) AS BleedValveRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Touch Up Paint' THEN LineRevenue ELSE 0 END) AS TouchUpPaintRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Inhibitor' THEN LineRevenue ELSE 0 END) AS InhibitorRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Bundle' THEN LineRevenue ELSE 0 END) AS BundleRevenue, " & _
        "  SUM(CASE WHEN ProductType = 'Other / Unclassified' THEN LineRevenue ELSE 0 END) AS OtherUnclassifiedRevenue, " & _
        "  SUM(CASE WHEN IsClearanceRadiator = 0 THEN LineRevenue ELSE 0 END) AS OtherProductRevenue, " & _
        "  SUM(LineRevenue) - (MAX(OrderSubtotal) + MAX(OrderDiscount)) AS ReconciliationDifference " & _
        "FROM report_lines " & _
        "WHERE DateTimePaid >= @start_date " & _
        "  AND DateTimePaid < DATE_ADD(@end_date, INTERVAL 1 DAY) " & _
        "GROUP BY OrderNo " & _
        "HAVING SUM(CASE WHEN IsClearanceRadiator = 1 THEN QtyReport ELSE 0 END) > 0"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error creating clearance order summaries."

    conn.Execute "ALTER TABLE report_clearance_orders ADD PRIMARY KEY (OrderNo), ADD INDEX idx_rco_email (EmailKey), ADD INDEX idx_rco_paid (DateTimePaid)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing clearance order summaries."

    conn.Execute _
        "CREATE TEMPORARY TABLE report_clearance_customer_period AS " & _
        "SELECT EmailKey, " & _
        "  COUNT(*) AS ClearanceOrdersInPeriod, " & _
        "  SUM(ClearanceRadiatorQty) AS ClearanceRadiatorQty, " & _
        "  SUM(ClearanceRadiatorRevenue) AS ClearanceRadiatorRevenue, " & _
        "  SUM(OtherProductRevenue) AS OtherProductRevenueInClearanceOrders, " & _
        "  SUM(OrderNetProductRevenue) AS ProductRevenueInClearanceOrders " & _
        "FROM report_clearance_orders " & _
        "WHERE EmailKey <> '' GROUP BY EmailKey"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error creating clearance-customer period summaries."

    conn.Execute "ALTER TABLE report_clearance_customer_period ADD PRIMARY KEY (EmailKey)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing clearance-customer period summaries."

    conn.Execute _
        "CREATE TEMPORARY TABLE report_clearance_customer_anchor AS " & _
        "SELECT EmailKey, EmailAddress, FirstName, Surname, CompanyName, " & _
        "       OrderNo AS FirstClearanceOrderNo, DateTimePaid AS FirstClearanceDateTime " & _
        "FROM ( " & _
        "  SELECT co.*, ROW_NUMBER() OVER " & _
        "         (PARTITION BY EmailKey ORDER BY DateTimePaid, OrderNo) AS RowNo " & _
        "  FROM report_clearance_orders co WHERE EmailKey <> '' " & _
        ") a WHERE RowNo = 1"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error identifying each customer's first clearance order in the period."

    conn.Execute "ALTER TABLE report_clearance_customer_anchor ADD PRIMARY KEY (EmailKey)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing clearance-customer anchors."

    conn.Execute _
        "CREATE TEMPORARY TABLE report_customer_summary AS " & _
        "SELECT " & _
        "  a.EmailKey, a.EmailAddress, a.FirstName, a.Surname, a.CompanyName, " & _
        "  a.FirstClearanceOrderNo, a.FirstClearanceDateTime, " & _
        "  p.ClearanceOrdersInPeriod, p.ClearanceRadiatorQty, " & _
        "  p.ClearanceRadiatorRevenue, p.OtherProductRevenueInClearanceOrders, " & _
        "  p.ProductRevenueInClearanceOrders, " & _
        "  SUM(CASE WHEN o.DateTimePaid < a.FirstClearanceDateTime " & _
        "            OR (o.DateTimePaid = a.FirstClearanceDateTime AND o.OrderNo < a.FirstClearanceOrderNo) " & _
        "           THEN 1 ELSE 0 END) AS PriorOrders, " & _
        "  SUM(CASE WHEN o.DateTimePaid < a.FirstClearanceDateTime " & _
        "            OR (o.DateTimePaid = a.FirstClearanceDateTime AND o.OrderNo < a.FirstClearanceOrderNo) " & _
        "           THEN o.OrderNetProductRevenue ELSE 0 END) AS PriorRevenue, " & _
        "  SUM(CASE WHEN o.DateTimePaid > a.FirstClearanceDateTime " & _
        "            OR (o.DateTimePaid = a.FirstClearanceDateTime AND o.OrderNo > a.FirstClearanceOrderNo) " & _
        "           THEN 1 ELSE 0 END) AS SubsequentOrders, " & _
        "  SUM(CASE WHEN o.DateTimePaid > a.FirstClearanceDateTime " & _
        "            OR (o.DateTimePaid = a.FirstClearanceDateTime AND o.OrderNo > a.FirstClearanceOrderNo) " & _
        "           THEN o.OrderNetProductRevenue ELSE 0 END) AS SubsequentRevenue, " & _
        "  COUNT(*) AS LifetimeOrders, " & _
        "  SUM(o.OrderNetProductRevenue) AS LifetimeProductRevenue " & _
        "FROM report_clearance_customer_anchor a " & _
        "INNER JOIN report_clearance_customer_period p ON p.EmailKey = a.EmailKey " & _
        "INNER JOIN report_all_orders o ON o.EmailKey = a.EmailKey " & _
        "GROUP BY a.EmailKey, a.EmailAddress, a.FirstName, a.Surname, a.CompanyName, " & _
        "         a.FirstClearanceOrderNo, a.FirstClearanceDateTime, " & _
        "         p.ClearanceOrdersInPeriod, p.ClearanceRadiatorQty, " & _
        "         p.ClearanceRadiatorRevenue, p.OtherProductRevenueInClearanceOrders, " & _
        "         p.ProductRevenueInClearanceOrders"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error creating customer lifetime summaries."

    conn.Execute "ALTER TABLE report_customer_summary ADD PRIMARY KEY (EmailKey), ADD INDEX idx_rcs_lifetime (LifetimeProductRevenue), ADD INDEX idx_rcs_subsequent (SubsequentOrders)"
    If Err.Number <> 0 Then DatabaseErrorAndEnd conn, "Error indexing customer lifetime summaries."

    On Error GoTo 0

    ' CSV exports are generated from the same temporary report data.
    If exportReport <> "" Then
        Dim rsCsv, fileName
        Set rsCsv = Server.CreateObject("ADODB.Recordset")
        fileName = "clearance-radiator-" & exportReport & "-" & startDate & "-to-" & endDate & ".csv"

        Response.Clear
        Response.ContentType = "text/csv"
        Response.CharSet = "utf-8"
        Response.AddHeader "Content-Disposition", "attachment; filename=""" & fileName & """"
        Response.Write ChrW(&HFEFF)

        Select Case exportReport
            Case "orders"
                rsCsv.Open _
                    "SELECT * FROM report_clearance_orders ORDER BY DateTimePaid, OrderNo", conn, 0, 1

                Response.Write "Order No,Date Paid,Email Address,First Name,Surname,Company Name,Currency," & _
                               "Clearance Radiator Qty,Clearance Radiator Revenue,Other Radiator Revenue," & _
                               "Valve Set Revenue,Wall Stay Revenue,Pipe Shrouds Revenue,Bleed Valve Revenue," & _
                               "Touch Up Paint Revenue,Inhibitor Revenue,Bundle Revenue,Other / Unclassified Revenue," & _
                               "Other Product Revenue,Order Subtotal,Order Discount,Net Product Revenue" & vbCrLf

                Do Until rsCsv.EOF
                    Response.Write Csv(rsCsv("OrderNo")) & "," & _
                                   Csv(CsvDateTime(rsCsv("DateTimePaid"))) & "," & _
                                   Csv(rsCsv("EmailAddress")) & "," & _
                                   Csv(rsCsv("FirstName")) & "," & _
                                   Csv(rsCsv("Surname")) & "," & _
                                   Csv(rsCsv("CompanyName")) & "," & _
                                   Csv(rsCsv("CurrencyCode")) & "," & _
                                   CsvNumber(rsCsv("ClearanceRadiatorQty")) & "," & _
                                   CsvMoney(rsCsv("ClearanceRadiatorRevenue")) & "," & _
                                   CsvMoney(rsCsv("OtherRadiatorRevenue")) & "," & _
                                   CsvMoney(rsCsv("ValveSetRevenue")) & "," & _
                                   CsvMoney(rsCsv("WallStayRevenue")) & "," & _
                                   CsvMoney(rsCsv("PipeShroudsRevenue")) & "," & _
                                   CsvMoney(rsCsv("BleedValveRevenue")) & "," & _
                                   CsvMoney(rsCsv("TouchUpPaintRevenue")) & "," & _
                                   CsvMoney(rsCsv("InhibitorRevenue")) & "," & _
                                   CsvMoney(rsCsv("BundleRevenue")) & "," & _
                                   CsvMoney(rsCsv("OtherUnclassifiedRevenue")) & "," & _
                                   CsvMoney(rsCsv("OtherProductRevenue")) & "," & _
                                   CsvMoney(rsCsv("OrderSubtotal")) & "," & _
                                   CsvMoney(rsCsv("OrderDiscount")) & "," & _
                                   CsvMoney(rsCsv("OrderNetProductRevenue")) & vbCrLf
                    rsCsv.MoveNext
                Loop

            Case "lines"
                rsCsv.Open _
                    "SELECT rl.* FROM report_lines rl " & _
                    "INNER JOIN report_clearance_orders co ON co.OrderNo = rl.OrderNo " & _
                    "ORDER BY rl.DateTimePaid, rl.OrderNo, rl.OrderDetailID", conn, 0, 1

                Response.Write "Order No,Date Paid,Email Address,Order Detail ID,Product ID,Product Code," & _
                               "Product Name,Options,Product Type,Is Clearance Radiator,Qty,Price Each," & _
                               "Line Value Before Discount,Allocated Discount,Line Revenue" & vbCrLf

                Do Until rsCsv.EOF
                    Response.Write Csv(rsCsv("OrderNo")) & "," & _
                                   Csv(CsvDateTime(rsCsv("DateTimePaid"))) & "," & _
                                   Csv(rsCsv("EmailAddress")) & "," & _
                                   Csv(rsCsv("OrderDetailID")) & "," & _
                                   Csv(rsCsv("ProductID")) & "," & _
                                   Csv(rsCsv("ProductCode")) & "," & _
                                   Csv(rsCsv("ProductName")) & "," & _
                                   Csv(rsCsv("OptionsList")) & "," & _
                                   Csv(rsCsv("ProductType")) & "," & _
                                   Csv(rsCsv("IsClearanceRadiator")) & "," & _
                                   CsvNumber(rsCsv("QtyReport")) & "," & _
                                   CsvMoney(rsCsv("PriceEach")) & "," & _
                                   CsvMoney(rsCsv("LineValueBeforeDiscount")) & "," & _
                                   CsvMoney(rsCsv("AllocatedDiscount")) & "," & _
                                   CsvMoney(rsCsv("LineRevenue")) & vbCrLf
                    rsCsv.MoveNext
                Loop

            Case "customers"
                rsCsv.Open _
                    "SELECT * FROM report_customer_summary " & _
                    "ORDER BY LifetimeProductRevenue DESC, EmailAddress", conn, 0, 1

                Response.Write "Email Address,First Name,Surname,Company Name,First Clearance Order No," & _
                               "First Clearance Date,Clearance Orders In Period,Clearance Radiator Qty," & _
                               "Clearance Radiator Revenue,Other Product Revenue In Clearance Orders," & _
                               "Product Revenue In Clearance Orders,Prior Orders,Prior Revenue," & _
                               "Subsequent Orders,Subsequent Revenue,Lifetime Orders,Lifetime Product Revenue" & vbCrLf

                Do Until rsCsv.EOF
                    Response.Write Csv(rsCsv("EmailAddress")) & "," & _
                                   Csv(rsCsv("FirstName")) & "," & _
                                   Csv(rsCsv("Surname")) & "," & _
                                   Csv(rsCsv("CompanyName")) & "," & _
                                   Csv(rsCsv("FirstClearanceOrderNo")) & "," & _
                                   Csv(CsvDateTime(rsCsv("FirstClearanceDateTime"))) & "," & _
                                   CsvNumber(rsCsv("ClearanceOrdersInPeriod")) & "," & _
                                   CsvNumber(rsCsv("ClearanceRadiatorQty")) & "," & _
                                   CsvMoney(rsCsv("ClearanceRadiatorRevenue")) & "," & _
                                   CsvMoney(rsCsv("OtherProductRevenueInClearanceOrders")) & "," & _
                                   CsvMoney(rsCsv("ProductRevenueInClearanceOrders")) & "," & _
                                   CsvNumber(rsCsv("PriorOrders")) & "," & _
                                   CsvMoney(rsCsv("PriorRevenue")) & "," & _
                                   CsvNumber(rsCsv("SubsequentOrders")) & "," & _
                                   CsvMoney(rsCsv("SubsequentRevenue")) & "," & _
                                   CsvNumber(rsCsv("LifetimeOrders")) & "," & _
                                   CsvMoney(rsCsv("LifetimeProductRevenue")) & vbCrLf
                    rsCsv.MoveNext
                Loop

            Case "products"
                rsCsv.Open _
                    "SELECT rl.ProductCode, rl.ProductName, rl.ProductType, " & _
                    "       COUNT(DISTINCT rl.OrderNo) AS ClearanceOrdersContainingProduct, " & _
                    "       SUM(rl.QtyReport) AS Qty, SUM(rl.LineValueBeforeDiscount) AS RevenueBeforeDiscount, " & _
                    "       SUM(rl.AllocatedDiscount) AS AllocatedDiscount, SUM(rl.LineRevenue) AS Revenue " & _
                    "FROM report_lines rl " & _
                    "INNER JOIN report_clearance_orders co ON co.OrderNo = rl.OrderNo " & _
                    "WHERE rl.IsClearanceRadiator = 0 " & _
                    "GROUP BY rl.ProductCode, rl.ProductName, rl.ProductType " & _
                    "ORDER BY Revenue DESC, Qty DESC, rl.ProductCode", conn, 0, 1

                Response.Write "Product Code,Product Name,Product Type,Clearance Orders Containing Product," & _
                               "Qty,Revenue Before Discount,Allocated Discount,Revenue" & vbCrLf

                Do Until rsCsv.EOF
                    Response.Write Csv(rsCsv("ProductCode")) & "," & _
                                   Csv(rsCsv("ProductName")) & "," & _
                                   Csv(rsCsv("ProductType")) & "," & _
                                   CsvNumber(rsCsv("ClearanceOrdersContainingProduct")) & "," & _
                                   CsvNumber(rsCsv("Qty")) & "," & _
                                   CsvMoney(rsCsv("RevenueBeforeDiscount")) & "," & _
                                   CsvMoney(rsCsv("AllocatedDiscount")) & "," & _
                                   CsvMoney(rsCsv("Revenue")) & vbCrLf
                    rsCsv.MoveNext
                Loop

            Case Else
                CloseRecordset rsCsv
                CloseConnection conn
                Response.ContentType = "text/plain"
                Response.Write "Unknown export type."
                Response.End
        End Select

        CloseRecordset rsCsv
        CloseConnection conn
        Response.End
    End If

    Set rsSummary = Server.CreateObject("ADODB.Recordset")
    rsSummary.Open _
        "SELECT " & _
        "  COUNT(*) AS ClearanceOrders, " & _
        "  COUNT(DISTINCT NULLIF(EmailKey, '')) AS ClearanceCustomers, " & _
        "  SUM(ClearanceRadiatorQty) AS ClearanceRadiatorQty, " & _
        "  SUM(ClearanceRadiatorRevenue) AS ClearanceRadiatorRevenue, " & _
        "  SUM(OtherProductRevenue) AS OtherProductRevenue, " & _
        "  SUM(OrderNetProductRevenue) AS TotalProductRevenue, " & _
        "  AVG(OrderNetProductRevenue) AS AverageProductRevenuePerOrder, " & _
        "  SUM(CASE WHEN OtherProductRevenue > 0 THEN 1 ELSE 0 END) AS OrdersWithOtherProducts, " & _
        "  SUM(CASE WHEN ABS(ReconciliationDifference) > 0.02 THEN 1 ELSE 0 END) AS ReconciliationWarnings " & _
        "FROM report_clearance_orders", conn, 0, 1

    Set rsCustomerSummary = Server.CreateObject("ADODB.Recordset")
    rsCustomerSummary.Open _
        "SELECT " & _
        "  COUNT(*) AS Customers, " & _
        "  SUM(CASE WHEN PriorOrders > 0 THEN 1 ELSE 0 END) AS ExistingCustomers, " & _
        "  SUM(CASE WHEN SubsequentOrders > 0 THEN 1 ELSE 0 END) AS RepeatCustomers, " & _
        "  SUM(SubsequentRevenue) AS SubsequentRevenue, " & _
        "  SUM(LifetimeProductRevenue) AS LifetimeProductRevenue " & _
        "FROM report_customer_summary", conn, 0, 1

    Set rsTypes = Server.CreateObject("ADODB.Recordset")
    rsTypes.Open _
        "SELECT rl.ProductType, COUNT(DISTINCT rl.OrderNo) AS Orders, " & _
        "       SUM(rl.QtyReport) AS Qty, SUM(rl.LineRevenue) AS Revenue " & _
        "FROM report_lines rl " & _
        "INNER JOIN report_clearance_orders co ON co.OrderNo = rl.OrderNo " & _
        "WHERE rl.IsClearanceRadiator = 0 " & _
        "GROUP BY rl.ProductType ORDER BY Revenue DESC", conn, 0, 1

    Set rsProducts = Server.CreateObject("ADODB.Recordset")
    rsProducts.Open _
        "SELECT rl.ProductCode, rl.ProductName, rl.ProductType, " & _
        "       COUNT(DISTINCT rl.OrderNo) AS Orders, SUM(rl.QtyReport) AS Qty, " & _
        "       SUM(rl.LineRevenue) AS Revenue " & _
        "FROM report_lines rl " & _
        "INNER JOIN report_clearance_orders co ON co.OrderNo = rl.OrderNo " & _
        "WHERE rl.IsClearanceRadiator = 0 " & _
        "GROUP BY rl.ProductCode, rl.ProductName, rl.ProductType " & _
        "ORDER BY Revenue DESC, Qty DESC, rl.ProductCode LIMIT 50", conn, 0, 1

    Set rsCustomers = Server.CreateObject("ADODB.Recordset")
    rsCustomers.Open _
        "SELECT * FROM report_customer_summary " & _
        "ORDER BY LifetimeProductRevenue DESC, EmailAddress LIMIT 100", conn, 0, 1

    Set rsOrders = Server.CreateObject("ADODB.Recordset")
    rsOrders.Open _
        "SELECT * FROM report_clearance_orders " & _
        "ORDER BY DateTimePaid DESC, OrderNo DESC LIMIT 100", conn, 0, 1
End If
%>
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Clearance Radiator Customer Value Report</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .metric-value { font-size: 1.55rem; font-weight: 600; }
        .metric-label { color: var(--bs-secondary-color); font-size: .875rem; }
        .table-report { font-size: .875rem; }
        .text-nowrap { white-space: nowrap; }
        body.report-loading, body.report-loading * { cursor: wait !important; }
        .report-loading-overlay {
            position: fixed;
            inset: 0;
            z-index: 2000;
            display: none;
            align-items: center;
            justify-content: center;
            background: rgba(255, 255, 255, .78);
        }
        body.report-loading .report-loading-overlay { display: flex; }
        .report-loading-panel {
            min-width: 15rem;
            padding: 1.5rem 2rem;
            text-align: center;
            background: #fff;
            border: 1px solid var(--bs-border-color);
            border-radius: var(--bs-border-radius-lg);
            box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
        }
    </style>
</head>
<body>
<div id="report-loading-overlay" class="report-loading-overlay" role="status" aria-live="polite" aria-hidden="true">
    <div class="report-loading-panel">
        <div class="spinner-border text-primary mb-3" aria-hidden="true"></div>
        <div class="fw-semibold">Running report&hellip;</div>
        <div class="small text-secondary mt-1">Please wait while the data is prepared.</div>
    </div>
</div>
<div class="container-fluid px-lg-4 my-4">
    <h1 class="h3 mb-1">Clearance Radiator Customer Value Report</h1>
    <p class="text-secondary mb-3">
        Analyses qualifying paid orders containing clearance radiators, what else was bought in those orders,
        and the wider order value of the customers identified by email address.
    </p>

    <form id="report-form" method="get" action="<%= H(scriptName) %>" class="row gy-2 gx-3 align-items-end border rounded p-3 mb-4">
        <div class="col-sm-4 col-md-3">
            <label for="start_date" class="form-label">Clearance order start date</label>
            <input type="date" class="form-control" id="start_date" name="start_date" value="<%= H(startDate) %>">
        </div>
        <div class="col-sm-4 col-md-3">
            <label for="end_date" class="form-label">Clearance order end date</label>
            <input type="date" class="form-control" id="end_date" name="end_date" value="<%= H(endDate) %>">
        </div>
        <div class="col-sm-4 col-md-2">
            <input type="hidden" name="run" value="1">
            <button id="run-report-button" type="submit" class="btn btn-primary w-100">Run report</button>
        </div>
    </form>

<% If hasRun Then %>
    <% If rsSummary.EOF Or CLng("0" & Nz(rsSummary("ClearanceOrders"))) = 0 Then %>
        <div class="alert alert-warning">No qualifying clearance radiator orders were found for the selected period.</div>
    <% Else %>
        <div class="d-flex flex-wrap gap-2 mb-4">
            <a class="btn btn-outline-primary btn-sm" href="<%= H(scriptName & "?" & queryStringBase & "&export=orders") %>">Download order summary CSV</a>
            <a class="btn btn-outline-primary btn-sm" href="<%= H(scriptName & "?" & queryStringBase & "&export=lines") %>">Download raw order lines CSV</a>
            <a class="btn btn-outline-primary btn-sm" href="<%= H(scriptName & "?" & queryStringBase & "&export=customers") %>">Download customer summary CSV</a>
            <a class="btn btn-outline-primary btn-sm" href="<%= H(scriptName & "?" & queryStringBase & "&export=products") %>">Download products CSV</a>
        </div>

        <div class="row g-3 mb-4">
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value"><%= H(Number0(rsSummary("ClearanceOrders"))) %></div>
                    <div class="metric-label">Clearance orders</div>
                </div>
            </div>
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value"><%= H(Number0(rsSummary("ClearanceCustomers"))) %></div>
                    <div class="metric-label">Customers</div>
                </div>
            </div>
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value"><%= H(Number0(rsSummary("ClearanceRadiatorQty"))) %></div>
                    <div class="metric-label">Clearance radiators</div>
                </div>
            </div>
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value">£<%= H(Money(rsSummary("ClearanceRadiatorRevenue"))) %></div>
                    <div class="metric-label">Clearance radiator revenue</div>
                </div>
            </div>
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value">£<%= H(Money(rsSummary("OtherProductRevenue"))) %></div>
                    <div class="metric-label">Other product revenue</div>
                </div>
            </div>
            <div class="col-6 col-md-4 col-xl-2">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value">£<%= H(Money(rsSummary("TotalProductRevenue"))) %></div>
                    <div class="metric-label">Total product revenue from clearance orders</div>
                </div>
            </div>
        </div>

        <div class="row g-3 mb-4">
            <div class="col-md-4">
                <div class="card h-100">
                    <div class="card-body">
                        <div class="metric-value">£<%= H(Money(rsSummary("AverageProductRevenuePerOrder"))) %></div>
                        <div class="metric-label">Average net product revenue per clearance order</div>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card h-100">
                    <div class="card-body">
                        <div class="metric-value"><%= H(Percent1(rsSummary("OrdersWithOtherProducts"), rsSummary("ClearanceOrders"))) %></div>
                        <div class="metric-label">Clearance orders containing other products</div>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card h-100">
                    <div class="card-body">
                        <div class="metric-value"><%= H(Percent1(rsSummary("OtherProductRevenue"), rsSummary("TotalProductRevenue"))) %></div>
                        <div class="metric-label">Share of clearance order revenue from other products</div>
                    </div>
                </div>
            </div>
        </div>

        <% If Not rsCustomerSummary.EOF Then %>
        <div class="row g-3 mb-4">
            <div class="col-6 col-lg-3">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value"><%= H(Percent1(rsCustomerSummary("ExistingCustomers"), rsCustomerSummary("Customers"))) %></div>
                    <div class="metric-label">Had a qualifying prior order</div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value"><%= H(Percent1(rsCustomerSummary("RepeatCustomers"), rsCustomerSummary("Customers"))) %></div>
                    <div class="metric-label">Ordered again after first clearance order in period</div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value">£<%= H(Money(rsCustomerSummary("SubsequentRevenue"))) %></div>
                    <div class="metric-label">Subsequent product revenue</div>
                </div>
            </div>
            <div class="col-6 col-lg-3">
                <div class="border rounded p-3 h-100">
                    <div class="metric-value">£<%= H(Money(rsCustomerSummary("LifetimeProductRevenue"))) %></div>
                    <div class="metric-label">All-time product revenue from clearance radiator customers</div>
                </div>
            </div>
        </div>
        <% End If %>

        <% If CLng("0" & Nz(rsSummary("ReconciliationWarnings"))) > 0 Then %>
        <div class="alert alert-warning">
            <strong>Reconciliation warning:</strong>
            <%= H(Number0(rsSummary("ReconciliationWarnings"))) %> clearance orders differ by more than £0.02 between
            the included order-line calculation and <code>Subtotal + Discount</code>.
            Check these rows in the order summary CSV before relying on the category split.
        </div>
        <% End If %>

        <h2 class="h4 mt-4">Other products by type</h2>
        <div class="table-responsive mb-4">
            <table class="table table-bordered table-striped table-sm table-report align-middle">
                <thead class="table-light">
                    <tr>
                        <th>Product type</th>
                        <th class="text-end">Clearance orders</th>
                        <th class="text-end">Quantity</th>
                        <th class="text-end">Net revenue</th>
                        <th class="text-end">Share of other product revenue</th>
                    </tr>
                </thead>
                <tbody>
                <% Do Until rsTypes.EOF %>
                    <tr>
                        <td><%= H(rsTypes("ProductType")) %></td>
                        <td class="text-end"><%= H(Number0(rsTypes("Orders"))) %></td>
                        <td class="text-end"><%= H(Number0(rsTypes("Qty"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsTypes("Revenue"))) %></td>
                        <td class="text-end"><%= H(Percent1(rsTypes("Revenue"), rsSummary("OtherProductRevenue"))) %></td>
                    </tr>
                <% rsTypes.MoveNext : Loop %>
                </tbody>
            </table>
        </div>

        <h2 class="h4">Top products bought alongside clearance radiators</h2>
        <p class="text-secondary small">Top 50 by net revenue. The products CSV contains the complete list.</p>
        <div class="table-responsive mb-4">
            <table class="table table-bordered table-striped table-sm table-report align-middle">
                <thead class="table-light">
                    <tr>
                        <th>Product code</th>
                        <th>Product name</th>
                        <th>Type</th>
                        <th class="text-end">Orders</th>
                        <th class="text-end">Qty</th>
                        <th class="text-end">Net revenue</th>
                    </tr>
                </thead>
                <tbody>
                <% Do Until rsProducts.EOF %>
                    <tr>
                        <td class="text-nowrap"><%= H(rsProducts("ProductCode")) %></td>
                        <td><%= H(rsProducts("ProductName")) %></td>
                        <td><%= H(rsProducts("ProductType")) %></td>
                        <td class="text-end"><%= H(Number0(rsProducts("Orders"))) %></td>
                        <td class="text-end"><%= H(Number0(rsProducts("Qty"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsProducts("Revenue"))) %></td>
                    </tr>
                <% rsProducts.MoveNext : Loop %>
                </tbody>
            </table>
        </div>

        <h2 class="h4">Customer value</h2>
        <p class="text-secondary small">Top 100 by all-time net product revenue.</p>
        <div class="table-responsive mb-4">
            <table class="table table-bordered table-striped table-sm table-report align-middle">
                <thead class="table-light">
                    <tr>
                        <th>Customer</th>
                        <th>Email</th>
                        <th class="text-end">Clearance orders</th>
                        <th class="text-end">Clearance revenue</th>
                        <th class="text-end">Other product revenue in clearance orders</th>
                        <th class="text-end">Prior orders</th>
                        <th class="text-end">Subsequent orders</th>
                        <th class="text-end">Subsequent revenue</th>
                        <th class="text-end">Lifetime revenue</th>
                    </tr>
                </thead>
                <tbody>
                <% Do Until rsCustomers.EOF %>
                    <tr>
                        <td><%= H(Trim(Nz(rsCustomers("FirstName")) & " " & Nz(rsCustomers("Surname")))) %></td>
                        <td><%= H(rsCustomers("EmailAddress")) %></td>
                        <td class="text-end"><%= H(Number0(rsCustomers("ClearanceOrdersInPeriod"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsCustomers("ClearanceRadiatorRevenue"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsCustomers("OtherProductRevenueInClearanceOrders"))) %></td>
                        <td class="text-end"><%= H(Number0(rsCustomers("PriorOrders"))) %></td>
                        <td class="text-end"><%= H(Number0(rsCustomers("SubsequentOrders"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsCustomers("SubsequentRevenue"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsCustomers("LifetimeProductRevenue"))) %></td>
                    </tr>
                <% rsCustomers.MoveNext : Loop %>
                </tbody>
            </table>
        </div>

        <h2 class="h4">Recent clearance orders</h2>
        <p class="text-secondary small">Most recent 100 in the selected period. The order summary CSV contains every order.</p>
        <div class="table-responsive mb-4">
            <table class="table table-bordered table-striped table-sm table-report align-middle">
                <thead class="table-light">
                    <tr>
                        <th>Order</th>
                        <th>Date paid</th>
                        <th>Email</th>
                        <th class="text-end">Clearance qty</th>
                        <th class="text-end">Clearance revenue</th>
                        <th class="text-end">Other revenue</th>
                        <th class="text-end">Net product revenue</th>
                    </tr>
                </thead>
                <tbody>
                <% Do Until rsOrders.EOF %>
                    <tr>
                        <td><%= H(rsOrders("OrderNo")) %></td>
                        <td class="text-nowrap"><%= H(FormatDateDisplay(rsOrders("DateTimePaid"))) %></td>
                        <td><%= H(rsOrders("EmailAddress")) %></td>
                        <td class="text-end"><%= H(Number0(rsOrders("ClearanceRadiatorQty"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsOrders("ClearanceRadiatorRevenue"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsOrders("OtherProductRevenue"))) %></td>
                        <td class="text-end text-nowrap">£<%= H(Money(rsOrders("OrderNetProductRevenue"))) %></td>
                    </tr>
                <% rsOrders.MoveNext : Loop %>
                </tbody>
            </table>
        </div>

        <div class="alert alert-light border small">
            <strong>Calculation notes:</strong>
            revenue excludes VAT and delivery. Any order-level discount is allocated proportionally across the included chargeable lines.
            Partial refunds and restocks are intentionally ignored. “First clearance order” means the customer's first clearance order
            within the selected report period.
        </div>
    <% End If %>
<% End If %>
</div>
<%
CloseRecordset rsSummary
CloseRecordset rsCustomerSummary
CloseRecordset rsTypes
CloseRecordset rsProducts
CloseRecordset rsCustomers
CloseRecordset rsOrders
CloseConnection conn
%>
<script>
(function () {
    "use strict";

    var form = document.getElementById("report-form");
    var button = document.getElementById("run-report-button");
    var overlay = document.getElementById("report-loading-overlay");

    function showLoading() {
        document.body.classList.add("report-loading");
        overlay.setAttribute("aria-hidden", "false");
        button.disabled = true;
        button.innerHTML = '<span class="spinner-border spinner-border-sm me-2" aria-hidden="true"></span>Running report&hellip;';
    }

    function resetLoading() {
        document.body.classList.remove("report-loading");
        overlay.setAttribute("aria-hidden", "true");
        button.disabled = false;
        button.textContent = "Run report";
        delete form.dataset.submitting;
    }

    form.addEventListener("submit", function (event) {
        if (form.dataset.submitting === "1") {
            return;
        }

        event.preventDefault();
        form.dataset.submitting = "1";
        showLoading();

        window.requestAnimationFrame(function () {
            window.setTimeout(function () {
                form.submit();
            }, 50);
        });
    });

    window.addEventListener("pageshow", resetLoading);
}());
</script>
</body>
</html>