{
  "name": "P0-02 \u00b7 UAT Fail-Closed Scope Patches",
  "nodes": [
    {
      "parameters": {},
      "id": "scope-trigger",
      "name": "Run Scope Patches",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "ALTER PROCEDURE [dbo].[API_DeXuatKhuyenMai_AI]\r\n    @Username VARCHAR(50) = ''\r\nAS\r\nBEGIN\n    SET NOCOUNT ON\n    DECLARE @SYSBranchID VARCHAR(50) = ''\n    DECLARE @SYSUserGroupID VARCHAR(50) = ''\n\n    IF NOT EXISTS (SELECT 1 FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0)\n    BEGIN\n        SELECT N'User kh\u00f4ng t\u1ed3n t\u1ea1i ho\u1eb7c \u0111\u00e3 b\u1ecb kh\u00f3a' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\n    SELECT @SYSBranchID = COALESCE(BranchID, ''),\n           @SYSUserGroupID = COALESCE(UserGroupID, '')\n    FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0\n\n    IF UPPER(@SYSUserGroupID) <> 'ADMIN' AND @SYSBranchID = ''\n    BEGIN\n        SELECT N'T\u00e0i kho\u1ea3n ch\u01b0a \u0111\u01b0\u1ee3c c\u1ea5p ph\u1ea1m vi chi nh\u00e1nh.' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\r\n    -- 1. \u0110\u1eccC C\u1ea4U H\u00ccNH CHI\u1ebeT KH\u1ea4U \u0110\u1ed8NG T\u1eea DATABASE\r\n    -- C\u1ea5u h\u00ecnh x\u1ea3 h\u00e0ng kh\u1ea9n c\u1ea5p (< 3 th\u00e1ng)\r\n    DECLARE @XaSauKhapCap_Thang INT = 3\r\n    DECLARE @XaSauKhapCap_PhanTram DECIMAL(5,2) = 50.00\r\n    SELECT TOP 1 \r\n        @XaSauKhapCap_Thang = NguongThoiGian_Thang, \r\n        @XaSauKhapCap_PhanTram = PhanTramDeXuat \r\n    FROM dbo.AR_AI_DiscountConfigTbl \r\n    WHERE LoaiDeXuat = 'XA_HANG_SAU' \r\n      AND NguongThoiGian_Thang <= 3 \r\n      AND IsActive = 1\r\n      AND (TuNgay IS NULL OR TuNgay <= GETDATE())\r\n      AND (DenNgay IS NULL OR DenNgay >= GETDATE())\r\n    ORDER BY NguongThoiGian_Thang ASC, PhanTramDeXuat DESC\r\n\r\n    -- C\u1ea5u h\u00ecnh x\u1ea3 h\u00e0ng c\u1eadn date (< 6 th\u00e1ng)\r\n    DECLARE @XaSauCanDate_Thang INT = 6\r\n    DECLARE @XaSauCanDate_PhanTram DECIMAL(5,2) = 25.00\r\n    SELECT TOP 1 \r\n        @XaSauCanDate_Thang = NguongThoiGian_Thang, \r\n        @XaSauCanDate_PhanTram = PhanTramDeXuat \r\n    FROM dbo.AR_AI_DiscountConfigTbl \r\n    WHERE LoaiDeXuat = 'XA_HANG_SAU' \r\n      AND NguongThoiGian_Thang > 3 AND NguongThoiGian_Thang <= 6\r\n      AND IsActive = 1\r\n      AND (TuNgay IS NULL OR TuNgay <= GETDATE())\r\n      AND (DenNgay IS NULL OR DenNgay >= GETDATE())\r\n    ORDER BY NguongThoiGian_Thang ASC, PhanTramDeXuat DESC\r\n\r\n    -- C\u1ea5u h\u00ecnh \u0111\u1ea9y h\u00e0ng ch\u1eadm (combo)\r\n    DECLARE @ComboDayHang_Thang INT = 6\r\n    DECLARE @ComboDayHang_PhanTram DECIMAL(5,2) = 15.00\r\n    SELECT TOP 1 \r\n        @ComboDayHang_Thang = NguongThoiGian_Thang, \r\n        @ComboDayHang_PhanTram = PhanTramDeXuat \r\n    FROM dbo.AR_AI_DiscountConfigTbl \r\n    WHERE LoaiDeXuat = 'COMBO_DAY_HANG' \r\n      AND IsActive = 1\r\n      AND (TuNgay IS NULL OR TuNgay <= GETDATE())\r\n      AND (DenNgay IS NULL OR DenNgay >= GETDATE())\r\n    ORDER BY NguongThoiGian_Thang DESC, PhanTramDeXuat DESC\r\n\r\n\r\n    -- 2. T\u00ednh t\u1ed1c \u0111\u1ed9 b\u00e1n (S\u1ed1 l\u01b0\u1ee3ng trung b\u00ecnh b\u00e1n ra m\u1ed7i ng\u00e0y trong 30 ng\u00e0y qua)\r\n    SELECT D.ItemID, SUM(D.Quantity) / 30.0 AS TocDo INTO #V \r\n    FROM AR_InvoiceDetailTbl D JOIN AR_InvoiceTbl I ON D.DocumentID = I.DocumentID \r\n    WHERE I.DocumentDate >= DATEADD(DAY, -30, GETDATE()) \r\n      AND ISNULL(I.StatusID, 0) != 10 \r\n      AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID) \r\n    GROUP BY D.ItemID\r\n\r\n    -- 3. L\u1ea5y h\u1ea1n d\u00f9ng g\u1ea7n nh\u1ea5t c\u1ee7a c\u00e1c m\u1eb7t h\u00e0ng (Ch\u1ec9 l\u1ea5y l\u00f4 c\u00f2n hi\u1ec7u l\u1ef1c)\r\n    SELECT ItemID, MIN(ExpireDate) AS HanDungNhat \r\n    INTO #Lot \r\n    FROM CF_LotTbl \r\n    WHERE ExpireDate >= GETDATE()\r\n    GROUP BY ItemID\r\n\r\n    -- 4. \u0110\u1ec1 xu\u1ea5t chi\u1ebfn l\u01b0\u1ee3c Khuy\u1ebfn m\u1ea1i (B\u1ea3n Final)\r\n    SELECT \r\n        I.ItemID, CF.ItemName, CF.Unit,\r\n        CAST(I.QuantityinStock AS INT) AS TonKho,\r\n        L.HanDungNhat AS HanDung,\r\n        CASE \r\n            WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauCanDate_Thang, GETDATE()) THEN N'X\u1ea2 H\u00c0NG S\u00c2U'\r\n            WHEN I.QuantityinStock > 0 AND (ISNULL(V.TocDo,0) = 0 OR (I.QuantityinStock / NULLIF(V.TocDo, 0)) > (@ComboDayHang_Thang * 30)) \r\n                THEN N'COMBO/\u0110\u1ea8Y H\u00c0NG'\r\n            ELSE N'THEO D\u00d5I' \r\n        END AS LoaiDeXuat,\r\n        CASE \r\n            WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauCanDate_Thang, GETDATE()) THEN\r\n                CASE WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauKhapCap_Thang, GETDATE()) THEN @XaSauKhapCap_PhanTram ELSE @XaSauCanDate_PhanTram END\r\n            WHEN I.QuantityinStock > 0 AND (ISNULL(V.TocDo,0) = 0 OR (I.QuantityinStock / NULLIF(V.TocDo, 0)) > (@ComboDayHang_Thang * 30)) THEN @ComboDayHang_PhanTram\r\n            ELSE 0.00\r\n        END AS PhanTramDeXuat,\r\n        CASE \r\n            -- Tr\u01b0\u1eddng h\u1ee3p c\u1eadn date\r\n            WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauKhapCap_Thang, GETDATE()) \r\n                THEN N'KH\u1ea8N C\u1ea4P: H\u1ea1n d\u00f9ng ch\u1ec9 c\u00f2n < ' + CAST(@XaSauKhapCap_Thang AS VARCHAR) + N' th\u00e1ng (' + CONVERT(VARCHAR, L.HanDungNhat, 103) + N'). \u0110\u1ec1 xu\u1ea5t gi\u1ea3m gi\u00e1 ' + CAST(CAST(@XaSauKhapCap_PhanTram AS INT) AS VARCHAR) + N'% \u0111\u1ec3 x\u1ea3 ngay!'\r\n            WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauCanDate_Thang, GETDATE()) \r\n                THEN N'C\u1eacN DATE: H\u1ea1n d\u00f9ng c\u00f2n < ' + CAST(@XaSauCanDate_Thang AS VARCHAR) + N' th\u00e1ng (' + CONVERT(VARCHAR, L.HanDungNhat, 103) + N'). \u0110\u1ec1 xu\u1ea5t gi\u1ea3m gi\u00e1 ' + CAST(CAST(@XaSauCanDate_PhanTram AS INT) AS VARCHAR) + N'%.'\r\n            \r\n            -- Tr\u01b0\u1eddng h\u1ee3p h\u00e0ng ch\u1eadm, v\u00f2ng quay th\u1ea5p\r\n            WHEN I.QuantityinStock > 0 AND ISNULL(V.TocDo,0) = 0 \r\n                THEN N'\u26a1 C\u1ea2NH B\u00c1O: H\u00e0ng ch\u1eadm b\u00e1n (30 ng\u00e0y qua kh\u00f4ng b\u00e1n \u0111\u01b0\u1ee3c). \u0110\u1ec1 xu\u1ea5t chi\u1ebft kh\u1ea5u ' + CAST(CAST(@ComboDayHang_PhanTram AS INT) AS VARCHAR) + N'% khi ch\u1ea1y combo t\u1eb7ng k\u00e8m.'\r\n            WHEN I.QuantityinStock > 0 AND (I.QuantityinStock / NULLIF(V.TocDo, 0)) > (@ComboDayHang_Thang * 30) \r\n                THEN N'\ud83d\udce6 T\u1ed2N KHO CAO: D\u1ef1 ki\u1ebfn ' + CAST(CAST(I.QuantityinStock / NULLIF(V.TocDo, 0) AS INT) AS VARCHAR) + N' ng\u00e0y m\u1edbi h\u1ebft. Khuy\u1ebfn kh\u00edch gi\u1ea3m ' + CAST(CAST(@ComboDayHang_PhanTram AS INT) AS VARCHAR) + N'% khi gh\u00e9p combo.'\r\n            \r\n            ELSE N'\u1ed4n \u0111\u1ecbnh: T\u1ed1c \u0111\u1ed9 b\u00e1n t\u1ed1t.'\r\n        END AS ChiTietAI\r\n    FROM IV_StockTbl I \r\n    JOIN CF_ItemTbl CF ON I.ItemID = CF.ItemID \r\n    LEFT JOIN #V V ON I.ItemID = V.ItemID\r\n    LEFT JOIN #Lot L ON I.ItemID = L.ItemID\r\n    WHERE I.QuantityinStock > 0 \r\n      AND ISNULL(CF.ItemGroupID, '') = 'HH1' -- L\u1ecdc h\u00e0ng HH1\r\n    ORDER BY \r\n        -- \u01afu ti\u00ean h\u00e0ng c\u1eadn date l\u00ean \u0111\u1ea7u, sau \u0111\u00f3 \u0111\u1ebfn h\u00e0ng ch\u1eadm\r\n        CASE WHEN L.HanDungNhat <= DATEADD(MONTH, @XaSauCanDate_Thang, GETDATE()) THEN 1 \r\n             WHEN ISNULL(V.TocDo,0) = 0 THEN 2 \r\n             ELSE 3 END ASC, \r\n        TonKho DESC\r\n\r\n    DROP TABLE #V; DROP TABLE #Lot;\r\nEND"
      },
      "id": "scope-patch-1",
      "name": "Patch DeXuatKhuyenMai",
      "type": "n8n-nodes-base.microsoftSql",
      "typeVersion": 1,
      "position": [
        240,
        0
      ],
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "ALTER PROCEDURE API_SanPhamTrongTam_AI\n    @Username   VARCHAR(50) = '',\r\n    @MaKhachHang  VARCHAR(50) = '', -- M\u00e3 kh\u00e1ch h\u00e0ng\r\n    @TopN       INT = 500         \r\nAS\r\nBEGIN\n    SET NOCOUNT ON;\n\n    IF NOT EXISTS (SELECT 1 FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0)\n    BEGIN\n        SELECT N'User kh\u00f4ng t\u1ed3n t\u1ea1i ho\u1eb7c \u0111\u00e3 b\u1ecb kh\u00f3a' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\r\n    -- LOG FOR AUDITING\r\n    EXEC AI_WriteAuditLog\r\n        @Username     = @Username,\r\n        @ActionType   = 'AI_QUERY',\r\n        @TargetEntity = 'API_SanPhamTrongTam_AI',\r\n        @TargetID     = @MaKhachHang,\r\n        @TargetName   = NULL,\r\n        @ExtraInfo    = NULL;\r\n\r\n    -- Defend against NULL or non-positive bounds passed by web server binders\r\n    IF @TopN IS NULL OR @TopN <= 0 SET @TopN = 500;\r\n\r\n\r\n    -- 1. X\u00e1c \u0111\u1ecbnh ch\u01b0\u01a1ng tr\u00ecnh \u0111ang ho\u1ea1t \u0111\u1ed9ng\r\n    DECLARE @ProgramID VARCHAR(50) = ''\r\n    SELECT TOP 1 @ProgramID = DocumentID FROM AR_SanPhamTrongTamTbl\r\n    WHERE GETDATE() BETWEEN FromDate AND ToDate OR ToDate >= CAST(GETDATE() AS DATE)\r\n    ORDER BY ToDate DESC\r\n\r\n\r\n    -- 2. K\u1ebft qu\u1ea3 B\u1ea3ng 1: TR\u1ea0NG TH\u00c1I & L\u1ed8 TR\u00ccNH\r\n    DECLARE @ProgramInfo TABLE (DocumentID VARCHAR(50), TenChuongTrinh NVARCHAR(200), FromDate DATETIME, ToDate DATETIME)\r\n    INSERT INTO @ProgramInfo SELECT DocumentID, Memo, FromDate, ToDate FROM AR_SanPhamTrongTamTbl WHERE DocumentID = @ProgramID;\r\n\r\n    -- L\u1ea5y th\u00f4ng tin t\u1eeb ng\u00e0y, \u0111\u1ebfn ng\u00e0y c\u1ee7a ch\u01b0\u01a1ng tr\u00ecnh\r\n    DECLARE @TuNgay DATETIME, @DenNgay DATETIME\r\n    SELECT @TuNgay = FromDate, @DenNgay = ToDate FROM AR_SanPhamTrongTamTbl WHERE DocumentID = @ProgramID\r\n\r\n    -- L\u1ea5y BranchID c\u1ee7a User \u0111\u1ec3 ph\u00e2n quy\u1ec1n\r\n    DECLARE @SYSBranchID VARCHAR(50) = ''\n    DECLARE @SYSUserGroupID VARCHAR(50) = ''\n    SELECT @SYSBranchID = COALESCE(BranchID, ''),\n           @SYSUserGroupID = COALESCE(UserGroupID, '')\n    FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0\n\n    IF UPPER(@SYSUserGroupID) <> 'ADMIN' AND @SYSBranchID = ''\n    BEGIN\n        SELECT N'T\u00e0i kho\u1ea3n ch\u01b0a \u0111\u01b0\u1ee3c c\u1ea5p ph\u1ea1m vi chi nh\u00e1nh.' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\r\n    -- Danh s\u00e1ch s\u1ea3n ph\u1ea9m tr\u1ecdng t\u00e2m\r\n    SELECT DISTINCT ItemID INTO #TrongTam FROM AR_SanPhamTrongTamDetailTbl WHERE DocumentID = @ProgramID\r\n\r\n    -- T\u00ednh t\u1ed5ng mua t\u1eeb h\u00f3a \u0111\u01a1n v\u00e0 \u0111\u01a1n h\u00e0ng nh\u00e1p (StatusID != 10)\r\n    DECLARE @TongHoaDon DECIMAL(18,2) = 0\r\n    SELECT @TongHoaDon = ISNULL(SUM(I.TotalAmount), 0)\r\n    FROM (\r\n        SELECT I.ObjectID, I.DocumentDate, I.BranchID, I.StatusID, D.ItemID, D.TotalAmount\r\n        FROM AR_InvoiceTbl I JOIN AR_InvoiceDetailTbl D ON I.DocumentID = D.DocumentID\r\n        UNION ALL\r\n        SELECT O.ObjectID, O.DocumentDate, O.BranchID, O.StatusID, D.ItemID, D.TotalAmount\r\n        FROM AR_OrderTbl O JOIN AR_OrderDetailTbl D ON O.DocumentID = D.DocumentID\r\n    ) I\r\n    JOIN #TrongTam T ON I.ItemID = T.ItemID\r\n    WHERE I.ObjectID = @MaKhachHang\r\n      AND I.DocumentDate BETWEEN @TuNgay AND @DenNgay \r\n      AND ISNULL(I.StatusID, 0) != 10\r\n      AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID)\r\n\r\n    -- T\u00ednh t\u1ed5ng tr\u1ea3 h\u00e0ng tr\u1ecdng t\u00e2m\r\n    DECLARE @TongTraHang DECIMAL(18,2) = 0\r\n    SELECT @TongTraHang = ISNULL(SUM(D.TotalAmount), 0)\r\n    FROM AR_ReturnTbl R \r\n    JOIN AR_ReturnDetailTbl D ON R.DocumentID = D.DocumentID\r\n    JOIN #TrongTam T ON D.ItemID = T.ItemID\r\n    WHERE R.ObjectID = @MaKhachHang\r\n      AND R.DocumentDate BETWEEN @TuNgay AND @DenNgay \r\n      AND (@SYSBranchID = '' OR R.BranchID = @SYSBranchID)\r\n\r\n    -- Doanh s\u1ed1 t\u00edch l\u0169y th\u1ef1c t\u1ebf\r\n    DECLARE @CurrentSales BIGINT = 0;\r\n    SET @CurrentSales = CAST(ISNULL(@TongHoaDon - @TongTraHang, 0) AS BIGINT)\r\n\r\n    DROP TABLE #TrongTam;\r\n\r\n    -- N\u00e9n thang qu\u00e0 t\u1eb7ng th\u00e0nh chu\u1ed7i m\u0169i t\u00ean tr\u1ef1c quan\r\n    DECLARE @GiftLadder NVARCHAR(MAX) = ''\r\n    SET @GiftLadder = STUFF((\r\n        SELECT ' -> [' + CAST(CAST(TuDiem AS BIGINT) AS VARCHAR(20)) + ': ' + QuaTang + ']'\r\n        FROM AR_PromotionGiftTbl\r\n        WHERE DocumentID = @ProgramID\r\n        ORDER BY TuDiem ASC\r\n        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 4, '')\r\n\r\n    ;WITH NextGoal AS (\r\n        SELECT TOP 1 TuDiem, QuaTang FROM AR_PromotionGiftTbl\r\n        WHERE DocumentID = @ProgramID AND TuDiem > @CurrentSales ORDER BY TuDiem ASC\r\n    )\r\n    SELECT \r\n        P.TenChuongTrinh AS [Ch\u01b0\u01a1ng Tr\u00ecnh],\r\n        P.FromDate AS [T\u1eeb Ng\u00e0y], P.ToDate AS [\u0110\u1ebfn Ng\u00e0y],\r\n        @MaKhachHang AS [M\u00e3 Kh\u00e1ch], \r\n        @CurrentSales AS [Doanh S\u1ed1 Hi\u1ec7n T\u1ea1i],\r\n        CAST(ISNULL(G.TuDiem, 0) AS BIGINT) AS [M\u1ed1c K\u1ebf Ti\u1ebfp],\r\n        CASE WHEN G.TuDiem IS NOT NULL THEN CAST(G.TuDiem - @CurrentSales AS BIGINT) ELSE 0 END AS [C\u00f2n Thi\u1ebfu],\r\n        ISNULL(G.QuaTang, N'\u0110\u00e3 \u0111\u1ea1t m\u1ed1c cao nh\u1ea5t') AS [Qu\u00e0 K\u1ebf Ti\u1ebfp],\r\n        ISNULL(@GiftLadder, N'') AS [Thang Qu\u00e0 T\u1eb7ng To\u00e0n B\u1ed9]\r\n    FROM @ProgramInfo P\r\n    LEFT JOIN NextGoal G ON 1=1;\r\n\r\n\r\n    -- 3. K\u1ebft qu\u1ea3 B\u1ea3ng 2: DANH M\u1ee4C S\u1ea2N PH\u1ea8M TR\u1eccNG T\u00c2M\r\n    SELECT TOP (@TopN)\r\n        D.ItemID AS [M\u00e3 sp], \r\n        I.ItemName AS [S\u1ea3n Ph\u1ea9m], \r\n        I.Unit AS [\u0110VT],\r\n        ISNULL((SELECT SUM(QuantityinStock) FROM IV_StockTbl WHERE ItemID = D.ItemID), 0) AS [T\u1ed3n Kho],\r\n        CAST(ISNULL((\r\n            SELECT TOP 1 P.UnitPrice FROM AR_PriceDetailTbl P \r\n            JOIN AR_PriceTbl H ON P.DocumentID = H.DocumentID\r\n            WHERE P.ItemID = D.ItemID AND H.isDisable = 0 AND H.FromDate <= GETDATE()\r\n            ORDER BY H.FromDate DESC\r\n        ), 0) AS BIGINT) AS [Gi\u00e1 B\u00e1n]\r\n    FROM AR_SanPhamTrongTamDetailTbl D\r\n    JOIN CF_ItemTbl I ON D.ItemID = I.ItemID\r\n    WHERE D.DocumentID = @ProgramID\r\n      AND ISNULL(I.ItemGroupID, '') NOT IN ('KM', 'DV', 'VT', 'BB', 'Vat Tu', 'Bao Bi', 'TUI')\r\n      AND I.ItemID NOT LIKE 'BB%' AND I.ItemID NOT LIKE 'TUI%' AND I.ItemID NOT LIKE 'PB%' AND I.ItemID NOT LIKE 'NY%'\r\n    ORDER BY I.ItemName ASC;\r\nEND"
      },
      "id": "scope-patch-2",
      "name": "Patch SanPhamTrongTam",
      "type": "n8n-nodes-base.microsoftSql",
      "typeVersion": 1,
      "position": [
        480,
        0
      ],
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "ALTER PROCEDURE API_TichLuy_AI\n   @Username   VARCHAR(50)   = '',\r\n   @MaKhachHang  NVARCHAR(100) = '',\r\n   @ProgramID  VARCHAR(50)   = '',\r\n   @TuNgay   DATETIME      = NULL,\r\n   @DenNgay     DATETIME      = NULL,\r\n   @ItemIDs    NVARCHAR(MAX) = ''\r\nAS\r\nBEGIN\r\n   SET NOCOUNT ON\r\n    \r\n    DECLARE @SYSBranchID VARCHAR(50) = ''\n    DECLARE @SYSUserGroupID VARCHAR(50) = ''\n    SELECT @SYSBranchID = COALESCE(BranchID, ''),\n           @SYSUserGroupID = COALESCE(UserGroupID, '')\n    FROM SY_User WITH (NOLOCK) WHERE UserName = @Username AND COALESCE(Disable, 0) = 0\n   \r\n    -- 1. KI\u1ec2M TRA QUY\u1ec0N\r\n    IF NOT EXISTS (SELECT 1 FROM SY_User WITH (NOLOCK) WHERE UserName = @Username AND COALESCE(Disable, 0) = 0)\r\n    BEGIN\r\n        SELECT N'User kh\u00f4ng t\u1ed3n t\u1ea1i ho\u1eb7c \u0111\u00e3 b\u1ecb kh\u00f3a' AS Msg, 1 AS MsgType RETURN\r\n    END\n\n    IF UPPER(@SYSUserGroupID) <> 'ADMIN' AND @SYSBranchID = ''\n    BEGIN\n        SELECT N'T\u00e0i kho\u1ea3n ch\u01b0a \u0111\u01b0\u1ee3c c\u1ea5p ph\u1ea1m vi chi nh\u00e1nh.' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\r\n\r\n     -- SMART CUSTOMER RESOLUTION (NAME TO ID)\r\n     IF @MaKhachHang <> '' AND NOT EXISTS (SELECT 1 FROM dbo.CF_ObjectTbl WHERE ObjectID = @MaKhachHang)\r\n     BEGIN\r\n         DECLARE @ResolvedID VARCHAR(50) = ''\r\n         DECLARE @CleanSearch NVARCHAR(100) = dbo.ufn_clean_customer_name(@MaKhachHang)\r\n\r\n         -- 1. Fast Path: Match by ObjectID or ObjectName directly without scalar function scan\r\n         SELECT TOP 1 @ResolvedID = ObjectID \r\n         FROM dbo.CF_ObjectTbl \r\n         WHERE (ObjectID LIKE '%' + @CleanSearch + '%'\r\n            OR ObjectName LIKE '%' + @CleanSearch + '%') AND (@SYSBranchID = '' OR BranchID = @SYSBranchID)\r\n         ORDER BY \r\n             CASE WHEN ObjectID = @CleanSearch THEN 1\r\n                  WHEN ObjectName = @CleanSearch THEN 2\r\n                  WHEN ObjectName LIKE @CleanSearch + '%' THEN 3\r\n                  ELSE 4\r\n             END,\r\n             COALESCE((SELECT MAX(DocumentDate) FROM AR_InvoiceTbl WHERE ObjectID = CF_ObjectTbl.ObjectID), '1900-01-01') DESC,\r\n             LEN(ObjectName) ASC;\r\n\r\n         -- 2. Slow Path: Fallback to heavy clean function scan only if Fast Path found nothing\r\n         IF @ResolvedID = ''\r\n         BEGIN\r\n             SELECT TOP 1 @ResolvedID = ObjectID \r\n             FROM dbo.CF_ObjectTbl \r\n             WHERE (dbo.ufn_clean_customer_name(ObjectName) LIKE '%' + @CleanSearch + '%'\r\n                OR ObjectID LIKE '%' + @CleanSearch + '%') AND (@SYSBranchID = '' OR BranchID = @SYSBranchID)\r\n             ORDER BY \r\n                 CASE WHEN ObjectID = @CleanSearch THEN 1\r\n                      WHEN dbo.ufn_clean_customer_name(ObjectName) = @CleanSearch THEN 2\r\n                      WHEN dbo.ufn_clean_customer_name(ObjectName) LIKE @CleanSearch + '%' THEN 3\r\n                      ELSE 4\r\n                 END,\r\n                 COALESCE((SELECT MAX(DocumentDate) FROM AR_InvoiceTbl WHERE ObjectID = CF_ObjectTbl.ObjectID), '1900-01-01') DESC,\r\n                 LEN(ObjectName) ASC;\r\n         END\r\n\r\n         IF @ResolvedID <> ''\r\n         BEGIN\r\n             SET @MaKhachHang = @ResolvedID\r\n         END\r\n     END\r\n\r\n     \r\n\r\n\r\n    -- 2. X\u00c1C \u0110\u1ecaNH CH\u01af\u01a0NG TR\u00ccNH\r\n    IF @ProgramID = ''\r\n        SELECT TOP 1 @ProgramID = DocumentID FROM AR_SanPhamTrongTamTbl WITH (NOLOCK) ORDER BY ToDate DESC\r\n    \r\n    IF @TuNgay IS NULL OR @DenNgay IS NULL\r\n        SELECT @TuNgay = FromDate, @DenNgay = ToDate FROM AR_SanPhamTrongTamTbl WITH (NOLOCK) WHERE DocumentID = @ProgramID\r\n\r\n\r\n    -- 3. DANH S\u00c1CH S\u1ea2N PH\u1ea8M TR\u1eccNG T\u00c2M\r\n    SELECT DISTINCT ItemID INTO #TrongTam FROM (\r\n        SELECT CAST(value AS VARCHAR(50)) AS ItemID FROM STRING_SPLIT(@ItemIDs, ',') WHERE @ItemIDs != ''\r\n        UNION ALL\r\n        SELECT ItemID FROM AR_SanPhamTrongTamDetailTbl WITH (NOLOCK) WHERE @ItemIDs = '' AND DocumentID = @ProgramID\r\n    ) X\r\n\r\n\r\n     -- 4. T\u1ed4NG MUA & TR\u1ea2 H\u00c0NG TR\u1eccNG T\u00c2M (T\u00ednh c\u1ea3 h\u00f3a \u0111\u01a1n & \u0111\u01a1n nh\u00e1p)\r\n     SELECT I.ObjectID, SUM(I.TotalAmount) AS TongHoaDon INTO #HoaDon\r\n     FROM (\r\n         SELECT I.ObjectID, I.DocumentDate, I.BranchID, I.StatusID, D.ItemID, D.TotalAmount\r\n         FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n         UNION ALL\r\n         SELECT O.ObjectID, O.DocumentDate, O.BranchID, O.StatusID, D.ItemID, D.TotalAmount\r\n         FROM AR_OrderTbl O WITH (NOLOCK) JOIN AR_OrderDetailTbl D WITH (NOLOCK) ON O.DocumentID = D.DocumentID\r\n     ) I\r\n     JOIN #TrongTam T ON I.ItemID = T.ItemID\r\n     WHERE I.DocumentDate BETWEEN @TuNgay AND @DenNgay AND ISNULL(I.StatusID, 0) != 10\r\n       AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID)\r\n     GROUP BY I.ObjectID\r\n\r\n\r\n    SELECT R.ObjectID, SUM(D.TotalAmount) AS TongTraHang INTO #TraHang\r\n    FROM AR_ReturnTbl R WITH (NOLOCK) JOIN AR_ReturnDetailTbl D WITH (NOLOCK) ON R.DocumentID = D.DocumentID\r\n    JOIN #TrongTam T ON D.ItemID = T.ItemID\r\n    WHERE R.DocumentDate BETWEEN @TuNgay AND @DenNgay AND (@SYSBranchID = '' OR R.BranchID = @SYSBranchID)\r\n    GROUP BY R.ObjectID\r\n\r\n\r\n   SELECT\r\n       H.ObjectID,\r\n       CAST(H.TongHoaDon - ISNULL(T.TongTraHang, 0) AS DECIMAL(18,2)) AS TongTichLuy\r\n   INTO #TichLuy\r\n   FROM #HoaDon H LEFT JOIN #TraHang T ON H.ObjectID = T.ObjectID\r\n\r\n\r\n   -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   -- K\u1ebeT QU\u1ea2: T\u00cdCH H\u1ee2P S\u00c2U C\u00c1C C\u1ed8T CHO ROBOT AI\r\n   -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   SELECT\r\n       @ProgramID      AS ProgramID,\r\n       KH.ObjectID,\r\n       KH.ObjectName   AS TenCuaHang,\r\n       CAST(ISNULL(TL.TongTichLuy, 0) AS BIGINT) AS TichLuyDatDuoc,\r\n       \r\n       -- Qu\u00e0 t\u1eb7ng hi\u1ec7n t\u1ea1i\r\n       ISNULL((SELECT TOP 1 QuaTang FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem <= ISNULL(TL.TongTichLuy,0) ORDER BY TuDiem DESC), N'Ch\u01b0a \u0111\u1ea1t qu\u00e0') AS QuaDaDat,\r\n       \r\n       -- S\u1ed1 l\u01b0\u1ee3ng qu\u00e0\r\n       CASE WHEN ISNULL(TL.TongTichLuy,0) >= 1000000 THEN (SELECT COUNT(*) FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem <= ISNULL(TL.TongTichLuy,0)) ELSE 0 END AS SoPhanQua,\r\n\r\n       -- M\u1ed1c m\u1ee5c ti\u00eau ti\u1ebfp theo\r\n       ISNULL((SELECT TOP 1 CAST(TuDiem AS BIGINT) FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem > ISNULL(TL.TongTichLuy,0) ORDER BY TuDiem ASC),\r\n              (SELECT TOP 1 CAST(TuDiem AS BIGINT) FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID ORDER BY TuDiem DESC)) AS MucTieu,\r\n       \r\n       -- Ti\u1ebfn \u0111\u1ed9 %\r\n       CASE\r\n          WHEN EXISTS (SELECT 1 FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem > ISNULL(TL.TongTichLuy,0))\r\n          THEN CAST(ISNULL(TL.TongTichLuy,0) * 100 / (SELECT TOP 1 TuDiem FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem > ISNULL(TL.TongTichLuy,0) ORDER BY TuDiem ASC) AS INT)\r\n          ELSE 100\r\n       END AS [Percentage],\r\n\r\n       CASE\r\n           WHEN EXISTS (SELECT 1 FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem > ISNULL(TL.TongTichLuy,0))\r\n                THEN N'Thi\u1ebfu ' + FORMAT((SELECT TOP 1 TuDiem FROM AR_PromotionGiftTbl WHERE DocumentID = @ProgramID AND TuDiem > ISNULL(TL.TongTichLuy,0) ORDER BY TuDiem ASC) - ISNULL(TL.TongTichLuy,0), 'N0') + N'\u0111 \u0111\u1ec3 \u0111\u1ea1t m\u1ed1c ti\u1ebfp theo.'\r\n           ELSE N'Tuy\u1ec7t v\u1eddi! B\u1ea1n \u0111\u00e3 \u0111\u1ea1t m\u1ed1c qu\u00e0 cao nh\u1ea5t trong ch\u01b0\u01a1ng tr\u00ecnh.'\r\n       END AS LoiNhacAI\r\n\r\n   FROM CF_ObjectTbl KH\r\n   LEFT JOIN #TichLuy TL ON KH.ObjectID = TL.ObjectID\r\n   WHERE (@MaKhachHang != '' AND KH.ObjectID = @MaKhachHang)\r\n      OR (@MaKhachHang = '' AND EXISTS (SELECT 1 FROM AR_PromotionGiftTbl G WHERE G.DocumentID = @ProgramID AND ISNULL(TL.TongTichLuy,0) >= G.TuDiem * 0.7))\r\n   ORDER BY ISNULL(TL.TongTichLuy,0) DESC;\r\n\r\n\r\n   -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   -- B\u1ea2NG 2: S\u1ea2N PH\u1ea8M TR\u1eccNG T\u00c2M CH\u01afA PH\u00c1T SINH DOANH S\u1ed0 (G\u1ee2I \u00dd)\r\n   -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\r\n   IF @MaKhachHang != ''\r\n   BEGIN\r\n       SELECT DISTINCT I.ItemID\r\n       INTO #ItemsBought\r\n       FROM (\r\n           SELECT I.ObjectID, I.DocumentDate, I.StatusID, D.ItemID\r\n           FROM AR_InvoiceTbl I JOIN AR_InvoiceDetailTbl D ON I.DocumentID = D.DocumentID\r\n           UNION ALL\r\n           SELECT O.ObjectID, O.DocumentDate, O.StatusID, D.ItemID\r\n           FROM AR_OrderTbl O JOIN AR_OrderDetailTbl D ON O.DocumentID = D.DocumentID\r\n       ) I\r\n       WHERE I.ObjectID = @MaKhachHang \r\n         AND I.DocumentDate BETWEEN @TuNgay AND @DenNgay\r\n         AND ISNULL(I.StatusID, 0) != 10\r\n         AND I.ItemID IN (SELECT ItemID FROM #TrongTam)\r\n\r\n       SELECT TOP 12\r\n           I.ItemID,\r\n           I.ItemName,\r\n           I.Unit\r\n       FROM #TrongTam T\r\n       JOIN CF_ItemTbl I ON T.ItemID = I.ItemID\r\n       WHERE NOT EXISTS (SELECT 1 FROM #ItemsBought DM WHERE DM.ItemID = T.ItemID)\r\n       ORDER BY I.ItemName ASC\r\n\r\n       DROP TABLE #ItemsBought\r\n   END\r\n   ELSE\r\n   BEGIN\r\n       SELECT TOP 0 '' AS ItemID, '' AS ItemName, '' AS Unit\r\n   END\r\n\r\n\r\n   DROP TABLE #HoaDon; DROP TABLE #TraHang; DROP TABLE #TrongTam; DROP TABLE #TichLuy;\r\nEND"
      },
      "id": "scope-patch-3",
      "name": "Patch TichLuy",
      "type": "n8n-nodes-base.microsoftSql",
      "typeVersion": 1,
      "position": [
        720,
        0
      ],
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "ALTER PROCEDURE API_UpsellGoiY_AI\n    @Username     VARCHAR(50)   = '',\r\n    @MaKhachHang  NVARCHAR(100) = '',\r\n    @timkiem      NVARCHAR(50)  = '',      \r\n    @TopN         INT           = 10\r\nAS\r\nBEGIN\r\n    SET NOCOUNT ON\r\n\r\n    -- Defend against NULL or non-positive bounds passed by web server binders\r\n    IF @TopN IS NULL OR @TopN <= 0 SET @TopN = 10;\r\n\r\n    -- \u2550\u2550\u2550 Validate User \u2550\u2550\u2550\r\n    IF NOT EXISTS (SELECT 1 FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0)\r\n    BEGIN\r\n        SELECT N'User kh\u00f4ng t\u1ed3n t\u1ea1i ho\u1eb7c \u0111\u00e3 b\u1ecb kh\u00f3a' AS Msg, 1 AS MsgType\r\n        RETURN\r\n    END\r\n\r\n    DECLARE @SYSBranchID VARCHAR(50) = ''\n    DECLARE @SYSUserGroupID VARCHAR(50) = ''\n    SELECT @SYSBranchID = COALESCE(BranchID, ''),\n           @SYSUserGroupID = COALESCE(UserGroupID, '')\n    FROM SY_User WHERE UserName = @Username AND COALESCE(Disable, 0) = 0\n\n    IF UPPER(@SYSUserGroupID) <> 'ADMIN' AND @SYSBranchID = ''\n    BEGIN\n        SELECT N'T\u00e0i kho\u1ea3n ch\u01b0a \u0111\u01b0\u1ee3c c\u1ea5p ph\u1ea1m vi chi nh\u00e1nh.' AS Msg, 1 AS MsgType\n        RETURN\n    END\n\r\n    DECLARE @DoanhSoHienTai FLOAT = 0\r\n    DECLARE @MucTarget      FLOAT = 0\r\n    DECLARE @SoTienThieu    FLOAT = 0\r\n    DECLARE @ProgramID      VARCHAR(50) = ''\r\n\r\n    -- T\u1ef0 \u0110\u1ed8NG KH\u1eaeC PH\u1ee4C T\u00caN KH\u00c1CH H\u00c0NG / \u1ea2O GI\u00c1C:\r\n    IF @MaKhachHang <> '' AND NOT EXISTS (SELECT 1 FROM CF_ObjectTbl WHERE ObjectID = @MaKhachHang)\r\n    BEGIN\r\n        DECLARE @ResolvedID VARCHAR(50) = '';\r\n        \r\n        IF @MaKhachHang LIKE '%\\[%\\]%' ESCAPE '\\'\r\n        BEGIN\r\n            SET @MaKhachHang = SUBSTRING(@MaKhachHang, CHARINDEX('[', @MaKhachHang) + 1, CHARINDEX(']', @MaKhachHang) - CHARINDEX('[', @MaKhachHang) - 1);\r\n        END\r\n\r\n        IF EXISTS (SELECT 1 FROM CF_ObjectTbl WHERE ObjectID = @MaKhachHang)\r\n        BEGIN\r\n            SET @ResolvedID = @MaKhachHang;\r\n        END\r\n        ELSE\r\n        BEGIN\r\n            -- \u01afu ti\u00ean t\u00ecm kh\u00e1ch h\u00e0ng c\u00f9ng chi nh\u00e1nh tr\u01b0\u1edbc v\u00e0 c\u00f3 nhi\u1ec1u giao d\u1ecbch nh\u1ea5t\r\n            SELECT TOP 1 @ResolvedID = O.ObjectID \r\n            FROM CF_ObjectTbl O\r\n            LEFT JOIN (\r\n                SELECT ObjectID, COUNT(*) AS Cnt \r\n                FROM AR_InvoiceTbl \r\n                GROUP BY ObjectID\r\n            ) I ON O.ObjectID = I.ObjectID\r\n            WHERE (\r\n                O.ObjectName COLLATE SQL_Latin1_General_CP1_CI_AI = @MaKhachHang COLLATE SQL_Latin1_General_CP1_CI_AI\r\n                OR O.ObjectName COLLATE SQL_Latin1_General_CP1_CI_AI LIKE N'%' + @MaKhachHang + '%' COLLATE SQL_Latin1_General_CP1_CI_AI\r\n                OR REPLACE(O.ObjectName, ' ', '') COLLATE SQL_Latin1_General_CP1_CI_AI LIKE N'%' + REPLACE(@MaKhachHang, ' ', '') + '%' COLLATE SQL_Latin1_General_CP1_CI_AI\r\n            )\r\n              AND (ISNULL(@SYSBranchID, '') = '' OR O.BranchID = @SYSBranchID)\r\n            ORDER BY ISNULL(I.Cnt, 0) DESC;\r\n              \r\n            -- Fallback t\u00ecm to\u00e0n qu\u1ed1c (ch\u1ec9 ch\u1ea1y cho admin)\r\n            IF @ResolvedID = '' AND UPPER(@SYSUserGroupID) = 'ADMIN'\n            BEGIN\r\n                SELECT TOP 1 @ResolvedID = O.ObjectID \r\n                FROM CF_ObjectTbl O\r\n                LEFT JOIN (\r\n                    SELECT ObjectID, COUNT(*) AS Cnt \r\n                    FROM AR_InvoiceTbl \r\n                    GROUP BY ObjectID\r\n                ) I ON O.ObjectID = I.ObjectID\r\n                WHERE (\r\n                    O.ObjectName COLLATE SQL_Latin1_General_CP1_CI_AI = @MaKhachHang COLLATE SQL_Latin1_General_CP1_CI_AI\r\n                    OR O.ObjectName COLLATE SQL_Latin1_General_CP1_CI_AI LIKE N'%' + @MaKhachHang + '%' COLLATE SQL_Latin1_General_CP1_CI_AI\r\n                    OR REPLACE(O.ObjectName, ' ', '') COLLATE SQL_Latin1_General_CP1_CI_AI LIKE N'%' + REPLACE(@MaKhachHang, ' ', '') + '%' COLLATE SQL_Latin1_General_CP1_CI_AI\r\n                )\r\n                ORDER BY ISNULL(I.Cnt, 0) DESC;\r\n            END\r\n        END\r\n\r\n        IF NULLIF(@ResolvedID, '') IS NOT NULL\r\n        BEGIN\r\n            SET @MaKhachHang = @ResolvedID;\r\n        END\r\n    END\r\n\r\n    -- \u2550\u2550\u2550 Validate khachhang \u2550\u2550\u2550\r\n    IF @MaKhachHang <> '' AND NOT EXISTS (SELECT 1 FROM CF_ObjectTbl WITH (NOLOCK) WHERE ObjectID = @MaKhachHang)\r\n    BEGIN\r\n        SELECT N'Kh\u00f4ng t\u00ecm th\u1ea5y m\u00e3 kh\u00e1ch h\u00e0ng n\u00e0y trong h\u1ec7 th\u1ed1ng.' AS Msg, 1 AS MsgType\r\n        RETURN;\r\n    END\r\n\r\n    -- RLS GUARD: Reuse ERP permission system (AR_GetObjectByUserFnc) to handle branch/manager hierarchy securely\r\n    IF @MaKhachHang <> '' AND @Username <> '' AND NOT EXISTS (\r\n        SELECT 1 FROM dbo.AR_GetObjectByUserFnc(@Username) WHERE ObjectID = @MaKhachHang\r\n    )\r\n    BEGIN\r\n        SELECT N'B\u1ea1n kh\u00f4ng c\u00f3 quy\u1ec1n xem th\u00f4ng tin c\u1ee7a kh\u00e1ch h\u00e0ng n\u00e0y.' AS Msg, 1 AS MsgType\r\n        RETURN;\r\n    END\r\n\r\n    -- LOG FOR AUDITING\r\n    EXEC AI_WriteAuditLog\r\n        @Username     = @Username,\r\n        @ActionType   = 'AI_QUERY',\r\n        @TargetEntity = 'API_UpsellGoiY_AI',\r\n        @TargetID     = @MaKhachHang,\r\n        @TargetName   = @timkiem,\r\n        @ExtraInfo    = NULL;\r\n\r\n    -- \u2550\u2550\u2550 1. X\u00e1c \u0111\u1ecbnh ch\u01b0\u01a1ng tr\u00ecnh \u0111ang ho\u1ea1t \u0111\u1ed9ng \u2550\u2550\u2550\r\n    SELECT TOP 1 @ProgramID = DocumentID \r\n    FROM AR_SanPhamTrongTamTbl WITH (NOLOCK)\r\n    WHERE GETDATE() BETWEEN FromDate AND ToDate\r\n    ORDER BY ToDate DESC;\r\n\r\n    -- UAT FALLBACK: N\u1ebfu kh\u00f4ng c\u00f3 ch\u01b0\u01a1ng tr\u00ecnh \u0111ang ch\u1ea1y, l\u1ea5y ch\u01b0\u01a1ng tr\u00ecnh m\u1edbi nh\u1ea5t\r\n    IF ISNULL(@ProgramID, '') = ''\r\n    BEGIN\r\n        SELECT TOP 1 @ProgramID = DocumentID \r\n        FROM AR_SanPhamTrongTamTbl WITH (NOLOCK)\r\n        ORDER BY ToDate DESC;\r\n    END\r\n\r\n    -- \u2550\u2550\u2550 2. Doanh s\u1ed1 hi\u1ec7n t\u1ea1i c\u1ee7a kh\u00e1ch trong th\u00e1ng (T\u00ednh c\u1ea3 h\u00f3a \u0111\u01a1n & \u0111\u01a1n nh\u00e1p) \u2550\u2550\u2550\r\n    SELECT @DoanhSoHienTai = ISNULL(SUM(I.TotalAmount), 0)\r\n    FROM (\r\n        SELECT I.ObjectID, I.DocumentDate, I.BranchID, I.StatusID, D.TotalAmount\r\n        FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n        UNION ALL\r\n        SELECT O.ObjectID, O.DocumentDate, O.BranchID, O.StatusID, D.TotalAmount\r\n        FROM AR_OrderTbl O WITH (NOLOCK) JOIN AR_OrderDetailTbl D WITH (NOLOCK) ON O.DocumentID = D.DocumentID\r\n    ) I\r\n    WHERE I.ObjectID = @MaKhachHang\r\n      AND ISNULL(I.StatusID, 0) != 10\r\n      AND I.DocumentDate >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)\r\n      AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID);\r\n\r\n    -- \u2550\u2550\u2550 3. T\u1ef1 \u0111\u1ed9ng t\u00ecm m\u1ed1c th\u01b0\u1edfng ti\u1ebfp theo \u2550\u2550\u2550\r\n    IF @ProgramID <> ''\r\n    BEGIN\r\n        SELECT TOP 1 @MucTarget = CAST(TuDiem AS FLOAT)\r\n        FROM AR_PromotionGiftTbl WITH (NOLOCK)\r\n        WHERE DocumentID = @ProgramID AND TuDiem > @DoanhSoHienTai\r\n        ORDER BY TuDiem ASC;\r\n    END\r\n\r\n    SET @SoTienThieu = CASE WHEN @MucTarget > 0 THEN @MucTarget - @DoanhSoHienTai ELSE 0 END;\r\n\r\n    -- \u2550\u2550\u2550 3.5. Danh s\u00e1ch s\u1ea3n ph\u1ea9m tr\u1ecdng t\u00e2m \u2550\u2550\u2550\r\n    SELECT DISTINCT ItemID INTO #TrongTam \r\n    FROM AR_SanPhamTrongTamDetailTbl WITH (NOLOCK) \r\n    WHERE DocumentID = @ProgramID;\r\n\r\n    -- \u2550\u2550\u2550 4. Gi\u00e1 m\u1edbi nh\u1ea5t t\u1eeb B\u1ea3ng gi\u00e1 \u2550\u2550\u2550\r\n    SELECT\r\n        D.ItemID,\r\n        MAX(H.FromDate) AS MaxFromDate\r\n    INTO #LatestPriceHeader\r\n    FROM AR_PriceDetailTbl D WITH (NOLOCK)\r\n    JOIN AR_PriceTbl H WITH (NOLOCK) ON D.DocumentID = H.DocumentID\r\n    WHERE H.isDisable = 0\r\n      AND H.FromDate <= GETDATE()\r\n      AND (H.ToDate IS NULL OR H.ToDate >= GETDATE())\r\n    GROUP BY D.ItemID;\r\n\r\n    -- UAT FALLBACK: N\u1ebfu kh\u00f4ng c\u00f3 b\u1ea3ng gi\u00e1 ho\u1ea1t \u0111\u1ed9ng h\u00f4m nay, l\u1ea5y b\u1ea3ng gi\u00e1 m\u1edbi nh\u1ea5t m\u1ecdi th\u1eddi \u0111\u1ea1i\r\n    IF NOT EXISTS (SELECT 1 FROM #LatestPriceHeader)\r\n    BEGIN\r\n        INSERT INTO #LatestPriceHeader (ItemID, MaxFromDate)\r\n        SELECT\r\n            D.ItemID,\r\n            MAX(H.FromDate) AS MaxFromDate\r\n        FROM AR_PriceDetailTbl D WITH (NOLOCK)\r\n        JOIN AR_PriceTbl H WITH (NOLOCK) ON D.DocumentID = H.DocumentID\r\n        WHERE H.isDisable = 0\r\n        GROUP BY D.ItemID;\r\n    END\r\n\r\n    SELECT\r\n        D.ItemID,\r\n        MAX(D.UnitPrice) AS GiaHienTai\r\n    INTO #GiaThiTruong\r\n    FROM AR_PriceDetailTbl D WITH (NOLOCK)\r\n    JOIN AR_PriceTbl H WITH (NOLOCK) ON D.DocumentID = H.DocumentID\r\n    JOIN #LatestPriceHeader L ON D.ItemID = L.ItemID AND H.FromDate = L.MaxFromDate\r\n    WHERE H.isDisable = 0\r\n    GROUP BY D.ItemID;\r\n\r\n    -- \u2550\u2550\u2550 5. H\u00e0ng kh\u00e1ch hay mua (6 th\u00e1ng g\u1ea7n nh\u1ea5t) \u2550\u2550\u2550\r\n    SELECT D.ItemID, COUNT(DISTINCT I.DocumentID) AS TanSuatMua\r\n    INTO #KhachQuen \r\n    FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n    WHERE I.ObjectID = @MaKhachHang \r\n      AND ISNULL(I.StatusID,0) != 10 \r\n      AND I.DocumentDate >= DATEADD(MONTH, -6, GETDATE())\r\n    GROUP BY D.ItemID;\r\n\r\n    -- UAT FALLBACK: L\u1ea5y t\u1ea5t c\u1ea3 l\u1ecbch s\u1eed mua\r\n    IF NOT EXISTS (SELECT 1 FROM #KhachQuen)\r\n    BEGIN\r\n        INSERT INTO #KhachQuen (ItemID, TanSuatMua)\r\n        SELECT D.ItemID, COUNT(DISTINCT I.DocumentID) AS TanSuatMua\r\n        FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n        WHERE I.ObjectID = @MaKhachHang \r\n          AND ISNULL(I.StatusID,0) != 10\r\n        GROUP BY D.ItemID;\r\n    END\r\n\r\n    -- \u2550\u2550\u2550 6. Top 50 b\u00e1n ch\u1ea1y t\u1ea1i chi nh\u00e1nh \u2550\u2550\u2550\r\n    SELECT TOP 50 D.ItemID, SUM(D.TotalAmount) AS DoanhSoChiNhanh\r\n    INTO #BanChay \r\n    FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n    WHERE I.DocumentDate >= DATEADD(DAY, -180, GETDATE()) \r\n      AND ISNULL(I.StatusID, 0) != 10 \r\n      AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID)\r\n    GROUP BY D.ItemID;\r\n\r\n    -- UAT FALLBACK: L\u1ea5y top b\u00e1n ch\u1ea1y m\u1ecdi th\u1eddi \u0111\u1ea1i\r\n    IF NOT EXISTS (SELECT 1 FROM #BanChay)\r\n    BEGIN\r\n        INSERT INTO #BanChay (ItemID, DoanhSoChiNhanh)\r\n        SELECT TOP 50 D.ItemID, SUM(D.TotalAmount) AS DoanhSoChiNhanh\r\n        FROM AR_InvoiceTbl I WITH (NOLOCK) JOIN AR_InvoiceDetailTbl D WITH (NOLOCK) ON I.DocumentID = D.DocumentID\r\n        WHERE ISNULL(I.StatusID, 0) != 10 \r\n          AND (@SYSBranchID = '' OR I.BranchID = @SYSBranchID)\r\n        GROUP BY D.ItemID\r\n        ORDER BY DoanhSoChiNhanh DESC;\r\n    END\r\n\r\n    -- \u2550\u2550\u2550 7. T\u1ed3n kho t\u1ed5ng h\u1ee3p \u2550\u2550\u2550\r\n    SELECT ItemID, SUM(QuantityinStock) AS QuantityinStock\r\n    INTO #TonKho\r\n    FROM IV_StockTbl WITH (NOLOCK)\r\n    GROUP BY ItemID;\r\n\r\n    -- \u2550\u2550\u2550 7.5. Danh s\u00e1ch s\u1ea3n ph\u1ea9m tr\u1ecdng t\u00e2m     -- Chu\u1ea9n h\u00f3a c\u00e1c li\u00ean t\u1eeb n\u1ed1i ti\u1ebfng Vi\u1ec7t th\u00e0nh kho\u1ea3ng tr\u1eafng/d\u1ea5u ph\u1ea9y \u0111\u1ec1 ph\u00f2ng n8n ch\u01b0a x\u1eed l\u00fd\r\n    SET @timkiem = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@timkiem, N' c\u00f9ng v\u1edbi ', ','), N' C\u00f9ng v\u1edbi ', ','), N' \u0111i k\u00e8m ', ','), N' \u0110i k\u00e8m ', ','), N' v\u00e0 ', ','), N' V\u00e0 ', ',');\r\n    \r\n    -- Map common symptoms to accent-free keywords matching 'An ng\u1ee7 ngon Medstand'\r\n    IF @timkiem LIKE N'%m\u1ea5t ng\u1ee7%' OR @timkiem LIKE N'%mat ngu%' OR @timkiem LIKE N'%ng\u1ee7%'\r\n    BEGIN\r\n        SET @timkiem = @timkiem + N' ngon'\r\n    END\r\n    IF @timkiem LIKE N'%m\u1ec7t m\u1ecfi%' OR @timkiem LIKE N'%met moi%' OR @timkiem LIKE N'%m\u1ec7t%'\r\n    BEGIN\r\n        SET @timkiem = @timkiem + N' ngon'\r\n    END\r\n    IF @timkiem LIKE N'%l\u01b0\u1eddi \u0103n%' OR @timkiem LIKE N'%luoi an%' \r\n       OR @timkiem LIKE N'%bi\u1ebfng \u0103n%' OR @timkiem LIKE N'%bieng an%'\r\n       OR @timkiem LIKE N'%ch\u00e1n \u0103n%' OR @timkiem LIKE N'%chan an%'\r\n       OR @timkiem LIKE N'%k\u00e9n \u0103n%' OR @timkiem LIKE N'%ken an%'\r\n       OR @timkiem LIKE N'%\u0103n k\u00e9m%' OR @timkiem LIKE N'%an kem%'\r\n       OR @timkiem LIKE N'%\u0103n ngon%' OR @timkiem LIKE N'%an ngon%'\r\n    BEGIN\r\n        SET @timkiem = @timkiem + N' ngon'\r\n    END\r\n    SET @timkiem = REPLACE(REPLACE(REPLACE(REPLACE(@timkiem, N' v\u1edbi ', ','), N' V\u1edbi ', ','), N' & ', ','), N' + ', ',');\r\n\r\n    -- X\u1eed l\u00fd tri\u1ec7t \u0111\u1ec3 d\u1ea5u c\u00e2u v\u00e0 kho\u1ea3ng tr\u1eafng d\u01b0 th\u1eeba\r\n    SET @timkiem = LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@timkiem, '.', ''), ',', ''), '-', ''), '\"', ''), '''', '')));\r\n\r\n    -- Lo\u1ea1i b\u1ecf t\u1eeb kh\u00f3a chung chung (stop words) n\u1ebfu ch\u1ec9 t\u00ecm ki\u1ebfm duy nh\u1ea5t t\u1eeb \u0111\u00f3 \u0111\u1ec3 tr\u00e1nh kh\u1edbp sai v\u00e0o Thu\u1ed1c ho\r\n    IF LOWER(@timkiem) IN (\r\n        N'thu\u1ed1c', N'thuoc', \r\n        N'u\u1ed1ng', N'uong', \r\n        N'b\u00e1c s\u0129', N'bac si', N'b\u00e1c s\u1ef9', N'bac sy',\r\n        N'cho', N'tr\u1ecb', N'tri', N'\u0111i\u1ec1u tr\u1ecb', N'dieu tri',\r\n        N'b\u1ec7nh', N'benh', N'b\u1ecb', N'bi',\r\n        N'em', N'b\u00e9', N'be', N'tr\u1ebb', N'tre', N'con',\r\n        N'tui', N't\u00f4i', N'toi', N'g\u00ec', N'gi', N'n\u00e0o', N'nao',\r\n        N'u\u1ed1ng thu\u1ed1c', N'uong thuoc'\r\n    ) OR LEN(@timkiem) <= 1\r\n    BEGIN\r\n        SET @timkiem = '';\r\n    END\r\n\r\n    IF @timkiem != ''\r\n    BEGIN\r\n        -- Clean and split keyword using stop words\r\n        DECLARE @Terms TABLE (Term NVARCHAR(100));\r\n        DECLARE @StopWords TABLE (Word NVARCHAR(100));\r\n        INSERT INTO @StopWords (Word) VALUES \r\n        (N'v\u00e0'), (N'c\u1ee7a'), (N'thu\u1ed1c'), (N'b\u1ecb'), (N'cho'), (N'n\u00ean'), (N'u\u1ed1ng'), (N'g\u00ec'), (N't\u01b0'), (N'v\u1ea5n'), \r\n        (N'th\u00e0nh'), (N'ph\u1ea7n'), (N'c\u00f4ng'), (N'd\u1ee5ng'), (N'gi\u00e1'), (N't\u00ecm'), (N'hi\u1ec7u'), (N'qu\u1ea3'), (N't\u1ed1t'), \r\n        (N'nh\u1ea5t'), (N'c\u00f3'), (N'th\u1ec3'), (N'\u0111\u01b0\u1ee3c'), (N'l\u00e0'), (N'trong'), (N'v\u1edbi'), (N'c\u00f9ng'), (N'\u0111i'), \r\n        (N'k\u00e8m'), (N'kh\u00e1ch'), (N'em'), (N't\u00f4i'), (N'm\u00ecnh'), (N'b\u00e1c'), (N's\u0129'), (N'nh\u00e0'), (N'h\u1ecfi'), \r\n        (N'mu\u1ed1n'), (N'mua'), (N'b\u00e1n'), (N'th\u00f4ng'), (N'tin'), (N'chi'), (N'ti\u1ebft'), (N's\u1ea3n'),\r\n        (N'th\u00ec'), (N'\u1edf'), (N'h\u1ed9'), (N'gi\u00fap'), (N'b\u1edfi'), (N'v\u00ec'), (N'nh\u01b0'), (N'th\u1ebf'), (N'n\u00e0o'), (N'a'), (N'\u1ea1');\r\n\r\n        DECLARE @clean_timkiem NVARCHAR(200) = @timkiem;\r\n        SET @clean_timkiem = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@clean_timkiem, N' c\u00f9ng v\u1edbi ', ' '), N' C\u00f9ng v\u1edbi ', ' '), N' \u0111i k\u00e8m ', ' '), N' \u0110i k\u00e8m ', ' '), N' v\u00e0 ', ' '), N' V\u00e0 ', ' ');\r\n        SET @clean_timkiem = REPLACE(REPLACE(REPLACE(REPLACE(@clean_timkiem, N' v\u1edbi ', ' '), N' V\u1edbi ', ' '), N' & ', ' '), N' + ', ' ');\r\n        SET @clean_timkiem = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@clean_timkiem, '.', ' '), ',', ' '), '-', ' '), '?', ' '), '!', ' '), ':', ' ');\r\n        SET @clean_timkiem = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@clean_timkiem, ';', ' '), '(', ' '), ')', ' '), '[', ' '), ']', ' ');\r\n\r\n        INSERT INTO @Terms (Term)\r\n        SELECT DISTINCT LTRIM(RTRIM(value))\r\n        FROM STRING_SPLIT(@clean_timkiem, ' ')\r\n        WHERE LTRIM(RTRIM(value)) <> '' \r\n          AND LTRIM(RTRIM(value)) NOT IN (SELECT Word FROM @StopWords);\r\n\r\n        -- ====================================================================\r\n        -- K\u1ecaCH B\u1ea2N 1: T\u00ccM S\u1ea2N PH\u1ea8M THEO TRI\u1ec6U CH\u1ee8NG (SEARCH KEY)\r\n        -- Y\u00eau c\u1ea7u: Tr\u1ea3 v\u1ec1 ch\u00ednh x\u00e1c h\u00e0ng kh\u1edbp t\u1eeb kh\u00f3a. Tuy\u1ec7t \u0111\u1ed1i kh\u00f4ng nh\u00e9t Tr\u1ecdng T\u00e2m v\u00e0o.\r\n        -- ====================================================================\r\n        SELECT TOP (@TopN)\r\n            CAST(@DoanhSoHienTai AS BIGINT) AS DoanhSoDaDat,\r\n            CAST(@MucTarget AS BIGINT)      AS MucTieuTiepTheo,\r\n            CAST(@SoTienThieu AS BIGINT)    AS SoTienConThieu,\r\n            CASE \r\n                WHEN @ProgramID = '' THEN N'Hi\u1ec7n kh\u00f4ng c\u00f3 ch\u01b0\u01a1ng tr\u00ecnh t\u00edch l\u0169y n\u00e0o \u0111ang ch\u1ea1y.'\r\n                WHEN @MucTarget > 0  THEN N'Kh\u00e1ch thi\u1ebfu ' + FORMAT(@SoTienThieu, 'N0') + N'\u0111 \u0111\u1ec3 \u0111\u1ea1t m\u1ed1c th\u01b0\u1edfng k\u1ebf ti\u1ebfp.'\r\n                ELSE N'Ch\u00fac m\u1eebng! Kh\u00e1ch \u0111\u00e3 v\u01b0\u1ee3t m\u1ecdi m\u1ed1c th\u01b0\u1edfng cao nh\u1ea5t th\u00e1ng n\u00e0y.'\r\n            END AS LoiNhacAI,\r\n\r\n            I.ItemID, \r\n            I.ItemName, \r\n            I.Unit,\r\n            CAST(ISNULL(G.GiaHienTai, 0) AS BIGINT)   AS GiaBan,\r\n            ISNULL(S.QuantityinStock, 0)               AS TonKho,\r\n            (\r\n                (CASE WHEN ISNULL(S.QuantityinStock,0) > 0 THEN 2000000 ELSE 0 END) +\r\n                \r\n                -- \u01afu ti\u00ean 1: T\u00ean ch\u1ee9a t\u1eeb kho\u00e1 nguy\u00ean b\u1ea3n \u1edf \u0111\u1ea7u (VD: B\u1eaft \u0111\u1ea7u b\u1eb1ng ch\u1eef \"Thu\u1ed1c ho\")\r\n                (CASE WHEN I.ItemName COLLATE Vietnamese_CI_AS LIKE REPLACE(@timkiem, 'thuoc ', '') + N'%' OR I.ItemName COLLATE Vietnamese_CI_AS LIKE @timkiem + N'%' THEN 500000 ELSE 0 END) +\r\n                \r\n                -- \u01afu ti\u00ean 2: T\u00ean ch\u1ee9a ch\u00ednh x\u00e1c t\u1eeb kh\u00f3a r\u1eddi r\u1ea1c (Full-text match)\r\n                (CASE WHEN CHARINDEX(' '+@timkiem+' ', ' '+REPLACE(REPLACE(REPLACE(I.ItemName COLLATE Vietnamese_CI_AS,',',' '),'.',' '),'-',' ')+' ') > 0 THEN 300000 ELSE 0 END) +\r\n                \r\n                -- \u01afu ti\u00ean 3: T\u00ean ch\u1ec9 n\u1eb1m \u0111\u00e2u \u0111\u00f3 trong chu\u1ed7i (Contains)\r\n                (CASE WHEN I.ItemName COLLATE Vietnamese_CI_AS LIKE N'%'+@timkiem+N'%' THEN 100000 ELSE 0 END) +\r\n                \r\n                -- \u01afu ti\u00ean 4: T\u1eeb kh\u00f3a (TuKhoa) ch\u1ee9a full-text match\r\n                (CASE WHEN CHARINDEX(' '+@timkiem+' ', ' '+REPLACE(REPLACE(REPLACE(ISNULL(I.TuKhoa,'') COLLATE Vietnamese_CI_AS,',',' '),'.',' '),'-',' ')+' ') > 0 THEN 50000 ELSE 0 END) +\r\n                \r\n                -- \u01afu ti\u00ean 5: T\u1eeb kh\u00f3a (TuKhoa) contains\r\n                (CASE WHEN I.TuKhoa COLLATE Vietnamese_CI_AS LIKE N'%'+@timkiem+N'%' THEN 10000 ELSE 0 END) +\r\n\r\n                -- \u01afu ti\u00ean 6: S\u1ed1 l\u01b0\u1ee3ng t\u1eeb kho\u00e1 con kh\u1edbp (+50000 \u0111i\u1ec3m cho m\u1ed7i t\u1eeb kh\u1edbp)\r\n                COALESCE((\r\n                    SELECT COUNT(*) * 50000 \r\n                    FROM @Terms T \r\n                    WHERE N' ' + REPLACE(REPLACE(REPLACE(I.ItemName COLLATE Vietnamese_CI_AS, ',', ' '), '.', ' '), '-', ' ') + N' ' LIKE N'% ' + T.Term + N' %' \r\n                       OR N' ' + REPLACE(REPLACE(REPLACE(ISNULL(I.TuKhoa,'') COLLATE Vietnamese_CI_AS, ',', ' '), '.', ' '), '-', ' ') + N' ' LIKE N'% ' + T.Term + N' %'\r\n                ), 0)\r\n            ) AS PriorityScore,\r\n            N'Tri\u1ec7u ch\u1ee9ng: ' + @timkiem + CASE WHEN ISNULL(S.QuantityinStock, 0) <= 0 THEN N' | H\u1ebft h\u00e0ng' ELSE N' | C\u00f2n h\u00e0ng' END AS LyDoGoiY\r\n        INTO #KetQuaKichBan1\r\n        FROM CF_ItemTbl I WITH (NOLOCK)\r\n        LEFT JOIN #TonKho S ON I.ItemID = S.ItemID  \r\n        LEFT JOIN #GiaThiTruong G ON I.ItemID = G.ItemID\r\n        WHERE ISNULL(I.isDisable, 0) = 0\r\n          AND ISNULL(I.ItemGroupID, '') NOT IN ('KM', 'DV', 'VT', 'BB', 'Vat Tu', 'Bao Bi', 'TUI')\r\n          AND I.ItemID NOT LIKE 'BB%' AND I.ItemID NOT LIKE 'TUI%' AND I.ItemID NOT LIKE 'PB%' AND I.ItemID NOT LIKE 'NY%'\r\n          AND (\r\n              I.ItemName COLLATE Vietnamese_CI_AS LIKE N'%'+@timkiem+N'%' OR \r\n              I.TuKhoa COLLATE Vietnamese_CI_AS LIKE N'%'+@timkiem+N'%' OR\r\n              EXISTS (\r\n                  SELECT 1 FROM @Terms T \r\n                  WHERE N' ' + REPLACE(REPLACE(REPLACE(I.ItemName COLLATE Vietnamese_CI_AS, ',', ' '), '.', ' '), '-', ' ') + N' ' LIKE N'% ' + T.Term + N' %' \r\n                     OR N' ' + REPLACE(REPLACE(REPLACE(ISNULL(I.TuKhoa,'') COLLATE Vietnamese_CI_AS, ',', ' '), '.', ' '), '-', ' ') + N' ' LIKE N'% ' + T.Term + N' %'\r\n              )\r\n          )\r\n        ORDER BY PriorityScore DESC;\r\n\r\n        -- Fallback n\u1ebfu kh\u00f4ng t\u00ecm th\u1ea5y g\u00ec\r\n        IF NOT EXISTS (SELECT 1 FROM #KetQuaKichBan1)\r\n        BEGIN\r\n            SELECT \r\n                0 AS DoanhSoDaDat,\r\n                0 AS MucTieuTiepTheo,\r\n                0 AS SoTienConThieu,\r\n                N'R\u1ea5t ti\u1ebfc, h\u1ec7 th\u1ed1ng kh\u00f4ng t\u00ecm th\u1ea5y k\u1ebft qu\u1ea3 n\u00e0o' AS LoiNhacAI,\r\n                'N/A' AS ItemID, \r\n                N'Kh\u00f4ng t\u00ecm th\u1ea5y s\u1ea3n ph\u1ea9m' AS ItemName, \r\n                '' AS Unit, \r\n                0 AS GiaBan,\r\n                0 AS TonKho,\r\n                0 AS PriorityScore,\r\n                N'Vui l\u00f2ng th\u1eed l\u1ea1i v\u1edbi t\u1eeb kh\u00f3a kh\u00e1c ho\u1eb7c ki\u1ec3m tra l\u1ea1i t\u00ean.' AS LyDoGoiY;\r\n        END\r\n        ELSE\r\n        BEGIN\r\n            SELECT * FROM #KetQuaKichBan1 ORDER BY PriorityScore DESC;\r\n        END\r\n        DROP TABLE #KetQuaKichBan1;\r\n    END\r\n    ELSE\r\n    BEGIN\r\n        -- ====================================================================\r\n        -- K\u1ecaCH B\u1ea2N 2: G\u1ee2I \u00dd UPSELL T\u1ef0 \u0110\u1ed8NG (KH\u00d4NG C\u00d3 TRI\u1ec6U CH\u1ee8NG)\r\n        -- Y\u00eau c\u1ea7u: G\u1ee3i \u00fd H\u00e0ng Tr\u1ecdng T\u00e2m, H\u00e0ng B\u00e1n Ch\u1ea1y, Kh\u00e1ch Quen\r\n        -- ====================================================================\r\n        SELECT TOP (@TopN)\r\n            CAST(@DoanhSoHienTai AS BIGINT) AS DoanhSoDaDat,\r\n            CAST(@MucTarget AS BIGINT)      AS MucTieuTiepTheo,\r\n            CAST(@SoTienThieu AS BIGINT)    AS SoTienConThieu,\r\n            CASE \r\n                WHEN @ProgramID = '' THEN N'Hi\u1ec7n kh\u00f4ng c\u00f3 ch\u01b0\u01a1ng tr\u00ecnh t\u00edch l\u0169y n\u00e0o \u0111ang ch\u1ea1y.'\r\n                WHEN @MucTarget > 0  THEN N'Kh\u00e1ch thi\u1ebfu ' + FORMAT(@SoTienThieu, 'N0') + N'\u0111 \u0111\u1ec3 \u0111\u1ea1t m\u1ed1c th\u01b0\u1edfng k\u1ebf ti\u1ebfp.'\r\n                ELSE N'Ch\u00fac m\u1eebng! Kh\u00e1ch \u0111\u00e3 v\u01b0\u1ee3t m\u1ecdi m\u1ed1c th\u01b0\u1edfng cao nh\u1ea5t th\u00e1ng n\u00e0y.'\r\n            END AS LoiNhacAI,\r\n\r\n            I.ItemID, \r\n            I.ItemName, \r\n            I.Unit,\r\n            CAST(ISNULL(G.GiaHienTai, 0) AS BIGINT)   AS GiaBan,\r\n            ISNULL(S.QuantityinStock, 0)               AS TonKho,\r\n            (\r\n                (CASE WHEN TT.ItemID IS NOT NULL THEN 300000 ELSE 0 END) +\r\n                (CASE WHEN ISNULL(S.QuantityinStock,0) > 0 THEN 200000 ELSE 0 END) +\r\n                (CASE WHEN BC.ItemID IS NOT NULL THEN 100000 ELSE 0 END) +\r\n                (CASE WHEN KQ.ItemID IS NOT NULL THEN 500 ELSE 0 END)\r\n            ) AS PriorityScore,\r\n            CASE\r\n                WHEN TT.ItemID IS NOT NULL THEN N'H\u00e0ng TR\u1eccNG T\u00c2M - C\u1ea7n \u0111\u1ea9y!'\r\n                WHEN KQ.ItemID IS NOT NULL THEN N'Combo: H\u00e0ng kh\u00e1ch quen'\r\n                WHEN BC.ItemID IS NOT NULL THEN N'Combo: H\u00e0ng b\u00e1n ch\u1ea1y'\r\n                ELSE N'G\u1ee3i \u00fd s\u1eb5n c\u00f3'\r\n            END AS LyDoGoiY\r\n        INTO #KetQuaKichBan2\r\n        FROM CF_ItemTbl I WITH (NOLOCK)\r\n        LEFT JOIN #TonKho S ON I.ItemID = S.ItemID  \r\n        LEFT JOIN #GiaThiTruong G ON I.ItemID = G.ItemID\r\n        LEFT JOIN #KhachQuen KQ ON I.ItemID = KQ.ItemID\r\n        LEFT JOIN #BanChay BC ON I.ItemID = BC.ItemID\r\n        LEFT JOIN #TrongTam TT ON I.ItemID = TT.ItemID\r\n        WHERE ISNULL(I.isDisable, 0) = 0\r\n          AND ISNULL(I.ItemGroupID, '') NOT IN ('KM', 'DV', 'VT', 'BB', 'Vat Tu', 'Bao Bi', 'TUI')\r\n          AND I.ItemID NOT LIKE 'BB%' AND I.ItemID NOT LIKE 'TUI%' AND I.ItemID NOT LIKE 'PB%' AND I.ItemID NOT LIKE 'NY%'\r\n          AND ISNULL(S.QuantityinStock, 0) > 0\r\n          AND (TT.ItemID IS NOT NULL OR KQ.ItemID IS NOT NULL OR BC.ItemID IS NOT NULL);\r\n\r\n        -- UAT FALLBACK: N\u1ebfu kh\u00f4ng c\u00f3 s\u1ea3n ph\u1ea9m n\u00e0o c\u00f3 s\u1eb5n t\u1ed3n kho, l\u1ea5y c\u1ea3 s\u1ea3n ph\u1ea9m h\u1ebft h\u00e0ng\r\n        IF NOT EXISTS (SELECT 1 FROM #KetQuaKichBan2)\r\n        BEGIN\r\n            INSERT INTO #KetQuaKichBan2\r\n            SELECT TOP (@TopN)\r\n                CAST(@DoanhSoHienTai AS BIGINT) AS DoanhSoDaDat,\r\n                CAST(@MucTarget AS BIGINT)      AS MucTieuTiepTheo,\r\n                CAST(@SoTienThieu AS BIGINT)    AS SoTienConThieu,\r\n                CASE \r\n                    WHEN @ProgramID = '' THEN N'Hi\u1ec7n kh\u00f4ng c\u00f3 ch\u01b0\u01a1ng tr\u00ecnh t\u00edch l\u0169y n\u00e0o \u0111ang ch\u1ea1y.'\r\n                    WHEN @MucTarget > 0  THEN N'Kh\u00e1ch thi\u1ebfu ' + FORMAT(@SoTienThieu, 'N0') + N'\u0111 \u0111\u1ec3 \u0111\u1ea1t m\u1ed1c th\u01b0\u1edfng k\u1ebf ti\u1ebfp.'\r\n                    ELSE N'Ch\u00fac m\u1eebng! Kh\u00e1ch \u0111\u00e3 v\u01b0\u1ee3t m\u1ecdi m\u1ed1c th\u01b0\u1edfng cao nh\u1ea5t th\u00e1ng n\u00e0y.'\r\n                END AS LoiNhacAI,\r\n\r\n                I.ItemID, \r\n                I.ItemName, \r\n                I.Unit,\r\n                CAST(ISNULL(G.GiaHienTai, 0) AS BIGINT)   AS GiaBan,\r\n                ISNULL(S.QuantityinStock, 0)               AS TonKho,\r\n                (\r\n                    (CASE WHEN TT.ItemID IS NOT NULL THEN 300000 ELSE 0 END) +\r\n                    (CASE WHEN ISNULL(S.QuantityinStock,0) > 0 THEN 200000 ELSE 0 END) +\r\n                    (CASE WHEN BC.ItemID IS NOT NULL THEN 100000 ELSE 0 END) +\r\n                    (CASE WHEN KQ.ItemID IS NOT NULL THEN 500 ELSE 0 END)\r\n                ) AS PriorityScore,\r\n                CASE\r\n                    WHEN TT.ItemID IS NOT NULL THEN N'H\u00e0ng TR\u1eccNG T\u00c2M (H\u1ebft h\u00e0ng)'\r\n                    WHEN KQ.ItemID IS NOT NULL THEN N'Combo: H\u00e0ng kh\u00e1ch quen (H\u1ebft h\u00e0ng)'\r\n                    WHEN BC.ItemID IS NOT NULL THEN N'Combo: H\u00e0ng b\u00e1n ch\u1ea1y (H\u1ebft h\u00e0ng)'\r\n                    ELSE N'G\u1ee3i \u00fd s\u1eb5n c\u00f3 (H\u1ebft h\u00e0ng)'\r\n                END AS LyDoGoiY\r\n            FROM CF_ItemTbl I WITH (NOLOCK)\r\n            LEFT JOIN #TonKho S ON I.ItemID = S.ItemID  \r\n            LEFT JOIN #GiaThiTruong G ON I.ItemID = G.ItemID\r\n            LEFT JOIN #KhachQuen KQ ON I.ItemID = KQ.ItemID\r\n            LEFT JOIN #BanChay BC ON I.ItemID = BC.ItemID\r\n            LEFT JOIN #TrongTam TT ON I.ItemID = TT.ItemID\r\n            WHERE ISNULL(I.isDisable, 0) = 0\r\n              AND ISNULL(I.ItemGroupID, '') NOT IN ('KM', 'DV', 'VT', 'BB', 'Vat Tu', 'Bao Bi', 'TUI')\r\n              AND I.ItemID NOT LIKE 'BB%' AND I.ItemID NOT LIKE 'TUI%' AND I.ItemID NOT LIKE 'PB%' AND I.ItemID NOT LIKE 'NY%'\r\n              AND (TT.ItemID IS NOT NULL OR KQ.ItemID IS NOT NULL OR BC.ItemID IS NOT NULL);\r\n        END\r\n\r\n        SELECT * FROM #KetQuaKichBan2 ORDER BY PriorityScore DESC, TonKho DESC;\r\n        DROP TABLE #KetQuaKichBan2;\r\n    END\r\n\r\n    DROP TABLE #GiaThiTruong; DROP TABLE #KhachQuen; DROP TABLE #BanChay; DROP TABLE #TonKho; DROP TABLE #LatestPriceHeader; DROP TABLE #TrongTam;\r\nEND"
      },
      "id": "scope-patch-4",
      "name": "Patch UpsellGoiY",
      "type": "n8n-nodes-base.microsoftSql",
      "typeVersion": 1,
      "position": [
        960,
        0
      ],
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "\nSELECT p.name AS StoredProcedure,\n       CASE WHEN m.definition LIKE '%UPPER(@SYSUserGroupID)%<>%''ADMIN''%'\n             AND m.definition LIKE '%@SYSBranchID = ''''%'\n             AND m.definition LIKE '%RETURN%' THEN 1 ELSE 0 END AS HasFailClosedScopeGuard\nFROM sys.procedures p\nJOIN sys.sql_modules m ON m.object_id = p.object_id\nWHERE p.name IN ('API_DeXuatKhuyenMai_AI','API_SanPhamTrongTam_AI','API_TichLuy_AI','API_UpsellGoiY_AI')\nORDER BY p.name;\n"
      },
      "id": "scope-verify",
      "name": "Verify Scope Patches",
      "type": "n8n-nodes-base.microsoftSql",
      "typeVersion": 1,
      "position": [
        1200,
        0
      ],
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Run Scope Patches": {
      "main": [
        [
          {
            "node": "Patch DeXuatKhuyenMai",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Patch DeXuatKhuyenMai": {
      "main": [
        [
          {
            "node": "Patch SanPhamTrongTam",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Patch SanPhamTrongTam": {
      "main": [
        [
          {
            "node": "Patch TichLuy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Patch TichLuy": {
      "main": [
        [
          {
            "node": "Patch UpsellGoiY",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Patch UpsellGoiY": {
      "main": [
        [
          {
            "node": "Verify Scope Patches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false,
  "tags": []
}