Browse Source

update bản prod

ducnt 1 month ago
parent
commit
bf11576983
29 changed files with 671 additions and 250 deletions
  1. 3 2
      SicboSub/Common/Constant/CommonConstant.cs
  2. 114 2
      SicboSub/SicboSub.Api/Business/ExchangeBusinessImpl.cs
  3. 2 2
      SicboSub/SicboSub.Api/Business/GameBusinessImpl.cs
  4. 5 0
      SicboSub/SicboSub.Api/Business/IExchangeBusiness.cs
  5. 35 1
      SicboSub/SicboSub.Api/Business/UserBusinessImpl.cs
  6. 11 0
      SicboSub/SicboSub.Api/Controllers/ExchangeController.cs
  7. 13 0
      SicboSub/SicboSub.Api/DTO/ExchangeDto.cs
  8. 2 0
      SicboSub/SicboSub.Api/DTO/UserDto.cs
  9. 3 4
      SicboSub/SicboSub.Api/Program.cs
  10. 7 4
      SicboSub/SicboSub.Api/appsettings.json
  11. 4 1
      SicboSub/SicboSub.StartProcedure/Program.cs
  12. 2 2
      SicboSub/SicboSub.StartProcedure/RankingService.cs
  13. 8 3
      SicboSub/SicboSub.StartProcedure/appsettings.json
  14. 87 7
      SicboSub/SicboSub.Web/Controllers/HomeController.cs
  15. 81 72
      SicboSub/SicboSub.Web/Language/Language.Designer.cs
  16. 75 72
      SicboSub/SicboSub.Web/Language/Language.resx
  17. 35 32
      SicboSub/SicboSub.Web/Language/Language.vi.resx
  18. 29 1
      SicboSub/SicboSub.Web/Models/AuthModels.cs
  19. 40 0
      SicboSub/SicboSub.Web/Models/HistoryModels.cs
  20. 1 0
      SicboSub/SicboSub.Web/Models/HistoryViewModel.cs
  21. 2 2
      SicboSub/SicboSub.Web/Views/Home/Account.cshtml
  22. 51 4
      SicboSub/SicboSub.Web/Views/Home/History.cshtml
  23. 2 2
      SicboSub/SicboSub.Web/Views/Home/Index.cshtml
  24. 20 7
      SicboSub/SicboSub.Web/Views/Shared/_GameLayout.cshtml
  25. 2 1
      SicboSub/SicboSub.Web/appsettings.json
  26. 24 24
      SicboSub/SicboSub.Web/wwwroot/js/site.js
  27. 10 2
      SicboSubWs/SicboSubWs/src/com/vas/webservices/SicboSubWs.java
  28. 3 3
      SicboSubWs/etc/database.xml
  29. BIN
      SicboSub_Request to create domain name and map with public IP.docx

+ 3 - 2
SicboSub/Common/Constant/CommonConstant.cs

@@ -3,8 +3,8 @@
 public static class CommonConstant
 {
 
-    public const string Channel = "1542";
-    public const string CountryCode = "258";
+    public const string Channel = "2425";
+    public const string CountryCode = "509";
 
     public const string Success = "0";
     public const string Error = "-1";
@@ -118,6 +118,7 @@ public static class ApiUrlConstant
     public const String ExchangeRequestOtpUrl = "/apis/exchange/request-otp";
     public const String ExchangeVerifyOtpUrl = "/apis/exchange/verify-otp";
     public const String ExchangeResendOtpUrl = "/apis/exchange/resend-otp";
+    public const String ExchangeHistoryUrl = "/apis/exchange/history";
 
     // Auth URLs
     public const String AuthLoginUrl = "/apis/auth/login";

+ 114 - 2
SicboSub/SicboSub.Api/Business/ExchangeBusinessImpl.cs

@@ -190,8 +190,8 @@ namespace SicboSub.Api.Business
                 }
 
                 // 9. Generate new OTP
-                //string otpCode = GenerateOtpCode();
-                string otpCode = "111111";
+                string otpCode = GenerateOtpCode();
+                //string otpCode = "111111";
                 var now = DateTime.Now;
                 var expiredTime = now.AddMinutes(OTP_EXPIRE_MINUTES);
 
@@ -593,6 +593,118 @@ namespace SicboSub.Api.Business
             );
         }
 
+        /// <summary>
+        /// Lấy lịch sử rút đổi thưởng
+        /// </summary>
+        public async Task<IActionResult> GetHistory(HttpRequest httpRequest, ExchangeHistoryReq request)
+        {
+            var url = httpRequest.Path;
+            var json = JsonConvert.SerializeObject(request);
+            log.Debug("URL: " + url + " => Request: " + json);
+
+            try
+            {
+                string lang = CommonLogic.GetLanguage(httpRequest, request.lang);
+
+                // 1. Validate token
+                string token = httpRequest.Headers["Authorization"].ToString();
+                if (string.IsNullOrEmpty(token))
+                {
+                    return DotnetLib.Http.HttpResponse.BuildResponse(
+                        log, url, json,
+                        CommonErrorCode.UnauthorizedAccess,
+                        ConfigManager.Instance.GetConfigWebValue("UNAUTHORIZED", lang),
+                        new { }
+                    );
+                }
+
+                // 2. Validate request
+                if (string.IsNullOrEmpty(request.msisdn))
+                {
+                    return DotnetLib.Http.HttpResponse.BuildResponse(
+                        log, url, json,
+                        CommonErrorCode.InvalidParameter,
+                        ConfigManager.Instance.GetConfigWebValue("INVALID_PARAM", lang),
+                        new { }
+                    );
+                }
+
+                // 3. Build query
+                var query = dbContext.ExchangeHistories.AsNoTracking()
+                    .Where(x => x.Msisdn == request.msisdn);
+
+                // 4. Filter by date
+                if (!string.IsNullOrEmpty(request.fromDate))
+                {
+                    if (DateTime.TryParseExact(request.fromDate, "dd/MM/yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime fromDate))
+                    {
+                        query = query.Where(x => x.ExchangeTime >= fromDate);
+                    }
+                }
+
+                if (!string.IsNullOrEmpty(request.toDate))
+                {
+                    if (DateTime.TryParseExact(request.toDate, "dd/MM/yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime toDate))
+                    {
+                        query = query.Where(x => x.ExchangeTime <= toDate);
+                    }
+                }
+
+                // 5. Sort & Paging
+                query = query.OrderByDescending(x => x.ExchangeTime);
+
+                var total = await query.CountAsync();
+                
+                int pageIdx = request.pageNumber > 0 ? request.pageNumber : 0;
+                int pageSize = request.pageSize > 0 ? request.pageSize : 20;
+
+                var data = await query.Skip(pageIdx * pageSize).Take(pageSize).ToListAsync();
+
+                // 6. Map to DTO
+                var result = data.Select(x => new ExchangeHistoryRes
+                {
+                    id = x.Id ?? 0,
+                    msisdn = x.Msisdn ?? "",
+                    coinDeducted = x.CoinDeducted ?? 0,
+                    moneyAdded = x.MoneyAdded ?? 0,
+                    exchangeTime = x.ExchangeTime ?? DateTime.MinValue,
+                    status = x.Status ?? 0,
+                    // Map status name can be done here or FE
+                    statusName = GetStatusName(x.Status, lang)
+                }).ToList();
+
+                return DotnetLib.Http.HttpResponse.BuildResponse(
+                    log, url, json,
+                    CommonErrorCode.Success,
+                    "Success",
+                    result
+                );
+            }
+            catch (Exception ex)
+            {
+                log.Error("Exception: ", ex);
+            }
+
+            return DotnetLib.Http.HttpResponse.BuildResponse(
+                log, url, json,
+                CommonErrorCode.SystemError,
+                ConfigManager.Instance.GetConfigWebValue("SYSTEM_FAILURE"),
+                new { }
+            );
+        }
+
+        private string GetStatusName(byte? status, string lang)
+        {
+            // Simple mapping, can be improved with config
+            return status switch
+            {
+                0 => ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_PENDING", lang) == "" ? "Pending" : ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_PENDING", lang),
+                1 => ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_SUCCESS", lang) == "" ? "Success" : ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_SUCCESS", lang),
+                2 => ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_FAILED", lang) == "" ? "Failed" : ConfigManager.Instance.GetConfigWebValue("EXCHANGE_STATUS_FAILED", lang),
+                _ => "Unknown"
+            };
+        }
+
         #region Private Helper Methods
 
         /// <summary>

+ 2 - 2
SicboSub/SicboSub.Api/Business/GameBusinessImpl.cs

@@ -185,7 +185,7 @@ namespace SicboSub.Api.Business
                 {
                     if (DateTime.TryParseExact(request.fromDate, "dd/MM/yyyy HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out DateTime from))
                     {
-                        query = query.Where(x => x.reward.RewardDate >= from);
+                        query = query.Where(x => x.ranking.RankDate >= from);
                     }
                 }
 
@@ -193,7 +193,7 @@ namespace SicboSub.Api.Business
                 {
                     if (DateTime.TryParseExact(request.toDate, "dd/MM/yyyy HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out DateTime to))
                     {
-                        query = query.Where(x => x.reward.RewardDate <= to);
+                        query = query.Where(x => x.ranking.RankDate <= to);
                     }
                 }
 

+ 5 - 0
SicboSub/SicboSub.Api/Business/IExchangeBusiness.cs

@@ -22,5 +22,10 @@ namespace SicboSub.Api.Business
         /// Gửi lại OTP (resend)
         /// </summary>
         Task<IActionResult> ResendOtp(HttpRequest httpRequest, ExchangeResendOtpReq request);
+
+        /// <summary>
+        /// Lấy lịch sử đổi thưởng
+        /// </summary>
+        Task<IActionResult> GetHistory(HttpRequest httpRequest, ExchangeHistoryReq request);
     }
 }

+ 35 - 1
SicboSub/SicboSub.Api/Business/UserBusinessImpl.cs

@@ -68,6 +68,38 @@ namespace SicboSub.Api.Business
                     );
                 }
 
+                // Check active registration (Daily)
+                string productCode = configuration.GetSection("PackageCodeDaily").Value;
+                if (string.IsNullOrEmpty(productCode)) productCode = "SICBO_DAY";
+
+                bool isRegistered = false;
+                RegInfoDto? regPkg = null;
+
+                var regInfo = await dbContext.RegInfos.AsNoTracking()
+                    .Where(r => r.Msisdn == user.Msisdn 
+                             && r.ProductName == productCode // Check config package
+                             && r.Renew == 1 
+                             && r.Status == 1 
+                             && r.ExpireTime > DateTime.Now)
+                    .OrderByDescending(r => r.RegisterTime)
+                    .FirstOrDefaultAsync();
+
+                if (regInfo != null)
+                {
+                    isRegistered = true;
+                    regPkg = new RegInfoDto
+                    {
+                        RegisterId = regInfo.RegisterId,
+                        Msisdn = regInfo.Msisdn,
+                        ProductName = regInfo.ProductName,
+                        RegisterTime = regInfo.RegisterTime,
+                        NumberSpin = regInfo.NumberSpin,
+                        Status = (byte)(regInfo.Status),
+                        ExpireTime = regInfo.ExpireTime,
+                        Renew = (byte)(regInfo.Renew ?? 0)
+                    };
+                }
+
                 var result = new AccountInfoRes
                 {
                     id = user.Id,
@@ -87,7 +119,9 @@ namespace SicboSub.Api.Business
                     isActive = user.IsActive,
                     createdDate = user.CreatedDate,
                     lastLogin = user.LastLogin,
-                    betCoin = user.BetCoin
+                    betCoin = user.BetCoin,
+                    isRegistered = isRegistered,
+                    regPkg = regPkg
                 };
 
                 return DotnetLib.Http.HttpResponse.BuildResponse(

+ 11 - 0
SicboSub/SicboSub.Api/Controllers/ExchangeController.cs

@@ -52,5 +52,16 @@ namespace SicboSub.Api.Controllers
         {
             return await exchangeBusiness.ResendOtp(HttpContext.Request, request);
         }
+
+        /// <summary>
+        /// Lấy lịch sử rút đổi thưởng
+        /// POST /apis/exchange/history
+        /// </summary>
+        [HttpPost]
+        [Route(ApiUrlConstant.ExchangeHistoryUrl)]
+        public async Task<IActionResult> GetHistory([FromBody] ExchangeHistoryReq request)
+        {
+            return await exchangeBusiness.GetHistory(HttpContext.Request, request);
+        }
     }
 }

+ 13 - 0
SicboSub/SicboSub.Api/DTO/ExchangeDto.cs

@@ -31,6 +31,19 @@ namespace SicboSub.Api.DTO
         public string? lang { get; set; }
     }
 
