ducnt 1 ヶ月 前
コミット
3efb225223

+ 2 - 0
EsimLao/Common/Constant/CommonConstant.cs

@@ -170,6 +170,8 @@ public static class ApiUrlConstant
     public const String CustomerReviewCreateUrl = "/apis/content/review/create";
     public const String FaqCategoryLoadUrl = "/apis/content/faq-category";
     public const String FaqLoadUrl = "/apis/content/faq";
+    public const String DeviceCompatibilityLoadUrl = "/apis/content/device-compatibility";
+    public const String DeviceMetadataUrl = "/apis/content/device-metadata";
 }
 
 public static class CommonErrorCode

+ 36 - 0
EsimLao/Database/Database/DeviceEsimCompatibility.cs

@@ -0,0 +1,36 @@
+using System;
+
+namespace Database.Database;
+
+public partial class DeviceEsimCompatibility
+{
+    public int Id { get; set; }
+
+    public string Brand { get; set; } = null!;
+
+    public string ModelName { get; set; } = null!;
+
+    public string? ModelNameEn { get; set; }
+
+    public string? ModelNameLo { get; set; }
+
+    public bool? SupportsEsim { get; set; }
+
+    public string? Category { get; set; }
+
+    public string? Notes { get; set; }
+
+    public string? NotesEn { get; set; }
+
+    public string? NotesLo { get; set; }
+
+    public bool? IsPopular { get; set; }
+
+    public int? DisplayOrder { get; set; }
+
+    public bool? Status { get; set; }
+
+    public DateTime? CreatedDate { get; set; }
+
+    public DateTime? UpdatedDate { get; set; }
+}

+ 68 - 0
EsimLao/Database/Database/ModelContext.cs

@@ -39,6 +39,8 @@ public partial class ModelContext : DbContext
 
     public virtual DbSet<CustomerReview> CustomerReviews { get; set; }
 
+    public virtual DbSet<DeviceEsimCompatibility> DeviceEsimCompatibilities { get; set; }
+
     public virtual DbSet<Faq> Faqs { get; set; }
 
     public virtual DbSet<FaqCategory> FaqCategories { get; set; }
@@ -742,6 +744,72 @@ public partial class ModelContext : DbContext
                 .HasColumnName("STATUS");
         });
 
+        modelBuilder.Entity<DeviceEsimCompatibility>(entity =>
+        {
+            entity.HasKey(e => e.Id).HasName("DEVICE_ESIM_COMPATIBILITY_PK");
+
+            entity.ToTable("DEVICE_ESIM_COMPATIBILITY");
+
+            entity.HasIndex(e => e.Brand, "IDX_DEVICE_BRAND");
+            entity.HasIndex(e => e.ModelName, "IDX_DEVICE_MODEL");
+            entity.HasIndex(e => new { e.IsPopular, e.Status }, "IDX_DEVICE_POPULAR");
+            entity.HasIndex(e => new { e.Category, e.Status }, "IDX_DEVICE_CATEGORY");
+
+            entity.Property(e => e.Id)
+                .HasPrecision(10)
+                .ValueGeneratedNever()
+                .HasColumnName("ID");
+            entity.Property(e => e.Brand)
+                .HasMaxLength(100)
+                .HasColumnName("BRAND");
+            entity.Property(e => e.ModelName)
+                .HasMaxLength(200)
+                .HasColumnName("MODEL_NAME");
+            entity.Property(e => e.ModelNameEn)
+                .HasMaxLength(200)
+                .HasColumnName("MODEL_NAME_EN");
+            entity.Property(e => e.ModelNameLo)
+                .HasMaxLength(200)
+                .HasColumnName("MODEL_NAME_LO");
+            entity.Property(e => e.SupportsEsim)
+                .HasPrecision(1)
+                .HasDefaultValueSql("1")
+                .HasColumnName("SUPPORTS_ESIM");
+            entity.Property(e => e.Category)
+                .HasMaxLength(50)
+                .IsUnicode(false)
+                .HasDefaultValueSql("'Phone'")
+                .HasColumnName("CATEGORY");
+            entity.Property(e => e.Notes)
+                .HasMaxLength(1000)
+                .HasColumnName("NOTES");
+            entity.Property(e => e.NotesEn)
+                .HasMaxLength(1000)
+                .HasColumnName("NOTES_EN");
+            entity.Property(e => e.NotesLo)
+                .HasMaxLength(1000)
+                .HasColumnName("NOTES_LO");
+            entity.Property(e => e.IsPopular)
+                .HasPrecision(1)
+                .HasDefaultValueSql("0")
+                .HasColumnName("IS_POPULAR");
+            entity.Property(e => e.DisplayOrder)
+                .HasPrecision(10)
+                .HasDefaultValueSql("999")
+                .HasColumnName("DISPLAY_ORDER");
+            entity.Property(e => e.Status)
+                .HasPrecision(1)
+                .HasDefaultValueSql("1")
+                .HasColumnName("STATUS");
+            entity.Property(e => e.CreatedDate)
+                .HasDefaultValueSql("SYSDATE")
+                .HasColumnType("DATE")
+                .HasColumnName("CREATED_DATE");
+            entity.Property(e => e.UpdatedDate)
+                .HasColumnType("DATE")
+                .HasColumnName("UPDATED_DATE");
+        });
+
         modelBuilder.Entity<Faq>(entity =>
         {
             entity.HasKey(e => e.Id).HasName("FAQ_PK");

+ 162 - 0
EsimLao/Esim.Apis/Business/Content/ContentBusinessImpl.cs

@@ -2,6 +2,7 @@ using Common;
 using Common.Constant;
 using Common.Http;
 using Common.Logic;
+using Esim.Apis.DTO.Content;
 using Esim.Apis.Singleton;
 using Database.Database;
 using log4net;
@@ -330,5 +331,166 @@ namespace Esim.Apis.Business
             );
         }
 
