HomeController.cs 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Globalization;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using LotteryWebApp.Common;
  8. using LotteryWebApp.Extensions;
  9. using LotteryWebApp.Languages;
  10. using LotteryWebApp.Models;
  11. using LotteryWebApp.Service;
  12. using Microsoft.AspNetCore.Hosting;
  13. using Microsoft.AspNetCore.Http;
  14. using Microsoft.AspNetCore.Mvc;
  15. using Microsoft.Extensions.Configuration;
  16. using Newtonsoft.Json;
  17. using LotteryWebApp.Controllers;
  18. namespace LotteryWebApp.Areas.Millions.Controllers
  19. {
  20. [Area("Millions")]
  21. [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
  22. public class HomeController : BaseController
  23. {
  24. private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(Program));
  25. IConfiguration configuration;
  26. private readonly IWebHostEnvironment webHostEnvironment;
  27. APIFunctions api = new APIFunctions();
  28. public HomeController(IConfiguration _configuration, IWebHostEnvironment hostEnvironment)
  29. {
  30. configuration = _configuration;
  31. webHostEnvironment = hostEnvironment;
  32. }
  33. public String GetParameter(String key)
  34. {
  35. return configuration.GetSection(key).Value;
  36. }
  37. public async Task<IActionResult> Index(
  38. string termType,
  39. String uuid,
  40. String mcuid,
  41. String phonenumber,
  42. String token
  43. )
  44. {
  45. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  46. try
  47. {
  48. CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
  49. String lang = currentCulture.Name;
  50. String msisdnAuto = null;
  51. if (!CheckAuthToken())
  52. {
  53. if (token != null)
  54. {
  55. AutoLoginRequest autoLoginRequest = new AutoLoginRequest { token = token };
  56. AutoLoginResponse autoLoginResponse = await api.AutoLoginApiAsync(configuration, autoLoginRequest);
  57. if (autoLoginResponse.code == Code.SUCCESS_CODE)
  58. {
  59. string msisdnReal = validateMsisdn(autoLoginResponse.data.msisdn.Substring(1));
  60. if (msisdnReal == "") return RedirectToAction("Login", "Account", new { area = "" });
  61. CheckAccountRequest checkAccountRequest = new CheckAccountRequest
  62. {
  63. msisdn = msisdnReal,
  64. channel = Constants.WEB_CHANNEL,
  65. language = lang == "en" ? "0" : "1"
  66. };
  67. CheckAccountResponse checkAccountResponse = api.CheckAccountApi(configuration, checkAccountRequest);
  68. if (checkAccountResponse.status == Code.SUCCESS)
  69. {
  70. string tokenGetReal = checkAccountResponse.token;
  71. HttpContext.Session.SetComplexData("msisdn", msisdnReal);
  72. CreateAuthToken();
  73. HttpContext.Session.SetComplexData("token", tokenGetReal);
  74. UserGetProfileRequest userGetProfileRequest = new UserGetProfileRequest { users = msisdnReal, token = tokenGetReal };
  75. Profile profileGet = api.UserLoadProfileApi(configuration, userGetProfileRequest);
  76. HttpContext.Session.SetComplexData("profile", profileGet);
  77. UserStatusRequest userStatusRequest = new UserStatusRequest { users = msisdnReal, token = tokenGetReal };
  78. UserStatus userStatusGet = api.GetUserStatusApi(configuration, userStatusRequest);
  79. HttpContext.Session.SetComplexData("userStatus", userStatusGet);
  80. }
  81. else
  82. {
  83. return RedirectToAction("Login", "Account", new { area = "" });
  84. }
  85. }
  86. }
  87. else if (uuid != null)
  88. {
  89. String res = await CheckAutoLogin(log, uuid);
  90. if (res != null)
  91. {
  92. dynamic json = JsonConvert.DeserializeObject(res);
  93. if (json["code"] == "200" && json["errorCode"] == "200")
  94. {
  95. msisdnAuto = json["data"]["msisdn"];
  96. }
  97. }
  98. String msisdnDetect = validateMsisdn(msisdnAuto.Substring(1));
  99. if (msisdnDetect != "")
  100. {
  101. RegisterRequest request = new RegisterRequest { Msisdn = msisdnDetect };
  102. RegisterResponse reset = api.UserForgotPasswordApi(configuration, request);
  103. if (reset.status == Code.SUCCESS)
  104. {
  105. HttpContext.Session.Remove("regInfos");
  106. HttpContext.Session.SetComplexData("msisdn", msisdnDetect);
  107. return RedirectToAction("Login", "Account", new { area = "", step = 2 });
  108. }
  109. }
  110. return RedirectToAction("Login", "Account", new { area = "" });
  111. }
  112. else if (phonenumber != null)
  113. {
  114. // simplified or same logic as original
  115. return RedirectToAction("Login", "Account", new { area = "" });
  116. }
  117. else
  118. {
  119. // If no token/uuid and not auth, verify existing session token
  120. var savedToken = HttpContext.Session.GetString("token");
  121. if (string.IsNullOrEmpty(savedToken))
  122. {
  123. return RedirectToAction("Login", "Account", new { area = "" });
  124. }
  125. }
  126. }
  127. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  128. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  129. model.termType = termType != null ? termType : Constants.Millions_CODE;
  130. model.userStatus = userStatus;
  131. model.profile = profile;
  132. model.listTerm = new List<Term>();
  133. String tokenGet = HttpContext.Session.GetComplexData<String>("token");
  134. String fromDate = DateTime.Now.AddDays(-2).ToString("dd/MM/yyyy");
  135. String toDate = DateTime.Now.ToString("dd/MM/yyyy");
  136. // Get Top Winner
  137. GetTopWinnerRequest getTopWinnerRequest = new GetTopWinnerRequest { type = lang == "en" ? "0" : "1", token = tokenGet };
  138. GetTopWininerResponse getTopWininerResponse = api.GetTopWinnerApi(configuration, getTopWinnerRequest);
  139. if (getTopWininerResponse.responseCode == Code.SUCCESS)
  140. {
  141. model.topWinner = getTopWininerResponse.list;
  142. HttpContext.Session.SetComplexData("topWinner", model.topWinner);
  143. }
  144. // Get Term Results
  145. //ResultOfTermRequest resultOfTermRequest = new ResultOfTermRequest
  146. //{
  147. // gameId = model.termType,
  148. // token = tokenGet,
  149. // type = Constants.TERM_HAS_NOT_RESULT_TYPE,
  150. // order = Constants.DECS,
  151. // fromDate = fromDate,
  152. // toDate = toDate,
  153. // rowsOnPage = Constants.ROW_ON_PAGE,
  154. // seqPage = "1",
  155. // id = Constants.ALL_DATA
  156. //};
  157. //ResultOfTermResponse result = api.GetResultOfTermApi(configuration, resultOfTermRequest);
  158. //if (result.responseCode == Code.SESSION_EXPIRED)
  159. //{
  160. // return RedirectToAction("Login", "Account", new { area = "" });
  161. //}
  162. //else if (result.responseCode == Code.SUCCESS)
  163. //{
  164. // model.listTerm = result.listTerm;
  165. //}
  166. if (!string.IsNullOrEmpty(termType))
  167. {
  168. HttpContext.Session.SetString("termType", termType);
  169. }
  170. }
  171. catch (Exception ex)
  172. {
  173. log.Error(ex);
  174. return RedirectToAction("Login", "Account", new { area = "" });
  175. }
  176. return View(model);
  177. }
  178. public async Task<IActionResult> GameHome(string termType)
  179. {
  180. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  181. try
  182. {
  183. var token = HttpContext.Session.GetComplexData<string>("token");
  184. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  185. {
  186. return RedirectToAction("Login", "Account", new { area = "" });
  187. }
  188. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  189. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  190. model.termType = termType != null ? termType : Constants.Millions_CODE;
  191. model.userStatus = userStatus;
  192. model.profile = profile;
  193. model.listTerm = new List<Term>();
  194. if (!string.IsNullOrEmpty(termType))
  195. {
  196. HttpContext.Session.SetString("termType", termType);
  197. }
  198. // Get Term Results for Jackpot
  199. string cachedBolet = HttpContext.Session.GetString("bolet");
  200. if (!string.IsNullOrEmpty(cachedBolet))
  201. {
  202. model.bolet = cachedBolet;
  203. model.lastResult = HttpContext.Session.GetString("lastResult");
  204. model.lastResultDate = HttpContext.Session.GetString("lastResultDate");
  205. model.nextRoundDate = HttpContext.Session.GetString("nextRoundDate");
  206. }
  207. else
  208. {
  209. String fromDate = DateTime.Now.AddDays(-7).ToString("dd/MM/yyyy");
  210. String toDate = DateTime.Now.ToString("dd/MM/yyyy");
  211. string lang = CultureInfo.CurrentCulture.Name;
  212. string langValue = (lang.StartsWith("en") || lang.StartsWith("fr")) ? "0" : "1";
  213. // Get Last Result
  214. ResultOfTermRequest resultOfTermRequest = new ResultOfTermRequest
  215. {
  216. gameId = model.termType,
  217. language = langValue,
  218. token = token,
  219. type = Constants.TERM_HAS_RESULT_TYPE,
  220. order = Constants.DECS,
  221. fromDate = fromDate,
  222. toDate = toDate,
  223. rowsOnPage = Constants.ROW_ON_PAGE,
  224. seqPage = "1",
  225. id = Constants.ALL_DATA
  226. };
  227. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, resultOfTermRequest);
  228. if (result.responseCode == Code.SUCCESS && result.listTerm != null && result.listTerm.Count > 0)
  229. {
  230. model.bolet = result.listTerm[0].bolet;
  231. model.lastResult = result.listTerm[0].result;
  232. model.lastResultDate = result.listTerm[0].date_random;
  233. model.nextRoundDate = result.listTerm[0].date_end;
  234. HttpContext.Session.SetString("nextRoundDate", model.nextRoundDate ?? "");
  235. HttpContext.Session.SetString("bolet", model.bolet ?? "");
  236. HttpContext.Session.SetString("lastResult", model.lastResult ?? "");
  237. HttpContext.Session.SetString("lastResultDate", model.lastResultDate ?? "");
  238. }
  239. //// Get Next Round
  240. //ResultOfTermRequest nextRoundRequest = new ResultOfTermRequest
  241. //{
  242. // gameId = model.termType,
  243. // language = langValue,
  244. // token = token,
  245. // type = Constants.TERM_HAS_NOT_RESULT_TYPE,
  246. // order = Constants.ASC,
  247. // fromDate = DateTime.Now.ToString("dd/MM/yyyy"),
  248. // toDate = DateTime.Now.AddDays(7).ToString("dd/MM/yyyy"),
  249. // rowsOnPage = "1",
  250. // seqPage = "1",
  251. // id = Constants.ALL_DATA
  252. //};
  253. //ResultOfTermResponse nextResult = api.GetResultOfTermApi(configuration, nextRoundRequest);
  254. //if (nextResult.responseCode == Code.SUCCESS && nextResult.listTerm != null && nextResult.listTerm.Count > 0)
  255. //{
  256. // model.nextRoundDate = nextResult.listTerm[0].date_random;
  257. // HttpContext.Session.SetString("nextRoundDate", model.nextRoundDate ?? "");
  258. //}
  259. }
  260. }
  261. catch (Exception ex)
  262. {
  263. log.Error(ex);
  264. }
  265. return View(model);
  266. }
  267. public async Task<IActionResult> FAQ()
  268. {
  269. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  270. try
  271. {
  272. var token = HttpContext.Session.GetComplexData<string>("token");
  273. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  274. {
  275. return RedirectToAction("Login", "Account", new { area = "" });
  276. }
  277. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  278. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  279. model.userStatus = userStatus;
  280. model.profile = profile;
  281. }
  282. catch (Exception ex)
  283. {
  284. log.Error(ex);
  285. }
  286. return View(model);
  287. }
  288. public IActionResult More()
  289. {
  290. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  291. try
  292. {
  293. var token = HttpContext.Session.GetComplexData<string>("token");
  294. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  295. {
  296. return RedirectToAction("Login", "Account", new { area = "" });
  297. }
  298. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  299. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  300. model.userStatus = userStatus;
  301. model.profile = profile;
  302. }
  303. catch (Exception ex)
  304. {
  305. log.Error(ex);
  306. }
  307. return View(model);
  308. }
  309. public IActionResult Profile()
  310. {
  311. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  312. try
  313. {
  314. var token = HttpContext.Session.GetComplexData<string>("token");
  315. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  316. {
  317. return RedirectToAction("Login", "Account", new { area = "" });
  318. }
  319. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  320. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  321. model.userStatus = userStatus;
  322. model.profile = profile;
  323. }
  324. catch (Exception ex)
  325. {
  326. log.Error(ex);
  327. }
  328. return View(model);
  329. }
  330. [HttpPost]
  331. public IActionResult UserUpdateProfile(string fullName, string birthday)
  332. {
  333. try
  334. {
  335. string msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  336. string token = HttpContext.Session.GetComplexData<string>("token");
  337. if (string.IsNullOrEmpty(msisdn) || string.IsNullOrEmpty(token))
  338. {
  339. return Json(new { status = Code.ERROR, message = "Session expired" });
  340. }
  341. string birthdayFormat = birthday;
  342. if (!string.IsNullOrEmpty(birthday) && birthday.Contains("-"))
  343. {
  344. try {
  345. birthdayFormat = DateTime.ParseExact(birthday, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy");
  346. } catch { }
  347. }
  348. UserUpdateProfileRequest request = new UserUpdateProfileRequest
  349. {
  350. users = msisdn,
  351. token = token,
  352. fullName = fullName,
  353. birthday = birthdayFormat
  354. };
  355. UserUpdateProfileResponse response = api.UserUpdateProfileApi(configuration, request);
  356. if (response.status == Code.SUCCESS)
  357. {
  358. // Update session profile
  359. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  360. if (profile != null)
  361. {
  362. profile.fullName = fullName;
  363. profile.birthday = birthdayFormat;
  364. HttpContext.Session.SetComplexData("profile", profile);
  365. }
  366. }
  367. return Json(response);
  368. }
  369. catch (Exception ex)
  370. {
  371. log.Error(ex);
  372. return Json(new { status = Code.ERROR, message = ex.Message });
  373. }
  374. }
  375. public IActionResult Rule()
  376. {
  377. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  378. try
  379. {
  380. var token = HttpContext.Session.GetComplexData<string>("token");
  381. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  382. {
  383. return RedirectToAction("Login", "Account", new { area = "" });
  384. }
  385. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  386. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  387. model.userStatus = userStatus;
  388. model.profile = profile;
  389. }
  390. catch (Exception ex)
  391. {
  392. log.Error(ex);
  393. }
  394. return View(model);
  395. }
  396. public IActionResult JackpotResults(string termType, string fromFormatted, string toFormatted)
  397. {
  398. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  399. try
  400. {
  401. var token = HttpContext.Session.GetComplexData<string>("token");
  402. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  403. {
  404. return RedirectToAction("Login", "Account", new { area = "" });
  405. }
  406. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  407. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  408. model.userStatus = userStatus;
  409. model.profile = profile;
  410. model.bolet = HttpContext.Session.GetString("bolet");
  411. model.lastResult = HttpContext.Session.GetString("lastResult");
  412. model.lastResultDate = HttpContext.Session.GetString("lastResultDate");
  413. model.nextRoundDate = HttpContext.Session.GetString("nextRoundDate");
  414. model.termType = !string.IsNullOrEmpty(termType)
  415. ? termType
  416. : (HttpContext.Session.GetString("termType") ?? Constants.Millions_CODE);
  417. string lang = CultureInfo.CurrentCulture.Name;
  418. string langValue = (lang.StartsWith("en") || lang.StartsWith("fr")) ? "0" : "1";
  419. // Default: last 7 days if filter not provided
  420. if (string.IsNullOrEmpty(fromFormatted))
  421. {
  422. fromFormatted = DateTime.Now.AddDays(-365).ToString("yyyy-MM-dd");
  423. }
  424. if (string.IsNullOrEmpty(toFormatted))
  425. {
  426. toFormatted = DateTime.Now.ToString("yyyy-MM-dd");
  427. }
  428. ViewBag.FromFormatted = fromFormatted;
  429. ViewBag.ToFormatted = toFormatted;
  430. RpSearchDetailTicketRequest request = new RpSearchDetailTicketRequest
  431. {
  432. requestId = DateTime.Now.Ticks.ToString(),
  433. msisdn = "-1",
  434. gameId = model.termType,
  435. fromDate = DateTime.ParseExact(fromFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  436. toDate = DateTime.ParseExact(toFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  437. prize = "JACKPOT",
  438. language = langValue,
  439. token = token
  440. };
  441. RpSearchDetailTicketResponse result = api.RpSearchDetailTicketApi(configuration, request);
  442. log.Debug("RpSearchDetailTicket response: " + JsonConvert.SerializeObject(result));
  443. model.listTerm = new List<Term>();
  444. var winnersByDraw = new Dictionary<string, List<JackpotWinnerItem>>();
  445. if (result != null && result.responseCode == Code.SUCCESS && result.list != null)
  446. {
  447. // Group winners by randomId -> one draw card per group
  448. var grouped = result.list
  449. .GroupBy(w => w.randomId)
  450. .OrderByDescending(g => ParseDrawDate(g.First().randomDate));
  451. foreach (var group in grouped)
  452. {
  453. var first = group.First();
  454. DateTime drawDt = ParseDrawDate(first.randomDate);
  455. long totalPrize = 0;
  456. foreach (var w in group)
  457. {
  458. long m;
  459. if (long.TryParse(w.moneyWin, out m)) totalPrize += m;
  460. }
  461. Term term = new Term
  462. {
  463. id = first.randomId,
  464. seq = first.randomId,
  465. date_random = drawDt != DateTime.MinValue ? drawDt.ToString("dd/MM/yyyy HH:mm:ss") : first.randomDate,
  466. date_start = first.startDate,
  467. date_end = first.endDate,
  468. result = first.result,
  469. money_winner = totalPrize.ToString(),
  470. bolet = totalPrize.ToString(),
  471. split = group.Count().ToString(),
  472. gameId = model.termType
  473. };
  474. model.listTerm.Add(term);
  475. winnersByDraw[first.randomId] = group.ToList();
  476. }
  477. }
  478. // Cache winners by draw id so JackpotDetail can render them
  479. HttpContext.Session.SetComplexData("jackpotWinners", winnersByDraw);
  480. }
  481. catch (Exception ex)
  482. {
  483. log.Error(ex);
  484. model.listTerm = new List<Term>();
  485. }
  486. return View(model);
  487. }
  488. private static DateTime ParseDrawDate(string raw)
  489. {
  490. if (string.IsNullOrEmpty(raw)) return DateTime.MinValue;
  491. string[] formats = {
  492. "M/d/yyyy h:mm:ss tt",
  493. "MM/dd/yyyy h:mm:ss tt",
  494. "M/d/yyyy hh:mm:ss tt",
  495. "dd/MM/yyyy HH:mm:ss",
  496. "yyyy-MM-dd HH:mm:ss"
  497. };
  498. DateTime dt;
  499. if (DateTime.TryParseExact(raw, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
  500. {
  501. return dt;
  502. }
  503. if (DateTime.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
  504. {
  505. return dt;
  506. }
  507. return DateTime.MinValue;
  508. }
  509. public IActionResult JackpotDetail(string id, string termType)
  510. {
  511. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  512. try
  513. {
  514. var token = HttpContext.Session.GetComplexData<string>("token");
  515. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  516. {
  517. return RedirectToAction("Login", "Account", new { area = "" });
  518. }
  519. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  520. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  521. model.userStatus = userStatus;
  522. model.profile = profile;
  523. model.bolet = HttpContext.Session.GetString("bolet");
  524. model.lastResult = HttpContext.Session.GetString("lastResult");
  525. model.lastResultDate = HttpContext.Session.GetString("lastResultDate");
  526. model.termType = !string.IsNullOrEmpty(termType)
  527. ? termType
  528. : (HttpContext.Session.GetString("termType") ?? Constants.Millions_CODE);
  529. ViewBag.DrawId = id;
  530. var cache = HttpContext.Session.GetComplexData<Dictionary<string, List<JackpotWinnerItem>>>("jackpotWinners");
  531. List<JackpotWinnerItem> winners = null;
  532. if (cache != null && !string.IsNullOrEmpty(id) && cache.ContainsKey(id))
  533. {
  534. winners = cache[id];
  535. }
  536. ViewBag.Winners = winners ?? new List<JackpotWinnerItem>();
  537. }
  538. catch (Exception ex)
  539. {
  540. log.Error(ex);
  541. ViewBag.Winners = new List<JackpotWinnerItem>();
  542. }
  543. return View(model);
  544. }
  545. public IActionResult HowToPlay()
  546. {
  547. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  548. try
  549. {
  550. var token = HttpContext.Session.GetComplexData<string>("token");
  551. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  552. {
  553. return RedirectToAction("Login", "Account", new { area = "" });
  554. }
  555. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  556. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  557. model.userStatus = userStatus;
  558. model.profile = profile;
  559. }
  560. catch (Exception ex)
  561. {
  562. log.Error(ex);
  563. }
  564. return View(model);
  565. }
  566. public IActionResult Results(string termType, string fromDate, string toDate)
  567. {
  568. TermResultHistoryModel model = new TermResultHistoryModel();
  569. try
  570. {
  571. var token = HttpContext.Session.GetComplexData<string>("token");
  572. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  573. {
  574. return RedirectToAction("Login", "Account", new { area = "" });
  575. }
  576. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  577. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  578. model.termType = termType != null ? termType : (HttpContext.Session.GetString("termType") ?? Constants.Millions_CODE);
  579. // Set default dates if not provided (same as root implementation)
  580. string fromFormatted = fromDate != null ? fromDate : DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
  581. string toFormatted = toDate != null ? toDate : DateTime.Now.ToString("yyyy-MM-dd");
  582. model.fromDate = fromFormatted;
  583. model.toDate = toFormatted;
  584. // Load initial results
  585. ResultOfTermRequest resultOfTermRequest = new ResultOfTermRequest
  586. {
  587. gameId = model.termType,
  588. token = token,
  589. type = Constants.TERM_HAS_RESULT_TYPE,
  590. order = Constants.DECS,
  591. fromDate = DateTime.ParseExact(fromFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  592. toDate = DateTime.ParseExact(toFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  593. rowsOnPage = Constants.ROW_ON_PAGE,
  594. seqPage = "1",
  595. id = Constants.ALL_DATA
  596. };
  597. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, resultOfTermRequest);
  598. if (result.responseCode == Code.SUCCESS)
  599. {
  600. model.listTerm = result.listTerm ?? new List<Term>();
  601. }
  602. else
  603. {
  604. model.listTerm = new List<Term>();
  605. }
  606. }
  607. catch (Exception ex)
  608. {
  609. log.Error(ex);
  610. model.listTerm = new List<Term>();
  611. }
  612. return View(model);
  613. }
  614. public IActionResult TermResultHistory(string termType, string fromDate, string toDate)
  615. {
  616. TermResultHistoryModel model = new TermResultHistoryModel();
  617. try
  618. {
  619. var token = HttpContext.Session.GetComplexData<string>("token");
  620. if (string.IsNullOrEmpty(token)) return Json(new { status = "error", message = "Session expired" });
  621. string fromFormatted = fromDate != null ? fromDate : DateTime.Now.AddDays(-2).ToString("yyyy-MM-dd");
  622. string toFormatted = toDate != null ? toDate : DateTime.Now.ToString("yyyy-MM-dd");
  623. model.termType = termType;
  624. model.fromDate = fromFormatted;
  625. model.toDate = toFormatted;
  626. ResultOfTermRequest request = new ResultOfTermRequest
  627. {
  628. gameId = termType,
  629. token = token,
  630. type = Constants.TERM_HAS_RESULT_TYPE,
  631. order = Constants.DECS,
  632. fromDate = DateTime.ParseExact(fromFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  633. toDate = DateTime.ParseExact(toFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  634. rowsOnPage = Constants.ROW_ON_PAGE,
  635. seqPage = "1",
  636. id = Constants.ALL_DATA
  637. };
  638. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, request);
  639. if (result.responseCode == Code.SUCCESS)
  640. {
  641. model.listTerm = result.listTerm ?? new List<Term>();
  642. }
  643. else
  644. {
  645. model.listTerm = new List<Term>();
  646. }
  647. }
  648. catch (Exception ex)
  649. {
  650. log.Error(ex);
  651. model.listTerm = new List<Term>();
  652. }
  653. return PartialView("_TermResultHistoryV2", model);
  654. }
  655. public IActionResult TermResultHistoryGrouped(string fromDate, string toDate)
  656. {
  657. try
  658. {
  659. var token = HttpContext.Session.GetComplexData<string>("token");
  660. if (string.IsNullOrEmpty(token)) return Json(new { status = "error", message = "Session expired" });
  661. string fromFormatted = fromDate != null ? fromDate : DateTime.Now.AddDays(-2).ToString("yyyy-MM-dd");
  662. string toFormatted = toDate != null ? toDate : DateTime.Now.ToString("yyyy-MM-dd");
  663. string[] gameIds = { Constants.Millions_CODE };
  664. var allTerms = new List<Term>();
  665. foreach (var gid in gameIds)
  666. {
  667. ResultOfTermRequest request = new ResultOfTermRequest
  668. {
  669. gameId = gid,
  670. token = token,
  671. type = Constants.TERM_HAS_RESULT_TYPE,
  672. order = Constants.DECS,
  673. fromDate = DateTime.ParseExact(fromFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  674. toDate = DateTime.ParseExact(toFormatted, "yyyy-MM-dd", CultureInfo.InvariantCulture).ToString("dd/MM/yyyy"),
  675. rowsOnPage = "50",
  676. seqPage = "1",
  677. id = Constants.ALL_DATA
  678. };
  679. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, request);
  680. if (result.responseCode == Code.SUCCESS && result.listTerm != null)
  681. {
  682. allTerms.AddRange(result.listTerm);
  683. }
  684. }
  685. // Group by date part of date_random
  686. var grouped = allTerms.GroupBy(x => {
  687. DateTime dt;
  688. if (DateTime.TryParse(x.date_random, out dt))
  689. return dt.Date;
  690. return DateTime.MinValue;
  691. })
  692. .Where(g => g.Key != DateTime.MinValue)
  693. .OrderByDescending(g => g.Key)
  694. .ToList();
  695. return PartialView("_TermResultHistoryGrouped", grouped);
  696. }
  697. catch (Exception ex)
  698. {
  699. log.Error(ex);
  700. return PartialView("_TermResultHistoryGrouped", new List<IGrouping<DateTime, Term>>());
  701. }
  702. }
  703. public IActionResult History(string termType, string status, string seqPage)
  704. {
  705. UserTicketHistoryModel model = new UserTicketHistoryModel();
  706. try
  707. {
  708. var token = HttpContext.Session.GetComplexData<string>("token");
  709. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  710. {
  711. return RedirectToAction("Login", "Account", new { area = "" });
  712. }
  713. string msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  714. model.termType = termType ?? Constants.Millions_CODE;
  715. model.status = status ?? Constants.ALL_DATA; // -1 for all, or 0, 1, 2
  716. model.seqPage = seqPage ?? "1";
  717. UserTicketRequest request = new UserTicketRequest
  718. {
  719. gameId = model.termType,
  720. msisdn = msisdn,
  721. token = token,
  722. type = model.status,
  723. order = Constants.DECS,
  724. rowsOnPage = Constants.ROW_ON_PAGE,
  725. seqPage = model.seqPage
  726. };
  727. UserTicketResponse result = api.GetUserTicketApi(configuration, request);
  728. if (result.responseCode == Code.SUCCESS)
  729. {
  730. model.listTicket = result.listTicket ?? new List<Ticket>();
  731. model.totalPage = result.totalPage;
  732. }
  733. else
  734. {
  735. model.listTicket = new List<Ticket>();
  736. model.totalPage = "0";
  737. }
  738. }
  739. catch (Exception ex)
  740. {
  741. log.Error(ex);
  742. model.listTicket = new List<Ticket>();
  743. }
  744. return View(model);
  745. }
  746. public IActionResult TermUserTicketHistory(string termType, string status, string seqPage)
  747. {
  748. UserTicketHistoryModel model = new UserTicketHistoryModel();
  749. try
  750. {
  751. var token = HttpContext.Session.GetComplexData<string>("token");
  752. if (string.IsNullOrEmpty(token)) return Json(new { status = "error", message = "Session expired" });
  753. string msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  754. model.termType = termType;
  755. model.status = status;
  756. model.seqPage = seqPage ?? "1";
  757. UserTicketRequest request = new UserTicketRequest
  758. {
  759. gameId = termType,
  760. msisdn = msisdn,
  761. token = token,
  762. type = status,
  763. order = Constants.DECS,
  764. rowsOnPage = Constants.ROW_ON_PAGE,
  765. seqPage = model.seqPage
  766. };
  767. UserTicketResponse result = api.GetUserTicketApi(configuration, request);
  768. if (result.responseCode == Code.SUCCESS)
  769. {
  770. model.listTicket = result.listTicket ?? new List<Ticket>();
  771. model.totalPage = result.totalPage;
  772. }
  773. else
  774. {
  775. model.listTicket = new List<Ticket>();
  776. model.totalPage = "0";
  777. }
  778. }
  779. catch (Exception ex)
  780. {
  781. log.Error(ex);
  782. model.listTicket = new List<Ticket>();
  783. }
  784. return PartialView("_TermUserTicketHistory", model);
  785. }
  786. public IActionResult RewardHistory(string seqPage)
  787. {
  788. RewardHistoryModel model = BuildRewardHistory(seqPage, fallbackRedirectOnExpired: true, out IActionResult redirect);
  789. if (redirect != null) return redirect;
  790. return View(model);
  791. }
  792. public IActionResult RewardHistoryPartial(string seqPage)
  793. {
  794. var token = HttpContext.Session.GetComplexData<string>("token");
  795. if (string.IsNullOrEmpty(token))
  796. return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  797. RewardHistoryModel model = BuildRewardHistory(seqPage, fallbackRedirectOnExpired: false, out _);
  798. return PartialView("_RewardHistoryList", model);
  799. }
  800. private RewardHistoryModel BuildRewardHistory(string seqPage, bool fallbackRedirectOnExpired, out IActionResult redirect)
  801. {
  802. redirect = null;
  803. RewardHistoryModel model = new RewardHistoryModel
  804. {
  805. seqPage = string.IsNullOrEmpty(seqPage) ? "1" : seqPage
  806. };
  807. try
  808. {
  809. var token = HttpContext.Session.GetComplexData<string>("token");
  810. if (string.IsNullOrEmpty(token))
  811. {
  812. if (fallbackRedirectOnExpired)
  813. redirect = RedirectToAction("Login", "Account", new { area = "" });
  814. return model;
  815. }
  816. string msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  817. TransactionInfoRequest request = new TransactionInfoRequest
  818. {
  819. msisdn = msisdn,
  820. token = token,
  821. order = Constants.DECS,
  822. rowsOnPage = Constants.ROW_ON_PAGE,
  823. seqPage = model.seqPage
  824. };
  825. TransactionInfoResponse result = api.GetTransactionInfoApi(configuration, request);
  826. if (result != null && result.responseCode == Code.SUCCESS)
  827. {
  828. model.list = result.list ?? new List<Transaction>();
  829. model.totalPage = result.totalPage ?? "0";
  830. }
  831. }
  832. catch (Exception ex)
  833. {
  834. log.Error(ex);
  835. }
  836. return model;
  837. }
  838. [HttpPost]
  839. [ValidateAntiForgeryToken]
  840. public IActionResult TermResult(string termType)
  841. {
  842. try
  843. {
  844. var token = HttpContext.Session.GetComplexData<string>("token");
  845. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  846. log.Info($"[Millions.TermResult] START - termType={termType}, msisdn={msisdn}");
  847. if (string.IsNullOrEmpty(token))
  848. {
  849. log.Info($"[Millions.TermResult] Session expired - termType={termType}, msisdn={msisdn}");
  850. return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  851. }
  852. string lang = CultureInfo.CurrentCulture.Name;
  853. string langValue = (lang.StartsWith("en") || lang.StartsWith("fr")) ? "0" : "1";
  854. ResultOfTermRequest request = new ResultOfTermRequest
  855. {
  856. gameId = termType,
  857. language = langValue,
  858. token = token,
  859. type = Constants.TERM_HAS_NOT_RESULT_TYPE,
  860. order = Constants.DECS,
  861. rowsOnPage = "5",
  862. seqPage = "1",
  863. id = Constants.ALL_DATA
  864. };
  865. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, request);
  866. log.Info($"[Millions.TermResult] Response - termType={termType}, code={result?.responseCode}, msg={result?.responseMessage}, termCount={result?.listTerm?.Count ?? 0}");
  867. return Json(result);
  868. }
  869. catch (Exception ex)
  870. {
  871. log.Error($"[Millions.TermResult] EXCEPTION - termType={termType}", ex);
  872. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  873. }
  874. }
  875. [HttpPost]
  876. public IActionResult ConfirmTicketData([FromBody] ConfirmTicketDataRequest request)
  877. {
  878. try
  879. {
  880. var token = HttpContext.Session.GetComplexData<string>("token");
  881. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  882. if (string.IsNullOrEmpty(token)) return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  883. request.token = token;
  884. request.msisdn = msisdn;
  885. request.language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1";
  886. request.requestId = Guid.NewGuid().ToString();
  887. // DEBUG: Log request data
  888. var ticketDebug = request.ticket != null ? string.Join("; ", request.ticket.Select(t => $"code={t.code}, money={t.money}")) : "NULL";
  889. log.Info($"[ConfirmTicketData] gameId={request.gameId}, msisdn={request.msisdn}, tickets=[{ticketDebug}]");
  890. ConfirmTicketDataResponse response = api.ConfirmTicketDataApi(configuration, request);
  891. // DEBUG: Log response
  892. log.Info($"[ConfirmTicketData] Response: code={response.responseCode}, msg={response.responseMessage}, transId={response.transId}");
  893. return Json(response);
  894. }
  895. catch (Exception ex)
  896. {
  897. log.Error(ex);
  898. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  899. }
  900. }
  901. [HttpPost]
  902. public IActionResult PrepareTicketPayment([FromBody] MillionsPaymentRequest paymentRequest)
  903. {
  904. try
  905. {
  906. if (paymentRequest?.ticketData == null || paymentRequest.ticketData.ticket == null || !paymentRequest.ticketData.ticket.Any())
  907. {
  908. return Json(new { responseCode = Code.FAILURE, responseMessage = Lang.ticket_invalid });
  909. }
  910. if (paymentRequest.paymentSource != Constants.BASIC_WALLET_TICKET &&
  911. paymentRequest.paymentSource != Constants.NATCASH_WALLET_TICKET)
  912. {
  913. return Json(new { responseCode = Code.FAILURE, responseMessage = Lang.error_happened });
  914. }
  915. var token = HttpContext.Session.GetComplexData<string>("token");
  916. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  917. if (string.IsNullOrEmpty(token))
  918. {
  919. return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  920. }
  921. ConfirmTicketDataRequest request = paymentRequest.ticketData;
  922. request.token = token;
  923. request.msisdn = msisdn;
  924. request.language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1";
  925. request.requestId = Guid.NewGuid().ToString();
  926. log.Info($"[Millions.PrepareTicketPayment] Confirm ticket request: {JsonConvert.SerializeObject(request)}");
  927. ConfirmTicketDataResponse response = api.ConfirmTicketDataApi(configuration, request);
  928. log.Info($"[Millions.PrepareTicketPayment] Confirm ticket response: {JsonConvert.SerializeObject(response)}");
  929. if (response.responseCode != Code.SUCCESS || paymentRequest.paymentSource != Constants.NATCASH_WALLET_TICKET)
  930. {
  931. return Json(response);
  932. }
  933. string param = "transactionId=" + response.transId + "&requestId=" + response.requestId + "&money=" + response.totalMoney;
  934. string privateUrl = CreatePrivateURL(configuration, param, "seconds", "0", "0", GetParameter("rsaPolicy"));
  935. return Json(new
  936. {
  937. responseCode = response.responseCode,
  938. responseMessage = response.responseMessage,
  939. transId = response.transId,
  940. requestId = response.requestId,
  941. totalMoney = response.totalMoney,
  942. paymentSource = paymentRequest.paymentSource,
  943. redirectUrl = GetParameter(Constants.SUB_DOMAIN) + "/BuyTicket/BackToApp?" + privateUrl
  944. });
  945. }
  946. catch (Exception ex)
  947. {
  948. log.Error("[Millions.PrepareTicketPayment] EXCEPTION: ", ex);
  949. return Json(new { responseCode = Code.ERROR, responseMessage = Lang.error_happened });
  950. }
  951. }
  952. [HttpPost]
  953. public IActionResult ConfirmOTP([FromBody] ConfirmOTPRequest request)
  954. {
  955. try
  956. {
  957. var token = HttpContext.Session.GetComplexData<string>("token");
  958. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  959. if (string.IsNullOrEmpty(token)) return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  960. request.token = token;
  961. request.msisdn = msisdn;
  962. ConfirmOTPResponse response = api.ConfirmOTPApi(configuration, request);
  963. return Json(response);
  964. }
  965. catch (Exception ex)
  966. {
  967. log.Error(ex);
  968. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  969. }
  970. }
  971. [HttpPost]
  972. public IActionResult SendOTP()
  973. {
  974. try
  975. {
  976. var token = HttpContext.Session.GetComplexData<string>("token");
  977. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  978. if (string.IsNullOrEmpty(token)) return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  979. SendOTPRequest request = new SendOTPRequest
  980. {
  981. msisdn = msisdn,
  982. token = token,
  983. language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1",
  984. channel = configuration.GetSection("channel").Value
  985. };
  986. SendOTPResponse response = api.SendOTPApi(configuration, request);
  987. return Json(response);
  988. }
  989. catch (Exception ex)
  990. {
  991. log.Error(ex);
  992. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  993. }
  994. }
  995. [HttpPost]
  996. public IActionResult ConfirmBuyingTicketV2([FromBody] ConfirmBuyingTicketRequest request)
  997. {
  998. try
  999. {
  1000. var token = HttpContext.Session.GetComplexData<string>("token");
  1001. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  1002. if (string.IsNullOrEmpty(token)) return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  1003. // Step 1: Verify OTP first
  1004. ConfirmOTPRequest otpRequest = new ConfirmOTPRequest
  1005. {
  1006. otp = request.paymentCode,
  1007. msisdn = msisdn,
  1008. token = token,
  1009. language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1",
  1010. channel = configuration.GetSection("channel").Value
  1011. };
  1012. ConfirmOTPResponse otpResponse = api.ConfirmOTPApi(configuration, otpRequest);
  1013. if (otpResponse.responseCode != Code.SUCCESS)
  1014. {
  1015. return Json(new { responseCode = otpResponse.responseCode, responseMessage = otpResponse.responseMessage });
  1016. }
  1017. // Step 2: Proceed to Confirm buying
  1018. request.token = token;
  1019. request.msisdn = msisdn;
  1020. request.requestId = Guid.NewGuid().ToString();
  1021. request.language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1";
  1022. request.channel = configuration.GetSection("channel").Value;
  1023. ConfirmBuyingTicketResponse response = api.ConfirmBuyingTicketApi(configuration, request);
  1024. if (response.responseCode == Code.SUCCESS)
  1025. {
  1026. UpdateUserStatus(msisdn, token);
  1027. }
  1028. return Json(response);
  1029. }
  1030. catch (Exception ex)
  1031. {
  1032. log.Error(ex);
  1033. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  1034. }
  1035. }
  1036. [HttpPost]
  1037. public IActionResult ConfirmBuyingTicket([FromBody] ConfirmBuyingTicketRequest request)
  1038. {
  1039. try
  1040. {
  1041. var token = HttpContext.Session.GetComplexData<string>("token");
  1042. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  1043. if (string.IsNullOrEmpty(token)) return Json(new { responseCode = Code.SESSION_EXPIRED, responseMessage = "Session expired" });
  1044. request.token = token;
  1045. request.msisdn = msisdn;
  1046. request.requestId = Guid.NewGuid().ToString();
  1047. request.language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1";
  1048. request.channel = configuration.GetSection("channel").Value;
  1049. ConfirmBuyingTicketResponse response = api.ConfirmBuyingTicketApi(configuration, request);
  1050. if (response.responseCode == Code.SUCCESS)
  1051. {
  1052. UpdateUserStatus(msisdn, token);
  1053. }
  1054. return Json(new {
  1055. responseCode = response.responseCode,
  1056. responseMessage = response.responseMessage,
  1057. transId = response.transId,
  1058. orderId = response.orderId,
  1059. userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus")
  1060. });
  1061. }
  1062. catch (Exception ex)
  1063. {
  1064. log.Error(ex);
  1065. return Json(new { responseCode = Code.ERROR, responseMessage = ex.Message });
  1066. }
  1067. }
  1068. public IActionResult BuyTicket(string termType)
  1069. {
  1070. try
  1071. {
  1072. var token = HttpContext.Session.GetComplexData<string>("token");
  1073. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  1074. log.Info($"[Millions.BuyTicket] START - termType={termType}, msisdn={msisdn}");
  1075. if (string.IsNullOrEmpty(token) && !User.Identity.IsAuthenticated)
  1076. {
  1077. log.Info($"[Millions.BuyTicket] Redirect login - missing token, termType={termType}, msisdn={msisdn}");
  1078. return RedirectToAction("Login", "Account", new { area = "" });
  1079. }
  1080. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  1081. model.termType = termType ?? Constants.Millions_CODE;
  1082. log.Info($"[Millions.BuyTicket] Check active term - gameId={model.termType}, msisdn={msisdn}");
  1083. Profile profile = HttpContext.Session.GetComplexData<Profile>("profile");
  1084. UserStatus userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  1085. model.userStatus = userStatus;
  1086. model.profile = profile;
  1087. // Get active term
  1088. ResultOfTermRequest request = new ResultOfTermRequest
  1089. {
  1090. gameId = model.termType,
  1091. token = token,
  1092. type = Constants.TERM_HAS_NOT_RESULT_TYPE,
  1093. order = Constants.DECS,
  1094. rowsOnPage = "1",
  1095. seqPage = "1",
  1096. id = Constants.ALL_DATA
  1097. };
  1098. ResultOfTermResponse result = api.GetResultOfTermApi(configuration, request);
  1099. log.Info($"[Millions.BuyTicket] Active term response - gameId={model.termType}, code={result?.responseCode}, msg={result?.responseMessage}, termCount={result?.listTerm?.Count ?? 0}");
  1100. if (result.responseCode == Code.SUCCESS && result.listTerm != null && result.listTerm.Count > 0)
  1101. {
  1102. model.listTerm = result.listTerm;
  1103. }
  1104. else
  1105. {
  1106. model.listTerm = new List<Term>();
  1107. }
  1108. if (model.termType == Constants.PIC10_BIGSMALL_CODE || model.termType == Constants.PIC10_ODDEVEN_CODE)
  1109. {
  1110. log.Info($"[Millions.BuyTicket] Check past terms - gameId={model.termType}, msisdn={msisdn}");
  1111. ResultOfTermRequest pastRequest = new ResultOfTermRequest
  1112. {
  1113. gameId = model.termType,
  1114. token = token,
  1115. type = Constants.TERM_HAS_RESULT_TYPE,
  1116. order = Constants.DECS,
  1117. fromDate = DateTime.Now.AddDays(-10).ToString("dd/MM/yyyy"),
  1118. toDate = DateTime.Now.ToString("dd/MM/yyyy"),
  1119. rowsOnPage = "5",
  1120. seqPage = "1",
  1121. id = Constants.ALL_DATA
  1122. };
  1123. ResultOfTermResponse pastResult = api.GetResultOfTermApi(configuration, pastRequest);
  1124. log.Info($"[Millions.BuyTicket] Past term response - gameId={model.termType}, code={pastResult?.responseCode}, msg={pastResult?.responseMessage}, termCount={pastResult?.listTerm?.Count ?? 0}");
  1125. if (pastResult.responseCode == Code.SUCCESS && pastResult.listTerm != null)
  1126. {
  1127. var pastTerms = pastResult.listTerm.Take(5).ToList();
  1128. pastTerms.Reverse(); // Display chronological order
  1129. ViewBag.PastTerms = pastTerms;
  1130. }
  1131. else
  1132. {
  1133. ViewBag.PastTerms = new List<Term>();
  1134. }
  1135. }
  1136. log.Info($"[Millions.BuyTicket] END - gameId={model.termType}, activeTermCount={model.listTerm?.Count ?? 0}, msisdn={msisdn}");
  1137. return View(model);
  1138. }
  1139. catch (Exception ex)
  1140. {
  1141. log.Error($"[Millions.BuyTicket] EXCEPTION - termType={termType}", ex);
  1142. return RedirectToAction("GameHome", new { termType = termType });
  1143. }
  1144. }
  1145. public IActionResult TransferWinMoney()
  1146. {
  1147. if (!CheckAuthToken())
  1148. {
  1149. return RedirectToAction("Login", "Account", new { area = "" });
  1150. }
  1151. HomeIndex_ViewModel model = new HomeIndex_ViewModel();
  1152. model.profile = HttpContext.Session.GetComplexData<Profile>("profile");
  1153. model.userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus");
  1154. return View(model);
  1155. }
  1156. [HttpPost]
  1157. public IActionResult ConfirmTransfer(string otp, string phone, string amount, int channelPayment = 1)
  1158. {
  1159. try
  1160. {
  1161. var token = HttpContext.Session.GetComplexData<string>("token");
  1162. var msisdn = HttpContext.Session.GetComplexData<string>("msisdn");
  1163. if (string.IsNullOrEmpty(token)) return Json(new { status = Code.SESSION_EXPIRED, message = "Session expired" });
  1164. var transferChannel = channelPayment == 2
  1165. ? Constants.NATCASH_WALLET_TRANSFER
  1166. : Constants.BASIC_WALLET_TRANSFER;
  1167. // Step 1: Verify OTP
  1168. ConfirmOTPRequest otpRequest = new ConfirmOTPRequest
  1169. {
  1170. otp = otp,
  1171. msisdn = msisdn,
  1172. token = token,
  1173. language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1",
  1174. channel = configuration.GetSection("channel").Value
  1175. };
  1176. ConfirmOTPResponse otpResponse = api.ConfirmOTPApi(configuration, otpRequest);
  1177. if (otpResponse.responseCode != Code.SUCCESS)
  1178. {
  1179. return Json(new { status = otpResponse.responseCode, message = otpResponse.responseMessage });
  1180. }
  1181. // Step 2: If OTP success, call Transfer Money Api
  1182. TransferMoneyRequest xferRequest = new TransferMoneyRequest
  1183. {
  1184. msisdn = msisdn,
  1185. msisdnReceive = phone,
  1186. money = amount,
  1187. otp = otp,
  1188. token = token,
  1189. channelPayment = transferChannel,
  1190. language = CultureInfo.CurrentCulture.Name.StartsWith("en") ? "0" : "1",
  1191. channel = configuration.GetSection("channel").Value
  1192. };
  1193. TransferMoneyResponse xferResponse = api.TransferMoneyApi(configuration, xferRequest);
  1194. if (xferResponse.responseCode == Code.SUCCESS)
  1195. {
  1196. UpdateUserStatus(msisdn, token);
  1197. }
  1198. return Json(new {
  1199. status = xferResponse.responseCode,
  1200. message = xferResponse.responseMessage,
  1201. paymentCode = xferResponse.paymentCode,
  1202. responseCode = xferResponse.responseCode,
  1203. userStatus = HttpContext.Session.GetComplexData<UserStatus>("userStatus")
  1204. });
  1205. }
  1206. catch (Exception ex)
  1207. {
  1208. log.Error(ex);
  1209. return Json(new { status = Code.ERROR, message = ex.Message });
  1210. }
  1211. }
  1212. private void UpdateUserStatus(string msisdn, string token)
  1213. {
  1214. try
  1215. {
  1216. UserStatusRequest userStatusRequest = new UserStatusRequest { users = msisdn, token = token };
  1217. UserStatus userStatusGet = api.GetUserStatusApi(configuration, userStatusRequest);
  1218. if (userStatusGet != null)
  1219. {
  1220. HttpContext.Session.SetComplexData("userStatus", userStatusGet);
  1221. }
  1222. }
  1223. catch (Exception ex)
  1224. {
  1225. log.Error("UpdateUserStatus Error: " + ex.Message);
  1226. }
  1227. }
  1228. public IActionResult Logout()
  1229. {
  1230. ClearCache();
  1231. return Redirect(GetParameter(Constants.SUB_DOMAIN) + "/Account/Login");
  1232. }
  1233. }
  1234. public class MillionsPaymentRequest
  1235. {
  1236. public string paymentSource { get; set; }
  1237. public ConfirmTicketDataRequest ticketData { get; set; }
  1238. }
  1239. }