student 4 недель назад
Родитель
Сommit
1c40e5eb7b
33 измененных файлов с 1014 добавлено и 1142 удалено
  1. 1 0
      KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/common/Common.java
  2. 1 1
      KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/database/WsProcessUtils.java
  3. 50 0
      KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/services/WSProcessor.java
  4. 125 32
      KittyFallWs/KittyFallWs/src/com/vas/webservices/KittyFallWs.java
  5. 1 0
      Kitty_Fall/Kitty_Fall/Common/Common.csproj
  6. 406 382
      Kitty_Fall/Kitty_Fall/Common/Connected Services/Kitty_FallVasWs/Reference.cs
  7. 0 13
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/ApplicationModels.cs
  8. 0 37
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/CvModels.cs
  9. 0 81
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/CvRes.cs
  10. 0 111
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/EmployerModels.cs
  11. 0 118
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/EmployerRes.cs
  12. 0 7
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/InterviewModels.cs
  13. 0 28
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/JobModels.cs
  14. 0 54
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/JobPostReq.cs
  15. 0 49
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/LoadCategoryReq.cs
  16. 0 10
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MasterDataModels.cs
  17. 0 102
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MasterDataRes.cs
  18. 0 18
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MyJobBaseReq.cs
  19. 0 11
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/NotificationModels.cs
  20. 39 0
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/UserBuyTurnReq.cs
  21. 2 22
      Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/UserInfo.cs
  22. 2 1
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/User/IUserBusiness.cs
  23. 130 41
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/User/UserBusinessImpl.cs
  24. 11 3
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Controllers/UserController.cs
  25. 1 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Filters/JwtAuthFilter.cs
  26. 138 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Controllers/HomeController.cs
  27. 9 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.Designer.cs
  28. 3 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.resx
  29. 3 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.vi.resx
  30. 13 4
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/Home/Index.cshtml
  31. 1 0
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/_ViewImports.cshtml
  32. 35 8
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/all.min.js
  33. 43 9
      Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/input.js

+ 1 - 0
KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/common/Common.java