+        /// <summary>
+        /// Load device eSIM compatibility list
+        /// </summary>
+        public async Task<IActionResult> DeviceCompatibilityLoad(HttpRequest httpRequest, DeviceCompatibilityReq request)
+        {
+            var url = httpRequest.Path;
+            var json = JsonConvert.SerializeObject(request);
+            log.Debug("URL: " + url + " => Request: " + json);
+            try
+            {
+                string lang = CommonLogic.GetLanguage(httpRequest, request.lang);
+                int pageNumber = request.pageNumber < 0 ? 0 : request.pageNumber;
+                int pageSize = request.pageSize <= 0 ? 50 : request.pageSize;
+
+                // Base query - only active devices
+                var query = dbContext.DeviceEsimCompatibilities
+                    .Where(d => d.Status == true && d.SupportsEsim == true);
+
+                // Filter by brand
+                if (!string.IsNullOrEmpty(request.brand))
+                {
+                    query = query.Where(d => d.Brand == request.brand);
+                }
+
+                // Filter by category
+                if (!string.IsNullOrEmpty(request.category))
+                {
+                    query = query.Where(d => d.Category == request.category);
+                }
+
+                // Filter by popular flag
+                if (request.isPopular.HasValue && request.isPopular.Value)
+                {
+                    query = query.Where(d => d.IsPopular == true);
+                }
+
+                // Search by keyword in model name (all language variants)
+                if (!string.IsNullOrEmpty(request.searchKeyword))
+                {
+                    var keyword = request.searchKeyword.ToLower();
+                    query = query.Where(d =>
+                        d.ModelName.ToLower().Contains(keyword) ||
+                        (d.ModelNameEn != null && d.ModelNameEn.ToLower().Contains(keyword)) ||
+                        (d.ModelNameLo != null && d.ModelNameLo.ToLower().Contains(keyword))
+                    );
+                }
+
+                // Get total count for pagination
+                int totalCount = query.Count();
+                int totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
+
+                // Apply pagination and ordering
+                var devices = query
+                    .OrderBy(d => d.DisplayOrder)
+                    .ThenBy(d => d.Brand)
+                    .ThenBy(d => d.ModelName)
+                    .Skip(pageNumber * pageSize)
+                    .Take(pageSize)
+                    .Select(d => new
+                    {
+                        d.Id,
+                        d.Brand,
+                        modelName = lang == "en"
+                            ? (d.ModelNameEn ?? d.ModelName)
+                            : (d.ModelNameLo ?? d.ModelName),
+                        d.Category,
+                        notes = lang == "en"
+                            ? (d.NotesEn ?? d.Notes)
+                            : (d.NotesLo ?? d.Notes),
+                        supportsEsim = d.SupportsEsim ?? true,
+                        isPopular = d.IsPopular ?? false,
+                        displayOrder = d.DisplayOrder ?? 999
+                    })
+                    .ToList();
+
+                return ApiResponseHelper.BuildResponse(
+                    log, url, json,
+                    CommonErrorCode.Success,
+                    ConfigManager.Instance.GetConfigWebValue("LOAD_SUCCESS", lang),
+                    new
+                    {
+                        devices = devices,
+                        pagination = new
+                        {
+                            pageNumber,
+                            pageSize,
+                            totalCount,
+                            totalPages
+                        }
+                    }
+                );
+            }
+            catch (Exception exception)
+            {
+                log.Error("Exception: ", exception);
+            }
+            return ApiResponseHelper.BuildResponse(
+                log, url, json,
+                CommonErrorCode.SystemError,
+                ConfigManager.Instance.GetConfigWebValue("SYSTEM_FAILURE"),
+                new { }
+            );
+        }
+
+        /// <summary>
+        /// Get list of device brands and categories (for filters/tabs)
+        /// </summary>
+        public async Task<IActionResult> GetDeviceBrandsAndCategories(HttpRequest httpRequest)
+        {
+            var url = httpRequest.Path;
+            log.Debug("URL: " + url);
+            try
+            {
+                // Get distinct brands with device count
+                var brands = dbContext.DeviceEsimCompatibilities
+                    .Where(d => d.Status == true && d.SupportsEsim == true)
+                    .GroupBy(d => d.Brand)
+                    .Select(g => new
+                    {
+                        brand = g.Key,
+                        deviceCount = g.Count(),
+                        popularCount = g.Count(d => d.IsPopular == true)
+                    })
+                    .OrderBy(b => b.brand)
+                    .ToList();
+
+                // Get distinct categories with device count
+                var categories = dbContext.DeviceEsimCompatibilities
+                    .Where(d => d.Status == true && d.SupportsEsim == true)
+                    .GroupBy(d => d.Category)
+                    .Select(g => new
+                    {
+                        category = g.Key,
+                        deviceCount = g.Count()
+                    })
+                    .OrderBy(c => c.category)
+                    .ToList();
+
+                return ApiResponseHelper.BuildResponse(
+                    log, url, "",
+                    CommonErrorCode.Success,
+                    ConfigManager.Instance.GetConfigWebValue("LOAD_SUCCESS"),
+                    new
+                    {
+                        brands = brands,
+                        categories = categories
+                    }
+                );
+            }
+            catch (Exception exception)
+            {
+                log.Error("Exception: ", exception);
+            }
+            return ApiResponseHelper.BuildResponse(
+                log, url, "",
+                CommonErrorCode.SystemError,
+                ConfigManager.Instance.GetConfigWebValue("SYSTEM_FAILURE"),
+                new { }
+            );
+        }
+
     }
 }

