-- 客户维度每日标签统计综合查询
-- 设计逻辑：和原运营监控SQL逻辑完全一致，新增按CustomerCode维度分组统计
WITH 
-- 步骤1：获取所有到货交接单（时间已是UTC-5）
ArrivalForms AS (
    SELECT 
        Id AS FormId,
        HandoverNumber,
        ReceiptTime,
        DATE(ReceiptTime) AS ReceiptDate,
        HOUR(ReceiptTime) AS ReceiptHour
    FROM arrival_handover_forms
),
-- 步骤2：获取所有换单请求，关联客户表获取CustomerCode
LabelRequests AS (
    SELECT 
        r.Id AS RequestId,
        r.NeutralWaybillNumber,
        r.BillOfLadingNumber,
        r.MasterPackageNumber,
        r.Label,
        r.LabelRetrievedAt,
        r.CreatedAt AS RequestCreatedAt,
        c.CustomerCode, -- 通过customerid关联客户表获取客户代码
        -- 转换为UTC-5时间
        CASE WHEN r.LabelRetrievedAt IS NOT NULL THEN CONVERT_TZ(r.LabelRetrievedAt, '+00:00', '-05:00') END AS LabelRetrievedAt_UTC5,
        DATE(CONVERT_TZ(r.LabelRetrievedAt, '+00:00', '-05:00')) AS LabelRetrievedDate_UTC5
    FROM label_replace_requests r
    LEFT JOIN customers c ON r.customerid = c.Id -- 通过customerid关联客户表
),
-- 步骤3：关联到货交接单和换单请求（优先匹配大箱号，无大箱号匹配则用提单号）
FormRequestRelation AS (
    SELECT 
        -- 优先取大箱号匹配的交接单信息，无则取提单号匹配的
        COALESCE(f_m.FormId, f_b.FormId) AS FormId,
        COALESCE(f_m.HandoverNumber, f_b.HandoverNumber) AS HandoverNumber,
        COALESCE(f_m.ReceiptTime, f_b.ReceiptTime) AS ReceiptTime,
        COALESCE(f_m.ReceiptDate, f_b.ReceiptDate) AS ReceiptDate,
        COALESCE(f_m.ReceiptHour, f_b.ReceiptHour) AS ReceiptHour,
        r.RequestId,
        r.NeutralWaybillNumber,
        r.Label,
        r.LabelRetrievedAt,
        r.LabelRetrievedAt_UTC5,
        r.LabelRetrievedDate_UTC5,
        r.RequestCreatedAt,
        r.CustomerCode, -- 传递客户代码
        -- 是否有标签
        CASE WHEN r.Label IS NOT NULL AND r.Label != '' THEN 1 ELSE 0 END AS HasLabel
    FROM LabelRequests r
    -- 先匹配大箱号
    LEFT JOIN ArrivalForms f_m ON r.MasterPackageNumber = f_m.HandoverNumber
    -- 大箱号匹配不到再匹配提单号
    LEFT JOIN ArrivalForms f_b ON r.BillOfLadingNumber = f_b.HandoverNumber
    -- 只保留有匹配到交接单的订单
    WHERE COALESCE(f_m.FormId, f_b.FormId) IS NOT NULL
),
-- 步骤4：获取每个交接单的首次扫描时间
FormFirstScan AS (
    SELECT 
        fr.FormId,
        MIN(s.CreatedAt) AS FirstScanTime,
        CONVERT_TZ(MIN(s.CreatedAt), '+00:00', '-05:00') AS FirstScanTime_UTC5
    FROM FormRequestRelation fr
    LEFT JOIN label_scan_history s ON fr.NeutralWaybillNumber = s.NeutralWaybillNumber
    GROUP BY fr.FormId
),
-- 步骤5：先计算每个交接单的总订单数和达标阈值
FormTotalOrderCount AS (
    SELECT 
        FormId,
        COUNT(DISTINCT RequestId) AS TotalOrderCount,
        CEIL(COUNT(DISTINCT RequestId) * 0.8) AS QualifyNeedCount
    FROM FormRequestRelation
    GROUP BY FormId
),
-- 步骤6：计算每个交接单每个标签的推送时间及排序，匹配达标阈值
FormLabelPushTimes AS (
    SELECT 
        fr.FormId,
        fr.LabelRetrievedAt_UTC5,
        -- 按推送时间排序，计算累计推送的标签数
        ROW_NUMBER() OVER (PARTITION BY fr.FormId ORDER BY fr.LabelRetrievedAt_UTC5) AS PushOrder,
        ftoc.QualifyNeedCount
    FROM FormRequestRelation fr
    INNER JOIN FormTotalOrderCount ftoc ON fr.FormId = ftoc.FormId
    WHERE fr.HasLabel = 1 AND fr.LabelRetrievedAt_UTC5 IS NOT NULL
),
-- 步骤7：计算每个交接单的首次达标日期和时间
FormFirstQualifiedDate AS (
    SELECT 
        FormId,
        MIN(DATE(LabelRetrievedAt_UTC5)) AS FirstQualifiedDate,
        MIN(LabelRetrievedAt_UTC5) AS FirstQualifiedTime_UTC5
    FROM FormLabelPushTimes
    WHERE PushOrder >= QualifyNeedCount
    GROUP BY FormId
),
-- 步骤8：计算每个交接单的标签率（按当前实际情况统计，无需冻结）
FormLabelRateAndQualifiedDate AS (
    SELECT 
        fr.FormId,
        ftoc.TotalOrderCount,
        -- 有标签的订单数
        COUNT(DISTINCT CASE WHEN fr.HasLabel = 1 THEN fr.RequestId END) AS HasLabelOrderCount,
        -- 标签率：当前有标签订单数 / 总订单数
        CASE 
            WHEN ftoc.TotalOrderCount = 0 THEN 0
            ELSE COUNT(DISTINCT CASE WHEN fr.HasLabel = 1 THEN fr.RequestId END) / ftoc.TotalOrderCount
        END AS LabelRate,
        fqd.FirstQualifiedDate,
        fqd.FirstQualifiedTime_UTC5
    FROM FormRequestRelation fr
    INNER JOIN FormTotalOrderCount ftoc ON fr.FormId = ftoc.FormId
    LEFT JOIN FormFirstQualifiedDate fqd ON fr.FormId = fqd.FormId
    GROUP BY fr.FormId, ftoc.TotalOrderCount, fqd.FirstQualifiedDate, fqd.FirstQualifiedTime_UTC5
),
-- 步骤9：计算每个订单的考核时间（基于达标时间和到货时间较晚者）
OrderAssessment AS (
    SELECT 
        fr.*,
        flr.LabelRate,
        flr.FirstQualifiedDate,
        flr.FirstQualifiedTime_UTC5,
        fs.FirstScanTime_UTC5,
        -- 订单创建日期（UTC-5）
        DATE(CONVERT_TZ(fr.RequestCreatedAt, '+00:00', '-05:00')) AS RequestCreatedDate_UTC5,
        -- 考核基准时间：如果首次扫描早于到仓则用首次扫描时间，再和标签率达标时间取较晚者
        GREATEST(
            CASE 
                WHEN fs.FirstScanTime_UTC5 IS NOT NULL AND fs.FirstScanTime_UTC5 < fr.ReceiptTime 
                THEN fs.FirstScanTime_UTC5 
                ELSE fr.ReceiptTime 
            END,
            flr.FirstQualifiedTime_UTC5
        ) AS AssessmentBaseTime,
        -- 考核时间计算（仅标签率≥80%且有标签的订单）
        CASE 
            WHEN flr.FirstQualifiedTime_UTC5 IS NOT NULL AND fr.HasLabel = 1 THEN
                CASE 
                    -- 考核基准时间16点前：考核截止次日16点
                    WHEN HOUR(GREATEST(
                        CASE 
                            WHEN fs.FirstScanTime_UTC5 IS NOT NULL AND fs.FirstScanTime_UTC5 < fr.ReceiptTime 
                            THEN fs.FirstScanTime_UTC5 
                            ELSE fr.ReceiptTime 
                        END,
                        flr.FirstQualifiedTime_UTC5
                    )) < 16 THEN 
                        DATE_ADD(
                            DATE_ADD(DATE(GREATEST(
                                CASE 
                                    WHEN fs.FirstScanTime_UTC5 IS NOT NULL AND fs.FirstScanTime_UTC5 < fr.ReceiptTime 
                                    THEN fs.FirstScanTime_UTC5 
                                    ELSE fr.ReceiptTime 
                                END,
                                flr.FirstQualifiedTime_UTC5
                            )), INTERVAL 1 DAY),
                            INTERVAL 16 HOUR
                        )
                    -- 考核基准时间16点后：考核截止次日23:59:59
                    ELSE 
                        DATE_ADD(
                            DATE_ADD(DATE(GREATEST(
                                CASE 
                                    WHEN fs.FirstScanTime_UTC5 IS NOT NULL AND fs.FirstScanTime_UTC5 < fr.ReceiptTime 
                                    THEN fs.FirstScanTime_UTC5 
                                    ELSE fr.ReceiptTime 
                                END,
                                flr.FirstQualifiedTime_UTC5
                            )), INTERVAL 1 DAY),
                            INTERVAL '23:59:59' HOUR_SECOND
                        )
                END
            ELSE NULL
        END AS AssessmentTime
    FROM FormRequestRelation fr
    LEFT JOIN FormLabelRateAndQualifiedDate flr ON fr.FormId = flr.FormId
    LEFT JOIN FormFirstScan fs ON fr.FormId = fs.FormId
    WHERE fr.HasLabel = 1 -- 仅统计有标签的订单
),
-- 步骤7：获取每个订单的扫描状态
OrderScanStatus AS (
    SELECT 
        s.NeutralWaybillNumber,
        -- 首次成功时间（UTC-5）
        MIN(CASE WHEN s.Result = 0 THEN CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') END) AS FirstSuccessTime_UTC5,
        DATE(MIN(CASE WHEN s.Result = 0 THEN CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00') END)) AS FirstSuccessDate_UTC5,
        -- 是否成功
        MAX(CASE WHEN s.Result = 0 THEN 1 ELSE 0 END) AS IsSuccess,
        -- 是否是STOP标签
        MAX(CASE WHEN s.Result = 0 AND s.Description LIKE '%成功返回STOP标签%' THEN 1 ELSE 0 END) AS IsStopLabel
    FROM label_scan_history s
    GROUP BY s.NeutralWaybillNumber
),
-- 步骤8：合并订单信息和扫描状态
OrderFullInfo AS (
    SELECT 
        oa.*,
        oss.FirstSuccessTime_UTC5,
        oss.FirstSuccessDate_UTC5,
        oss.IsSuccess,
        oss.IsStopLabel,
        -- 是否在考核时间内完成
        CASE 
            WHEN oa.AssessmentTime IS NOT NULL AND oss.IsSuccess = 1 
                AND oss.FirstSuccessTime_UTC5 <= oa.AssessmentTime 
            THEN 1 ELSE 0 
        END AS IsCompletedInAssessment
    FROM OrderAssessment oa
    LEFT JOIN OrderScanStatus oss ON oa.NeutralWaybillNumber = oss.NeutralWaybillNumber
),
-- 步骤9：独立统计每日+客户维度成功换单的去重订单数
CustomerDailySuccessCount AS (
    SELECT
        DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 日期,
        c.CustomerCode,
        COUNT(DISTINCT s.NeutralWaybillNumber) AS 当日换单完成数
    FROM label_scan_history s
    INNER JOIN label_replace_requests r ON s.NeutralWaybillNumber = r.NeutralWaybillNumber
    INNER JOIN customers c ON r.customerid = c.Id
    WHERE s.Result = 0
    GROUP BY DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')), c.CustomerCode
),
-- 步骤10：独立统计每日+客户维度失败换单的去重订单数（当日有失败且无成功）
CustomerDailyFailCount AS (
    SELECT
        日期,
        CustomerCode,
        COUNT(DISTINCT NeutralWaybillNumber) AS 当日换单失败数
    FROM (
        SELECT 
            DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 日期,
            c.CustomerCode,
            s.NeutralWaybillNumber,
            MAX(CASE WHEN s.Result = 0 THEN 1 ELSE 0 END) AS has_success,
            MAX(CASE WHEN s.Result != 0 THEN 1 ELSE 0 END) AS has_fail
        FROM label_scan_history s
        INNER JOIN label_replace_requests r ON s.NeutralWaybillNumber = r.NeutralWaybillNumber
        INNER JOIN customers c ON r.customerid = c.Id
        GROUP BY DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')), c.CustomerCode, s.NeutralWaybillNumber
    ) t
    WHERE has_fail = 1 AND has_success = 0
    GROUP BY 日期, CustomerCode
),
-- 步骤11：独立统计每日+客户维度的扫描次数
CustomerDailyScanCount AS (
    SELECT
        DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 日期,
        c.CustomerCode,
        COUNT(*) AS 当日扫描数
    FROM label_scan_history s
    INNER JOIN label_replace_requests r ON s.NeutralWaybillNumber = r.NeutralWaybillNumber
    INNER JOIN customers c ON r.customerid = c.Id
    GROUP BY DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')), c.CustomerCode
),
-- 步骤12：独立统计每日+客户维度STOP标签的去重订单数
CustomerDailyStopCount AS (
    SELECT
        DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')) AS 日期,
        c.CustomerCode,
        COUNT(DISTINCT s.NeutralWaybillNumber) AS 当日STOP数
    FROM label_scan_history s
    INNER JOIN label_replace_requests r ON s.NeutralWaybillNumber = r.NeutralWaybillNumber
    INNER JOIN customers c ON r.customerid = c.Id
    WHERE s.Result = 0 AND s.Description LIKE '%成功返回STOP标签%'
    GROUP BY DATE(CONVERT_TZ(s.CreatedAt, '+00:00', '-05:00')), c.CustomerCode
),
-- 步骤12：获取所有日期维度
AllDates AS (
    SELECT ReceiptDate AS 日期 FROM OrderFullInfo -- 到仓日期（UTC-5）
    UNION
    SELECT LabelRetrievedDate_UTC5 AS 日期 FROM OrderFullInfo WHERE LabelRetrievedDate_UTC5 IS NOT NULL -- 标签推送日期（UTC-5）
    UNION
    SELECT FirstSuccessDate_UTC5 AS 日期 FROM OrderFullInfo WHERE FirstSuccessDate_UTC5 IS NOT NULL -- 换单成功日期（UTC-5）
    UNION
    SELECT DATE(AssessmentBaseTime) AS 日期 FROM OrderFullInfo WHERE AssessmentBaseTime IS NOT NULL -- 考核基准日期（UTC-5）
    UNION
    SELECT DATE(AssessmentTime) AS 日期 FROM OrderFullInfo WHERE AssessmentTime IS NOT NULL -- 考核截止日期（UTC-5）
    UNION
    SELECT DATE(CONVERT_TZ(CreatedAt, '+00:00', '-05:00')) AS 日期 FROM label_scan_history WHERE CreatedAt IS NOT NULL -- 扫描日期（转UTC-5）
    UNION
    SELECT DATE(CONVERT_TZ(LabelRetrievedAt, '+00:00', '-05:00')) AS 日期 FROM label_replace_requests WHERE LabelRetrievedAt IS NOT NULL -- 标签推送日期（转UTC-5）
    UNION
    SELECT DATE(CONVERT_TZ(CreatedAt, '+00:00', '-05:00')) AS 日期 FROM label_scan_history WHERE Result = 0 AND CreatedAt IS NOT NULL -- 换单完成日期（转UTC-5）
),
-- 步骤10：去重排序日期
DistinctDates AS (
    SELECT DISTINCT 日期
    FROM AllDates
    ORDER BY 日期
),
-- 步骤13：每日+客户维度指标汇总
DailyCustomerMetrics AS (
    SELECT 
        dd.日期,
        ofi.CustomerCode, -- 客户代码维度
        -- 当天新增换单数：到仓时间是当天的有标签订单数
        COUNT(DISTINCT CASE WHEN ofi.ReceiptDate = dd.日期 THEN ofi.RequestId END) AS 当天新增换单数,
        -- 当天应该换单数：有考核时间、考核基准日期是当天或考核截止日期是当天，且换单完成时间小于等于统计日期的订单（有考核时间默认标签率≥80%）
        COUNT(DISTINCT CASE 
            WHEN ofi.AssessmentTime IS NOT NULL
                AND (DATE(ofi.AssessmentBaseTime) = dd.日期 OR DATE(ofi.AssessmentTime) = dd.日期)
                AND (ofi.IsSuccess = 0 OR ofi.FirstSuccessDate_UTC5 <= dd.日期)
            THEN ofi.RequestId 
        END) AS 当天应该换单数,
        -- 当日标签推送数：标签推送时间是当天的订单数
        COUNT(DISTINCT CASE WHEN ofi.LabelRetrievedDate_UTC5 = dd.日期 THEN ofi.RequestId END) AS 当日标签推送数,
        -- 累计要换的总单数：有标签，标签推送时间<=统计日期，创建时间<=统计日期，且统计日当天未完成换单的不重复订单总数（不考虑标签率、到仓时间、考核时间）
        COUNT(DISTINCT CASE 
            WHEN ofi.HasLabel = 1 
                AND ofi.LabelRetrievedDate_UTC5 <= dd.日期
                AND ofi.RequestCreatedDate_UTC5 <= dd.日期
                AND (ofi.IsSuccess = 0 OR ofi.FirstSuccessDate_UTC5 > dd.日期)
            THEN ofi.RequestId 
        END) AS 累计要换的总单数,
        -- 24小时换单成功数：当天应该换单数中、首次成功时间在考核基准时间与考核时间之间、且完成时间是当天的订单数
        COUNT(DISTINCT CASE 
            WHEN ofi.AssessmentTime IS NOT NULL
                AND (DATE(ofi.AssessmentBaseTime) = dd.日期 OR DATE(ofi.AssessmentTime) = dd.日期)
                AND ofi.IsCompletedInAssessment = 1
                AND ofi.FirstSuccessDate_UTC5 = dd.日期
            THEN ofi.RequestId 
        END) AS 24H完成数
    FROM DistinctDates dd
    CROSS JOIN OrderFullInfo ofi
    GROUP BY dd.日期, ofi.CustomerCode -- 按日期+客户代码分组
)
-- 最终输出
SELECT 
    dcm.CustomerCode, -- 客户代码作为第一列
    dcm.日期,
    dcm.当天新增换单数,
    dcm.累计要换的总单数,
    dcm.当天应该换单数,
    COALESCE(cdsc.当日换单完成数, 0) AS 当日换单完成数,
    COALESCE(cdfc.当日换单失败数, 0) AS 当日换单失败数,
    COALESCE(cdstop.当日STOP数, 0) AS 当日STOP数,
    dcm.24H完成数 AS 24小时换单成功数,
    dcm.当日标签推送数,
    COALESCE(cdscan.当日扫描数, 0) AS 当日扫描数,
    -- 当天换单完成率：当日换单完成数 / 当天应该换单数
    CASE 
        WHEN dcm.当天应该换单数 = 0 THEN '0.00%'
        ELSE CONCAT(ROUND(COALESCE(cdsc.当日换单完成数, 0) / dcm.当天应该换单数 * 100, 2), '%')
    END AS 当天换单完成率,
    -- 24小时换单率：考核时间内完成数 / 当天应该考核的订单总数
    CASE 
        WHEN dcm.当天应该换单数 = 0 THEN '0.00%'
        ELSE CONCAT(ROUND(dcm.24H完成数 / dcm.当天应该换单数 * 100, 2), '%')
    END AS 24小时换单率,
    -- 数据拉取时间
    (UTC_TIMESTAMP() - INTERVAL 5 HOUR) AS 数据拉取时间（UTC_5）
FROM DailyCustomerMetrics dcm
LEFT JOIN CustomerDailySuccessCount cdsc ON dcm.日期 = cdsc.日期 AND dcm.CustomerCode = cdsc.CustomerCode
LEFT JOIN CustomerDailyFailCount cdfc ON dcm.日期 = cdfc.日期 AND dcm.CustomerCode = cdfc.CustomerCode
LEFT JOIN CustomerDailyScanCount cdscan ON dcm.日期 = cdscan.日期 AND dcm.CustomerCode = cdscan.CustomerCode
LEFT JOIN CustomerDailyStopCount cdstop ON dcm.日期 = cdstop.日期 AND dcm.CustomerCode = cdstop.CustomerCode
WHERE dcm.CustomerCode IS NOT NULL -- 过滤无客户代码的订单
ORDER BY dcm.日期 DESC, dcm.CustomerCode;