+    /// <summary>
+    /// Request lịch sử đổi thưởng
+    /// </summary>
+    public class ExchangeHistoryReq
+    {
+        public string msisdn { get; set; } = null!;
+        public string? lang { get; set; }
+        public string? fromDate { get; set; }
+        public string? toDate { get; set; }
+        public int pageNumber { get; set; }
+        public int pageSize { get; set; }
+    }
+
     #endregion
 
     #region Response DTOs

+ 2 - 0
SicboSub/SicboSub.Api/DTO/UserDto.cs

@@ -26,5 +26,7 @@ namespace SicboSub.Api.DTO
         public byte? isActive { get; set; }
         public DateTime createdDate { get; set; }
         public DateTime? lastLogin { get; set; }
+        public bool isRegistered { get; set; }
+        public RegInfoDto? regPkg { get; set; }
     }
 }

+ 3 - 4
SicboSub/SicboSub.Api/Program.cs

@@ -61,11 +61,10 @@ using (var scope = app.Services.CreateScope())
     var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
     try
     {
-        logger.LogInformation("Initializing ConfigManager...");
-        ConfigManager.Instance.Initialize();
-        logger.LogInformation("ConfigManager initialized successfully");
+        logger.LogInformation("Initializing ConfigManager (Async)...");
         
-        // Start background refresh task
+        // Start background refresh task immediately
+        // Does not block main thread prevents startup hang if DB connection fails
         Task.Run(() => ConfigManager.Instance.RefreshConfigs());
     }
     catch (Exception ex)

+ 7 - 4
SicboSub/SicboSub.Api/appsettings.json

@@ -1,13 +1,16 @@
 {
-  "Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1539))(CONNECT_DATA=(SERVICE_NAME=ORA12C)));User Id=sicbo;Password=qwK99QfuhEmcFE;Connection Timeout=120;",
+  //"Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1539))(CONNECT_DATA=(SERVICE_NAME=ORA12C)));User Id=sicbo;Password=qwK99QfuhEmcFE;Connection Timeout=120;",
+  //"wsUser": "sicboSub",
+  //"wsPass": "123456a@",
+  "Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdbvas1)));User Id=SICBO;Password=S1cbo$2025;Connection Timeout=120;",
   "wsUrl": "http://127.0.0.1:8199/SicboSubWs?wsdl",
-  "wsUser": "sicboSub",
-  "wsPass": "123456a@",
+  "wsUser": "ws_SicboSub",
+  "wsPass": "SicboSub@123",
   "PackageCodeDaily": "SICBO_DAILY",
   "Kestrel": {
     "EndPoints": {
       "Http": {
-        "Url": "http://127.0.0.1:9106"
+        "Url": "http://127.0.0.1:8741"
       }
     }
   },

+ 4 - 1
SicboSub/SicboSub.StartProcedure/Program.cs

@@ -43,6 +43,7 @@ namespace SicboSub.StartProcedure
             }
 
             var service = new RankingService(connectionString, config);
+            var exchangeService = new ExchangeService(connectionString, config);
 
             // 2. Phân tích tham số đầu vào hoặc Chạy mặc định
             // Cách dùng: 
@@ -119,6 +120,9 @@ namespace SicboSub.StartProcedure
                         {
                              if (DateTime.Now.Day != 1) lastMonthlyRunDay = -1;
                         }
+
+                        // Run Exchange Processing specifically in Daily mode (common use case)
+                         await exchangeService.ExecuteExchangeProcessingAsync();
                     }
                     else if (mode == "MONTHLY")
                     {
@@ -129,7 +133,6 @@ namespace SicboSub.StartProcedure
                     }
                     else if (mode == "EXCHANGE")
                     {
-                        var exchangeService = new ExchangeService(connectionString, config);
                         await exchangeService.ExecuteExchangeProcessingAsync();
                     }
 

+ 2 - 2
SicboSub/SicboSub.StartProcedure/RankingService.cs

@@ -173,8 +173,8 @@ namespace SicboSub.StartProcedure
                         wsPackage,
                         reward.REWARD_VALUE.ToString(),
                         wsPackage,
-                        null, 
-                        "Ranking Reward"
+                        reward.RANK_POSITION.ToString(),
+                        reward.RANK_TYPE
                     );
 
                      if (response != null && response.@return != null && response.@return.errorCode == "0")

+ 8 - 3
SicboSub/SicboSub.StartProcedure/appsettings.json

@@ -1,6 +1,11 @@
 {
-  "Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1539))(CONNECT_DATA=(SERVICE_NAME=ORA12C)));User Id=sicbo;Password=qwK99QfuhEmcFE;Connection Timeout=120;",
+  //"Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1539))(CONNECT_DATA=(SERVICE_NAME=ORA12C)));User Id=sicbo;Password=qwK99QfuhEmcFE;Connection Timeout=120;",
   "wsUrl": "http://127.0.0.1:8199/SicboSubWs?wsdl",
-  "wsUser": "sicboSub",
-  "wsPass": "123456a@"
+  //"wsUser": "sicboSub",
+  //"wsPass": "123456a@",
+  "Connection": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdbvas1)));User Id=SICBO;Password=S1cbo$2025;Connection Timeout=120;",
+  //"wsUrl": "http://127.0.0.1:8720/SicboSubWs?wsdl",
+  "wsUser": "ws_SicboSub",
+  "wsPass": "SicboSub@123",
+  "SERVICE_ID": "SICBO_DAILY"
 }

+ 87 - 7
SicboSub/SicboSub.Web/Controllers/HomeController.cs