+ 4 - 0
EsimLao/Esim.Apis/Business/Content/IContentBusiness.cs

@@ -1,6 +1,7 @@
 
 using System;
 using Common.Http;
+using Esim.Apis.DTO.Content;
 using Microsoft.AspNetCore.Mvc;
 
 namespace Esim.Apis.Business
@@ -14,5 +15,8 @@ namespace Esim.Apis.Business
 
         Task<IActionResult> FaqCategoryLoad(HttpRequest httpRequest, FaqCategoryLoadReq request);
         Task<IActionResult> FaqLoad(HttpRequest httpRequest, FaqLoadReq request);
+
+        Task<IActionResult> DeviceCompatibilityLoad(HttpRequest httpRequest, DeviceCompatibilityReq request);
+        Task<IActionResult> GetDeviceBrandsAndCategories(HttpRequest httpRequest);
     }
 }

+ 23 - 0
EsimLao/Esim.Apis/Controllers/ContentController.cs

@@ -3,6 +3,7 @@ using Common;
 using Common.Constant;
 using Common.Http;
 using Esim.Apis.Business;
+using Esim.Apis.DTO.Content;
 using Database.Database;
 using Microsoft.AspNetCore.Mvc;
 
@@ -77,5 +78,27 @@ namespace RevoSystem.Apis.Controllers
             return await contentBusiness.FaqLoad(HttpContext.Request, request);
         }
 
+        /// <summary>
+        /// Load device eSIM compatibility list
+        /// POST /apis/content/device-compatibility
+        /// </summary>
+        [HttpPost]
+        [Route(ApiUrlConstant.DeviceCompatibilityLoadUrl)]
+        public async Task<IActionResult> DeviceCompatibilityLoad(DeviceCompatibilityReq request)
+        {
+            return await contentBusiness.DeviceCompatibilityLoad(HttpContext.Request, request);
+        }
+
+        /// <summary>
+        /// Get device brands and categories list (for filters)
+        /// GET /apis/content/device-metadata
+        /// </summary>
+        [HttpGet]
+        [Route(ApiUrlConstant.DeviceMetadataUrl)]
+        public async Task<IActionResult> GetDeviceBrandsAndCategories()
+        {
+            return await contentBusiness.GetDeviceBrandsAndCategories(HttpContext.Request);
+        }
+
     }
 }

+ 52 - 0
EsimLao/Esim.Apis/DTO/Content/DeviceCompatibilityReq.cs

@@ -0,0 +1,52 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Esim.Apis.DTO.Content
+{
+    /// <summary>
+    /// Request DTO for device eSIM compatibility check
+    /// </summary>
+    public class DeviceCompatibilityReq
+    {
+        /// <summary>
+        /// Brand filter (Apple, Samsung, Google, etc.)
+        /// null = all brands
+        /// </summary>
+        public string? brand { get; set; }
+
+        /// <summary>
+        /// Device category filter (Phone, Tablet, Laptop, Watch)
+        /// null = all categories
+        /// </summary>
+        public string? category { get; set; }
+
+        /// <summary>
+        /// Search keyword for model name
+        /// Searches in MODEL_NAME, MODEL_NAME_EN, MODEL_NAME_LO
+        /// </summary>
+        public string? searchKeyword { get; set; }
+
+        /// <summary>
+        /// Filter popular devices only (for quick lookup tabs)
+        /// true = only popular devices
+        /// false/null = all devices
+        /// </summary>
+        public bool? isPopular { get; set; }
+
+        /// <summary>
+        /// Language for response (lo, en, vi)
+        /// Default: "lo"
+        /// </summary>
+        public string? lang { get; set; }
+
+        /// <summary>
+        /// Page number (0-indexed)
+        /// </summary>
+        public int pageNumber { get; set; } = 0;
+
+        /// <summary>
+        /// Page size
+        /// Default: 50 (higher than other APIs for device list)
+        /// </summary>
+        public int pageSize { get; set; } = 50;
+    }
+}