@@ -147,6 +147,7 @@ public class Common {
         public static final String INVITE_FRIEND_REGISTER_SUCCESS = "INVITE_FRIEND_REGISTER_SUCCESS";
         public static final String INVITE_FRIEND_FAILURE = "INVITE_FRIEND_FAILURE";
         public static final String EXCHANGE_SUCCESS = "EXCHANGE_SUCCESS";
+        public static final String EXCHANGE_POINT_SUCCESS = "EXCHANGE_POINT_SUCCESS";
         public static final String EXCHANGE_FAILURE = "EXCHANGE_FAILURE";
         public static final String MINIGAME_REWARD_SUCCESS = "MINIGAME_REWARD_SUCCESS";
         public static final String PLAYING_TIMES_REWARD = "PLAYING_TIMES_REWARD";

+ 1 - 1
KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/database/WsProcessUtils.java

@@ -6962,7 +6962,7 @@ public class WsProcessUtils extends DbProcessorAbstract {
         CallableStatement cs = null;
         ResultSet rs = null;
         Connection connection = null;
-        String sql = "{call ADD_TURN_SPIN ( ?, ? )}";
+        String sql = "{call ADD_TURN ( ?, ? )}";
         try {
             connection = getConnection(dbName);
             cs = connection.prepareCall(sql);

+ 50 - 0
KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/services/WSProcessor.java

@@ -553,6 +553,56 @@ public class WSProcessor extends WebserviceFW {
         return mpsUrl;
     }
     
+    
+    
+    public String addPoint(String msisdn, int point) {
+        // TODO add your handling code here: 
+//        Map<String, String> params = new HashMap();
+        WebserviceObject wsObj = this.getWebservice("add_money");
+//        String isdn = msisdn.substring(Common.COUNTRY_CODE.length());
+//        String keyPath = "../etc/key/" + packName + "/";
+
+        MpsConfigObj mpsConfig = Common.mapMpsConfig.get("ADD_POINT_" + point);
+
+//        MpsConfigObj mpsConfig = Common.mapMpsConfig.get(actionCode);
+        String mpsUrl = makeMpsUrl(msisdn, mpsConfig, wsObj.getWsdl(), false, null);
+
+        String value = null;
+        //
+        TransactionLog log = new TransactionLog();
+        log.setMsisdn(msisdn);
+        log.setType(3);
+        log.setRequest(mpsUrl);
+        log.setCommand(wsObj.getWsCode());
+        log.setErrorCode("000");
+        log.setChannel(wsObj.getWsdl());
+        log.setRequestTime(new Timestamp(System.currentTimeMillis()));
+        setTimeSt(System.currentTimeMillis());
+        try {
+            String response = sendMps(mpsUrl);
+            //
+            log.setResponse(response.length() >= 4000 ? response.substring(0, 3999) : response);
+            log.setResponseTime(new Timestamp(System.currentTimeMillis()));
+
+            logger.info("Response from MPS:" + response);
+            String data_complete_spamsms = EncryptUtil.decodeMpsResponse(response, mpsConfig.getKeyPath());
+            value = EncryptUtil.analyseCodeReturn(data_complete_spamsms);
+            logger.info("mps response value:" + value);
+            String error = value.split("\\|")[0];
+
+            log.setErrorCode(error);
+            return error;
+        } catch (Exception ex) {
+            logger.error("Error when add money via MPS", ex);
+            log.setResponse("Exception");
+            log.setResponseTime(new Timestamp(System.currentTimeMillis()));
+        } finally {
+            logTime("Time to " + wsObj.getWsCode());
+            ProcessTransLog.enqueue(log);
+        }
+        return value;
+    }
+    
     public static String getMessageFromResult(Logger logger, String resultFromMps) {
         logger.info("Response from MPS to convert to message:" + resultFromMps);
         if (resultFromMps.contains("416")) {

+ 125 - 32
KittyFallWs/KittyFallWs/src/com/vas/webservices/KittyFallWs.java

@@ -1474,7 +1474,7 @@ public class KittyFallWs extends WebserviceAbstract {
                         String REQ = reqDf.format(new Date()) + productInfo.getProductId() + msisdn.substring(Common.COUNTRY_CODE.length());
                         logger.info("after get product info " + fee);
                         // right -----------------------------------------------
-                        resultPaid = ws.requestMpsOtp(msisdn, fee, REQ, productInfo.getProductName());
+//                        resultPaid = ws.requestMpsOtp(msisdn, fee, REQ, productInfo.getProductName());
                         
                         String errorCode = resultPaid.split("\\|")[0];
                         if (WSProcessor.LIST_SUCCESS_RES.contains(resultPaid)) {
@@ -1837,9 +1837,8 @@ public class KittyFallWs extends WebserviceAbstract {
             @WebParam(name = "WsUser") String wsUser,
             @WebParam(name = "WsPass") String wsPass,
             @WebParam(name = "Msisdn") String msisdn,
-            @WebParam(name = "PackageName") String packageName,
-            @WebParam(name = "Fee") String fee,
-            @WebParam(name = "ServiceId") String serviceId) {
+            @WebParam(name = "PackageName") String packageName )
+    {
 
         Response response = new Response();
         response.setErrorCode(SUCCESS);
@@ -1851,9 +1850,7 @@ public class KittyFallWs extends WebserviceAbstract {
             br.append("wsChargeFeeOtp Params:\n").
                     append("WsUser:").append(wsUser).
                     append("\n Msisdn:").append(msisdn).
-                    append("\n serviceId:").append(serviceId).
-                    append("\n packageName:").append(packageName).
-                    append("\n Fee:").append(fee);
+                    append("\n packageName:").append(packageName);
             logger.info(br);
 
             Request request = new Request();
@@ -1871,19 +1868,11 @@ public class KittyFallWs extends WebserviceAbstract {
                 logger.info("msisdn is null");
                 response.setErrorCode(PARAM_NOT_ENOUGH);
                 response.setContent("msisdn is null");
-            } else if (serviceId == null || serviceId.length() == 0) {
-                logger.info("serviceId is null");
-                response.setErrorCode(PARAM_NOT_ENOUGH);
-                response.setContent("serviceId is null");
-            } else if (packageName == null || packageName.length() == 0) {
+            }  else if (packageName == null || packageName.length() == 0) {
                 logger.info("packageName is null");
                 response.setErrorCode(PARAM_NOT_ENOUGH);
                 response.setContent("packageName is null");
-            } else if (fee == null || fee.length() == 0) {
-                logger.info("fee is null");
-                response.setErrorCode(PARAM_NOT_ENOUGH);
-                response.setContent("fee is null");
-            }
+            } 
 //------- ----------Dành cho thị trường có OTP -------------------------
     /*
             if (SUCCESS.equals(response.getErrorCode())) {
@@ -1998,6 +1987,7 @@ public class KittyFallWs extends WebserviceAbstract {
                 } else {
                     msisdn = formatMsisdn(msisdn);
                     int moneyCharge = Common.ADD_SPIN_FEE;
+                    String fee = "0";
                     if (fee != null && fee.length() > 0) {
                         moneyCharge = Integer.parseInt(fee);
                     }
@@ -2015,8 +2005,8 @@ public class KittyFallWs extends WebserviceAbstract {
                     String REQ = reqDf.format(new Date()) + "1" + msisdn.substring(Common.COUNTRY_CODE.length());
 
                     // charge
-                  String resultPaid = ws.chargeFeeOtp(msisdn, moneyCharge, REQ);
-//                    String resultPaid = "0";
+//                    String resultPaid = ws.chargeFeeOtp(msisdn, moneyCharge, REQ);
+                    String resultPaid = "0";
                     boolean registered = false;
                     List<RegisterInfo> listRegInday = null;
                     listRegInday = db.getRegisterInday(msisdn, productInfo.getProductName());
@@ -2050,27 +2040,27 @@ public class KittyFallWs extends WebserviceAbstract {
                             chargeLog.setFee(moneyCharge);
                             chargeLog.setChargeTime(new Timestamp(System.currentTimeMillis()));
                             chargeLog.setMsisdn(msisdn);
-                            String mTOOL_RUN = MessageResponse.get(Common.Message.TOOL_RUN,logger);
-                            if(mTOOL_RUN.equals("START") && msisdnTool == true){
-                                chargeLog.setDescription("Charge tool " + productInfo.getProductName());
-                                chargeLog.setAccountId("1");
-                            }else{
-                                chargeLog.setDescription("Charge");
-                            }
+//                            String mTOOL_RUN = MessageResponse.get(Common.Message.TOOL_RUN,logger);
+//                            if(mTOOL_RUN.equals("START") && msisdnTool == true){
+//                                chargeLog.setDescription("Charge tool " + productInfo.getProductName());
+//                                chargeLog.setAccountId("1");
+//                            }else{
+                                chargeLog.setDescription("Charge " + productInfo.getProductName());
+//                            }
                             
                             chargeLog.setStatus(Common.Constant.CHARGE_STATUS);
                             db.iInsertChargeLog(chargeLog);
                         }
                         
                         // Update Spin
-//                        db.addTurnSpin(msisdn,productInfo.getNumberSpin());
+                        db.addTurnSpin(msisdn,productInfo.getNumberSpin());
                         logger.info("Buy turn success success " + msisdn + ", fee " + fee);
                         
-//                        LuckySprin mLuckySprin = db.igetLuckySprin(msisdn);
-//                        if(mLuckySprin != null){
-//                          response.setRemainSpin(mLuckySprin.getAdded()- mLuckySprin.getUsed());  
-//                          response.setTotalSpin(mLuckySprin.getAdded());
-//                        }
+                        LuckySprin mLuckySprin = db.igetLuckySprin(msisdn);
+                        if(mLuckySprin != null){
+                          response.setRemainSpin(mLuckySprin.getAdded()- mLuckySprin.getUsed());  
+                          response.setTotalSpin(mLuckySprin.getAdded());
+                        }
                         response.setMoneyDeducted(moneyCharge);
                         response.setTotalSpinAdd(productInfo.getNumberSpin());
                         
@@ -2585,6 +2575,109 @@ public class KittyFallWs extends WebserviceAbstract {
     }
     
     
+     @WebMethod(operationName = "wsAddPoint")
+    @SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL)
+    public Response wsAddPoint(
+            @WebParam(name = "WsUser") String wsUser,
+            @WebParam(name = "WsPass") String wsPass,
+            @WebParam(name = "Msisdn") String msisdn,
+            @WebParam(name = "PackageName") String packageName,
+            @WebParam(name = "Point") String point,
+            @WebParam(name = "ServiceId") String serviceId) {
+
+        Response response = new Response();
+        response.setErrorCode(SUCCESS);
+
+        try {
+            String ip = getIpClient();
+            UserInfo userInfo = null;
+            br.setLength(0);
+            br.append("wsAddPoint Params:\n").
+                    append("WsUser:").append(wsUser).
+                    append("\n Msisdn:").append(msisdn).
+                    append("\n PackageName:").append(packageName).
+                    append("\n Msisdn:").append(msisdn).
+                    append("\n ServiceId:").append(serviceId).
+                    append("\n Point:").append(point);
+            logger.info(br);
+
+            Request request = new Request();
+            request.setUser(wsUser);
+//            request.setPass(password);
+            if (wsUser == null || wsUser.length() == 0) {
+                logger.info("wsUser is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("wsUser is null");
+            } else if (wsPass == null || wsPass.length() == 0) {
+                logger.info("wsPass is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("wsPass is null");
+            } else if (msisdn == null || msisdn.length() == 0) {
+                logger.info("msisdn is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("msisdn is null");
+            } else if (packageName == null || packageName.length() == 0) {
+                logger.info("packageName is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("packageName is null");
+            } else if (point == null || point.length() == 0) {
+                logger.info("point is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("point is null");
+            } else if (serviceId == null || serviceId.length() == 0) {
+                logger.info("serviceId is null");
+                response.setErrorCode(PARAM_NOT_ENOUGH);
+                response.setContent("serviceId is null");
+            }
+
+            if (SUCCESS.equals(response.getErrorCode())) {
+                // kiem tra thong tin dang nhap
+                userInfo = authenticate(wsUser, wsPass, ip);
+                if (userInfo == null || userInfo.getWsUserId() <= 0) {
+                    response.setErrorCode(WRONG_PASSWORD);
+                    response.setContent("Authenticate fail!");
+                } else {
+                    msisdn = formatMsisdn(msisdn);
+                    // check account
+                    AccountInfo accountInfo = db.iGetAccountByMsisdn(msisdn, serviceId);
+                    // create account
+                    if (accountInfo.getMsisdn() == null || accountInfo.getMsisdn().isEmpty()) {
+                        response.setErrorCode(Common.ErrorCode.ACCOUNT_NOT_EXISTED);
+                        response.setContent(MessageResponse.getDefaultMessage(Common.Message.ACCOUNT_NOT_EXISTED, logger));
+                    } else {
+
+                        int dataConvert = Integer.parseInt(point);
+                        ws.addPoint(msisdn, dataConvert);
+
+                        ChargeLog chargeLog = new ChargeLog();
+                        chargeLog.setFee(-dataConvert);
+                        chargeLog.setChargeTime(new Timestamp(System.currentTimeMillis()));
+                        chargeLog.setMsisdn(msisdn);
+                        chargeLog.setDescription("Exchange points to data");
+                        chargeLog.setStatus(Common.Constant.UNCHARGE_STATUS);
+                        db.iInsertChargeLog(chargeLog);
+
+                        response.setErrorCode(Common.ErrorCode.SUCCESS);
+                        String message = MessageResponse.get(Common.Message.EXCHANGE_POINT_SUCCESS, logger);
+                        message = message.replaceAll("%point%", point + "");
+                        response.setContent(message);
+
+                    }
+                }
+            }
+
+        } catch (Exception e) {
+            logger.error("Error processing", e);
+            response.setErrorCode(EXCEPTION);
+            String message = MessageResponse.get(Common.Message.SYSTEM_FAIL, logger);
+            response.setContent(message);
+        }
+
+        return response;
+    }
+    
+    
+    
     
 
     //     ------------------------- END ----------------------

+ 1 - 0
Kitty_Fall/Kitty_Fall/Common/Common.csproj

@@ -23,6 +23,7 @@
 		<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.20" />
 	</ItemGroup>
 	<ItemGroup>
+	  <Folder Include="Connected Services\" />
 	  <Folder Include="Http\Apis\Response\" />
 	</ItemGroup>
 	<ItemGroup>

Разница между файлами не показана из-за своего большого размера
+ 406 - 382
Kitty_Fall/Kitty_Fall/Common/Connected Services/Kitty_FallVasWs/Reference.cs


+ 0 - 13
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/ApplicationModels.cs

@@ -1,13 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class ApplyJobReq : BaseReq
-    {
-        [Required]
-        public long job_id { get; set; }
-        public long? cv_id { get; set; }
-        public string? cover_letter { get; set; }
-    }
-}

+ 0 - 37
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/CvModels.cs

@@ -1,37 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class CvCreateReq : BaseReq
-    {
-        [Required]
-        public int template_id { get; set; }
-        [Required]
-        public string title { get; set; }
-        public string? personal_info { get; set; }
-        public string? objective { get; set; }
-        public string? education { get; set; }
-        public string? experience { get; set; }
-        public string? skills { get; set; }
-        public int is_main { get; set; } = 0;
-    }
-
-    public class CvDetailReq : BaseReq
-    {
-        [Required]
-        public long cv_id { get; set; }
-    }
-
-    public class CvUpdateReq : CvCreateReq
-    {
-        [Required]
-        public long cv_id { get; set; }
-    }
-
-    public class CvActionReq : BaseReq
-    {
-        [Required]
-        public long cv_id { get; set; }
-    }
-}

+ 0 - 81
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/CvRes.cs

@@ -1,81 +0,0 @@
-using System;
-using Newtonsoft.Json.Linq;
-
-namespace Common.Http.Apis.Request
-{
-    // CV Create Response
-    public class CvCreateRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public CvCreateRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // CV Update Response
-    public class CvUpdateRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public CvUpdateRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // CV Detail Response
-    public class CvDetailRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public CvDetailRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // CV List Response
-    public class CvListRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public CvListRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-}

+ 0 - 111
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/EmployerModels.cs

@@ -1,111 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class CompanyUpdateReq : BaseReq
-    {
-        [Required]
-        public string name_en { get; set; }
-        public string name_mm { get; set; }
-        public string? logo_url { get; set; }
-        public string? description_en { get; set; }
-        public string? description_mm { get; set; }
-        public string? website { get; set; }
-        public string? address_en { get; set; }
-        public string? address_mm { get; set; }
-        public string? tax_code { get; set; }
-        public System.Collections.Generic.List<string>? license_urls { get; set; }
-    }
-
-    public class JobCreateReq : BaseReq
-    {
-        [Required]
-        public decimal category_id { get; set; }
-        [Required]
-        public decimal location_id { get; set; }
-        [Required]
-        public string title_en { get; set; }
-        [Required]
-        public string title_mm { get; set; }
-        [Required]
-        public string description_en { get; set; }
-        [Required]
-        public string description_mm { get; set; }
-        public string? requirements_en { get; set; }
-        public string? requirements_mm { get; set; }
-        public string? benefits_en { get; set; }
-        public string? benefits_mm { get; set; }
-        public decimal? salary_min { get; set; }
-        public decimal? salary_max { get; set; }
-        public string salary_currency { get; set; } = "MMK";
-        public int is_salary_negotiable { get; set; } = 0;
-        public string job_type { get; set; } = "FULL_TIME";
-        public string? experience_level { get; set; }
-        public DateTime? expired_at { get; set; }
-        public int show_apply_information { get; set; } = 0;
-        public string? apply_info_email { get; set; }
-        public string? apply_info_viber { get; set; }
-        public string? apply_info_link { get; set; }
-        public string? apply_info_address { get; set; }
-    }
-
-    public class JobUpdateReq : JobCreateReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-    }
-
-    public class EmployerJobDetailReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-    }
-
-    public class JobRenewReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-
-        [Required]
-        public DateTime expired_at { get; set; }
-    }
-
-    public class JobStatusReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-        [Required]
-        public string status { get; set; }
-    }
-
-    public class EmployerAppListReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-        public string? status { get; set; }
-        public int page_index { get; set; } = 1;
-        public int page_size { get; set; } = 20;
-    }
-
-    public class AppStatusReq : BaseReq
-    {
-        [Required]
-        public decimal application_id { get; set; }
-        [Required]
-        public string status { get; set; }
-        public string? employer_note { get; set; }
-    }
-
-    public class EmployerAppCvReq : BaseReq
-    {
-        [Required]
-        public decimal application_id { get; set; }
-    }
-
-    public class CompanyDetailReq : LanguageReq
-    {
-        [Required]
-        public decimal company_id { get; set; }
-    }
-}

+ 0 - 118
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/EmployerRes.cs

@@ -1,118 +0,0 @@
-using System;
-using Newtonsoft.Json.Linq;
-
-namespace Common.Http.Apis.Request
-{
-    // Employer Job List
-    public class EmployerJobListRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public EmployerJobListRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-
-    // Employer Application List
-    public class EmployerAppListRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public EmployerAppListRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-
-    // Company Info
-    public class CompanyInfoRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public CompanyInfoRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // Company Update Response
-    public class CompanyUpdateRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public CompanyUpdateRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // Job Status Update Response
-    public class JobStatusUpdateRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public JobStatusUpdateRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-    // Company List
-    public class CompanyListRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public CompanyListRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-}

+ 0 - 7
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/InterviewModels.cs

@@ -1,7 +0,0 @@
-namespace Common.Http.Apis.Request
-{
-    public class InterviewQuestionReq : BaseReq
-    {
-        public decimal? category_id { get; set; }
-    }
-}

+ 0 - 28
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/JobModels.cs

@@ -1,28 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class JobSearchReq : BaseReq
-    {
-        public decimal? category_id { get; set; }
-        public decimal? location_id { get; set; }
-        public string? keyword { get; set; }
-        public string[]? job_types { get; set; }
-        public string? experience_level { get; set; }
-        public int page_index { get; set; } = 1;
-        public int page_size { get; set; } = 20;
-    }
-
-    public class JobDetailReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-    }
-
-    public class JobActionReq : BaseReq
-    {
-        [Required]
-        public decimal job_id { get; set; }
-    }
-}

+ 0 - 54
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/JobPostReq.cs

@@ -1,54 +0,0 @@
-using System;
-using Newtonsoft.Json.Linq;
-
-namespace Common.Http.Apis.Request
-{
-    public class JobPostReq : BaseReq
-    {
-        public string title_en { get; set; }
-        public string title_mm { get; set; }
-        public decimal category_id { get; set; }
-        public decimal location_id { get; set; }
-        public string description_en { get; set; }
-        public string description_mm { get; set; }
-        public string requirements_en { get; set; }
-        public string requirements_mm { get; set; }
-        public string? benefits_en { get; set; }
-        public string? benefits_mm { get; set; }
-        public decimal? salary_min { get; set; }
-        public decimal? salary_max { get; set; }
-        public string? salary_currency { get; set; } = "MMK";
-        public int is_salary_negotiable { get; set; } = 0;
-        public string job_type { get; set; }
-        public string experience_level { get; set; }
-        public string? expired_at { get; set; }
-        public int show_apply_information { get; set; } = 0;
-        public string? apply_info_email { get; set; }
-        public string? apply_info_viber { get; set; }
-        public string? apply_info_link { get; set; }
-        public string? apply_info_address { get; set; }
-    }
-
-    public class JobPostData
-    {
-        public decimal? jobId { get; set; }
-    }
-
-    public class JobPostRes : CommonResponse
-    {
-        public JobPostData? data { get; set; }
-
-        public JobPostRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"]?.ToObject<JobPostData>();
-                }
-            }
-        }
-    }
-}

+ 0 - 49
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/LoadCategoryReq.cs

@@ -1,49 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using Database.Database;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace Common.Http.Apis.Request
-{
-    public class LoadCategoryReq
-    {
-        [Required]
-        public string language { get; set; }
-        public int pageNumber { get; set; }
-        public int pageSize { get; set; }
-    }
-
-    public class CategoryData
-    {
-        public int  id { get; set; }
-        public string? name { get; set; }
-        public string? name_local { get; set; }
-        public string? image { get; set; }
-        public string? image_local { get; set; }
-        public string? status { get; set; }
-    }
-
-    public class LoadCategoryData
-    {
-        public int? TotalPage { get; set; }
-        public List<CategoryData>? articles { get; set; }
-    }
-
-    public class LoadCategoryRes : CommonResponse
-    {
-        public LoadCategoryData? Data { get; set; }
-
-        public LoadCategoryRes(string dataGet)
-        {
-            JObject jObject = JObject.Parse(dataGet);
-            BuildCommonResponse(dataGet);
-
-            if (jObject != null && jObject["data"] != null)
-            {
-                Data = jObject["data"]!.ToObject<LoadCategoryData>();
-            }
-        }
-    }
-}

+ 0 - 10
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MasterDataModels.cs

@@ -1,10 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class BannerReq : BaseReq
-    {
-        public string? position { get; set; }
-    }
-}

+ 0 - 102
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MasterDataRes.cs

@@ -1,102 +0,0 @@
-using System;
-using Newtonsoft.Json.Linq;
-using Common.Http;
-using System.Collections.Generic;
-
-namespace Common.Http.Apis.Request
-{
-    // 1. Response cho Banner
-    public class BannerRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public BannerRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-
-    // 2. Response cho Category
-    public class CategoryRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public CategoryRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-
-    // 3. Response cho Location
-    public class LocationRes : CommonResponse
-    {
-        public JArray? data { get; set; }
-
-        public LocationRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JArray;
-                }
-            }
-        }
-    }
-
-    // 4. Response cho Job Search
-    public class JobSearchRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public JobSearchRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-
-    // 5. Response cho Job Detail
-    public class JobDetailRes : CommonResponse
-    {
-        public JObject? data { get; set; }
-
-        public JobDetailRes(string dataGet)
-        {
-            if (!string.IsNullOrEmpty(dataGet))
-            {
-                JObject jObject = JObject.Parse(dataGet);
-                BuildCommonResponse(dataGet);
-                if (jObject != null && jObject["data"] != null)
-                {
-                    data = jObject["data"] as JObject;
-                }
-            }
-        }
-    }
-}

+ 0 - 18
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/MyJobBaseReq.cs

@@ -1,18 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class BaseReq
-    {
-        public string? msisdn { get; set; }
-        [Required]
-        public string language { get; set; } = "en"; // "en" or "mm"
-    }
-
-    public class LanguageReq
-    {
-        [Required]
-        public string language { get; set; } = "en";
-    }
-}

+ 0 - 11
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/NotificationModels.cs

@@ -1,11 +0,0 @@
-using System;
-using System.ComponentModel.DataAnnotations;
-
-namespace Common.Http.Apis.Request
-{
-    public class NotificationActionReq : BaseReq
-    {
-        [Required]
-        public long notification_id { get; set; }
-    }
-}

+ 39 - 0
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/UserBuyTurnReq.cs

@@ -0,0 +1,39 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using Newtonsoft.Json.Linq;
+
+namespace Common.Http.Apis.Request
+{
+    public class UserBuyTurnReq
+    {
+        [Required]
+        public string? msisdn { get; set; }
+
+        [Required]
+        public string? packageName { get; set; }
+        [Required]
+        public string language { get; set; }
+
+    }
+
+    public class UserBuyTurnData
+    {
+        public string? requestId { get; set; }
+
+    }
+
+    public class UserBuyTurnRes : CommonResponse
+    {
+        public UserBuyTurnData? data { get; set; }
+        public UserBuyTurnRes(String dataGet)
+        {
+            JObject jObject = JObject.Parse(dataGet);
+            BuildCommonResponse(dataGet);
+
+            if (jObject != null && jObject["data"] != null)
+            {
+                data = jObject["data"]!.ToObject<UserBuyTurnData>();
+            }
+        }
+    }
+}

+ 2 - 22
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/UserInfo.cs

@@ -35,18 +35,7 @@ namespace Common.Http.Apis.Request
             }
         }
     }
-    public class UserUpdateRoleReq : BaseReq
-    {
-        [Required]
-        public string msisdn { get; set; }
-        [Required]
-        public string role { get; set; }
-        public string? companyName { get; set; }
-        public string? website { get; set; }
-        public string? description { get; set; }
-        public string? logoUrl { get; set; }
-        public string? address { get; set; }
-    }
+  
 
     public class UserUpdateRoleRes : CommonResponse
     {
@@ -63,14 +52,5 @@ namespace Common.Http.Apis.Request
         }
     }
 
-    public class UserUpdateProfileReq : BaseReq
-    {
-        [Required]
-        public string msisdn { get; set; }
-        public string? fullname { get; set; }
-        public string? email { get; set; }
-        public string? birthday { get; set; }
-        public string? address { get; set; }
-        public string? picture { get; set; }
-    }
+   
 }

+ 2 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/User/IUserBusiness.cs

@@ -32,6 +32,7 @@ namespace Kitty_Fall.Apis.Business.User
         Task<IActionResult> UserResendOtp(HttpRequest httpRequest, UserSendOtpReq request);
         Task<IActionResult> UserOtpConfirm(HttpRequest httpRequest, UserSendOtpReq request);
         Task<IActionResult> MyIdAutoLogin(HttpRequest httpRequest, MyIdAutoLoginReq request);
-        Task<IActionResult> UpdateProfile(HttpRequest httpRequest, UserUpdateProfileReq request);
+        //Task<IActionResult> UpdateProfile(HttpRequest httpRequest, UserUpdateProfileReq request);
+        Task<IActionResult> UserBuyTurn(HttpRequest httpRequest, UserBuyTurnReq request);
     }
 }

+ 130 - 41
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/User/UserBusinessImpl.cs

@@ -675,6 +675,95 @@ namespace Kitty_Fall.Apis.Business.User
             );
         }
 
+
+
+
+        public async Task<IActionResult> UserBuyTurn(HttpRequest httpRequest, UserBuyTurnReq request)
+        {
+            var url = httpRequest.Path;
+
+            try
+            {
+                Logic.ChangeLanguage(request.language);
+                var json = JsonConvert.SerializeObject(request);
+                log.Debug("URL: " + url + " => Request: " + json);
+
+                // validate msisdn
+                string? msisdn = CommonLogic.ValidateMsisdn(
+                    GetParameter("CountryCode"),
+                    request.msisdn
+                );
+                if (msisdn == null || msisdn == "")
+                {
+                    return CommonLogic.BuildResponse(
+                        url,
+                        json,
+                        CommonErrorCode.Error,
+                        Lang.msisdnInvalid,
+                        new { }
+                    );
+                }
+
+                // check packageName
+                var packg = dbContext
+                    .Packgs.Where(x => x.ProductName == request.packageName)
+                    .FirstOrDefault();
+                if (packg == null)
+                {
+                    return CommonLogic.BuildResponse(
+                        url,
+                        json,
+                        CommonErrorCode.Error,
+                        Lang.packageInvalid,
+                        new { }
+                    );
+                }
+
+
+                Kitty_FallVasWs.wsChargeFeeOtpResponse wsChargeFeeOtpResponse =
+                await wsClient.wsChargeFeeOtpAsync(
+                       wsUser,
+                       wsPass,
+                       msisdn,
+                       packg.ProductName
+                );
+
+                var jsonData = JsonConvert.SerializeObject(wsChargeFeeOtpResponse);
+                log.Info("Response: wsChargeFeeOtpResponse => data: " + jsonData);
+
+                if (wsChargeFeeOtpResponse.@return.errorCode == CommonErrorCode.Success)
+                {
+                    return CommonLogic.BuildResponse(
+                        url,
+                        json,
+                        CommonErrorCode.SUCCESS,
+                        wsChargeFeeOtpResponse.@return.content,
+                        new { }
+                    );
+                }
+                else
+                {
+                    return CommonLogic.BuildResponse(
+                        url,
+                        json,
+                        int.Parse(wsChargeFeeOtpResponse.@return.errorCode),
+                        wsChargeFeeOtpResponse.@return.content,
+                        new
+                        {
+                        }
+                    );
+                }
+
+            }
+            catch (Exception exception)
+            {
+                log.Error("Exception: ", exception);
+            }
+            return await Task.FromResult<IActionResult>(
+                new BadRequestObjectResult(new { message = "Bad request" })
+            );
+        }
+
         public async Task<IActionResult> UserSendOtp(
             HttpRequest httpRequest,
             UserSendOtpReq request
@@ -1275,46 +1364,46 @@ namespace Kitty_Fall.Apis.Business.User
             return GetHttpSendRequest;
         }
 
-        public async Task<IActionResult> UpdateProfile(HttpRequest httpRequest, UserUpdateProfileReq request)
-        {
-            var url = httpRequest.Path;
-            var json = JsonConvert.SerializeObject(request);
-            try
-            {
-                // Normalize msisdn để chấp nhận cả "9681454634" lẫn "959681454634"
-                string? msisdn = CommonLogic.ValidateMsisdn(GetParameter("CountryCode"), request.msisdn);
-                if (string.IsNullOrEmpty(msisdn))
-                {
-                    return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, Lang.msisdnInvalid, new { });
-                }
-
-                var user = dbContext.AccountUsers.FirstOrDefault(x => x.Msisdn == msisdn);
-                if (user == null)
-                {
-                    return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, "User not found", new { });
-                }
-
-                if (!string.IsNullOrEmpty(request.fullname)) user.Fullname = request.fullname;
-                if (!string.IsNullOrEmpty(request.email)) user.Email = request.email;
-                if (!string.IsNullOrEmpty(request.birthday))
-                {
-                    if (DateTime.TryParse(request.birthday, out DateTime birthday))
-                    {
-                        user.Birthday = birthday;
-                    }
-                }
-                if (!string.IsNullOrEmpty(request.picture)) user.Picture = request.picture;
-
-                user.UpdateDate = DateTime.Now;
-                await dbContext.SaveChangesAsync();
-
-                return CommonLogic.BuildResponse(url, json, CommonErrorCode.SUCCESS, "Profile updated successfully", user);
-            }
-            catch (Exception ex)
-            {
-                log.Error("UpdateProfile Error: ", ex);
-                return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, "Internal Server Error", new { });
-            }
-        }
+        //public async Task<IActionResult> UpdateProfile(HttpRequest httpRequest, UserUpdateProfileReq request)
+        //{
+        //    var url = httpRequest.Path;
+        //    var json = JsonConvert.SerializeObject(request);
+        //    try
+        //    {
+        //        // Normalize msisdn để chấp nhận cả "9681454634" lẫn "959681454634"
+        //        string? msisdn = CommonLogic.ValidateMsisdn(GetParameter("CountryCode"), request.msisdn);
+        //        if (string.IsNullOrEmpty(msisdn))
+        //        {
+        //            return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, Lang.msisdnInvalid, new { });
+        //        }
+
+        //        var user = dbContext.AccountUsers.FirstOrDefault(x => x.Msisdn == msisdn);
+        //        if (user == null)
+        //        {
+        //            return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, "User not found", new { });
+        //        }
+
+        //        if (!string.IsNullOrEmpty(request.fullname)) user.Fullname = request.fullname;
+        //        if (!string.IsNullOrEmpty(request.email)) user.Email = request.email;
+        //        if (!string.IsNullOrEmpty(request.birthday))
+        //        {
+        //            if (DateTime.TryParse(request.birthday, out DateTime birthday))
+        //            {
+        //                user.Birthday = birthday;
+        //            }
+        //        }
+        //        if (!string.IsNullOrEmpty(request.picture)) user.Picture = request.picture;
+
+        //        user.UpdateDate = DateTime.Now;
+        //        await dbContext.SaveChangesAsync();
+
+        //        return CommonLogic.BuildResponse(url, json, CommonErrorCode.SUCCESS, "Profile updated successfully", user);
+        //    }
+        //    catch (Exception ex)
+        //    {
+        //        log.Error("UpdateProfile Error: ", ex);
+        //        return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, "Internal Server Error", new { });
+        //    }
+        //}
     }
 }

+ 11 - 3
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Controllers/UserController.cs

@@ -124,11 +124,19 @@ namespace RevoSystem.Apis.Controllers
         }
 
       
+        // [HttpPost]
+        // [Route(UrlConstant.UserUpdateProfileUrl)]
+        // public async Task<IActionResult> UpdateProfile([FromBody] UserUpdateProfileReq request)
+        // {
+        //     return await userBusiness.UpdateProfile(HttpContext.Request, request);
+        // }
+
         [HttpPost]
-        [Route(UrlConstant.UserUpdateProfileUrl)]
-        public async Task<IActionResult> UpdateProfile([FromBody] UserUpdateProfileReq request)
+        [Route(UrlConstant.UserBuyTurnUrl)]
+        public async Task<IActionResult> UserBuyTurn([FromBody] UserBuyTurnReq request)
         {
-            return await userBusiness.UpdateProfile(HttpContext.Request, request);
+            return await userBusiness.UserBuyTurn(HttpContext.Request, request);
         }
+
     }
 }

+ 1 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Filters/JwtAuthFilter.cs

@@ -38,6 +38,7 @@ namespace Kitty_Fall.Apis.Filters
             UrlConstant.UserMyIdAutoLogin,
             UrlConstant.UserRegisterSubOtp,
             UrlConstant.UserRegisterSubConfirm,
+            UrlConstant.UserRegisterSubQuickUrl,
         };
 
         public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

+ 138 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Controllers/HomeController.cs

@@ -48,6 +48,144 @@ namespace Kitty_Fall.Website.Controllers
             return Json(new { success = true });
         }
 
+        [HttpPost]
+        public async Task<IActionResult> RegisterQAction(string? productName)
+        {
+            var msisdn = HttpContext.Session.GetComplexData<string>("msisdn") ?? "";
+            if (string.IsNullOrWhiteSpace(msisdn))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Please login again." });
+            }
+
+            var baseUrl = GetParameter("url");
+            if (string.IsNullOrWhiteSpace(baseUrl))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Missing API base URL." });
+            }
+
+            var packageName = string.IsNullOrWhiteSpace(productName)
+                ? GetParameter("productName")
+                : productName.Trim();
+
+            if (string.IsNullOrWhiteSpace(packageName))
+            {
+                var packages = await PackagesCacheHelper.GetOrLoadAsync(log, HttpContext.Session, baseUrl, GetCurrentLanguage());
+                packageName = packages.FirstOrDefault() is { } firstPackage
+                    ? ReadPackageString(firstPackage, "productName")
+                    : "";
+            }
+
+            if (string.IsNullOrWhiteSpace(packageName))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Package is not configured." });
+            }
+
+            try
+            {
+                var language = GetCurrentLanguage();
+                var res = await DotnetLib.Rest.RestHandler.SendPostAsync(
+                    log,
+                    baseUrl + UrlConstant.UserRegisterSubQuickUrl,
+                    new UserRegisterReq
+                    {
+                        msisdn = msisdn,
+                        packageName = packageName,
+                        language = language
+                    },
+                    language
+                );
+
+                if (res?.data == null)
+                {
+                    return Json(new { errorCode = CommonErrorCode.Error, message = "Register API returned empty response." });
+                }
+
+                var jObject = JObject.Parse(res.data);
+                var errorCode = ReadErrorCode(jObject);
+                var message = jObject["message"]?.ToString() ?? jObject["msg"]?.ToString() ?? "";
+                return Json(new
+                {
+                    errorCode,
+                    message,
+                    productName = packageName
+                });
+            }
+            catch (Exception ex)
+            {
+                log.Error("RegisterQAction error: ", ex);
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Register package failed." });
+            }
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> BuyTurnQAction(string? productName)
+        {
+            var msisdn = HttpContext.Session.GetComplexData<string>("msisdn") ?? "";
+            if (string.IsNullOrWhiteSpace(msisdn))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Please login again." });
+            }
+
+            var baseUrl = GetParameter("url");
+            if (string.IsNullOrWhiteSpace(baseUrl))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Missing API base URL." });
+            }
+
+            var packageName = string.IsNullOrWhiteSpace(productName)
+                ? GetParameter("productName")
+                : productName.Trim();
+
+            if (string.IsNullOrWhiteSpace(packageName))
+            {
+                var packages = await PackagesCacheHelper.GetOrLoadAsync(log, HttpContext.Session, baseUrl, GetCurrentLanguage());
+                packageName = packages.FirstOrDefault() is { } firstPackage
+                    ? ReadPackageString(firstPackage, "productName")
+                    : "";
+            }
+
+            if (string.IsNullOrWhiteSpace(packageName))
+            {
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Package is not configured." });
+            }
+
+            try
+            {
+                var language = GetCurrentLanguage();
+                var res = await DotnetLib.Rest.RestHandler.SendPostAsync(
+                    log,
+                    baseUrl + UrlConstant.UserBuyTurnUrl,
+                    new UserBuyTurnReq
+                    {
+                        msisdn = msisdn,
+                        packageName = packageName,
+                        language = language
+                    },
+                    language
+                );
+
+                if (res?.data == null)
+                {
+                    return Json(new { errorCode = CommonErrorCode.Error, message = "Buy turn API returned empty response." });
+                }
+
+                var jObject = JObject.Parse(res.data);
+                var errorCode = ReadErrorCode(jObject);
+                var message = jObject["message"]?.ToString() ?? jObject["msg"]?.ToString() ?? "";
+                return Json(new
+                {
+                    errorCode,
+                    message,
+                    productName = packageName
+                });
+            }
+            catch (Exception ex)
+            {
+                log.Error("BuyTurnQAction error: ", ex);
+                return Json(new { errorCode = CommonErrorCode.Error, message = "Buy turn failed." });
+            }
+        }
+
         private async Task LoadHomeDataAsync()
         {
             var msisdn = HttpContext.Session.GetComplexData<string>("msisdn") ?? "";

+ 9 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.Designer.cs

@@ -104,6 +104,15 @@ namespace Kitty_Fall.Website.Language {
                 return ResourceManager.GetString("Confirm", resourceCulture);
             }
         }
+
+        /// <summary>
+        ///   Looks up a localized string similar to Buy Turn.
+        /// </summary>
+        public static string BuyTurn {
+            get {
+                return ResourceManager.GetString("BuyTurn", resourceCulture);
+            }
+        }
         
         /// <summary>
         ///   Looks up a localized string similar to Confirm Subscription.

+ 3 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.resx

@@ -150,6 +150,9 @@
   <data name="SubscribeNow" xml:space="preserve">
     <value>Subscribe now</value>
   </data>
+  <data name="BuyTurn" xml:space="preserve">
+    <value>Buy Turn</value>
+  </data>
   <data name="PlayNow" xml:space="preserve">
     <value>Play now</value>
   </data>

+ 3 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.vi.resx

@@ -150,6 +150,9 @@
   <data name="SubscribeNow" xml:space="preserve">
     <value>Subscribe now</value>
   </data>
+  <data name="BuyTurn" xml:space="preserve">
+    <value>Buy Turn</value>
+  </data>
   <data name="PlayNow" xml:space="preserve">
     <value>Play now</value>
   </data>

+ 13 - 4
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/Home/Index.cshtml

@@ -11,6 +11,8 @@
     var packageProductName = ViewBag.PackageProductName as string ?? "";
     var packagePeriodText = packageExpireDays <= 1 ? "Day" : $"{packageExpireDays} Days";
     var packageTurnText = packageTurns <= 1 ? "Turn" : "Turns";
+    var isSubscriber = Context.Session.IsSubscriber();
+    var packageAction = isSubscriber ? "buy-turn" : "subscribe";
 }
 
 <main class="kitty-app" aria-label="Kitty Fall home screen">
@@ -81,7 +83,14 @@
             </div>
             <div class="package-action">
                 <p><strong>@packageFee.ToString("N0")</strong> MMK/@packagePeriodText</p>
-                <button class="subscribe-trigger" type="button" data-open-subscription data-product-name="@packageProductName">@Lang.SubscribeNow</button>
+                @if (isSubscriber)
+                {
+                    <button class="subscribe-trigger" type="button" data-confirm-subscription data-package-action="@packageAction" data-product-name="@packageProductName">@Lang.BuyTurn</button>
+                }
+                else
+                {
+                    <button class="subscribe-trigger" type="button" data-open-subscription data-product-name="@packageProductName">@Lang.SubscribeNow</button>
+                }
             </div>
         </div>
     </section>
@@ -124,7 +133,7 @@
                         <p>@Lang.ThisPackageWillBe <strong>@Lang.AutoRenewedDaily</strong></p>
                     </div>
 
-                    <button class="confirm-button" type="button" data-confirm-subscription data-product-name="@packageProductName">
+                    <button class="confirm-button" type="button" data-confirm-subscription data-package-action="@packageAction" data-product-name="@packageProductName">
                         <span class="confirm-button-icon" aria-hidden="true"></span>
                         <span>@Lang.Confirm</span>
                     </button>
@@ -159,7 +168,7 @@
                         <div class="result-benefit">
                             <span class="result-ticket-icon">
                                 <img src="~/kitty/assets/kitty-fall/ticket.png" alt="">
-                                <strong>x@packageTurns</strong>
+                                // <strong>x@packageTurns</strong>
                             </span>
                             <p><strong>@packageTurns</strong> @Lang.TurnsHaveBeenAdded</p>
                         </div>
@@ -203,7 +212,7 @@
 
                     <img class="result-status-icon result-status-fail" src="~/kitty/assets/kitty-fall/result-fail-icon.png" alt="">
                     <p class="result-title result-title-fail">@Lang.SubscriptionFailedTitle</p>
-                    <p class="result-copy-fail">@Lang.SubscriptionFailedCopy<br>@Lang.PleaseTryAgain</p>
+                    <p class="result-copy-fail" data-fallback-message="@Lang.SubscriptionFailedCopy @Lang.PleaseTryAgain">@Lang.SubscriptionFailedCopy<br>@Lang.PleaseTryAgain</p>
 
                     <button class="result-button result-button-fail confirm-button" type="button" data-close-subscription>
                         <span class="confirm-button-icon" aria-hidden="true"></span>

+ 1 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/_ViewImports.cshtml

@@ -1,4 +1,5 @@
 @using Kitty_Fall.Website
 @using Kitty_Fall.Website.Models
 @using Kitty_Fall.Website.Language
+@using Common.Extension
 @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

+ 35 - 8
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/all.min.js

@@ -232,10 +232,15 @@ const initKittyFall = () => {
       ignoreBackdropUntil = 0;
       setActivePanel("confirm");
     };
-    const showSubscriptionResult = event => {
-      event?.preventDefault();
-      event?.stopPropagation();
-      const panelName = Math.random() < 0.5 ? "success" : "fail";
+    const setSubscriptionFailMessage = message => {
+      const messageElement = subscriptionModal.querySelector(".result-copy-fail");
+      if (!messageElement) return;
+      messageElement.textContent = message || messageElement.dataset.fallbackMessage || "";
+    };
+    const showSubscriptionResult = (panelName, message) => {
+      if (panelName === "fail") {
+        setSubscriptionFailMessage(message);
+      }
       setActivePanel(panelName);
       subscriptionModal.classList.add("is-open");
       subscriptionModal.setAttribute("aria-hidden", "false");
@@ -246,15 +251,37 @@ const initKittyFall = () => {
         subscriptionModal.querySelector(`[data-modal-panel="${panelName}"] .confirm-close`)?.focus({preventScroll:true});
       });
     };
+    const confirmSubscription = (event, button) => {
+      event?.preventDefault();
+      event?.stopPropagation();
+      const confirmButton = button || event?.target?.closest("[data-confirm-subscription]");
+      if (!confirmButton || confirmButton.disabled) return;
+      confirmButton.disabled = true;
+      const actionUrl = confirmButton.dataset.packageAction === "buy-turn" ? "/Home/BuyTurnQAction" : "/Home/RegisterQAction";
+      $.ajax({
+        url: actionUrl,
+        type: "POST",
+        data: {
+          productName: confirmButton.dataset.productName || ""
+        },
+        success: function(response) {
+          const isSuccess = response && String(response.errorCode) === "0";
+          showSubscriptionResult(isSuccess ? "success" : "fail", response?.message || "");
+        },
+        error: function() {
+          showSubscriptionResult("fail", "");
+        },
+        complete: function() {
+          confirmButton.disabled = false;
+        }
+      });
+    };
     openSubscriptionButtons.forEach(button => {
       button.addEventListener("click", openSubscriptionModal);
     });
     closeSubscriptionButtons.forEach(button => {
       button.addEventListener("click", closeSubscriptionModal);
     });
-    confirmSubscriptionButtons.forEach(button => {
-      button.addEventListener("click", showSubscriptionResult);
-    });
     document.addEventListener("click", event => {
       const openButton = event.target.closest("[data-open-subscription]");
       const confirmButton = event.target.closest("[data-confirm-subscription]");
@@ -262,7 +289,7 @@ const initKittyFall = () => {
       if (openButton) {
         openSubscriptionModal(event);
       } else if (confirmButton) {
-        showSubscriptionResult(event);
+        confirmSubscription(event, confirmButton);
       } else if (closeButton) {
         closeSubscriptionModal(event);
       }

+ 43 - 9
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/input.js

@@ -281,10 +281,17 @@ const initKittyFall = () => {
             setActivePanel("confirm");
         };
 
-        const showSubscriptionResult = (event) => {
-            event?.preventDefault();
-            event?.stopPropagation();
-            const panelName = Math.random() < 0.5 ? "success" : "fail";
+        const setSubscriptionFailMessage = (message) => {
+            const messageElement = subscriptionModal.querySelector(".result-copy-fail");
+            if (!messageElement) return;
+            messageElement.textContent = message || messageElement.dataset.fallbackMessage || "";
+        };
+
+        const showSubscriptionResult = (panelName, message) => {
+            if (panelName === "fail") {
+                setSubscriptionFailMessage(message);
+            }
+
             setActivePanel(panelName);
             subscriptionModal.classList.add("is-open");
             subscriptionModal.setAttribute("aria-hidden", "false");
@@ -297,6 +304,37 @@ const initKittyFall = () => {
             });
         };
 
+        const confirmSubscription = (event, button) => {
+            event?.preventDefault();
+            event?.stopPropagation();
+
+            const confirmButton = button || event?.target?.closest("[data-confirm-subscription]");
+            if (!confirmButton || confirmButton.disabled) return;
+
+            confirmButton.disabled = true;
+            const actionUrl = confirmButton.dataset.packageAction === "buy-turn"
+                ? "/Home/BuyTurnQAction"
+                : "/Home/RegisterQAction";
+
+            $.ajax({
+                url: actionUrl,
+                type: "POST",
+                data: {
+                    productName: confirmButton.dataset.productName || ""
+                },
+                success: function (response) {
+                    const isSuccess = response && String(response.errorCode) === "0";
+                    showSubscriptionResult(isSuccess ? "success" : "fail", response?.message || "");
+                },
+                error: function () {
+                    showSubscriptionResult("fail", "");
+                },
+                complete: function () {
+                    confirmButton.disabled = false;
+                }
+            });
+        };
+
         openSubscriptionButtons.forEach((button) => {
             button.addEventListener("click", openSubscriptionModal);
         });
@@ -305,10 +343,6 @@ const initKittyFall = () => {
             button.addEventListener("click", closeSubscriptionModal);
         });
 
-        confirmSubscriptionButtons.forEach((button) => {
-            button.addEventListener("click", showSubscriptionResult);
-        });
-
         document.addEventListener("click", (event) => {
             const openButton = event.target.closest("[data-open-subscription]");
             const confirmButton = event.target.closest("[data-confirm-subscription]");
@@ -317,7 +351,7 @@ const initKittyFall = () => {
             if (openButton) {
                 openSubscriptionModal(event);
             } else if (confirmButton) {
-                showSubscriptionResult(event);
+                confirmSubscription(event, confirmButton);
             } else if (closeButton) {
                 closeSubscriptionModal(event);
             }

Некоторые файлы не были показаны из-за большого количества измененных файлов