USE [YL_MESDB]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

IF OBJECT_ID(N'dbo.生产管理_产品合格率工位_查询', N'P') IS NULL
BEGIN
    EXEC(N'CREATE PROCEDURE [dbo].[生产管理_产品合格率工位_查询] AS BEGIN SET NOCOUNT ON; END');
END
GO

ALTER PROCEDURE [dbo].[生产管理_产品合格率工位_查询]
    @生产订单号 nvarchar(100) = N'',
    @物料编码 nvarchar(200) = N'',
    @物料名称 nvarchar(200) = N'',
    @关闭日期_Start nvarchar(50) = N'',
    @关闭日期_End nvarchar(50) = N'',
    @工序 nvarchar(100) = N'',
    @工位 nvarchar(100) = N'',
    @合格状态 nvarchar(20) = N'不合格'
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @开始日期 date = TRY_CONVERT(date, NULLIF(@关闭日期_Start, N''));
    DECLARE @结束日期 date = TRY_CONVERT(date, NULLIF(@关闭日期_End, N''));

    IF @开始日期 IS NULL AND @结束日期 IS NULL AND @生产订单号 = N''
    BEGIN
        SET @开始日期 = DATEADD(day, -30, CONVERT(date, GETDATE()));
        SET @结束日期 = CONVERT(date, GETDATE());
    END;

    CREATE TABLE #已关闭订单
    (
        [生产订单号] nvarchar(100) NOT NULL PRIMARY KEY,
        [关闭日期] datetime NULL,
        [物料名称] nvarchar(200) NULL,
        [物料编码] nvarchar(50) NULL,
        [计划数量] decimal(18, 4) NULL
    );

    DECLARE @SapSql nvarchar(max) =
        N'SELECT 生产订单号, 实际结算日期, 产品名称, 产品编码, 产品计划数量, 单据状态 FROM SBO_YL.dbo.UBT_OWOR WHERE 单据状态 IS NOT NULL';

    IF @生产订单号 <> N''
        SET @SapSql += N' AND 生产订单号 = ''' + REPLACE(@生产订单号, N'''', N'''''') + N'''';

    IF @开始日期 IS NOT NULL
        SET @SapSql += N' AND 实际结算日期 >= ''' + CONVERT(nvarchar(10), @开始日期, 120) + N'''';

    IF @结束日期 IS NOT NULL
        SET @SapSql += N' AND 实际结算日期 < ''' + CONVERT(nvarchar(10), DATEADD(day, 1, @结束日期), 120) + N'''';

    DECLARE @OpenQuerySql nvarchar(max) =
        N'INSERT INTO #已关闭订单
              ([生产订单号], [关闭日期], [物料名称], [物料编码], [计划数量])
          SELECT CONVERT(nvarchar(100), [生产订单号]) AS [生产订单号],
                 [实际结算日期] AS [关闭日期],
                 [产品名称] AS [物料名称],
                 [产品编码] AS [物料编码],
                 CAST(ISNULL([产品计划数量], 0) AS decimal(18, 4)) AS [计划数量]
          FROM OPENQUERY([SAP], ''' + REPLACE(@SapSql, N'''', N'''''') + N''')
          WHERE (@物料编码 = N'''' OR [产品编码] LIKE N''%'' + @物料编码 + N''%'')
            AND (@物料名称 = N'''' OR [产品名称] LIKE N''%'' + @物料名称 + N''%'')';

    EXEC sp_executesql
        @OpenQuerySql,
        N'@物料编码 nvarchar(200), @物料名称 nvarchar(200)',
        @物料编码 = @物料编码,
        @物料名称 = @物料名称;

    CREATE TABLE #明细汇总
    (
        [生产订单号] nvarchar(100) NOT NULL,
        [工序号] int NULL,
        [工序] nvarchar(200) NOT NULL,
        [工位] nvarchar(200) NOT NULL,
        [完成数量] decimal(18, 4) NOT NULL,
        [不良数量] decimal(18, 4) NOT NULL,
        [合格率] decimal(18, 2) NULL,
        [检测说明] nvarchar(max) NULL
    );

    ;WITH 明细基础 AS
    (
        SELECT
            o.[生产订单号],
            COALESCE(t.[订单行号], q.[行号]) AS [工序号],
            COALESCE(NULLIF(q.[工序名称], N''), NULLIF(t.[工序名称], N''), N'') AS [工序],
            COALESCE(NULLIF(q.[工位名称], N''), NULLIF(t.[指派对象], N''), N'空白') AS [工位],
            CAST(ISNULL(q.[检验数量], ISNULL(q.[合格数], 0) + ISNULL(q.[不合格数], 0)) AS decimal(18, 4)) AS [完成数量],
            CAST(ISNULL(q.[不合格数], 0) AS decimal(18, 4)) AS [不良数量],
            NULLIF(LTRIM(RTRIM(CONVERT(nvarchar(max), q.[检测说明]))), N'') AS [检测说明]
        FROM #已关闭订单 AS o
        INNER JOIN [dbo].[YL_质量检验_质检记录] AS q
            ON CONVERT(nvarchar(100), q.[计划号]) = o.[生产订单号]
        LEFT JOIN [dbo].[MES_接口_生产计划_生产任务] AS t
            ON q.[TaskAID] = t.[AID]
        WHERE q.[质检类型] = N'收检'
          AND (@工序 = N'' OR COALESCE(NULLIF(q.[工序名称], N''), NULLIF(t.[工序名称], N''), N'') LIKE N'%' + @工序 + N'%')
          AND (@工位 = N'' OR COALESCE(NULLIF(q.[工位名称], N''), NULLIF(t.[指派对象], N''), N'空白') LIKE N'%' + @工位 + N'%')
    )
    INSERT INTO #明细汇总
        ([生产订单号], [工序号], [工序], [工位], [完成数量], [不良数量], [合格率], [检测说明])
    SELECT
        [生产订单号],
        [工序号],
        [工序],
        [工位],
        SUM([完成数量]) AS [完成数量],
        SUM([不良数量]) AS [不良数量],
        CAST(
            CASE
                WHEN SUM([完成数量]) = 0 THEN NULL
                ELSE (SUM([完成数量]) - SUM([不良数量])) * 100.0 / SUM([完成数量])
            END AS decimal(18, 2)
        ) AS [合格率],
        STRING_AGG(CONVERT(nvarchar(max), [检测说明]), N'；') AS [检测说明]
    FROM 明细基础
    GROUP BY [生产订单号], [工序号], [工序], [工位];

    ;WITH 一级汇总 AS
    (
        SELECT
            [生产订单号],
            SUM([完成数量]) AS [完成数量],
            SUM([不良数量]) AS [不良数量],
            CAST(
                CASE
                    WHEN SUM([完成数量]) = 0 THEN NULL
                    ELSE (SUM([完成数量]) - SUM([不良数量])) * 100.0 / SUM([完成数量])
                END AS decimal(18, 2)
            ) AS [合格率]
        FROM #明细汇总
        GROUP BY [生产订单号]
    )
    SELECT
        o.[关闭日期],
        o.[生产订单号],
        o.[物料名称],
        o.[物料编码],
        o.[计划数量],
        a.[完成数量],
        a.[不良数量],
        a.[合格率],
        (
            SELECT
                d.[工序],
                d.[工序号],
                d.[工位],
                d.[完成数量],
                d.[不良数量],
                d.[合格率],
                ISNULL(d.[检测说明], N'') AS [检测说明]
            FROM #明细汇总 AS d
            WHERE d.[生产订单号] = o.[生产订单号]
            ORDER BY d.[工序号], d.[工序], d.[工位]
            FOR JSON PATH
        ) AS [明细JSON]
    FROM #已关闭订单 AS o
    INNER JOIN 一级汇总 AS a
        ON o.[生产订单号] = a.[生产订单号]
    WHERE (@合格状态 = N'' OR @合格状态 = N'全部'
           OR (@合格状态 = N'合格' AND ISNULL(a.[合格率], 0) >= 100)
           OR (@合格状态 = N'不合格' AND ISNULL(a.[合格率], 0) < 100))
    ORDER BY o.[关闭日期] DESC, TRY_CONVERT(int, o.[生产订单号]) DESC, o.[生产订单号] DESC;
END
GO