@@ -125,12 +125,12 @@ namespace SicboSub.Web.Controllers
                 var token = GetToken();
                 if (!string.IsNullOrEmpty(token))
                 {
-                   var request = new TokenLoginReq
+                   var request = new AccountInfoReq
                     {
-                        token = token,
-                        language = GetLanguage()
+                        msisdn = GetMsisdn(),
+                        lang = GetLanguage()
                     };
-                    var url = GetParameter("Url") + ApiUrlConstant.AuthLoginUrl;
+                    var url = GetParameter("Url") + ApiUrlConstant.UserInfoUrl;
                     // Gọi API xác thực/lấy thông tin
                     var resData = await DotnetLib.Rest.RestHandler.SendPostWithAuthen(
                         log,
@@ -144,13 +144,35 @@ namespace SicboSub.Web.Controllers
                     
                     if (resData != null)
                     {
-                        TokenLoginRes response = new TokenLoginRes(resData.data);
+                        AccountInfoRes response = new AccountInfoRes(resData.data);
                         if (response.errorCode == CommonErrorCode.Success && response.data != null)
                         {
                             // Update Session
                             HttpContext.Session.SetComplexData("winCoin", response.data.winCoin);
                             HttpContext.Session.SetComplexData("betCoin", response.data.betCoin);
-                            HttpContext.Session.SetComplexData("userInfo", response.data);
+                            
+                            var currentUser = HttpContext.Session.GetComplexData<TokenLoginData>("userInfo");
+                            if(currentUser != null) {
+                                currentUser.winCoin = response.data.winCoin;
+                                currentUser.betCoin = response.data.betCoin;
+                                currentUser.isRegistered = response.data.isRegistered;
+                                if(response.data.regPkg != null) {
+                                    currentUser.regPkg = new RegInfoData {
+                                        RegisterId = response.data.regPkg.RegisterId,
+                                        Msisdn = response.data.regPkg.Msisdn,
+                                        ProductName = response.data.regPkg.ProductName,
+                                        RegisterTime = response.data.regPkg.RegisterTime,
+                                        NumberSpin = response.data.regPkg.NumberSpin,
+                                        Status = response.data.regPkg.Status,
+                                        ExpireTime = response.data.regPkg.ExpireTime,
+                                        Renew = response.data.regPkg.Renew
+                                    };
+                                } else {
+                                    currentUser.regPkg = null;
+                                }
+                                HttpContext.Session.SetComplexData("userInfo", currentUser);
+                            }
+
                             HttpContext.Session.SetComplexData("isRegistered", response.data.isRegistered);
                         }
                     }
@@ -188,7 +210,13 @@ namespace SicboSub.Web.Controllers
             }
 
             // 2. Nếu chưa đăng nhập, kiểm tra Token trên URL
+            // Debug logging
+            log.Info($"Index: Request QueryString: {Request.QueryString}");
+            var tokenKeys = Request.Query.Keys;
+            log.Info($"Index: Query Keys: {string.Join(", ", tokenKeys)}");
+            
             var token = Request.Query["token"].FirstOrDefault();
+            log.Info($"Index: Token extracted: '{token}'");
 
             if (!string.IsNullOrEmpty(token))
             {
@@ -376,6 +404,56 @@ namespace SicboSub.Web.Controllers
             return new List<PurchaseHistoryItem>();
         }
 
+        /// <summary>
+        /// Helper to load exchange history
+        /// </summary>
+        private async Task<List<ExchangeHistoryItem>> LoadExchangeHistoryInternal()
+        {
+            try
+            {
+                var token = GetToken();
+                // 30 days ago
+                var fromDate = DateTime.Now.AddDays(-30).ToString("dd/MM/yyyy 00:00:00");
+                var toDate = DateTime.Now.ToString("dd/MM/yyyy 23:59:59");
+
+                var request = new ExchangeHistoryReq
+                {
+                    msisdn = GetMsisdn(),
+                    lang = GetLanguage(),
+                    fromDate = fromDate,
+                    toDate = toDate,
+                    pageNumber = 0,
+                    pageSize = 20
+                };
+
+                var url = GetParameter("Url") + ApiUrlConstant.ExchangeHistoryUrl;
+
+                var resData = await DotnetLib.Rest.RestHandler.SendPostWithAuthen(
+                    log,
+                    url,
+                    request,
+                    token,
+                    token,
+                    "",
+                    GetLanguage()
+                );
+
+                if (resData != null)
+                {
+                    ExchangeHistoryRes response = new ExchangeHistoryRes(resData.data);
+                    if (response.errorCode == CommonErrorCode.Success && response.data != null)
+                    {
+                        return response.data;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                log.Error("LoadExchangeHistoryInternal: Error", ex);
+            }
+            return new List<ExchangeHistoryItem>();
+        }
+
         public async Task<IActionResult> History()
         {
             if (!IsAuthenticated()) return RedirectToLogin(_configuration);
@@ -384,12 +462,14 @@ namespace SicboSub.Web.Controllers
             // User requested: "history prize then pass its msisdn and it is Daily prize"
             var prizeHistory = await LoadRankingInternal("DAILY", GetMsisdn());
             var purchaseHistory = await LoadPurchaseHistoryInternal();
+            var exchangeHistory = await LoadExchangeHistoryInternal();
             
             var model = new HistoryViewModel
             {
                 GameHistory = gameHistory,
                 PrizeHistory = prizeHistory,
-                PurchaseHistory = purchaseHistory
+                PurchaseHistory = purchaseHistory,
+                ExchangeHistory = exchangeHistory
             };
             
             ViewData["Msisdn"] = GetMsisdn();

+ 81 - 72
SicboSub/SicboSub.Web/Language/Language.Designer.cs

@@ -61,7 +61,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Account.
+        ///   Looks up a localized string similar to Kont.
         /// </summary>
         public static string Account {
             get {
@@ -70,7 +70,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Buy more.
+        ///   Looks up a localized string similar to Achte plis.
         /// </summary>
         public static string BuyMore {
             get {
@@ -79,7 +79,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Buy Now.
+        ///   Looks up a localized string similar to Achte kounye a.
         /// </summary>
         public static string Buynow {
             get {
@@ -88,7 +88,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Cancel.
+        ///   Looks up a localized string similar to Anile.
         /// </summary>
         public static string Cancel {
             get {
@@ -97,7 +97,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Close.
+        ///   Looks up a localized string similar to Femen.
         /// </summary>
         public static string Close {
             get {
@@ -106,7 +106,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Coin Amount.
+        ///   Looks up a localized string similar to Kantite pyes.
         /// </summary>
         public static string CoinAmount {
             get {
@@ -115,7 +115,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Coins.
+        ///   Looks up a localized string similar to Pyes.
         /// </summary>
         public static string Coins {
             get {
@@ -124,7 +124,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Account.
+        ///   Looks up a localized string similar to Kont.
         /// </summary>
         public static string ColAccount {
             get {
@@ -133,7 +133,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Coin.
+        ///   Looks up a localized string similar to Pyes.
         /// </summary>
         public static string ColCoin {
             get {
@@ -142,7 +142,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ID.
+        ///   Looks up a localized string similar to No.
         /// </summary>
         public static string ColID {
             get {
@@ -160,7 +160,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Player.
+        ///   Looks up a localized string similar to Jwe.
         /// </summary>
         public static string ColPlayer {
             get {
@@ -169,7 +169,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Rewards.
+        ///   Looks up a localized string similar to Rekonpans.
         /// </summary>
         public static string ColRewards {
             get {
@@ -178,7 +178,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Status.
+        ///   Looks up a localized string similar to Estati.
         /// </summary>
         public static string ColStatus {
             get {
@@ -187,7 +187,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Time.
+        ///   Looks up a localized string similar to Tan.
         /// </summary>
         public static string ColTime {
             get {
@@ -205,7 +205,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Type.
+        ///   Looks up a localized string similar to Tip.
         /// </summary>
         public static string ColType {
             get {
@@ -214,7 +214,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Value.
+        ///   Looks up a localized string similar to Kantite .
         /// </summary>
         public static string ColValue {
             get {
@@ -223,7 +223,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Confirm.
+        ///   Looks up a localized string similar to Konfime.
         /// </summary>
         public static string Confirm {
             get {
@@ -232,7 +232,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Confirm buy more.
+        ///   Looks up a localized string similar to Konfime pou achte plis.
         /// </summary>
         public static string ConfirmBuyMore {
             get {
@@ -241,7 +241,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to  &lt;p class=&quot;register-message&quot;&gt;Do you confirm&lt;br/&gt;to buy the&lt;br/&gt;&lt;span class=&quot;highlight-text&quot;&gt;Subscribe Daily Pack: 500 Coins/day – only 3 HTG (Free first day, auto-renew)&lt;/span&gt;?&lt;/p&gt;.
+        ///   Looks up a localized string similar to  &lt;p class=&quot;register-message&quot;&gt;ou konfime&lt;br/&gt;pou achte a&lt;br/&gt;&lt;span class=&quot;highlight-text&quot;&gt;Abonman chak jou pake: 500 Pyes monnen/jou – sèlman 3 HTG&lt;/span&gt;?&lt;/p&gt;.
         /// </summary>
         public static string ConfirmDailyPackage {
             get {
@@ -250,7 +250,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Congratulations.
+        ///   Looks up a localized string similar to Felisitasyon.
         /// </summary>
         public static string Congratulations {
             get {
@@ -259,7 +259,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Congratulations, you have successfully claimed your prize..
+        ///   Looks up a localized string similar to Felisitasyon, ou reklame pri a ak sikse.
         /// </summary>
         public static string Congratulationsyouhave {
             get {
@@ -268,7 +268,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Daily.
+        ///   Looks up a localized string similar to Jounen.
         /// </summary>
         public static string Daily {
             get {
@@ -277,7 +277,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Daily Package.
+        ///   Looks up a localized string similar to Pake jounen .
         /// </summary>
         public static string DailyPackage {
             get {
@@ -286,7 +286,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Data Not Found.
+        ///   Looks up a localized string similar to Data entwouvab.
         /// </summary>
         public static string DataNotFound {
             get {
@@ -295,7 +295,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Do you want to buy.
+        ///   Looks up a localized string similar to Ou vle achte?.
         /// </summary>
         public static string DoYouWantToBuy {
             get {
@@ -303,6 +303,15 @@ namespace SicboSub.Web.Language {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Retre.
+        /// </summary>
+        public static string Exchange {
+            get {
+                return ResourceManager.GetString("Exchange", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Failed.
         /// </summary>
@@ -313,7 +322,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Game.
+        ///   Looks up a localized string similar to Jwet.
         /// </summary>
         public static string Game {
             get {
@@ -322,7 +331,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to History.
+        ///   Looks up a localized string similar to Istorik.
         /// </summary>
         public static string History {
             get {
@@ -331,7 +340,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Game.
+        ///   Looks up a localized string similar to Jwet.
         /// </summary>
         public static string HistoryTabGame {
             get {
@@ -340,7 +349,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Prize.
+        ///   Looks up a localized string similar to Pri.
         /// </summary>
         public static string HistoryTabPrize {
             get {
@@ -349,7 +358,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Purchase.
+        ///   Looks up a localized string similar to Achte.
         /// </summary>
         public static string HistoryTabPurchase {
             get {
@@ -358,7 +367,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Home.
+        ///   Looks up a localized string similar to Akey.
         /// </summary>
         public static string Home {
             get {
@@ -376,7 +385,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Insufficient coins to withdraw.
+        ///   Looks up a localized string similar to Ou pa gen ase pyes pouw fe retre .
         /// </summary>
         public static string Insufficient {
             get {
@@ -385,7 +394,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Main balance.
+        ///   Looks up a localized string similar to Balans prensipal.
         /// </summary>
         public static string MainBalance {
             get {
@@ -394,7 +403,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Monthly.
+        ///   Looks up a localized string similar to Mwa.
         /// </summary>
         public static string Monthly {
             get {
@@ -403,7 +412,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Msisdn.
+        ///   Looks up a localized string similar to Nimewo.
         /// </summary>
         public static string Msisdn {
             get {
@@ -412,7 +421,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to My coins.
+        ///   Looks up a localized string similar to Pyes mwen.
         /// </summary>
         public static string MyCoins {
             get {
@@ -421,7 +430,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to My play.
+        ///   Looks up a localized string similar to Jwet mwen.
         /// </summary>
         public static string Myplay {
             get {
@@ -430,7 +439,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Next.
+        ///   Looks up a localized string similar to Pwochen.
         /// </summary>
         public static string Next {
             get {
@@ -448,7 +457,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Package.
+        ///   Looks up a localized string similar to Pake.
         /// </summary>
         public static string Package {
             get {
@@ -457,7 +466,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Phone number.
+        ///   Looks up a localized string similar to Nimewo telefon.
         /// </summary>
         public static string PhoneNumber {
             get {
@@ -466,7 +475,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Play.
+        ///   Looks up a localized string similar to Jwe.
         /// </summary>
         public static string Play {
             get {
@@ -475,7 +484,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Player.
+        ///   Looks up a localized string similar to Jwe.
         /// </summary>
         public static string Player {
             get {
@@ -493,7 +502,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Price.
+        ///   Looks up a localized string similar to Prim.
         /// </summary>
         public static string Price {
             get {
@@ -502,7 +511,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Prize.
+        ///   Looks up a localized string similar to Pri.
         /// </summary>
         public static string Prize {
             get {
@@ -511,7 +520,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Purchase.
+        ///   Looks up a localized string similar to Achte.
         /// </summary>
         public static string Purchase {
             get {
@@ -529,7 +538,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Ranking.
+        ///   Looks up a localized string similar to Klasman.
         /// </summary>
         public static string Ranking {
             get {
@@ -538,7 +547,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Ranking coin.
+        ///   Looks up a localized string similar to klasman pyes.
         /// </summary>
         public static string Rankingcoin {
             get {
@@ -547,7 +556,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Register.
+        ///   Looks up a localized string similar to Anrejistre.
         /// </summary>
         public static string Register {
             get {
@@ -556,7 +565,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Rewards.
+        ///   Looks up a localized string similar to Rekonpans.
         /// </summary>
         public static string Rewards {
             get {
@@ -565,7 +574,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Select Package.
+        ///   Looks up a localized string similar to Chwazi pake.
         /// </summary>
         public static string SelectPackage {
             get {
@@ -574,7 +583,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Status.
+        ///   Looks up a localized string similar to Estati.
         /// </summary>
         public static string Status {
             get {
@@ -583,7 +592,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Failed.
+        ///   Looks up a localized string similar to Echek.
         /// </summary>
         public static string StatusFail {
             get {
@@ -592,7 +601,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Failed.
+        ///   Looks up a localized string similar to Echek.
         /// </summary>
         public static string StatusFailed {
             get {
@@ -601,7 +610,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Lost.
+        ///   Looks up a localized string similar to Pedi.
         /// </summary>
         public static string StatusLost {
             get {
@@ -610,7 +619,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Pending.
+        ///   Looks up a localized string similar to An atant.
         /// </summary>
         public static string StatusPending {
             get {
@@ -619,7 +628,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Successful.
+        ///   Looks up a localized string similar to Reyisi.
         /// </summary>
         public static string StatusSuccessful {
             get {
@@ -628,7 +637,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Won.
+        ///   Looks up a localized string similar to Genyen.
         /// </summary>
         public static string StatusWon {
             get {
@@ -646,7 +655,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Switch to Daily.
+        ///   Looks up a localized string similar to Chanje nan plan jounen.
         /// </summary>
         public static string SwitchToDaily {
             get {
@@ -655,7 +664,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Switch to Monthly.
+        ///   Looks up a localized string similar to Chanje nan plan mwa.
         /// </summary>
         public static string SwitchToMonthly {
             get {
@@ -664,7 +673,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Time.
+        ///   Looks up a localized string similar to Tan.
         /// </summary>
         public static string Time {
             get {
@@ -682,7 +691,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Total play coins.
+        ///   Looks up a localized string similar to Total pyes.
         /// </summary>
         public static string TotalCoins {
             get {
@@ -691,7 +700,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Total value this month.
+        ///   Looks up a localized string similar to Total pou mwa a.
         /// </summary>
         public static string TotalValueThisMonth {
             get {
@@ -700,7 +709,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Total value today.
+        ///   Looks up a localized string similar to Total pou jodia.
         /// </summary>
         public static string TotalValueToday {
             get {
@@ -709,7 +718,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Total withdraw today.
+        ///   Looks up a localized string similar to Total retre pou jodia.
         /// </summary>
         public static string TotalWithdrawToday {
             get {
@@ -718,7 +727,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Tunnel.
+        ///   Looks up a localized string similar to Tinel.
         /// </summary>
         public static string Tunnel {
             get {
@@ -727,7 +736,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Buy Turn.
+        ///   Looks up a localized string similar to Achte tou.
         /// </summary>
         public static string TypeBuyTurn {
             get {
@@ -736,7 +745,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Unsubscribe.
+        ///   Looks up a localized string similar to Dezaktive.
         /// </summary>
         public static string Unsubscribe {
             get {
@@ -754,7 +763,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Verify.
+        ///   Looks up a localized string similar to Verifye.
         /// </summary>
         public static string Verify {
             get {
@@ -763,7 +772,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to View ranking coin tablet 👉.
+        ///   Looks up a localized string similar to Klasman pyes 👉.
         /// </summary>
         public static string ViewRankingCoin {
             get {
@@ -772,7 +781,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Winner.
+        ///   Looks up a localized string similar to Ganyan.
         /// </summary>
         public static string Winner {
             get {
@@ -781,7 +790,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Withdraw.
+        ///   Looks up a localized string similar to Retre.
         /// </summary>
         public static string Withdraw {
             get {
@@ -790,7 +799,7 @@ namespace SicboSub.Web.Language {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Withdraw value.
+        ///   Looks up a localized string similar to Kantite retre.
         /// </summary>
         public static string WithdrawValue {
             get {

+ 75 - 72
SicboSub/SicboSub.Web/Language/Language.resx

@@ -118,226 +118,226 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <data name="Myplay" xml:space="preserve">
-    <value>My play</value>
+    <value>Jwet mwen</value>
   </data>
   <data name="Rankingcoin" xml:space="preserve">
-    <value>Ranking coin</value>
+    <value>klasman pyes</value>
   </data>
   <data name="ViewRankingCoin" xml:space="preserve">
-    <value>View ranking coin tablet 👉</value>
+    <value>Klasman pyes 👉</value>
   </data>
   <data name="MyCoins" xml:space="preserve">
-    <value>My coins</value>
+    <value>Pyes mwen</value>
   </data>
   <data name="Register" xml:space="preserve">
-    <value>Register</value>
+    <value>Anrejistre</value>
   </data>
   <data name="BuyMore" xml:space="preserve">
-    <value>Buy more</value>
+    <value>Achte plis</value>
   </data>
   <data name="Play" xml:space="preserve">
-    <value>Play</value>
+    <value>Jwe</value>
   </data>
   <data name="SelectPackage" xml:space="preserve">
-    <value>Select Package</value>
+    <value>Chwazi pake</value>
   </data>
   <data name="Coins" xml:space="preserve">
-    <value>Coins</value>
+    <value>Pyes</value>
   </data>
   <data name="HTG" xml:space="preserve">
     <value>HTG</value>
   </data>
   <data name="Cancel" xml:space="preserve">
-    <value>Cancel</value>
+    <value>Anile</value>
   </data>
   <data name="Next" xml:space="preserve">
-    <value>Next</value>
+    <value>Pwochen</value>
   </data>
   <data name="ConfirmBuyMore" xml:space="preserve">
-    <value>Confirm buy more</value>
+    <value>Konfime pou achte plis</value>
   </data>
   <data name="DoYouWantToBuy" xml:space="preserve">
-    <value>Do you want to buy</value>
+    <value>Ou vle achte?</value>
   </data>
   <data name="Price" xml:space="preserve">
-    <value>Price</value>
+    <value>Prim</value>
   </data>
   <data name="Confirm" xml:space="preserve">
-    <value>Confirm</value>
+    <value>Konfime</value>
   </data>
   <data name="ConfirmDailyPackage" xml:space="preserve">
-    <value> &lt;p class="register-message"&gt;Do you confirm&lt;br/&gt;to buy the&lt;br/&gt;&lt;span class="highlight-text"&gt;Subscribe Daily Pack: 500 Coins/day – only 3 HTG (Free first day, auto-renew)&lt;/span&gt;?&lt;/p&gt;</value>
+    <value> &lt;p class="register-message"&gt;ou konfime&lt;br/&gt;pou achte a&lt;br/&gt;&lt;span class="highlight-text"&gt;Abonman chak jou pake: 500 Pyes monnen/jou – sèlman 3 HTG&lt;/span&gt;?&lt;/p&gt;</value>
   </data>
   <data name="DailyPackage" xml:space="preserve">
-    <value>Daily Package</value>
+    <value>Pake jounen </value>
   </data>
   <data name="PhoneNumber" xml:space="preserve">
-    <value>Phone number</value>
+    <value>Nimewo telefon</value>
   </data>
   <data name="Tunnel" xml:space="preserve">
-    <value>Tunnel</value>
+    <value>Tinel</value>
   </data>
   <data name="MainBalance" xml:space="preserve">
-    <value>Main balance</value>
+    <value>Balans prensipal</value>
   </data>
   <data name="TotalWithdrawToday" xml:space="preserve">
-    <value>Total withdraw today</value>
+    <value>Total retre pou jodia</value>
   </data>
   <data name="CoinAmount" xml:space="preserve">
-    <value>Coin Amount</value>
+    <value>Kantite pyes</value>
   </data>
   <data name="WithdrawValue" xml:space="preserve">
-    <value>Withdraw value</value>
+    <value>Kantite retre</value>
   </data>
   <data name="Withdraw" xml:space="preserve">
-    <value>Withdraw</value>
+    <value>Retre</value>
   </data>
   <data name="TotalCoins" xml:space="preserve">
-    <value>Total play coins</value>
+    <value>Total pyes</value>
   </data>
   <data name="TotalValueToday" xml:space="preserve">
-    <value>Total value today</value>
+    <value>Total pou jodia</value>
   </data>
   <data name="TotalValueThisMonth" xml:space="preserve">
-    <value>Total value this month</value>
+    <value>Total pou mwa a</value>
   </data>
   <data name="HistoryTabGame" xml:space="preserve">
-    <value>Game</value>
+    <value>Jwet</value>
   </data>
   <data name="HistoryTabPrize" xml:space="preserve">
-    <value>Prize</value>
+    <value>Pri</value>
   </data>
   <data name="HistoryTabPurchase" xml:space="preserve">
-    <value>Purchase</value>
+    <value>Achte</value>
   </data>
   <data name="ColID" xml:space="preserve">
-    <value>ID</value>
+    <value>No</value>
   </data>
   <data name="ColTime" xml:space="preserve">
-    <value>Time</value>
+    <value>Tan</value>
   </data>
   <data name="ColStatus" xml:space="preserve">
-    <value>Status</value>
+    <value>Estati</value>
   </data>
   <data name="ColAccount" xml:space="preserve">
-    <value>Account</value>
+    <value>Kont</value>
   </data>
   <data name="ColValue" xml:space="preserve">
-    <value>Value</value>
+    <value>Kantite </value>
   </data>
   <data name="ColCoin" xml:space="preserve">
-    <value>Coin</value>
+    <value>Pyes</value>
   </data>
   <data name="ColNo" xml:space="preserve">
     <value>No</value>
   </data>
   <data name="ColType" xml:space="preserve">
-    <value>Type</value>
+    <value>Tip</value>
   </data>
   <data name="StatusWon" xml:space="preserve">
-    <value>Won</value>
+    <value>Genyen</value>
   </data>
   <data name="StatusLost" xml:space="preserve">
-    <value>Lost</value>
+    <value>Pedi</value>
   </data>
   <data name="StatusPending" xml:space="preserve">
-    <value>Pending</value>
+    <value>An atant</value>
   </data>
   <data name="StatusSuccessful" xml:space="preserve">
-    <value>Successful</value>
+    <value>Reyisi</value>
   </data>
   <data name="StatusFail" xml:space="preserve">
-    <value>Failed</value>
+    <value>Echek</value>
   </data>
   <data name="TypeBuyTurn" xml:space="preserve">
-    <value>Buy Turn</value>
+    <value>Achte tou</value>
   </data>
   <data name="SwitchToMonthly" xml:space="preserve">
-    <value>Switch to Monthly</value>
+    <value>Chanje nan plan mwa</value>
   </data>
   <data name="SwitchToDaily" xml:space="preserve">
-    <value>Switch to Daily</value>
+    <value>Chanje nan plan jounen</value>
   </data>
   <data name="Daily" xml:space="preserve">
-    <value>Daily</value>
+    <value>Jounen</value>
   </data>
   <data name="Monthly" xml:space="preserve">
-    <value>Monthly</value>
+    <value>Mwa</value>
   </data>
   <data name="Ranking" xml:space="preserve">
-    <value>Ranking</value>
+    <value>Klasman</value>
   </data>
   <data name="ColTop" xml:space="preserve">
     <value>Top</value>
   </data>
   <data name="ColPlayer" xml:space="preserve">
-    <value>Player</value>
+    <value>Jwe</value>
   </data>
   <data name="ColRewards" xml:space="preserve">
-    <value>Rewards</value>
+    <value>Rekonpans</value>
   </data>
   <data name="Home" xml:space="preserve">
-    <value>Home</value>
+    <value>Akey</value>
   </data>
   <data name="History" xml:space="preserve">
-    <value>History</value>
+    <value>Istorik</value>
   </data>
   <data name="Winner" xml:space="preserve">
-    <value>Winner</value>
+    <value>Ganyan</value>
   </data>
   <data name="Account" xml:space="preserve">
-    <value>Account</value>
+    <value>Kont</value>
   </data>
   <data name="Top" xml:space="preserve">
     <value>Top</value>
   </data>
   <data name="Player" xml:space="preserve">
-    <value>Player</value>
+    <value>Jwe</value>
   </data>
   <data name="Rewards" xml:space="preserve">
-    <value>Rewards</value>
+    <value>Rekonpans</value>
   </data>
   <data name="Game" xml:space="preserve">
-    <value>Game</value>
+    <value>Jwet</value>
   </data>
   <data name="Prize" xml:space="preserve">
-    <value>Prize</value>
+    <value>Pri</value>
   </data>
   <data name="Purchase" xml:space="preserve">
-    <value>Purchase</value>
+    <value>Achte</value>
   </data>
   <data name="Msisdn" xml:space="preserve">
-    <value>Msisdn</value>
+    <value>Nimewo</value>
   </data>
   <data name="Time" xml:space="preserve">
-    <value>Time</value>
+    <value>Tan</value>
   </data>
   <data name="Status" xml:space="preserve">
-    <value>Status</value>
+    <value>Estati</value>
   </data>
   <data name="Unsubscribe" xml:space="preserve">
-    <value>Unsubscribe</value>
+    <value>Dezaktive</value>
   </data>
   <data name="DataNotFound" xml:space="preserve">
-    <value>Data Not Found</value>
+    <value>Data entwouvab</value>
   </data>
   <data name="Package" xml:space="preserve">
-    <value>Package</value>
+    <value>Pake</value>
   </data>
   <data name="Verify" xml:space="preserve">
-    <value>Verify</value>
+    <value>Verifye</value>
   </data>
   <data name="Insufficient" xml:space="preserve">
-    <value>Insufficient coins to withdraw</value>
+    <value>Ou pa gen ase pyes pouw fe retre </value>
   </data>
   <data name="Congratulations" xml:space="preserve">
-    <value>Congratulations</value>
+    <value>Felisitasyon</value>
   </data>
   <data name="Congratulationsyouhave" xml:space="preserve">
-    <value>Congratulations, you have successfully claimed your prize.</value>
+    <value>Felisitasyon, ou reklame pri a ak sikse</value>
   </data>
   <data name="Close" xml:space="preserve">
-    <value>Close</value>
+    <value>Femen</value>
   </data>
   <data name="Value" xml:space="preserve">
     <value>Value</value>
@@ -352,15 +352,18 @@
     <value>Failed</value>
   </data>
   <data name="StatusFailed" xml:space="preserve">
-    <value>Failed</value>
+    <value>Echek</value>
   </data>
   <data name="PlayNow" xml:space="preserve">
     <value>Play Now</value>
   </data>
   <data name="Buynow" xml:space="preserve">
-    <value>Buy Now</value>
+    <value>Achte kounye a</value>
   </data>
   <data name="OTPVerification" xml:space="preserve">
     <value>OTP Verification</value>
   </data>
+  <data name="Exchange" xml:space="preserve">
+    <value>Retre</value>
+  </data>
 </root>

+ 35 - 32
SicboSub/SicboSub.Web/Language/Language.vi.resx

@@ -118,28 +118,28 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <data name="Myplay" xml:space="preserve">
-    <value>Lượt chơi của tôi</value>
+    <value>My play</value>
   </data>
   <data name="Rankingcoin" xml:space="preserve">
-    <value>Xếp hạng xu</value>
+    <value>Ranking coin</value>
   </data>
   <data name="ViewRankingCoin" xml:space="preserve">
-    <value>Xem bảng xếp hạng xu 👉</value>
+    <value>View ranking coin tablet 👉</value>
   </data>
   <data name="MyCoins" xml:space="preserve">
-    <value>Xu của tôi</value>
+    <value>My coins</value>
   </data>
   <data name="Register" xml:space="preserve">
-    <value>Đăng ký</value>
+    <value>Register</value>
   </data>
   <data name="BuyMore" xml:space="preserve">
     <value>Mua thêm</value>
   </data>
   <data name="Play" xml:space="preserve">
-    <value>Chơi</value>
+    <value>Play</value>
   </data>
   <data name="SelectPackage" xml:space="preserve">
-    <value>Chọn gói</value>
+    <value>Select Package</value>
   </data>
   <data name="Coins" xml:space="preserve">
     <value>Xu</value>
@@ -151,7 +151,7 @@
     <value>Hủy</value>
   </data>
   <data name="Next" xml:space="preserve">
-    <value>Tiếp tục</value>
+    <value>Next</value>
   </data>
   <data name="ConfirmBuyMore" xml:space="preserve">
     <value>Xác nhận mua thêm</value>
@@ -160,7 +160,7 @@
     <value>Bạn có muốn mua</value>
   </data>
   <data name="Price" xml:space="preserve">
-    <value>Giá</value>
+    <value>Price</value>
   </data>
   <data name="Confirm" xml:space="preserve">
     <value>Xác nhận</value>
@@ -172,43 +172,43 @@
     <value>Gói hàng ngày</value>
   </data>
   <data name="PhoneNumber" xml:space="preserve">
-    <value>Số điện thoại</value>
+    <value>Phone number</value>
   </data>
   <data name="Tunnel" xml:space="preserve">
-    <value>Kênh</value>
+    <value>Tunnel</value>
   </data>
   <data name="MainBalance" xml:space="preserve">
-    <value>Tài khoản chính</value>
+    <value>Main balance</value>
   </data>
   <data name="TotalWithdrawToday" xml:space="preserve">
-    <value>Tổng rút hôm nay</value>
+    <value>Total withdraw today</value>
   </data>
   <data name="CoinAmount" xml:space="preserve">
     <value>Số lượng xu</value>
   </data>
   <data name="WithdrawValue" xml:space="preserve">
-    <value>Giá trị rút</value>
+    <value>Withdraw value</value>
   </data>
   <data name="Withdraw" xml:space="preserve">
-    <value>Rút tiền</value>
+    <value>Withdraw</value>
   </data>
   <data name="TotalCoins" xml:space="preserve">
-    <value>Tổng số xu</value>
+    <value>Total play coins</value>
   </data>
   <data name="TotalValueToday" xml:space="preserve">
-    <value>Tổng giá trị hôm nay</value>
+    <value>Total value today</value>
   </data>
   <data name="TotalValueThisMonth" xml:space="preserve">
-    <value>Tổng giá trị tháng này</value>
+    <value>Total value this month</value>
   </data>
   <data name="HistoryTabGame" xml:space="preserve">
-    <value>Trò chơi</value>
+    <value>Game</value>
   </data>
   <data name="HistoryTabPrize" xml:space="preserve">
-    <value>Giải thưởng</value>
+    <value>Prize</value>
   </data>
   <data name="HistoryTabPurchase" xml:space="preserve">
-    <value>Mua hàng</value>
+    <value>Purchase</value>
   </data>
   <data name="ColID" xml:space="preserve">
     <value>ID</value>
@@ -235,37 +235,37 @@
     <value>Loại</value>
   </data>
   <data name="StatusWon" xml:space="preserve">
-    <value>Thắng</value>
+    <value>Won</value>
   </data>
   <data name="StatusLost" xml:space="preserve">
-    <value>Thua</value>
+    <value>Lost</value>
   </data>
   <data name="StatusPending" xml:space="preserve">
-    <value>Đang xử lý</value>
+    <value>Pending</value>
   </data>
   <data name="StatusSuccessful" xml:space="preserve">
-    <value>Thành công</value>
+    <value>Successful</value>
   </data>
   <data name="StatusFail" xml:space="preserve">
-    <value>Thất bại</value>
+    <value>Failed</value>
   </data>
   <data name="TypeBuyTurn" xml:space="preserve">
-    <value>Mua lượt</value>
+    <value>Buy Turn</value>
   </data>
   <data name="SwitchToMonthly" xml:space="preserve">
-    <value>Chuyển sang tháng</value>
+    <value>Switch to Monthly</value>
   </data>
   <data name="SwitchToDaily" xml:space="preserve">
-    <value>Chuyển sang ngày</value>
+    <value>Switch to Daily</value>
   </data>
   <data name="Daily" xml:space="preserve">
     <value>Ngày</value>
   </data>
   <data name="Monthly" xml:space="preserve">
-    <value>Tháng</value>
+    <value>Monthly</value>
   </data>
   <data name="Ranking" xml:space="preserve">
-    <value>Xếp hạng</value>
+    <value>Ranking</value>
   </data>
   <data name="ColTop" xml:space="preserve">
     <value>Top</value>
@@ -352,7 +352,7 @@
     <value>Failed</value>
   </data>
   <data name="StatusFailed" xml:space="preserve">
-    <value>Thất bại</value>
+    <value>Failed</value>
   </data>
   <data name="PlayNow" xml:space="preserve">
     <value>PlayNow</value>
@@ -363,4 +363,7 @@
   <data name="OTPVerification" xml:space="preserve">
     <value>OTP Verification</value>
   </data>
+  <data name="Exchange" xml:space="preserve">
+    <value>Exchange</value>
+  </data>
 </root>

+ 29 - 1
SicboSub/SicboSub.Web/Models/AuthModels.cs

@@ -42,7 +42,7 @@ namespace SicboSub.Web.Models
         public string? ProductName { get; set; }
         public DateTime? RegisterTime { get; set; }
         public short? NumberSpin { get; set; }
-        public bool? Status { get; set; }
+        public byte? Status { get; set; } // Matches API byte/byte?
         public DateTime? ExpireTime { get; set; }
         public byte? Renew { get; set; }
     }
@@ -66,5 +66,33 @@ namespace SicboSub.Web.Models
         }
     }
 
+    /// <summary>
+    /// Request lấy thông tin tài khoản
+    /// </summary>
+    public class AccountInfoReq
+    {
+        public string msisdn { get; set; } = null!;
+        public string? lang { get; set; }
+    }
+
+    /// <summary>
+    /// Response lấy thông tin tài khoản
+    /// </summary>
+    public class AccountInfoRes : CommonResponse
+    {
+        public TokenLoginData? data { get; set; } // Re-use TokenLoginData as it has same structure
+
+        public AccountInfoRes(string dataGet)
+        {
+            JObject jObject = JObject.Parse(dataGet);
+            BuildCommonResponse(dataGet);
+
+            if (jObject != null && jObject["data"] != null)
+            {
+                data = jObject["data"]!.ToObject<TokenLoginData>();
+            }
+        }
+    }
+
     #endregion
 }

+ 40 - 0
SicboSub/SicboSub.Web/Models/HistoryModels.cs

@@ -177,4 +177,44 @@ namespace SicboSub.Web.Models
              }
         }
     }
+
+    public class ExchangeHistoryReq
+    {
+        public string msisdn { get; set; } = null!;
+        public string? lang { get; set; }
+        public string? fromDate { get; set; }
+        public string? toDate { get; set; }
+        public int pageNumber { get; set; } = 0;
+        public int pageSize { get; set; } = 20;
+    }
+
+    public class ExchangeHistoryItem
+    {
+        public decimal id { get; set; }
+        public string msisdn { get; set; } = null!;
+        public decimal coinDeducted { get; set; }
+        public decimal moneyAdded { get; set; }
+        public DateTime exchangeTime { get; set; }
+        public byte status { get; set; }
+        public string? statusName { get; set; }
+    }
+
+    public class ExchangeHistoryRes : CommonResponse
+    {
+        public List<ExchangeHistoryItem>? data { get; set; }
+
+        public ExchangeHistoryRes(dynamic dataGet)
+        {
+            string json = "";
+            if (dataGet is string) json = dataGet;
+            else json = Newtonsoft.Json.JsonConvert.SerializeObject(dataGet);
+
+            BuildCommonResponse(json);
+            JObject jObject = JObject.Parse(json);
+            if (jObject != null && jObject["data"] != null)
+            {
+                data = jObject["data"]!.ToObject<List<ExchangeHistoryItem>>();
+            }
+        }
+    }
 }

+ 1 - 0
SicboSub/SicboSub.Web/Models/HistoryViewModel.cs

@@ -7,5 +7,6 @@ namespace SicboSub.Web.Models
         public List<PlayHistoryItem> GameHistory { get; set; } = new List<PlayHistoryItem>();
         public List<RankingHistoryItem> PrizeHistory { get; set; } = new List<RankingHistoryItem>();
         public List<PurchaseHistoryItem> PurchaseHistory { get; set; } = new List<PurchaseHistoryItem>();
+        public List<ExchangeHistoryItem> ExchangeHistory { get; set; } = new List<ExchangeHistoryItem>();
     }
 }

+ 2 - 2
SicboSub/SicboSub.Web/Views/Home/Account.cshtml

@@ -48,7 +48,7 @@
             <div class="info-row with-icon">
                 <div class="info-content">
                     <span class="info-label">@Language.TotalCoins</span>
-                    <span class="info-value coins">@String.Format("{0:n0}", betCoin)</span>
+                    <span class="info-value coins">@String.Format("{0:#,##0.###}", betCoin)</span>
                 </div>
                 @* <img class="settings-icon" src="~/img/042-settings.png" alt="Settings" style="cursor:pointer;" onclick="alert('Settings feature coming soon!')" /> *@
             </div>
@@ -56,7 +56,7 @@
             <!-- My Coins (Main Balance) -->
             <div class="info-row">
                 <span class="info-label">@Language.MyCoins</span>
-                <span class="info-value coins">@String.Format("{0:n0}", winCoin)</span>
+                <span class="info-value coins">@String.Format("{0:#,##0.###}", winCoin)</span>
             </div>
 
             <!-- Daily Package -->

+ 51 - 4
SicboSub/SicboSub.Web/Views/Home/History.cshtml

@@ -28,6 +28,9 @@
             <div class="tab-button" data-tab="purchase">
                 <span class="tab-label">@Language.Purchase</span>
             </div>
+            <div class="tab-button" data-tab="exchange">
+                <span class="tab-label">@Language.Exchange</span>
+            </div>
         </div>
 
         <!-- Game History Table -->
@@ -50,12 +53,12 @@
                         <div class="col-time">@item.bettingTime.ToString("dd/MM/yyyy, HH:mm:ss")</div>
                         @if (item.isWin)
                         {
-                             <div class="col-coin positive">+@item.winCoin.ToString("N0")</div>
+                             <div class="col-coin positive">+@item.winCoin.ToString("#,##0.###")</div>
                              <div class="col-status won">Won</div>
                         }
                         else
                         {
-                             <div class="col-coin negative">-@item.bettingValue.ToString("N0")</div>
+                             <div class="col-coin negative">-@item.bettingValue.ToString("#,##0.###")</div>
                              <div class="col-status lost">Lost</div>
                         }
                     </div>
@@ -87,7 +90,7 @@
                     <div class="table-row">
                         <div class="col-account">@msisdn</div>
                         <div class="col-time">@item.rewardDate.ToString("dd/MM/yyyy, HH:mm:ss")</div>
-                        <div class="col-value">@item.rewardValue.ToString("N0") <span class="usd">@item.rewardUnit</span></div>
+                        <div class="col-value">@item.rewardValue.ToString("#,##0.###") <span class="usd">@item.rewardUnit</span></div>
                         <div class="col-status successful">Top @item.rankPosition</div>
                     </div>
                 }
@@ -120,7 +123,7 @@
                     <div class="table-row">
                         <div class="col-no">@(no++)</div>
                         <div class="col-time">@item.registerTime.ToString("dd/MM/yyyy HH:mm:ss")</div>
-                        <div class="col-value">@item.fee.ToString("N0") <span class="coins">@Language.HTG</span></div>
+                        <div class="col-value">@item.fee.ToString("#,##0.###") <span class="coins">@Language.HTG</span></div>
                         <div class="col-type">@item.productName</div>
                         @if (item.status == 1) // Assuming 1 is Success
                         {
@@ -140,6 +143,49 @@
                 </div>
             }
         </div>
+
+        <!-- Exchange History Table (Hidden by default) -->
+        <div class="history-table hidden" id="exchange-table">
+            <!-- Header Row -->
+             <div class="table-header">
+                <div class="col-time">@Language.Time</div>
+                <div class="col-coin">Coin Deducted</div>
+                <div class="col-value">Money Added</div>
+                <div class="col-status">@Language.Status</div>
+            </div>
+
+            <!-- Data Rows -->
+            @if (Model != null && Model.ExchangeHistory != null && Model.ExchangeHistory.Count > 0)
+            {
+                foreach (var item in Model.ExchangeHistory)
+                {
+                    <div class="table-row">
+                        <div class="col-time">@item.exchangeTime.ToString("dd/MM/yyyy HH:mm:ss")</div>
+                        <div class="col-coin negative">-@item.coinDeducted.ToString("#,##0.###")</div>
+                        <div class="col-value positive">+@item.moneyAdded.ToString("#,##0.###")</div>
+                        
+                        @if (item.status == 1)
+                        {
+                             <div class="col-status successful">Success</div>
+                        }
+                        else if (item.status == 2)
+                        {
+                             <div class="col-status fail">Failed</div>
+                        }
+                        else
+                        {
+                             <div class="col-status pending" style="color: orange;">Pending</div>
+                        }
+                    </div>
+                }
+            }
+             else
+            {
+                <div class="table-row" style="justify-content:center;">
+                    <span></span>
+                </div>
+            }
+        </div>
     </div>
 </div>
 
@@ -155,6 +201,7 @@
             document.getElementById('game-table').classList.add('hidden');
             document.getElementById('prize-table').classList.add('hidden');
             document.getElementById('purchase-table').classList.add('hidden');
+            document.getElementById('exchange-table').classList.add('hidden');
             
             // Show selected table
             const tab = this.dataset.tab;

+ 2 - 2
SicboSub/SicboSub.Web/Views/Home/Index.cshtml

@@ -40,7 +40,7 @@
                     </div>
                     <div class="sword-parent">
                         <img class="sword-icon" src="~/img/003-sword.svg" alt="">
-                        <div id="betCoinVal" class="my-play">@String.Format("{0:n0}", ViewData["BetCoin"])</div>
+                        <div id="betCoinVal" class="my-play">@String.Format("{0:#,##0.###}", ViewData["BetCoin"])</div>
                     </div>
                 </div>
                 <div class="frame-container">
@@ -51,7 +51,7 @@
                     </div>
                     <div class="sword-parent">
                         <img class="sword-icon" src="~/img/021-medal.svg" alt="">
-                        <div id="winCoinVal" class="my-play">@String.Format("{0:n0}", ViewData["WinCoin"])</div>
+                        <div id="winCoinVal" class="my-play">@String.Format("{0:#,##0.###}", ViewData["WinCoin"])</div>
                     </div>
                 </div>
             </div>

+ 20 - 7
SicboSub/SicboSub.Web/Views/Shared/_GameLayout.cshtml

@@ -19,7 +19,7 @@
     <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
     <script src="~/js/site.js" asp-append-version="true"></script>
     <script>
-        // Auto-scale .home container to fit full screen
+        // Auto-scale .home container to fit full screen with Auto-Rotate logic
         function scaleToFit() {
             var homeEl = document.querySelector('.home');
             if (!homeEl) return;
@@ -29,13 +29,26 @@
             var windowWidth = window.innerWidth;
             var windowHeight = window.innerHeight;
             
-            // Calculate scale to fit entire layout in screen (contain mode - no element loss)
-            var scaleX = windowWidth / baseWidth;
-            var scaleY = windowHeight / baseHeight;
-            var scale = Math.min(scaleX, scaleY); // Use min to ensure all elements are visible
+            var isPortrait = windowHeight > windowWidth;
             
-            // Center the element and scale
-            homeEl.style.transform = 'translate(-50%, -50%) scale(' + scale + ')';
+            if (isPortrait) {
+                // Force Landscape on Portrait Screen
+                // We rotate 90 degrees, so Width becomes Height and Height becomes Width
+                var scaleX = windowHeight / baseWidth;
+                var scaleY = windowWidth / baseHeight;
+                var scale = Math.min(scaleX, scaleY);
+                
+                // Rotate 90 degrees
+                homeEl.style.transform = 'translate(-50%, -50%) rotate(90deg) scale(' + scale + ')';
+            } else {
+                // Already Landscape
+                var scaleX = windowWidth / baseWidth;
+                var scaleY = windowHeight / baseHeight;
+                var scale = Math.min(scaleX, scaleY);
+                
+                // Normal scaling
+                homeEl.style.transform = 'translate(-50%, -50%) scale(' + scale + ')';
+            }
         }
         
         // Run on DOM ready and resize

+ 2 - 1
SicboSub/SicboSub.Web/appsettings.json

@@ -6,7 +6,8 @@
     }
   },
   "AllowedHosts": "*",
-  "Url": "http://127.0.0.1:9106",
+  //"Url": "http://127.0.0.1:9106",
+  "Url": "http://127.0.0.1:8741",
   //"RedirectUrl": "http://149.28.132.56:8110",
   "RedirectUrl": "http://127.0.0.1:5042/?token=",
   "PackageCodeDaily": "SICBO_DAILY",

+ 24 - 24
SicboSub/SicboSub.Web/wwwroot/js/site.js

@@ -7,7 +7,7 @@ const Site = {
     /**
      * Hiển thị loading overlay
      */
-    showLoading: function() {
+    showLoading: function () {
         if ($('#loading-overlay').length === 0) {
             $('body').append('<div id="loading-overlay" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;display:flex;align-items:center;justify-content:center;"><div class="spinner-border text-light" role="status"></div></div>');
         }
@@ -17,14 +17,14 @@ const Site = {
     /**
      * Ẩn loading overlay
      */
-    hideLoading: function() {
+    hideLoading: function () {
         $('#loading-overlay').hide();
     },
 
     /**
      * Hiển thị thông báo thành công
      */
-    showSuccess: function(message) {
+    showSuccess: function (message) {
         if (typeof Swal !== 'undefined') {
             Swal.fire({
                 icon: 'success',
@@ -39,7 +39,7 @@ const Site = {
     /**
      * Hiển thị thông báo lỗi
      */
-    showError: function(message) {
+    showError: function (message) {
         if (typeof Swal !== 'undefined') {
             Swal.fire({
                 icon: 'error',
@@ -50,17 +50,17 @@ const Site = {
     },
 
     /**
-     * Format số với dấu phẩy
+     * Format số với dấu phẩy và tối đa 3 chữ số thập phân
      */
-    formatNumber: function(num) {
+    formatNumber: function (num) {
         if (num === null || num === undefined) return '0';
-        return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+        return Number(num).toLocaleString('en-US', { maximumFractionDigits: 3 });
     },
 
     /**
      * Format ngày tháng
      */
-    formatDate: function(dateStr) {
+    formatDate: function (dateStr) {
         if (!dateStr) return '';
         var date = new Date(dateStr);
         return date.toLocaleDateString('vi-VN');
@@ -69,7 +69,7 @@ const Site = {
     /**
      * Format ngày giờ
      */
-    formatDateTime: function(dateStr) {
+    formatDateTime: function (dateStr) {
         if (!dateStr) return '';
         var date = new Date(dateStr);
         return date.toLocaleString('vi-VN');
@@ -84,17 +84,17 @@ const API = {
     /**
      * POST request chung
      */
-    post: function(url, data, successCallback, errorCallback) {
+    post: function (url, data, successCallback, errorCallback) {
         Site.showLoading();
-        
+
         $.ajax({
             url: url,
             type: 'POST',
             contentType: 'application/json',
             data: JSON.stringify(data || {}),
-            success: function(response) {
+            success: function (response) {
                 Site.hideLoading();
-                
+
                 if (response.errorCode === '0' || response.errorCode === 0) {
                     if (typeof successCallback === 'function') {
                         successCallback(response);
@@ -107,7 +107,7 @@ const API = {
                     }
                 }
             },
-            error: function(xhr, status, error) {
+            error: function (xhr, status, error) {
                 Site.hideLoading();
                 console.error('API error:', error);
                 if (typeof errorCallback === 'function') {
@@ -122,15 +122,15 @@ const API = {
     /**
      * Refresh thông tin user
      */
-    refreshProfile: function(callback) {
+    refreshProfile: function (callback) {
         this.post('/Home/RefreshProfile', {}, callback);
     },
 
     /**
      * Đăng xuất
      */
-    logout: function(callback) {
-        this.post('/Home/DoLogout', {}, function(response) {
+    logout: function (callback) {
+        this.post('/Home/DoLogout', {}, function (response) {
             if (typeof callback === 'function') {
                 callback(response);
             }
@@ -142,7 +142,7 @@ const API = {
     /**
      * Lấy lịch sử chơi game
      */
-    getPlayHistory: function(fromDate, toDate, page, pageSize, callback) {
+    getPlayHistory: function (fromDate, toDate, page, pageSize, callback) {
         this.post('/Home/GetPlayHistory', {
             fromDate: fromDate,
             toDate: toDate,
@@ -154,7 +154,7 @@ const API = {
     /**
      * Lấy lịch sử ranking
      */
-    getRankingHistory: function(rankType, fromDate, toDate, page, pageSize, callback) {
+    getRankingHistory: function (rankType, fromDate, toDate, page, pageSize, callback) {
         this.post('/Home/GetRankingHistory', {
             rankType: rankType,
             fromDate: fromDate,
@@ -167,33 +167,33 @@ const API = {
     /**
      * Lấy danh sách gói Exchange
      */
-    getExchangeConfigs: function(callback) {
+    getExchangeConfigs: function (callback) {
         this.post('/Home/GetExchangeConfigs', {}, callback);
     },
 
     /**
      * Request OTP cho Exchange
      */
-    requestExchangeOtp: function(configId, callback, errorCallback) {
+    requestExchangeOtp: function (configId, callback, errorCallback) {
         this.post('/Home/RequestExchangeOtp', { configId: configId }, callback, errorCallback);
     },
 
     /**
      * Verify OTP
      */
-    verifyExchangeOtp: function(otpCode, callback, errorCallback) {
+    verifyExchangeOtp: function (otpCode, callback, errorCallback) {
         this.post('/Home/VerifyExchangeOtp', { otpCode: otpCode }, callback, errorCallback);
     },
 
     /**
      * Resend OTP
      */
-    resendExchangeOtp: function(callback, errorCallback) {
+    resendExchangeOtp: function (callback, errorCallback) {
         this.post('/Home/ResendExchangeOtp', {}, callback, errorCallback);
     }
 };
 
 // Document ready
-$(document).ready(function() {
+$(document).ready(function () {
     console.log('Site initialized');
 });

+ 10 - 2
SicboSubWs/SicboSubWs/src/com/vas/webservices/SicboSubWs.java

@@ -223,13 +223,18 @@ public class SicboSubWs extends WebserviceAbstract {
                 chargeLog.setStatus(Common.Constant.REGISTER_STATUS);
                 db.iInsertChargeLog(chargeLog);
             }
+                        
 
             // send message
             String message = "";
             if (!isCreated) {
-                message = MessageResponse.get(Common.Message.CREATE_ACCOUNT_SUCCESS,
-                        Common.Message.CREATE_ACCOUNT_SUCCESS, logger);
+                message = MessageResponse.get(Common.Message.CREATE_ACCOUNT_SUCCESS, logger);
                 message = message.replaceAll("%password%", password);
+                SmsMtObj mt = new SmsMtObj();
+                mt.setMsisdn(msisdn);
+                mt.setChannel(Common.CHANNEL);
+                mt.setMessage(message);
+                db.insertMt(mt);
             }
             message = MessageResponse.get(Common.Message.REGISTER_SUCCESS,
                     Common.Message.REGISTER_SUCCESS, logger);
@@ -415,9 +420,12 @@ public class SicboSubWs extends WebserviceAbstract {
                             // register
 //                        ProductInfo product = db.iLoadPackageByName(subServiceName);
                             response = registerByMps(msisdn, productInfo, amount, "1");
+                            logger.info("params: " + params +"registerByMps:SubRequest");
                         } else if (params.equals("1")) {
                             // unsub
                             response = cancelServiceMps(msisdn, productInfo, "1");
+                            logger.info("params: " + params +"cancelServiceMps:SubRequest");
+
                         } else {
                             logger.info("Unknown params: " + params);
                             response.setErrorCode(PARAM_NOT_VALID);

+ 3 - 3
SicboSubWs/etc/database.xml

@@ -15,9 +15,9 @@
 <property name="username">sicbo</property>
 	<property name="password">qwK99QfuhEmcFE</property>
 	<!-- <property name="connection">jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=yes)(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))
-(CONNECT_DATA=(FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=180)(DELAY=5))(SERVICE_NAME=vascp)))</property>
-	<property name="username">hobby_hub</property>
-	<property name="password">M90$hsd4575</property> -->
+(CONNECT_DATA=(FAILOVER_MODE=(TYPE=select)(METHOD=basic)(RETRIES=180)(DELAY=5))(SERVICE_NAME=pdbvas1)))</property>
+	<property name="username">SICBO</property>
+	<property name="password">S1cbo$2025</property> -->
 
     <property name="initialPoolSize">5</property>   
 	<property name="maxPoolSize">30</property>

BIN
SicboSub_Request to create domain name and map with public IP.docx