diff --git a/DealerSelectionAPI.sln b/DealerSelectionAPI.sln
new file mode 100644
index 0000000..4b798c8
--- /dev/null
+++ b/DealerSelectionAPI.sln
@@ -0,0 +1,98 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33829.357
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi", "Source\DealerSelection.WebApi\DealerSelection.WebApi.csproj", "{C65D4378-AC83-4B22-A896-E2B47B7CB841}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi", "WebApi", "{73409D39-9D85-4EE7-B870-129129E11448}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{2E11D0F3-B91E-49E3-8040-EB3195B75738}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api", "Source\DealerSelection.Api\DealerSelection.Api.csproj", "{1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Infrastructure", "Source\DealerSelection.Infrastructure\DealerSelection.Api.Infrastructure.csproj", "{BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Interface", "Source\DealerSelection.Interface\DealerSelection.Api.Interface.csproj", "{0F9BC8AF-A572-4423-A1BD-C0DF4694E613}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Models", "Source\DealerSelection.Api.Models\DealerSelection.Api.Models.csproj", "{027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi.Models", "Source\DealerSelection.WebApi.Models\DealerSelection.WebApi.Models.csproj", "{29FCE055-C131-474C-B398-0855E803905E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.DependencyInjection", "Source\DealerSelection.DependencyInjection\DealerSelection.DependencyInjection.csproj", "{5FC735F8-39BF-41C5-8896-9EA2ED173CDE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{AA19DD64-E46D-476E-9999-2C6F20007DEE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Common", "Source\DealerSelection.Common\DealerSelection.Common.csproj", "{CA12113A-A11B-4EB0-AA56-E80062962D18}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{42B510F1-8DE3-4944-9395-4945B565C614}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi.IntegrationTests", "Source\Tests\DealerSelection.WebApi.IntegrationTests\DealerSelection.WebApi.IntegrationTests.csproj", "{EFD6DA2D-906C-44E5-A95F-60B31353DEB7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobService", "Source\WebJobService\WebJobService.csproj", "{583C09D6-5582-483E-A54F-89EB414F617C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Release|Any CPU.Build.0 = Release|Any CPU
+ {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {29FCE055-C131-474C-B398-0855E803905E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {29FCE055-C131-474C-B398-0855E803905E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {29FCE055-C131-474C-B398-0855E803905E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {29FCE055-C131-474C-B398-0855E803905E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CA12113A-A11B-4EB0-AA56-E80062962D18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA12113A-A11B-4EB0-AA56-E80062962D18}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CA12113A-A11B-4EB0-AA56-E80062962D18}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CA12113A-A11B-4EB0-AA56-E80062962D18}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {583C09D6-5582-483E-A54F-89EB414F617C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {583C09D6-5582-483E-A54F-89EB414F617C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {583C09D6-5582-483E-A54F-89EB414F617C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {583C09D6-5582-483E-A54F-89EB414F617C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {C65D4378-AC83-4B22-A896-E2B47B7CB841} = {73409D39-9D85-4EE7-B870-129129E11448}
+ {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2} = {2E11D0F3-B91E-49E3-8040-EB3195B75738}
+ {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E} = {2E11D0F3-B91E-49E3-8040-EB3195B75738}
+ {0F9BC8AF-A572-4423-A1BD-C0DF4694E613} = {2E11D0F3-B91E-49E3-8040-EB3195B75738}
+ {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB} = {2E11D0F3-B91E-49E3-8040-EB3195B75738}
+ {29FCE055-C131-474C-B398-0855E803905E} = {73409D39-9D85-4EE7-B870-129129E11448}
+ {5FC735F8-39BF-41C5-8896-9EA2ED173CDE} = {73409D39-9D85-4EE7-B870-129129E11448}
+ {CA12113A-A11B-4EB0-AA56-E80062962D18} = {AA19DD64-E46D-476E-9999-2C6F20007DEE}
+ {EFD6DA2D-906C-44E5-A95F-60B31353DEB7} = {42B510F1-8DE3-4944-9395-4945B565C614}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {114CDF7F-ED0A-416A-8B06-0056936D24EE}
+ EndGlobalSection
+EndGlobal
diff --git a/Source/DealerSelection.Api.Models/AuthModel.cs b/Source/DealerSelection.Api.Models/AuthModel.cs
new file mode 100644
index 0000000..530af24
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/AuthModel.cs
@@ -0,0 +1,14 @@
+namespace DealerSelection.Api.Models
+{
+ public class AuthModel
+ {
+ public string Role { get; set; }
+
+ public string ClientId { get; set; }
+
+ public string SecretId { get; set; }
+
+ public string KeyName { get; set; }
+ public int BuId { get; set; }
+ }
+}
diff --git a/Source/DealerSelection.Api.Models/AuthValidateModel.cs b/Source/DealerSelection.Api.Models/AuthValidateModel.cs
new file mode 100644
index 0000000..f1c85fc
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/AuthValidateModel.cs
@@ -0,0 +1,14 @@
+namespace DealerSelection.Api.Models
+{
+ public class AuthValidateModel
+ {
+ public string ClientId { get; set; }
+ public string SecretId { get; set; }
+ public int BuId { get; set; }
+ }
+
+ public class TokenModel
+ {
+ public string Token { get; set; }
+ }
+}
diff --git a/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs b/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs
new file mode 100644
index 0000000..36719d6
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs
@@ -0,0 +1,48 @@
+namespace DealerSelection.Api.Models;
+
+public class CustomerDealerInfoRequest
+{
+ public CustomerDealerInfoRequest(int buId, int recordId, int mobileNumber, string modelCode, string modelName,
+ string modelVariant, string dealerName, string dealerCode, string pinCode, string latitude, string longitude,
+ DealerSelectionJobStatus dealerSelectionJobStatus)
+ {
+ BuId = buId;
+ RecordId = recordId;
+ MobileNumber = mobileNumber;
+ ModelCode = modelCode;
+ ModelName = modelName;
+ ModelVariant = modelVariant;
+ DealerName = dealerName;
+ DealerCode = dealerCode;
+ PinCode = pinCode;
+ Latitude = latitude;
+ Longitude = longitude;
+ DealerSelectionJobStatus = dealerSelectionJobStatus;
+ }
+
+ public int BuId { get; }
+ public int RecordId { get; }
+ public int MobileNumber { get; }
+ public string ModelCode { get; }
+ public string ModelName { get; }
+ public string ModelVariant { get; }
+ public string DealerName { get; }
+ public string DealerCode { get; }
+ public string PinCode { get; }
+ public string Latitude { get; }
+ public string Longitude { get; }
+ public DealerSelectionJobStatus DealerSelectionJobStatus { get; }
+
+ public override string? ToString()
+ {
+ return base.ToString();
+ }
+
+ public string RequestDetail()
+ {
+ return $"BuId: {BuId}, RecordId: {RecordId}, MobileNumber: {MobileNumber}, ModelCode: {ModelCode}, " +
+ $"ModelName:{ModelName}, ModelVariant:{ModelVariant}, DealerName: {DealerName}, DealerCode: {DealerCode}, " +
+ $"PinCode: {PinCode}, Latitude: {Latitude}, Longitude: {Longitude}, DealerSelectionJobStatus: {DealerSelectionJobStatus}";
+ }
+
+}
diff --git a/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj b/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj
new file mode 100644
index 0000000..78af948
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+ 1701;1702;8618
+
+
+
+ 1701;1702;8618
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs b/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs
new file mode 100644
index 0000000..2f1550f
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs
@@ -0,0 +1,10 @@
+namespace DealerSelection.Api.Models;
+
+public enum DealerSelectionJobStatus
+{
+ OldData = -1,
+ ReadyForJob = 0,
+ Picked = 1,
+ SentToBot = 2,
+ Complete = 3,
+}
diff --git a/Source/DealerSelection.Api.Models/MulesoftResponse.cs b/Source/DealerSelection.Api.Models/MulesoftResponse.cs
new file mode 100644
index 0000000..679379d
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/MulesoftResponse.cs
@@ -0,0 +1,21 @@
+
+namespace DealerSelection.Api.Models;
+public class MulesoftResponse
+{
+ public MulesoftResponse(int buId, int bookingId, bool isRequestSuccessfull, string result, string message, string errorCode)
+ {
+ BuId = buId;
+ BookingId = bookingId;
+ IsRequestSuccessfull = isRequestSuccessfull;
+ Result = result;
+ Message = message;
+ ErrorField = errorCode;
+ }
+ public int BuId { get; set; }
+ public int BookingId { get; set; }
+ public bool IsRequestSuccessfull { get; }
+ public string Result { get; }
+ public string Message { get; }
+ public string ErrorField { get; }
+
+}
diff --git a/Source/DealerSelection.Api.Models/MulesoftToken.cs b/Source/DealerSelection.Api.Models/MulesoftToken.cs
new file mode 100644
index 0000000..e61887c
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/MulesoftToken.cs
@@ -0,0 +1,8 @@
+
+namespace DealerSelection.Api.Models;
+
+public class MulesoftToken
+{
+ public string Value { get; set; }
+ public int ExpiresIn { get; set; }
+}
diff --git a/Source/DealerSelection.Api.Models/Procedure.cs b/Source/DealerSelection.Api.Models/Procedure.cs
new file mode 100644
index 0000000..49205da
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/Procedure.cs
@@ -0,0 +1,15 @@
+
+namespace DealerSelection.Api.Infrastructure;
+
+public class Procedure
+{
+ public const string UpdateDealerDetails = "usp_update_dealer_details";
+ public const string GetCustomerBookingInfo = "usp_get_customer_booking_info";
+ public const string InsertUpdateDealerDetail = "usp_Insert_Update_Dealer_Details";
+ public const string InsertLSQDetail = "usp_insert_lsq_data";
+ public const string GetDataForLsqPush = "usp_get_data_for_lsq_push";
+ public const string GetCustomerInfoOnBookingId = "usp_get_customer_Info_on_BookingId";
+ public const string GetCustomerDataForJob = "usp_get_CustomerDataForJob"; //TO BE ADDED IN DB
+ public const string IsDuplicateMobileNumber = "usp_isDuplicateMobileNumber"; //TO BE ADDED IN DB
+ public const string UpdateDealerSelectionJobStatus = "usp_update_DealerSelectionJobStatus"; //TO BE ADDED IN DB
+}
diff --git a/Source/DealerSelection.Api.Models/Response.cs b/Source/DealerSelection.Api.Models/Response.cs
new file mode 100644
index 0000000..9dda97e
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/Response.cs
@@ -0,0 +1,31 @@
+
+namespace DealerSelection.Api.Models;
+public class Response
+{
+ public Response(int buId,int recordId, bool isRequestSuccessfull, string result, string message, string errorCode)
+ {
+ BuId = buId;
+ RecordId = recordId;
+ IsRequestSuccessfull = isRequestSuccessfull;
+ Result = result;
+ Message = message;
+ ErrorCode = errorCode;
+ }
+ public bool IsRequestSuccessfull { get; }
+ public string Result { get; }
+ public string Message { get; }
+ public string ErrorCode { get; }
+ public int RecordId { get; }
+ public int BuId { get; }
+
+}
+public enum ErrorCode
+{
+ successErrorCode = 01,
+ successWithLookupErrorCode = 02,
+ awaitedErrorCode = 03,
+ noRecordFound = 04
+
+}
+
+
diff --git a/Source/DealerSelection.Api.Models/TokenValidProperty.cs b/Source/DealerSelection.Api.Models/TokenValidProperty.cs
new file mode 100644
index 0000000..c715f5e
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/TokenValidProperty.cs
@@ -0,0 +1,10 @@
+namespace DealerSelection.Api.Models
+{
+ public class TokenValidProperty
+ {
+ public bool isValid { get; set; }
+
+ public double Ttl { get; set; }
+
+ }
+}
diff --git a/Source/DealerSelection.Api.Models/UnexpectedDataException.cs b/Source/DealerSelection.Api.Models/UnexpectedDataException.cs
new file mode 100644
index 0000000..8429f1d
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/UnexpectedDataException.cs
@@ -0,0 +1,9 @@
+namespace DealerSelection.Api.Models
+{
+ public class UnexpectedDataException : Exception
+ {
+ public UnexpectedDataException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api.Models/WebEngageEvent.cs b/Source/DealerSelection.Api.Models/WebEngageEvent.cs
new file mode 100644
index 0000000..2eb319a
--- /dev/null
+++ b/Source/DealerSelection.Api.Models/WebEngageEvent.cs
@@ -0,0 +1,70 @@
+using Newtonsoft.Json;
+
+namespace DealerSelection.Api.Models;
+
+public class WebEngageEventData
+{
+ public WebEngageEventData( string phoneNumber)
+ {
+
+ PhoneNumber = phoneNumber;
+
+ }
+
+
+ [JsonProperty("Booking ID")]
+ public string BookingID { get; }
+
+ [JsonProperty("Booking Status")]
+ public string BookingStatus { get; }
+
+ [JsonProperty("Booking Amount")]
+ public string BookingAmount { get; }
+
+ [JsonProperty("Full Name")]
+ public string FullName { get; }
+
+ [JsonProperty("Phone Number")]
+ public string PhoneNumber { get; }
+
+ [JsonProperty("Motorcycle Name")]
+ public string MotorcycleName { get; }
+
+ [JsonProperty("Motorcycle Code")]
+ public string MotorcycleCode { get; }
+
+ [JsonProperty("Location")]
+ public string Location { get; }
+
+ [JsonProperty("Dealer Name")]
+ public string DealerName { get; }
+
+ [JsonProperty("Dealer Phone Number")]
+ public string DealerPhoneNumber { get; }
+
+ [JsonProperty("Booking Receipt Link")]
+ public string BookingReceiptLink { get; }
+
+ [JsonProperty("Landing page URL")]
+ public string LandingPageURL { get; }
+
+
+
+}
+public class WebEngageEvent
+{
+ public WebEngageEvent(string userId, string eventName, WebEngageEventData data)
+ {
+ UserId = userId;
+ EventName = eventName;
+ EventData = data;
+ }
+ [JsonProperty("userId")]
+ public string UserId { get; }
+
+ [JsonProperty("eventName")]
+ public string EventName { get; }
+
+ [JsonProperty("eventData")]
+ public WebEngageEventData EventData { get; }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/AssignDealerApi.cs b/Source/DealerSelection.Api/AssignDealerApi.cs
new file mode 100644
index 0000000..ddfc59e
--- /dev/null
+++ b/Source/DealerSelection.Api/AssignDealerApi.cs
@@ -0,0 +1,190 @@
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Infrastructure.AssignDealer;
+using DealerSelection.Api.Infrastructure.CustomerDetail;
+using DealerSelection.Api.Infrastructure.Mulesoft;
+using DealerSelection.Api.Interface;
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Configuration;
+using DealerSelection.Common.Interfaces.HttpClient;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Org.BouncyCastle.Asn1.Tsp;
+using RestSharp;
+
+public class AssignDealerApi : IAssignDealerApi
+{
+
+ #region MuleSoft
+
+ public static string baseApiUrl = ConfigurationHelper.GetSetting("muleSoftAPIDomain", true);
+ public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting("muleSoftDealerDetail", true);
+ public static string bookingApiUrl = ConfigurationHelper.GetSetting("muleSoftBookingAPILeadSquareDomain", true);
+ public static string masterSchemaId = ConfigurationHelper.GetSetting("masterSchemaId", true);
+ public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting("masterDealerDetailSchemaId", true);
+ public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting("muleSoftStateWisePrice", true);
+ public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting("muleSoftBrandWiseModel", true);
+ public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateWisePricemasterSchemaId", true);
+ public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting("muleSoftBrandWiseModelmasterSchemaId", true);
+
+ public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaId", true);
+ public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaApi", true);
+ public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaId", true);
+ public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaApi", true);
+ public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemId", true);
+ public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemApi", true);
+
+ #endregion
+
+
+ #region Caching
+
+ public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting("MuleSoftCacheGetDealersDetail", true);
+ private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10;
+
+ public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting("MuleSoftCacheGetPriceOnState", true);
+ private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10;
+
+ public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting("MuleSoftCacheGetModelOnBrand", true);
+ private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10;
+
+ public static string CacheGetActiveState = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveState", true);
+ private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10;
+
+ public static string CacheGetActiveCity = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveCity", true);
+ private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10;
+
+ public static string CacheModelDetails = ConfigurationHelper.GetSetting("MuleSoftCacheModelDetails", true);
+ private int _cacheModelDetails = !string.IsNullOrEmpty(CacheModelDetails) ? int.Parse(CacheModelDetails) : 10;
+
+
+ #endregion
+
+ private readonly ILogger _logger;
+ private IAssignDealerRepository Repository { get; }
+ private DealerSelection.Api.Infrastructure.CustomerDetail.IRepository CustomerDetailRepository { get; }
+ private IMulesoftApi MulesoftApi { get; }
+ private IHttpClientHandler ClientHandler { get; }
+ private readonly IMemoryCache _memoryCache;
+
+ public AssignDealerApi(IAssignDealerRepository repository, IMulesoftApi mulesoftApi, DealerSelection.Api.Infrastructure.CustomerDetail.IRepository customerRepo,
+ IHttpClientHandler clientHandler, IMemoryCache memoryCache, ILogger logger)
+ {
+ Repository = repository;
+ MulesoftApi = mulesoftApi;
+ CustomerDetailRepository = customerRepo;
+ ClientHandler = clientHandler;
+ _memoryCache = memoryCache;
+ _logger = logger;
+ }
+ public async Task GetCustomerDataForJob(int buId, int recordId)
+ {
+ try
+ {
+
+ MulesoftCustomerInfoDto customerInfo= await CustomerDetailRepository.GetCustomerData( buId, recordId);
+ await AssignDealers(customerInfo);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetDealers:- " + ex.StackTrace.ToString());
+ }
+ }
+
+ private async Task AssignDealers(MulesoftCustomerInfoDto customerInfo)
+ {
+ try
+ {
+ MulesoftResponse dealerResponse = await MulesoftApi.GetDealers(customerInfo.BuId, customerInfo.BuName, customerInfo.CustomerLat, customerInfo.CustomerLong);
+ if (dealerResponse!=null && dealerResponse.IsRequestSuccessfull)
+ {
+
+ JObject obj = JObject.Parse(dealerResponse.Result);
+ if (obj != null && obj["Data"] != null && obj["Data"].Count() > 0)
+ {
+ if (obj["Data"].Count() == 1)
+ {
+ //Save dealer Detail and Send to LSQ
+ JToken jArrResultData = (JToken)obj["Data"][0];
+ if (jArrResultData != null)
+ {
+ customerInfo.DealerCode = (JValue)jArrResultData["Code"] != null ? Convert.ToString(((JValue)jArrResultData["Code"]).Value) : "0";
+ customerInfo.DealerName = (JValue)jArrResultData["DisplayName"] != null ? Convert.ToString(((JValue)jArrResultData["DisplayName"]).Value) : "0";
+
+ try
+ {
+ var responseApi = await MulesoftApi.CallLSQBookingApi(customerInfo);
+
+ if (responseApi != null && responseApi.IsRequestSuccessfull)
+ await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.Complete);
+ else
+ await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.ReadyForJob);
+ }
+ catch (Exception ex)
+ {
+ await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.ReadyForJob);
+ _logger.LogError("Error in LSQ " + ex.StackTrace.ToString());
+ }
+ }
+ }
+ else
+ {
+ //Send to Webengage
+ CustomCfg cfg = CustomCfg.GetCustomCfg(customerInfo.BuId);
+ WebEngageEventData eventData = new WebEngageEventData(customerInfo.MobileNumber);
+ WebEngageEvent events = new WebEngageEvent(customerInfo.MobileNumber, cfg.WebengageEventName, eventData);
+ await WebEngageEventsAPICall(events, cfg);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + customerInfo.BuId + "Api:- GetDealers:- " + ex.StackTrace.ToString());
+ }
+ }
+
+ private async Task WebEngageEventsAPICall(WebEngageEvent message, CustomCfg cfg)
+ {
+ _logger.LogInformation("WebEngageEventsAPICall Started: " + JsonConvert.SerializeObject(message));
+ try
+ {
+ var json = JsonConvert.SerializeObject(message);
+ var baseApiUrl = Convert.ToString(cfg.WebengageApiHost + cfg.WebEngageLicenseCode + "/events");
+ var options = new RestClientOptions(baseApiUrl)
+ {
+ MaxTimeout = -1,
+ };
+ var client = new RestClient();
+ var request = new RestRequest(baseApiUrl, Method.Post);
+ request.AddHeader("Content-Type", "application/json");
+ request.AddHeader("Authorization", "Bearer " + cfg.WebEngageAuthToken);
+ request.AddStringBody(json, DataFormat.Json);
+ RestResponse response = await client.ExecuteAsync(request);
+ var content = response.Content;
+
+ _logger.LogInformation("WebEngageEventsAPICall End: " + content);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("PendingStatusUpdateApi:- WebEngageEventsAPICall:- " + ex.Message.ToString());
+ }
+ }
+
+
+ private async Task UpdateDealerDetail(MulesoftCustomerInfoDto customerInfo, DealerSelectionJobStatus jobStatus)
+ {
+ CustomerDealerInfoRequestDto dto = new CustomerDealerInfoRequestDto
+ {
+ BuId = customerInfo.BuId,
+ DealerName = jobStatus == DealerSelectionJobStatus.Complete ? customerInfo.DealerName : "",
+ DealerCode = jobStatus == DealerSelectionJobStatus.Complete ? customerInfo.DealerCode : "",
+ DealerSelectionJobStatus = jobStatus == DealerSelectionJobStatus.Complete ? DealerSelectionJobStatus.Complete : DealerSelectionJobStatus.ReadyForJob,
+ RecordId = customerInfo.RecordId
+
+ };
+ await CustomerDetailRepository.UpdateDealerDetail(dto);
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs b/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs
new file mode 100644
index 0000000..b52f63f
--- /dev/null
+++ b/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs
@@ -0,0 +1,151 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace DealerSelection.Api.CommonUtil
+{
+
+ public static class AESEncryption
+ {
+
+ public static byte[] EncryptString(string plainText, byte[] key, byte[] iv)
+ {
+ // Instantiate a new Aes object to perform string symmetric encryption
+ Aes encryptor = Aes.Create();
+
+ encryptor.Mode = CipherMode.CBC;
+
+ // Set key and IV
+ byte[] aesKey = new byte[32];
+ Array.Copy(key, 0, aesKey, 0, 32);
+ encryptor.Key = aesKey;
+ encryptor.IV = iv;
+
+ // Instantiate a new MemoryStream object to contain the encrypted bytes
+ MemoryStream memoryStream = new MemoryStream();
+
+ // Instantiate a new encryptor from our Aes object
+ ICryptoTransform aesEncryptor = encryptor.CreateEncryptor();
+
+ // Instantiate a new CryptoStream object to process the data and write it to the
+ // memory stream
+ CryptoStream cryptoStream = new CryptoStream(memoryStream, aesEncryptor, CryptoStreamMode.Write);
+
+ // Convert the plainText string into a byte array
+ byte[] plainBytes = Encoding.ASCII.GetBytes(plainText);
+
+ // Encrypt the input plaintext string
+ cryptoStream.Write(plainBytes, 0, plainBytes.Length);
+
+ // Complete the encryption process
+ cryptoStream.FlushFinalBlock();
+
+ // Convert the encrypted data from a MemoryStream to a byte array
+ byte[] cipherBytes = memoryStream.ToArray();
+
+ // Close both the MemoryStream and the CryptoStream
+ memoryStream.Close();
+ cryptoStream.Close();
+
+ // Convert the encrypted byte array to a base64 encoded string
+ string cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length);
+
+ // Return the encrypted data as a string
+ return cipherBytes;
+ }
+
+ public static string DecryptString(string cipherText, string key)
+ {
+ // Instantiate a new Aes object to perform string symmetric encryption
+ Aes encryptor = Aes.Create();
+
+ encryptor.Mode = CipherMode.CBC;
+
+ byte[] salt = Convert.FromBase64String(cipherText).Take(16).ToArray();
+ byte[] IVV = Convert.FromBase64String(cipherText).Skip(16).Take(16).ToArray();
+
+
+ byte[] aesKey;
+ using (var pbkdf2 = new Rfc2898DeriveBytes(key, salt, 65536, HashAlgorithmName.SHA256))
+ {
+ aesKey = pbkdf2.GetBytes(32);
+ }
+
+ // Set key and IV
+ //byte[] aesKey = new byte[32];
+ //Array.Copy(key, 0, aesKey, 0, 32);
+ encryptor.Key = aesKey;
+ encryptor.IV = IVV;
+
+
+
+
+ // Instantiate a new MemoryStream object to contain the encrypted bytes
+ MemoryStream memoryStream = new MemoryStream();
+
+ // Instantiate a new encryptor from our Aes object
+ ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
+
+ // Instantiate a new CryptoStream object to process the data and write it to the
+ // memory stream
+ CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
+
+ // Will contain decrypted plaintext
+ string plainText = string.Empty;
+
+ try
+ {
+ // Convert the ciphertext string into a byte array
+ byte[] cipherBytes = Convert.FromBase64String(cipherText).Skip(32).ToArray();
+
+ // Decrypt the input ciphertext string
+ cryptoStream.Write(cipherBytes, 0, cipherBytes.Length);
+
+ // Complete the decryption process
+ cryptoStream.FlushFinalBlock();
+
+ // Convert the decrypted data from a MemoryStream to a byte array
+ byte[] plainBytes = memoryStream.ToArray();
+
+ // Convert the decrypted byte array to string
+ plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length);
+ }
+ finally
+ {
+ // Close both the MemoryStream and the CryptoStream
+ memoryStream.Close();
+ cryptoStream.Close();
+ }
+
+ // Return the decrypted data as a string
+ return plainText;
+ }
+
+ public static dynamic ReturnEncKey(string password,string message)
+ {
+
+ byte[] salt = new byte[16];
+ byte[] encKey;
+ using (var rng = RandomNumberGenerator.Create())
+ {
+ rng.GetBytes(salt);
+ }
+
+ using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 65536, HashAlgorithmName.SHA256))
+ {
+ encKey = pbkdf2.GetBytes(32);
+ }
+
+ Random random = new Random();
+
+ byte[] iv = new byte[16];
+ random.NextBytes(iv);
+ byte[] encrypted = EncryptString(message, encKey, iv);
+ byte[] finalstring = salt.Concat(iv).Concat(encrypted).ToArray();
+ string encstring = Convert.ToBase64String(finalstring);
+
+ return encstring;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs b/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs
new file mode 100644
index 0000000..c8dba12
--- /dev/null
+++ b/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs
@@ -0,0 +1,132 @@
+using DealerSelection.Common.Configuration;
+
+namespace DealerSelection.Api.CommonUtil
+{
+ public class CustomCfg
+ {
+ public int BuId { get; set; }
+ public string BuCode { get; set; }
+ public string InfoBipAppilcationId { get; set; }
+ public string InfoBipMessageId { get; set; }
+ public string InfoBipFroms { get; set; }
+ public string CCAvenueAccessCode { get; set; }
+ public string CCAvenueMerchantCode { get; set; }
+ public string CCAvenueBaseUrl { get; set; }
+ public string BookingPrice { get; set; }
+ public string CCAvenueWorkingKey { get; set; }
+ public string WebengageLandingPageUrl { get; set; }
+ public string WebengageEventName { get; set; }
+ public string WebEngageLicenseCode { get; set; }
+ public string WebEngageAuthToken { get; set; }
+ public string WebengageApiHost { get; set; }
+ public string ValidateDuplicate { get; set; }
+ public int ValidateDuplicateHour { get; set; }
+
+ public string ClientId { get; set; }
+ public string ClientSecret { get; set; }
+ public string Key { get; set; }
+ public string Audience { get; set; }
+ public string Issuer { get; set; }
+ public string Role { get; set; }
+
+ public string ExpireMinutes { get; set; }
+ public static CustomCfg GetCustomCfg(int buId)
+ {
+ CustomCfg cfg = new CustomCfg();
+ switch (buId)
+ {
+ case 1:
+ cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("KtmCfg:InfoBipAppilcationId", true);
+ cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("KtmCfg:InfoBipMessageId", true);
+ cfg.InfoBipFroms = ConfigurationHelper.GetSetting("KtmCfg:InfoBipFrom", true);
+
+ cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueAccessCode", true);
+ cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueMerchantCode", true);
+ cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueBaseUrl", true);
+ cfg.BookingPrice = ConfigurationHelper.GetSetting("KtmCfg:BookingPrice", true);
+ cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueWorkingKey", true);
+ cfg.BuCode= ConfigurationHelper.GetSetting("KtmCfg:BuCode", true);
+ cfg.WebengageLandingPageUrl= ConfigurationHelper.GetSetting("KtmCfg:LandingPageUrl", true);
+ cfg.WebengageEventName = ConfigurationHelper.GetSetting("KtmCfg:WebengageEventName", true);
+ cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("KtmCfg:WebEngageLicenseCode", true);
+ cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("KtmCfg:WebEngageAuthToken", true);
+ cfg.WebengageApiHost = ConfigurationHelper.GetSetting("KtmCfg:WebengageApiHost", true);
+ cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("KtmCfg:ValidateDuplicate", true);
+ cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("KtmCfg:ValidateDuplicateHr", true);
+ cfg.BuId = buId;
+
+ cfg.ClientId = ConfigurationHelper.GetSetting("KtmCfg:ClientId", true);
+ cfg.ClientSecret = ConfigurationHelper.GetSetting("KtmCfg:ClientSecret", true);
+ cfg.Key = ConfigurationHelper.GetSetting("KtmCfg:Key", true);
+ cfg.Audience = ConfigurationHelper.GetSetting("KtmCfg:Audience", true);
+ cfg.Issuer = ConfigurationHelper.GetSetting("KtmCfg:Issuer", true);
+ cfg.Role = ConfigurationHelper.GetSetting("KtmCfg:Role", true);
+ cfg.ExpireMinutes = ConfigurationHelper.GetSetting("KtmCfg:ExpireMinutes", true);
+ break;
+ case 2:
+ cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("BajajCfg:InfoBipAppilcationId", true);
+ cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("BajajCfg:InfoBipMessageId", true);
+ cfg.InfoBipFroms = ConfigurationHelper.GetSetting("BajajCfg:InfoBipFrom", true);
+ cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueAccessCode", true);
+ cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueMerchantCode", true);
+ cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueBaseUrl", true);
+ cfg.BookingPrice = ConfigurationHelper.GetSetting("BajajCfg:BookingPrice", true);
+ cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueWorkingKey", true);
+ cfg.BuCode = ConfigurationHelper.GetSetting("BajajCfg:BuCode", true);
+ cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting("BajajCfg:LandingPageUrl", true);
+ cfg.WebengageEventName = ConfigurationHelper.GetSetting("BajajCfg:WebengageEventName", true);
+ cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("BajajCfg:WebEngageLicenseCode", true);
+ cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("BajajCfg:WebEngageAuthToken", true);
+ cfg.WebengageApiHost = ConfigurationHelper.GetSetting("BajajCfg:WebengageApiHost", true);
+ cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("BajajCfg:ValidateDuplicate", true);
+ cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("BajajCfg:ValidateDuplicateHr", true);
+ cfg.BuId = buId;
+
+ cfg.ClientId = ConfigurationHelper.GetSetting("BajajCfg:ClientId", true);
+ cfg.ClientSecret = ConfigurationHelper.GetSetting("BajajCfg:ClientSecret", true);
+ cfg.Key = ConfigurationHelper.GetSetting("BajajCfg:Key", true);
+ cfg.Audience = ConfigurationHelper.GetSetting("BajajCfg:Audience", true);
+ cfg.Issuer = ConfigurationHelper.GetSetting("BajajCfg:Issuer", true);
+ cfg.Role = ConfigurationHelper.GetSetting("BajajCfg:Role", true);
+ cfg.ExpireMinutes = ConfigurationHelper.GetSetting("BajajCfg:ExpireMinutes", true);
+ break;
+ case 3:
+ cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipAppilcationId", true);
+ cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipMessageId", true);
+ cfg.InfoBipFroms = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipFrom", true);
+ cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueAccessCode", true);
+ cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueMerchantCode", true);
+ cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueBaseUrl", true);
+ cfg.BookingPrice = ConfigurationHelper.GetSetting("TriumphCfg:BookingPrice", true);
+ cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueWorkingKey", true);
+ cfg.BuCode = ConfigurationHelper.GetSetting("TriumphCfg:BuCode", true);
+ cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting("TriumphCfg:LandingPageUrl", true);
+ cfg.WebengageEventName = ConfigurationHelper.GetSetting("TriumphCfg:WebengageEventName", true);
+ cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("TriumphCfg:WebEngageLicenseCode", true);
+ cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("TriumphCfg:WebEngageAuthToken", true);
+ cfg.WebengageApiHost = ConfigurationHelper.GetSetting("TriumphCfg:WebengageApiHost", true);
+ cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("TriumphCfg:ValidateDuplicate", true);
+ cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("TriumphCfg:ValidateDuplicateHr", true);
+ cfg.BuId = buId;
+
+ cfg.ClientId = ConfigurationHelper.GetSetting("TriumphCfg:ClientId", true);
+ cfg.ClientSecret = ConfigurationHelper.GetSetting("TriumphCfg:ClientSecret", true);
+ cfg.Key = ConfigurationHelper.GetSetting("TriumphCfg:Key", true);
+ cfg.Audience = ConfigurationHelper.GetSetting("TriumphCfg:Audience", true);
+ cfg.Issuer = ConfigurationHelper.GetSetting("TriumphCfg:Issuer", true);
+ cfg.Role = ConfigurationHelper.GetSetting("TriumphCfg:Role", true);
+ cfg.ExpireMinutes = ConfigurationHelper.GetSetting("TriumphCfg:ExpireMinutes", true);
+ break;
+ default:
+ cfg.InfoBipAppilcationId = "";
+ cfg.InfoBipMessageId = "";
+ cfg.InfoBipFroms = "";
+ cfg.BuId = buId;
+ break;
+ }
+ return cfg;
+
+ }
+ }
+
+}
diff --git a/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs b/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs
new file mode 100644
index 0000000..e96c3ee
--- /dev/null
+++ b/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs
@@ -0,0 +1,28 @@
+namespace DealerSelection.Api.CommonUtil
+{
+ public static class GenerateRandomString
+ {
+ public static string GenerateString(int lgth)
+ {
+ string random = "";
+ try
+ {
+ Random ran = new Random();
+ string b = "abcdefghijklmnopqrstuvwxyz";
+ int length = lgth;
+
+ for (int i = 0; i < length; i++)
+ {
+ int a = ran.Next(26);
+ random = random + b.ElementAt(a);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ return random;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs b/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs
new file mode 100644
index 0000000..375f4e1
--- /dev/null
+++ b/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs
@@ -0,0 +1,86 @@
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Configuration;
+using Newtonsoft.Json.Linq;
+using System.Net;
+using System.Net.Http.Headers;
+using System.Text;
+using DealerSelection.Common.Interfaces.HttpClient;
+using DealerSelection.Common.Logging;
+
+namespace DealerSelection.Api.CommonUtil
+{
+
+ ///
+ /// Summary description for TestRideExcellon
+ ///
+ public static class MuleSoftIntegration
+ {
+ public static string ClientId = ConfigurationHelper.GetSetting("muleSoftAPIClientID", true);
+ public static string ClientSecret = ConfigurationHelper.GetSetting("muleSoftAIPClientSecret", true);
+ public static string TokenGenerateUrl = ConfigurationHelper.GetSetting("muleSoftGenerateTokenURL", true);
+
+ public static async Task generateToken(IHttpClientHandler clientHandler)
+ {
+ AzureLogHelper.LogMessage("Api:- generateToken Started :- " + DateTime.Now);
+ MulesoftToken token = new MulesoftToken();
+ try
+ {
+ var url = TokenGenerateUrl + "/token";
+
+ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
+ HttpClient client = clientHandler.GetHttpClient();
+ Uri requestUri = new Uri(url);
+
+ client.DefaultRequestHeaders.Add("client_id", ClientId);
+ client.DefaultRequestHeaders.Add("client_secret", ClientSecret);
+ client.DefaultRequestHeaders.Add("grant_type", "CLIENT_CREDENTIALS");
+ client.DefaultRequestHeaders.Add("cache-control", "no-cache");
+
+ var response = await client.PostAsync(requestUri, null);
+
+ if (response != null)
+ {
+ JObject obj = JObject.Parse(await response.Content.ReadAsStringAsync());
+ if (response.StatusCode.ToString() == "OK")
+ {
+ if (!string.IsNullOrEmpty(Convert.ToString(obj["access_token"])))
+ token.Value = Convert.ToString(obj["access_token"]);
+ if (!string.IsNullOrEmpty(Convert.ToString(obj["expires_in"])))
+ token.ExpiresIn = Convert.ToInt32(obj["expires_in"]);
+ }
+ }
+ return token;
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ return token;
+ }
+
+
+ public static async Task ReturnMuleSoftResponse(IHttpClientHandler clientHandler, string encstring, string url, string authToken, string encKeyToHeader)
+ {
+ try
+ {
+ var data = "{\"encData\": \"" + encstring + "\"}";
+
+ HttpClient request = clientHandler.GetHttpClient();
+ Uri requestUri = new Uri(url);
+
+ var httpContent = new MultipartFormDataContent();
+ httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
+ request.DefaultRequestHeaders.Add("client_id", ClientId);
+ request.DefaultRequestHeaders.Add("client_secret", ClientSecret);
+ request.DefaultRequestHeaders.Add("Authorization", "Bearer " + authToken);
+ request.DefaultRequestHeaders.Add("encKey", encKeyToHeader);
+ return await request.PostAsync(requestUri, new StringContent(data, UnicodeEncoding.UTF8, "application/json"));
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ return null;
+ }
+ }
+}
diff --git a/Source/DealerSelection.Api/DealerSelection.Api.csproj b/Source/DealerSelection.Api/DealerSelection.Api.csproj
new file mode 100644
index 0000000..ef879f9
--- /dev/null
+++ b/Source/DealerSelection.Api/DealerSelection.Api.csproj
@@ -0,0 +1,42 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+ 1701;1702;8618;8601;8600;8602;8603;CA2254
+
+
+
+ 1701;1702;8618;8601;8600;8602;8603;CA2254
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+ CCAvenue\MCPG.CCA.Util.dll
+ True
+
+
+
+
diff --git a/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs b/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs
new file mode 100644
index 0000000..a8a97ae
--- /dev/null
+++ b/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs
@@ -0,0 +1,143 @@
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Infrastructure.InfoBip;
+using DealerSelection.Api.Interface;
+using DealerSelection.Common.Interfaces.HttpClient;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System.Net;
+using System.Text;
+
+///
+/// Summary description for KarixSmsService
+///
+public class InfoBipSmsServiceApi : IInfoBipSmsServiceApi
+{
+
+ static string userAuth = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("Bajaj_OTP1" + ":" + "BAL@October2022"));
+ private IRepository Repository { get; }
+ private readonly ILogger _logger;
+ private IHttpClientHandler ClientHandler { get; }
+ public InfoBipSmsServiceApi(IRepository repository, IHttpClientHandler clientHandler, ILogger logger)
+ {
+ Repository = repository;
+ ClientHandler = clientHandler;
+ _logger = logger;
+ }
+ public InfoBipSmsServiceApi()
+ {
+
+ }
+
+ public async Task sendOTP(int buId, string strMobile)
+ {
+ CustomCfg cfg = CustomCfg.GetCustomCfg(buId);
+ JObject obj = new JObject();
+ try
+ {
+ var reqObject = new SendOTP
+ {
+ applicationId = cfg.InfoBipAppilcationId,
+ messageId = cfg.InfoBipMessageId,
+ from = cfg.InfoBipFroms,
+ to = "91" + strMobile
+ };
+ var json = JsonConvert.SerializeObject(reqObject);
+
+ string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin";
+
+ obj = await GetDataFromInfoBip(buId, strMobile, apiUrl, "verify", json);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- sendOTP:- " + ex.StackTrace.ToString());
+ }
+
+ return obj;
+ }
+
+ public async Task resendOTP(int buId, string strMobile, string strOtpPinId)
+ {
+ var errorMessage = "";
+ JObject obj = new JObject();
+ try
+ {
+ string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin/" + strOtpPinId + "/resend";
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl);
+ request.Method = "POST";
+ request.Headers.Add("Authorization", "Basic " + userAuth);
+ request.Headers.Add("cache-control", "no-cache");
+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+ Stream responseStream = response.GetResponseStream();
+ StreamReader reader = new StreamReader(responseStream);
+ string content = reader.ReadToEnd();
+ string apiRequest = strOtpPinId;
+ string apiResponse = content;
+ obj = JObject.Parse(content);
+ await Repository.SaveResponse(buId, strMobile, "resend otp", apiRequest, apiResponse, errorMessage);
+ }
+ catch (Exception ex)
+ {
+ errorMessage = ex.Message;
+ _logger.LogError("BUID:- " + buId + "Api:- resendOTP:- " + ex.Message.ToString());
+ }
+
+
+ return obj;
+ }
+
+ public async Task verifyOTP(int buId, string strMobile, string strOtpPinId, string otpPin)
+ {
+ JObject obj = new();
+ try
+ {
+ var reqObject = new OTP
+ {
+ pin = otpPin
+ };
+ var json = JsonConvert.SerializeObject(reqObject);
+
+ string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin/" + strOtpPinId + "/verify";
+
+ obj = await GetDataFromInfoBip(buId, strMobile, apiUrl, "verify", json);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BUID:- " + buId + " Api:- verifyOTP:- " + ex.StackTrace.ToString());
+ }
+
+
+ return obj;
+ }
+
+ private async Task GetDataFromInfoBip(int buId, string strMobile, string baseUrl, string otpRequestType, string data)
+ {
+ HttpClient client = ClientHandler.GetHttpClient();
+ Uri requestUri = new Uri(baseUrl);
+
+
+ client.DefaultRequestHeaders.Add("Authorization", "Basic " + userAuth);
+ client.DefaultRequestHeaders.Add("cache-control", "no-cache");
+
+ var response = await client.PostAsync(requestUri, new StringContent(data, UnicodeEncoding.UTF8, "application/json"));
+
+ JObject obj = JObject.Parse(await response.Content.ReadAsStringAsync());
+
+ _logger.LogError($"BuId: {buId}, MobileNumber: {strMobile}, OTP Type: {otpRequestType}, ApiRequest: {data} , ApiResponse: {response}");
+
+ return obj;
+ }
+}
+
+public class OTP
+{
+ public string pin { get; set; }
+}
+
+public class SendOTP
+{
+ public string applicationId { get; set; }
+ public string messageId { get; set; }
+ public string from { get; set; }
+ public string to { get; set; }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/JwtTokenApi.cs b/Source/DealerSelection.Api/JwtTokenApi.cs
new file mode 100644
index 0000000..371f0a5
--- /dev/null
+++ b/Source/DealerSelection.Api/JwtTokenApi.cs
@@ -0,0 +1,112 @@
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Infrastructure.Jwt;
+using DealerSelection.Api.Interface;
+using DealerSelection.Api.Models;
+using Microsoft.Extensions.Logging;
+using Microsoft.IdentityModel.Tokens;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+
+public class JwtTokenApi : IJwtTokenApi
+{
+ private IJwtRepository Repository { get; }
+ private readonly ILogger _logger;
+
+ public JwtTokenApi(IJwtRepository repository, ILogger logger)
+ {
+ Repository = repository;
+ _logger = logger;
+ }
+
+ public async Task GenerateToken(AuthValidateModel user)
+ {
+ try
+ {
+ bool isValidUser = await Authenticate(user);
+ if (isValidUser)
+ {
+ AuthModel auth = new AuthModel
+ {
+ BuId = user.BuId,
+ ClientId = user.ClientId,
+ SecretId = user.SecretId,
+ Role = "Admin"
+ };
+ CustomCfg cfg = CustomCfg.GetCustomCfg(auth.BuId);
+
+ var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(cfg.Key));
+ string expireMinutes = cfg.ExpireMinutes;
+ int tokenExpireMinutes = string.IsNullOrEmpty(expireMinutes) ? 1439 : int.Parse(expireMinutes);
+ var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
+ var claims = new[]
+ {
+ new Claim(ClaimTypes.NameIdentifier,auth.ClientId),
+ new Claim(ClaimTypes.Role,auth.Role),
+ };
+ var token = new JwtSecurityToken(
+ cfg.Issuer,
+ cfg.Audience,
+ claims,
+ expires: DateTime.UtcNow.AddMinutes(tokenExpireMinutes),
+ signingCredentials: credentials);
+ return new JwtSecurityTokenHandler().WriteToken(token);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("JwtTokenApi Api GenerateToken:- " + ex.Message.ToString());
+ }
+
+ return null;
+ }
+
+ public async Task Authenticate(AuthValidateModel userLogin)
+ {
+ try
+ {
+ CustomCfg cfg = CustomCfg.GetCustomCfg(userLogin.BuId);
+
+ return cfg.ClientId.ToLower() == userLogin.ClientId.ToLower() &&
+ cfg.ClientSecret.ToLower() == userLogin.SecretId.ToLower();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("JwtTokenApi Api Authenticate:- " + ex.Message.ToString());
+ }
+ return false;
+ }
+
+ public async Task IsTokenExpired(string tokenValue)
+ {
+ TokenValidProperty tokenValid = new TokenValidProperty();
+ try
+ {
+ var tokenTicks = GetTokenExpirationTime(tokenValue);
+ var tokenDate = DateTimeOffset.FromUnixTimeSeconds(tokenTicks).UtcDateTime;
+
+ var now = DateTime.UtcNow;
+ var valid = tokenDate >= now;
+
+ tokenValid.isValid = valid;
+ tokenValid.Ttl = tokenDate.TimeOfDay.TotalSeconds - now.TimeOfDay.TotalSeconds;
+
+ return tokenValid;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("JwtTokenApi Api IsTokenExpired:- " + ex.Message.ToString());
+ return tokenValid;
+ }
+ }
+
+ private static long GetTokenExpirationTime(string token)
+ {
+ var handler = new JwtSecurityTokenHandler();
+ var jwtSecurityToken = handler.ReadJwtToken(token);
+ var tokenExp = jwtSecurityToken.Claims.First(claim => claim.Type.Equals("exp")).Value;
+ var ticks = long.Parse(tokenExp);
+ return ticks;
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/MulesoftApi.cs b/Source/DealerSelection.Api/MulesoftApi.cs
new file mode 100644
index 0000000..921af0b
--- /dev/null
+++ b/Source/DealerSelection.Api/MulesoftApi.cs
@@ -0,0 +1,722 @@
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Infrastructure.Mulesoft;
+using DealerSelection.Api.Interface;
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Configuration;
+using DealerSelection.Common.Interfaces.HttpClient;
+using DealerSelection.Common.Logging;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System.Text;
+
+public class MulesoftApi : IMulesoftApi
+{
+
+ #region MuleSoft
+
+ public static string baseApiUrl = ConfigurationHelper.GetSetting("muleSoftAPIDomain", true);
+ public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting("muleSoftDealerDetail", true);
+ public static string bookingApiUrl = ConfigurationHelper.GetSetting("muleSoftBookingAPILeadSquareDomain", true);
+ public static string masterSchemaId = ConfigurationHelper.GetSetting("masterSchemaId", true);
+ public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting("masterDealerDetailSchemaId", true);
+ public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting("muleSoftStateWisePrice", true);
+ public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting("muleSoftBrandWiseModel", true);
+ public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateWisePricemasterSchemaId", true);
+ public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting("muleSoftBrandWiseModelmasterSchemaId", true);
+
+ public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaId", true);
+ public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaApi", true);
+ public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaId", true);
+ public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaApi", true);
+ public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemId", true);
+ public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemApi", true);
+
+ #endregion
+
+
+ #region Caching
+
+ public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting("MuleSoftCacheGetDealersDetail", true);
+ private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10;
+
+ public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting("MuleSoftCacheGetPriceOnState", true);
+ private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10;
+
+ public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting("MuleSoftCacheGetModelOnBrand", true);
+ private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10;
+
+ public static string CacheGetActiveState = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveState", true);
+ private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10;
+
+ public static string CacheGetActiveCity = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveCity", true);
+ private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10;
+
+ public static string CacheModelDetails = ConfigurationHelper.GetSetting("MuleSoftCacheModelDetails", true);
+ private int _cacheModelDetails = !string.IsNullOrEmpty(CacheModelDetails) ? int.Parse(CacheModelDetails) : 10;
+
+
+ #endregion
+
+ private readonly ILogger _logger;
+ private IRepository Repository { get; }
+ private IMulesoftTokenApi MulesoftTokenApi { get; }
+ private IHttpClientHandler ClientHandler { get; }
+ private readonly IMemoryCache _memoryCache;
+
+ public MulesoftApi(IRepository repository, IMulesoftTokenApi mulesoftTokenApi,
+ IHttpClientHandler clientHandler, IMemoryCache memoryCache, ILogger logger)
+ {
+ Repository = repository;
+ MulesoftTokenApi = mulesoftTokenApi;
+ ClientHandler = clientHandler;
+ _memoryCache = memoryCache;
+ _logger = logger;
+ }
+
+
+ public async Task GetDealers(int buId, string buUnit, string strlat, string strLong)
+ {
+ MulesoftResponse response = null;
+ try
+ {
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"bu\": \"" + buUnit + "\", \"latitude\": " + strlat + ", \"longitude\": "
+ + strLong + ", \"masterSchemaId\": \"" + masterSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, baseApiUrl, authToken, encKeyToHeader);
+
+ if (response2 != null)
+ {
+ response = await ValidateMuleSoftResponse(buId, response2);
+
+ }
+
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + buId + "Api:- GetDealers:- " + ex.StackTrace.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetAndInsertDealerDetails(int buId, string dealerCode)
+ {
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "getDealerDetails_" + buId + dealerCode;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ AzureLogHelper.LogMessage("Api:- GetAndInsertDealerDetails:- API:- " + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"branchCode\": \"" + dealerCode +
+ "\",\"masterSchemaId\": \"" + masterDealerDetailSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, dealerDetailApiUrl, authToken, encKeyToHeader);
+ response = await DecryptDealerDetail(buId, response2);
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetDealersDetail),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, response, cacheExpiryOptions);
+ }
+ }
+ _logger.LogError("Api:- GetAndInsertDealerDetails From Cache:- " + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetAndInsertDealerDetails:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetStateWisePrice(int buId, string stateCode, string itemId)
+ {
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "getStateWisePrice_" + buId + stateCode + itemId;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ _logger.LogError("Api:- GetStateWisePrice API:- " + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"statecode\": \"" + stateCode.ToUpper() + "\",\"itemId\": \""
+ + itemId + "\",\"masterSchemaId\": \"" + muleSoftPricemasterSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, muleSoftStateWisePrice, authToken, encKeyToHeader);
+ response = await ValidateMuleSoftResponse(buId, response2);
+ var jsonresult = JObject.Parse(response.Result);
+
+ if (Convert.ToBoolean(jsonresult["IsRequestSuccessfull"]) && jsonresult["Data"] != null)
+ {
+ string exShowroomPrice = jsonresult["Data"][0]["ExPrice"].ToString();
+ MulesoftResponse mulesoftResponse = new MulesoftResponse(buId, 0, Convert.ToBoolean(jsonresult["IsRequestSuccessfull"]),
+ exShowroomPrice, "", "");
+
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetPriceOnState),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, mulesoftResponse, cacheExpiryOptions);
+
+ return mulesoftResponse;
+ }
+ else
+ {
+ return new MulesoftResponse(buId, 0, false, response.Result, "", "");
+ }
+ }
+ }
+ _logger.LogError("Api:- GetStateWisePrice From Cache :- " + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetStateWisePrice:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetModelOnBrand(int buId, string brand)
+ {
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "getModelOnBrand_" + buId + brand;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ _logger.LogError("Api:- GetModelOnBrand API:- " + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"brand\": \"" + brand.ToUpper() +
+ "\",\"masterSchemaId\": \"" + muleSoftModelmasterSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, muleSoftBrandWiseModel, authToken, encKeyToHeader);
+ response = await ValidateMuleSoftResponse(buId, response2);
+
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetModelOnBrand),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, response, cacheExpiryOptions);
+ }
+ }
+ _logger.LogError("Api:- GetModelOnBrand From Cache:- " + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetModelOnBrand:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetActiveState(int buId)
+ {
+ CustomCfg cfg = CustomCfg.GetCustomCfg(buId);
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "getActiveState_" + buId;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ _logger.LogError("Api:- GetActiveState API:- " + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"bu\": \"" + cfg.BuCode.ToUpper() +
+ "\",\"masterSchemaId\": \"" + muleSoftStateMasterSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, encstring,
+ muleSoftStateMasterSchemaApi, authToken, encKeyToHeader);
+
+ response = await ValidateMuleSoftResponse(0, response2);
+
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetActiveState),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, response, cacheExpiryOptions);
+ }
+ }
+ _logger.LogError("Api:- GetActiveState from Cache:- " + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetActiveState:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetActiveCity(int buId, string stateCode)
+ {
+ CustomCfg cfg = CustomCfg.GetCustomCfg(buId);
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "getActiveCity_" + buId + stateCode;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ _logger.LogError("Api GetActiveCity:- API:- " + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"bu\": \"" + cfg.BuCode.ToUpper() + "\",\"stateId\": \"" + stateCode.ToUpper() +
+ "\",\"masterSchemaId\": \"" + muleSoftCityMasterSchemaId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, muleSoftCityMasterSchemaApi,
+ authToken, encKeyToHeader);
+ response = await ValidateMuleSoftResponse(0, response2);
+
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetActiveCity),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, response, cacheExpiryOptions);
+ }
+ }
+
+ _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetActiveCity:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task ModelDetailsByItemCode(int buId, string itemId)
+ {
+ MulesoftResponse response = null;
+ try
+ {
+ var cacheKey = "modelDetailsItemCode_" + buId + itemId;
+ if (!_memoryCache.TryGetValue(cacheKey, out response))
+ {
+ _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey);
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+ string message = "{\"itemid\": \"" + itemId + "\",\"masterSchemaId\": \""
+ + muleSoftModelMasterSchemaItemId + "\"}";
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler,
+ encstring, muleSoftModelMasterSchemaItemApi, authToken, encKeyToHeader);
+ response = await ValidateMuleSoftResponse(0, response2);
+
+ var cacheExpiryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheModelDetails),
+ Priority = CacheItemPriority.High
+ };
+ _memoryCache.Set(cacheKey, response, cacheExpiryOptions);
+ }
+ }
+
+ _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetStateWisePrice:- " + ex.Message.ToString());
+ }
+ return response;
+ }
+
+ public async Task GetCustomerInfo(int buId, string bookingId)
+ {
+ return await Repository.GetCustomerInfo(buId, bookingId);
+ }
+
+ public async Task CallLSQBookingApi( MulesoftCustomerInfoDto customerInfo)
+ {
+ _logger.LogInformation($"BU:- {customerInfo.BuId} at MulesofApi:- CallBookingApi for Booking Id:- {customerInfo.BookingId}");
+ try
+ {
+ if (customerInfo != null)
+ {
+ string mx_Composite_Key = string.Empty, enquiryClassification = string.Empty,
+ leadPlatform = "Website", autoModel = string.Empty,
+ bookingStatus = string.Empty, isSuccessBooking = "True";
+ string utmSource = GetUTMDetails(customerInfo.ReferralUrl, "utm_source");
+ string utmMedium = GetUTMDetails(customerInfo.ReferralUrl, "utm_medium");
+ string sourceCampaign = GetUTMDetails(customerInfo.ReferralUrl, "utm_campaign");
+ string utmContent = GetUTMDetails(customerInfo.ReferralUrl, "utm_content");
+
+ if (!string.IsNullOrEmpty(customerInfo.DealerCode))
+ mx_Composite_Key = customerInfo.MobileNumber + customerInfo.DealerCode + "Open";
+ else
+ mx_Composite_Key = customerInfo.MobileNumber + "nullOpen";
+
+ string mx_Source_Of_Enquiry = "Organic"; string mx_Enquiry_Sub_source = "Website";
+ if (!string.IsNullOrEmpty(customerInfo.UtmCustomDetails1))
+ {
+ mx_Source_Of_Enquiry = customerInfo.UtmCustomDetails1;
+
+ }
+ if (!string.IsNullOrEmpty(customerInfo.UtmCustomDetails2))
+ {
+ mx_Enquiry_Sub_source = customerInfo.UtmCustomDetails2;
+
+ }
+ if (customerInfo.IsRegisterInterestRequest || string.IsNullOrWhiteSpace(customerInfo.DealerCode) || string.IsNullOrWhiteSpace(customerInfo.ModelCode))
+ {
+ enquiryClassification = "Cold";
+ autoModel = "No";
+ customerInfo.DealerCode = string.Empty;
+ }
+ else
+ {
+ enquiryClassification = "Hot";
+ autoModel = "Yes";
+ }
+ if (customerInfo.Status != "Successful")
+ {
+ customerInfo.Status = string.Empty;
+ customerInfo.BookingId = string.Empty;
+ customerInfo.CCTransactionId = string.Empty;
+ customerInfo.ReceiptId = string.Empty;
+ customerInfo.AmountPaid = string.Empty;
+ isSuccessBooking = "False";
+ }
+ string pincode = customerInfo.PinCode;
+ //default pincode value, incase pincode column is empty for the record
+ if (string.IsNullOrEmpty(pincode))
+ pincode = "400070";
+
+ string message = "{\"bu\": \"PB\", \"model_Code\": \"" + customerInfo.ModelCode + "\"," +
+ "\"color\": \"" + customerInfo.ColorCode + "\"," +
+ "\"customer_Name\": \"" + customerInfo.CustomerName + "\"" +
+ ", \"location_of_the_customer\": \"\", \"dealer_Code\": \"" + customerInfo.DealerCode + "\", " +
+ "\"mobile\": \"" + customerInfo.MobileNumber + "\"" +
+ ", \"otp_verified\": \"true\", \"pincode\": \"" + pincode + "\"," +
+ " \"enquiry_mode\": \"Digital\"" +
+ ", \"source\": \"" + mx_Source_Of_Enquiry + "\", \"sub_source\": \"" + mx_Enquiry_Sub_source + "\"," +
+ " \"referral_URL\": \"\"" +
+ ", \"composite_Key\": \"" + mx_Composite_Key + "\", \"enquiry_Classification\": \"" + enquiryClassification + "\"," +
+ " \"auto_model\": \"" + autoModel + "\"" +
+ ", \"bu_Sub_type\": \"\", \"sitcore_Booking_ID\": \"" + customerInfo.BookingId + "\", " +
+ "\"booking_Status\": \"" + customerInfo.Status + "\"" +
+ ", \"cc_Avenue_Transaction_ID\": \"" + customerInfo.CCTransactionId + "\"," +
+ " \"booking_receipt_Number\": \"" + customerInfo.ReceiptId + "\"," +
+ " \"booking_amount_TRM\": \"" + customerInfo.AmountPaid + "\"," +
+ " \"test_ride_date\": \"\", \"test_ride_slot\": \"\"" +
+ ", \"test_ride_location\": \"\"," +
+ "\"utmSource\": \"" + utmSource + "\", \"utmMedium\":\"" + utmMedium + "\"," +
+ " \"sourceCampaign\": \"" + sourceCampaign + "\", \"utmContent\":\"" + utmContent + "\"," +
+ " \"consentToWhatsapp\": \"" + customerInfo.IsWhatsappOptIn + "\",\"leadPlatform\": \"" + leadPlatform + "\" }";
+
+
+
+ string authToken = await MulesoftTokenApi.FetchToken();
+
+ if (!string.IsNullOrEmpty(authToken))
+ {
+ string password = GenerateRandomString.GenerateString(32);
+ string encstring = AESEncryption.ReturnEncKey(password, message);
+
+ var plainTextBytes = Encoding.UTF8.GetBytes(password);
+ string encKeyToHeader = Convert.ToBase64String(plainTextBytes);
+
+ // var url = "";
+ var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, encstring, bookingApiUrl, authToken, encKeyToHeader);
+
+ LeadData _leadData = DecryptBookingApi(response2);
+ await Repository.UpdateMulesoftResponse(customerInfo.BuId, customerInfo.RecordId, customerInfo.BookingId, message, isSuccessBooking, _leadData);
+ return new Response(customerInfo.BuId, 0, true, "true", "", "");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- CallBookingApi:- " + ex.StackTrace.ToString());
+ }
+ return new Response(customerInfo.BuId, 0, false, "false", "", "");
+ }
+
+ public async Task> GetDataForLsqPush(int buId)
+ {
+ return await Repository.GetDataForLsqPush(buId);
+ }
+
+ private LeadData DecryptBookingApi(HttpResponseMessage response)
+ {
+ LeadData _leadData = new LeadData();
+ JObject obj = JObject.Parse(response.Content.ReadAsStringAsync().Result);
+ try
+ {
+ if (response.StatusCode.ToString() == "OK")
+ {
+ if (obj["encData"] != null && !string.IsNullOrEmpty(Convert.ToString(obj["encData"])))
+ {
+ string pass = string.Empty;
+ string encResult2 = Convert.ToString(obj["encData"]);
+ // get enckey from response header
+ if (response.Headers.Contains("Enckey"))
+ {
+ var decodekey = response.Headers.GetValues("Enckey").First();
+ if (!string.IsNullOrEmpty(decodekey))
+ {
+ var base64EncodedBytes = Convert.FromBase64String(decodekey);
+ pass = Encoding.UTF8.GetString(base64EncodedBytes);
+ }
+ }
+
+ // Decrypt result by encKey
+ if (!string.IsNullOrEmpty(encResult2))
+ {
+ _leadData.ApiResponse = AESEncryption.DecryptString(encResult2, pass);
+
+ _logger.LogInformation("DecryptBookingApi decrpted message: " + _leadData.ApiResponse);
+
+ JObject obj1 = JObject.Parse(_leadData.ApiResponse);
+ string lead_status_code = (string)obj1["statusCode"];
+
+ if (lead_status_code == "200" && obj1["message"]?["IsSuccess"] != null)
+ {
+ _leadData.Lead_status = (string)obj1["message"]["IsSuccess"];
+ _leadData.LeadResponseStatus = lead_status_code;
+ if (_leadData.Lead_status.ToLower().Equals("true"))
+ {
+ _leadData.Lead_transferred = "y";
+ string[] ids = ((string)obj1["message"]["Value"]).Split(' ');
+ if (ids.Length == 1)
+ ids = ((string)obj1["message"]["Value"]).Split(',');
+ if (ids.Length > 0)
+ _leadData.Prospect_id = ids[0];
+ if (ids.Length > 1)
+ _leadData.Opportunity_id = ids[1];
+ }
+ else
+ {
+ _leadData.Lead_transferred = "n";
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ _leadData.Lead_transferred = "n";
+ _leadData.Lead_status = "Failure";
+ _leadData.ApiResponse = ((int)response.StatusCode) + JsonConvert.SerializeObject(obj, Formatting.None);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- DecryptBookingApi:- " + ex.StackTrace.ToString());
+ }
+ return _leadData;
+ }
+
+ private async Task ValidateMuleSoftResponse(int buId, HttpResponseMessage response2)
+ {
+ JObject obj = JObject.Parse(await response2.Content.ReadAsStringAsync());
+
+ try
+ {
+ if (response2.StatusCode.ToString() == "OK")
+ {
+ if (obj["encData"] != null && !string.IsNullOrWhiteSpace(Convert.ToString(obj["encData"])))
+ {
+ string pass = string.Empty;
+ string encResult2 = Convert.ToString(obj["encData"]);
+ // get enckey from response header
+ if (response2.Headers.Contains("encKey"))
+ {
+ var decodekey = response2.Headers.GetValues("encKey").First();
+ if (!string.IsNullOrEmpty(decodekey))
+ {
+ var base64EncodedBytes = Convert.FromBase64String(decodekey);
+ pass = Encoding.UTF8.GetString(base64EncodedBytes);
+ }
+ }
+ // Decrypt result by encKey
+ if (!string.IsNullOrWhiteSpace(encResult2))
+ {
+ string decrypted = AESEncryption.DecryptString(encResult2, pass);
+ JObject obj1 = JObject.Parse(decrypted);
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj1, Formatting.None), "Dealer Found", "");
+ }
+ }
+ }
+ else if (((int)response2.StatusCode) == 404)
+ {
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "No Dealer Found", "");
+ }
+ else if (((int)response2.StatusCode) == 401)
+ {
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), Convert.ToString(obj["error"]), "");
+ }
+ else
+ {
+ return new MulesoftResponse(buId, 0, false, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), "");
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- ValidateMuleSoftResponse:- " + ex.StackTrace.ToString());
+ }
+ return new MulesoftResponse(buId, 0, false, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), "");
+ }
+
+ private async Task DecryptDealerDetail(int buId, HttpResponseMessage response2)
+ {
+ JObject obj = JObject.Parse(await response2.Content.ReadAsStringAsync());
+
+ try
+ {
+ if (response2.StatusCode.ToString() == "OK")
+ {
+ if (obj["encData"] != null && !string.IsNullOrWhiteSpace(Convert.ToString(obj["encData"])))
+ {
+ string pass = string.Empty;
+ string encResult2 = Convert.ToString(obj["encData"]);
+ // get enckey from response header
+ if (response2.Headers.Contains("encKey"))
+ {
+ var decodekey = response2.Headers.GetValues("encKey").First();
+ if (!string.IsNullOrEmpty(decodekey))
+ {
+ var base64EncodedBytes = Convert.FromBase64String(decodekey);
+ pass = Encoding.UTF8.GetString(base64EncodedBytes);
+ }
+ }
+ // Decrypt result by encKey
+ if (!string.IsNullOrWhiteSpace(encResult2))
+ {
+ string decrypted = AESEncryption.DecryptString(encResult2, pass);
+ JObject obj1 = JObject.Parse(decrypted);
+ if (obj1 != null)
+ {
+ JToken jArrResultData = (JToken)obj1["Data"];
+ if (jArrResultData != null)
+ {
+ DealerDetailDto dto = new DealerDetailDto();
+ dto.BuId = buId;
+ dto.DealerCode = (JValue)jArrResultData["Code"] != null ? Convert.ToString(((JValue)jArrResultData["Code"]).Value) : "0";
+ dto.Address1 = (JValue)jArrResultData["AddressLine1"] != null ? Convert.ToString(((JValue)jArrResultData["AddressLine1"]).Value) : "0";
+ dto.Address2 = (JValue)jArrResultData["AddressLine2"] != null ? Convert.ToString(((JValue)jArrResultData["AddressLine2"]).Value) : "0";
+ dto.City = (JValue)jArrResultData["CityName"] != null ? Convert.ToString(((JValue)jArrResultData["CityName"]).Value) : "0";
+ dto.State = (JValue)jArrResultData["StateName"] != null ? Convert.ToString(((JValue)jArrResultData["StateName"]).Value) : "0";
+ dto.Zip = (JValue)jArrResultData["Zip"] != null ? Convert.ToString(((JValue)jArrResultData["Zip"]).Value) : "0";
+ dto.DisplayName = (JValue)jArrResultData["DisplayName"] != null ? Convert.ToString(((JValue)jArrResultData["DisplayName"]).Value) : "0";
+ dto.ContactCard = (JValue)jArrResultData["ContactCard"] != null ? Convert.ToString(((JValue)jArrResultData["ContactCard"]).Value) : "0";
+ dto.SalesPersonMail = (JValue)jArrResultData["SalesPersonEmail"] != null ? Convert.ToString(((JValue)jArrResultData["SalesPersonEmail"]).Value) : "0";
+ dto.SaleMobileNumber = (JValue)jArrResultData["SalesPersonContact"] != null ? Convert.ToString(((JValue)jArrResultData["SalesPersonContact"]).Value) : "0";
+ dto.EcomSalesAddress = (JValue)jArrResultData["EcomSalesAddress"] != null ? Convert.ToString(((JValue)jArrResultData["EcomSalesAddress"]).Value) : "0";
+ await Repository.InsertAndUpdateDealerRecord(dto);
+ return new MulesoftResponse(buId, 0, true, dto.Zip, "Dealer Detail Updated", "");
+ }
+ }
+ }
+ }
+ }
+ else if (((int)response2.StatusCode) == 404)
+ {
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "No Dealer Found", "");
+
+ }
+ else if (((int)response2.StatusCode) == 401)
+ {
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), Convert.ToString(obj["error"]), "");
+ }
+ else
+ {
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), "");
+ }
+
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- DecryptDealerDetail:- " + ex.Message.ToString());
+ }
+ return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), "");
+ }
+
+ private string GetUTMDetails(string referrerUrl, string utmName)
+ {
+ try
+ {
+ Uri referrerUri = new(referrerUrl);
+ var query = referrerUri.Query.Replace("?", "");
+ if (!string.IsNullOrWhiteSpace(query))
+ {
+ var dict = query.Split('&').Select(q => q.Split('=')).ToDictionary(k => k[0], v => v[1]);
+
+ if (dict.ContainsKey(utmName))
+ return dict[utmName];
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Api:- GetUTMDetails:- " + ex.Message.ToString());
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Api/MulesoftTokenApi.cs b/Source/DealerSelection.Api/MulesoftTokenApi.cs
new file mode 100644
index 0000000..2ca5a04
--- /dev/null
+++ b/Source/DealerSelection.Api/MulesoftTokenApi.cs
@@ -0,0 +1,68 @@
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Interface;
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Interfaces.HttpClient;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Logging;
+
+namespace DealerSelection.Api;
+
+public class MulesoftTokenApi : IMulesoftTokenApi
+{
+ private readonly ILogger _logger;
+ private readonly IMemoryCache cache;
+ IHttpClientHandler ClientHandler { get; }
+
+ public MulesoftTokenApi(IMemoryCache cache, IHttpClientHandler clientHandler
+ , ILogger logger)
+ {
+ this.cache = cache;
+ ClientHandler = clientHandler;
+ _logger = logger;
+ }
+
+ public async Task FetchToken()
+ {
+ string token = string.Empty;
+ try
+ {
+ // if cache doesn't contain
+ // an entry called TOKEN
+ // error handling mechanism is mandatory
+ if (!cache.TryGetValue("TOKEN", out token))
+ {
+ var tokenmodel = await GetTokenFromApi();
+ // keep the value within cache for
+ // given amount of time
+ // if value is not accessed within the expiry time
+ // delete the entry from the cache
+ if (tokenmodel.ExpiresIn > 0)
+ {
+ var options = new MemoryCacheEntryOptions()
+ .SetAbsoluteExpiration(
+ TimeSpan.FromSeconds(tokenmodel.ExpiresIn - 300));
+
+ cache.Set("TOKEN", tokenmodel.Value, options);
+
+ token = tokenmodel.Value;
+
+ _logger.LogInformation("MulesoftTokenApi at FetchToken - token Generated Successfully :- " + DateTime.Now);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("MulesoftTokenApi Api:- FetchToken:- " + ex.Message.ToString());
+ }
+ return token;
+ }
+
+ private async Task GetTokenFromApi()
+ {
+ // get api implementation happens here
+ // returns a token model
+ _logger.LogInformation("MulesoftTokenApi at GetTokenFromApi Started :- " + DateTime.Now);
+ MulesoftToken token = await MuleSoftIntegration.generateToken(ClientHandler);
+ return token;
+ }
+}
diff --git a/Source/DealerSelection.Api/YellowAIApi.cs b/Source/DealerSelection.Api/YellowAIApi.cs
new file mode 100644
index 0000000..c47c0c7
--- /dev/null
+++ b/Source/DealerSelection.Api/YellowAIApi.cs
@@ -0,0 +1,77 @@
+using DealerSelection.Api.Infrastructure.CustomerDetail;
+using DealerSelection.Api.Interface;
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Exceptions;
+using Microsoft.Extensions.Logging;
+using System.Text.RegularExpressions;
+
+namespace DealerSelection.Api;
+public class YellowAIApi : IYellowAIApi
+{
+
+ private readonly ILogger _logger;
+ private IRepository CustomerDetailRepository { get; }
+
+ public YellowAIApi(IRepository customerRepo, ILogger logger)
+ {
+ CustomerDetailRepository = customerRepo;
+ _logger = logger;
+ }
+
+
+ public async Task UpdateSelectedDealer(CustomerDealerInfoRequest request)
+ {
+ if (IsValidData(request.MobileNumber, request.DealerCode, request.DealerName))
+ {
+ var isDuplicate = await IsDuplicateMobileNumber(request.MobileNumber);
+ if (!isDuplicate)
+ {
+
+ //Push to LSQ then make it complete
+
+
+
+ //
+ CustomerDealerInfoRequestDto dto = new CustomerDealerInfoRequestDto
+ {
+ BuId = request.BuId,
+ RecordId = request.RecordId,
+ MobileNumber = request.MobileNumber,
+ ModelCode = request.ModelCode,
+ ModelName = request.ModelName,
+ ModelVariant = request.ModelVariant,
+ DealerName = request.DealerName,
+ DealerCode = request.DealerCode,
+ PinCode = request.PinCode,
+ Latitude = request.Latitude,
+ Longitude = request.Longitude,
+ DealerSelectionJobStatus = DealerSelectionJobStatus.Complete //Marking JobStatus Complete once we receive response from Yellow API
+ };
+ await CustomerDetailRepository.UpdateDealerDetail(dto);
+ }
+ else
+ _logger.LogWarning($"Duplicate MobileNumber exist. Data Details: {request.RequestDetail()}.");
+ }
+ else
+ {
+ _logger.LogWarning($"Invalid data. Data Details: {request.RequestDetail()}.");
+ throw new ValidationException("Invalid data.");
+ }
+ }
+
+ private static bool IsValidData(int mobileNumber, string dealerCode, string dealerName)
+ {
+ bool valid = Regex.IsMatch(mobileNumber.ToString(), @"^[0-9]{10}$");
+
+ if (valid && string.IsNullOrWhiteSpace(dealerCode) && string.IsNullOrWhiteSpace(dealerName))
+ valid = false;
+
+ return valid;
+ }
+
+ private async Task IsDuplicateMobileNumber(int mobileNumber)
+ {
+ return await CustomerDetailRepository.IsDuplicateMobileNumber(mobileNumber);
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs b/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs
new file mode 100644
index 0000000..9a17ef5
--- /dev/null
+++ b/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs
@@ -0,0 +1,9 @@
+namespace DealerSelection.Common.CommonBaseClass;
+
+public class ExceptionBase : Exception
+{
+ protected ExceptionBase(string message) : base(message)
+ { }
+ protected ExceptionBase(string message, Exception innerException) : base(message, innerException)
+ { }
+}
diff --git a/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs b/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs
new file mode 100644
index 0000000..1dc4400
--- /dev/null
+++ b/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs
@@ -0,0 +1,92 @@
+using DealerSelection.Common.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Net;
+
+namespace DealerSelection.Common.CommonBaseClass;
+
+public class ExceptionFilterBase : ExceptionFilterAttribute, IExceptionFilter
+{
+ protected IDictionary Mappings { get; }
+ public ExceptionFilterBase()
+ {
+ Mappings = new Dictionary
+ {
+ {typeof(System.Security.Authentication.AuthenticationException), HttpStatusCode.Unauthorized },
+ {typeof(System.Security.Authentication.InvalidCredentialException), HttpStatusCode.Unauthorized },
+ {typeof(AuthorizationException), HttpStatusCode.Forbidden },
+ {typeof(DataNotFoundException), HttpStatusCode.Forbidden },
+ {typeof(DuplicateException), HttpStatusCode.Conflict },
+
+ {typeof(InvalidDataException), HttpStatusCode.BadRequest },
+ {typeof(ValidationException), HttpStatusCode.BadRequest },
+ {typeof(NullValueException), HttpStatusCode.BadRequest },
+ {typeof(PartialSuccessException), HttpStatusCode.MultiStatus }
+
+ };
+ }
+
+ public override void OnException(ExceptionContext context)
+ {
+ Exception exception = context.Exception;
+ if (exception.StackTrace != null)
+ {
+ string exceptionStack = exception.StackTrace.StandardizeText(true);
+ context.HttpContext.Request.Headers.Add("BajaBooking-Custom-ExceptionStack", exceptionStack);
+ }
+
+ HttpStatusCode httpStatusCode = Mappings.ContainsKey(exception.GetType())
+ ? Mappings[exception.GetType()] : HttpStatusCode.InternalServerError;
+
+ foreach (KeyValuePair item in Mappings)
+ {
+ if (exception.GetType().IsSubclassOf(item.Key) || exception.GetType() == item.Key)
+ {
+ httpStatusCode = item.Value;
+ break;
+ }
+ }
+
+ try
+ {
+ if (context.Exception.InnerException != null)
+ context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", context.Exception.InnerException.ToString().StandardizeText(true));
+ }
+ catch (Exception ex)
+ {
+ try
+ {
+ context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", "Cannot add detailed error to header because: " + ex.Message);
+ }
+ catch
+ {
+ context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", "Cannot add detailed error to header for unknown reason: " + ex.Message);
+ }
+ }
+
+ //if (ConfigurationHelper.GetSetting("IncludeErrorInResponse", false) || httpStatusCode != HttpStatusCode.InternalServerError)
+ //{
+ // AssignError(context, httpStatusCode, false, exception.Message);
+ //}
+ //else
+ //{
+ // context.HttpContext.Request.Headers.Add("BajaBooking-Custom-RealException", exception.Message.StandardizeText(false));
+ //}
+ }
+ private static void AssignError(ExceptionContext context, HttpStatusCode httpStatusCode, bool withNewLine, string? message = null, string? reason = null)
+ {
+ reason ??= message;
+ string reasonPhrase = reason!.StandardizeText(withNewLine);
+ context.Result = new ContentResult { Content = reasonPhrase, StatusCode = (int)httpStatusCode, ContentType = "text/plain" };
+ }
+
+}
+public static class StringOps
+{
+ public static string StandardizeText(this string inp, bool withNewLine)
+ {
+ if(withNewLine)
+ return inp.Replace("\r", "\r ").Replace("\n", "\n ");
+ return inp.Replace("\r", " ").Replace("\n", " ");
+ }
+}
diff --git a/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs b/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs
new file mode 100644
index 0000000..e94a58b
--- /dev/null
+++ b/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs
@@ -0,0 +1,235 @@
+using DealerSelection.Common.Helpers;
+using DealerSelection.Common.Middleware;
+using Lamar;
+using Lamar.Microsoft.DependencyInjection;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Json;
+using Microsoft.AspNetCore.HttpOverrides;
+using Microsoft.AspNetCore.Mvc.Formatters;
+using Microsoft.AspNetCore.ResponseCompression;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.ApplicationInsights;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
+using System.IO.Compression;
+using System.Reflection;
+using System.Text;
+using System.Text.Json.Serialization;
+
+namespace DealerSelection.Common.CommonBaseClass;
+
+public abstract class StartupBase
+{
+ public WebApplication CreateHostBuilder(string[] args)
+ {
+ try
+ {
+ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
+
+ builder.Host.UseLamar((context, registry) =>
+ {
+ registry.IncludeRegistry(CreateDIRegistry());
+ registry.AddControllers();
+ });
+
+ SetupService(builder.Services);
+ SetupSwaggerOptions(builder);
+
+ #region AzureLogging
+
+ AzureLogging(builder);
+
+ #endregion
+
+ #region JWT Authentication
+ JWTAuthentication(builder);
+ #endregion
+
+ WebApplication app = builder.Build();
+ app.UseResponseCompression();
+
+ app.UseRouting();
+
+ if (Configuration.ConfigurationHelper.GetSetting("BrowseSwagger", true) == "True")
+ SetupSwagger(app);
+
+ app.UseCors(x => x
+ //.WithOrigins("https://www.ktmindia.com", "https://www.triumphmotorcyclesindia.com") //Used for PROD
+ .AllowAnyOrigin() //Only used for Development
+ .AllowAnyMethod()
+ .AllowAnyHeader());
+
+ //app.UseMiddleware();
+ app.UseMiddleware();
+ //app.UseMiddleware();
+ // app.UseMiddleware();
+
+ app.UseForwardedHeaders(new ForwardedHeadersOptions
+ {
+ ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
+ });
+
+ app.UseAuthentication();
+ app.UseAuthorization();
+ app.UseStaticFiles();
+ // app.MapControllers();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ endpoints.MapHealthChecks("/health");
+ });
+ return app;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ throw;
+ }
+ }
+
+ private void SetupService(IServiceCollection services)
+ {
+ //Caching
+ services.AddMemoryCache();
+
+ services.AddSingleton();
+ services.AddMvc(options => options.Filters.Add(new ExceptionFilterBase()));
+ services.AddMvc(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter()));
+
+ services.AddResponseCompression(options =>
+ {
+ options.Providers.Add();
+ options.EnableForHttps = true;
+ });
+
+ services.Configure(options =>
+ {
+ options.Level = CompressionLevel.Optimal;
+ });
+
+ services.AddResponseCompression(options =>
+ {
+ options.Providers.Add();
+ options.EnableForHttps = true;
+ });
+
+ services.AddEndpointsApiExplorer();
+ services.AddControllers().AddXmlDataContractSerializerFormatters();
+ services.AddHealthChecks();
+ services.Configure(options =>
+ {
+ options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ });
+ services.Configure(options =>
+ {
+ options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ });
+ }
+
+ private void AzureLogging(WebApplicationBuilder builder)
+ {
+ builder.Logging.AddApplicationInsights(
+ configureTelemetryConfiguration: (config) => config.ConnectionString =
+ builder.Configuration.GetConnectionString("AZURE_LOGGING"),
+ configureApplicationInsightsLoggerOptions: (options) => { }
+ );
+ builder.Logging.AddFilter("traces", LogLevel.Trace);
+ }
+
+
+ private void JWTAuthentication(WebApplicationBuilder builder)
+ {
+ List audiences = new List();
+ string[] getAudiences = builder.Configuration["Jwt:Audience"].Split(',');
+ foreach (var audience in getAudiences)
+ {
+ audiences.Add(audience);
+ }
+ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
+ {
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidateAudience = true,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ ValidIssuer = builder.Configuration["Jwt:Issuer"],
+ ValidAudiences = new List(audiences),
+ IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
+ };
+ });
+ }
+
+ private void SetupSwaggerOptions(WebApplicationBuilder builder)
+ {
+ builder.Services.AddSwaggerGen(options =>
+ {
+
+ SwashbuckleSchemaHelper schemaHelper = new SwashbuckleSchemaHelper();
+ //handle checking for duplicate return types and makes the name unique
+ options.CustomSchemaIds(type => schemaHelper.GetSchemaId(type));
+ // options.DocumentFilter();
+ // options.OperationFilter();
+
+ #region Swagger Customization For Authentication
+
+ options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
+ {
+ Name = "Authorization",
+ Type = SecuritySchemeType.Http,
+ Scheme = "Bearer",
+ //Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme },
+ BearerFormat = "JWT",
+ In = ParameterLocation.Header,
+ Description = "Please Enter a Valid JWT Token",
+ });
+ options.AddSecurityRequirement(new OpenApiSecurityRequirement
+ {
+ {
+ new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
+ {
+ Type=ReferenceType.SecurityScheme,
+ Id="Bearer"
+ }
+ },
+ new string[]{}
+ }
+ });
+ #endregion
+
+ options.SwaggerDoc("v1", new OpenApiInfo
+ {
+ Version = "v1",
+ Title = "Dealer Selection API",
+ Description = "Web API for Dealer Selection Management"
+ });
+ options.EnableAnnotations();
+
+ string xmlFileName = $"{Assembly.GetEntryAssembly()!.GetName().Name}.xml";
+ options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFileName));
+
+ });
+ }
+
+ private static void SetupSwagger(WebApplication app)
+ {
+ app.UseSwagger(c =>
+ {
+ c.RouteTemplate = "help/ui/{documentName}/swagger.json";
+ });
+ app.UseSwaggerUI(c =>
+ {
+ c.SwaggerEndpoint("/help/ui/v1/swagger.json", "Sample API");
+ c.RoutePrefix = "help/ui";
+ c.InjectStylesheet("/CustomContent/SwaggerHeader.css");
+ });
+ }
+ protected abstract ServiceRegistry CreateDIRegistry();
+}
diff --git a/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs b/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs
new file mode 100644
index 0000000..551cb67
--- /dev/null
+++ b/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs
@@ -0,0 +1,6 @@
+namespace DealerSelection.Common.CommonBaseClass;
+
+public abstract class WebApiConfigurationCfgBase
+{
+
+}
diff --git a/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs b/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs
new file mode 100644
index 0000000..1ea1951
--- /dev/null
+++ b/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs
@@ -0,0 +1,102 @@
+using Microsoft.Extensions.Configuration;
+using System.Configuration;
+using System.Reflection;
+
+namespace DealerSelection.Common.Configuration;
+
+public static class ConfigurationHelper
+{
+ public static int SetEnvironmentVariables(string settingsFile)
+ {
+ IConfigurationRoot? config = LoadSettingsFile(settingsFile);
+ int count = 0;
+
+ if (config != null)
+ {
+ foreach (KeyValuePair pair in config.AsEnumerable())
+ {
+ if (pair.Value == null)
+ continue;
+
+ Environment.SetEnvironmentVariable(pair.Key, pair.Value);
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ public static IConfigurationRoot? LoadSettingsFile(string settingsFile)
+ {
+ string basePath = FindBaseLocation(settingsFile);
+ IConfigurationBuilder builder = new ConfigurationBuilder()
+ .SetBasePath(basePath)
+ .AddJsonFile(settingsFile);
+
+ return builder.Build();
+ }
+
+ public static string GetConnectionString(string cxnName, string cfgFile = "connectionString.json")
+ {
+ IConfigurationRoot? root = LoadSettingsFile(cfgFile);
+ string settings = root.GetConnectionString(cxnName);
+ if (!string.IsNullOrEmpty(settings))
+ {
+ return settings;
+ }
+ throw new ConfigurationErrorsException($"Connection stirng {cxnName} not found in connection strings cfg file {cfgFile}.");
+ }
+ private static string FindBaseLocation(string settingsFile)
+ {
+ string?[] baseLocations =
+ {
+ Directory.GetCurrentDirectory(),
+ AppDomain.CurrentDomain.BaseDirectory,
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ };
+
+ foreach (string? baseLocation in baseLocations)
+ {
+ if (string.IsNullOrEmpty(baseLocation))
+ continue;
+ string path = Path.Combine(baseLocation, settingsFile);
+ if (File.Exists(path))
+ return baseLocation;
+ }
+
+ return baseLocations[1]!;
+ }
+
+ public static T? GetSetting(string key, bool mustExist)
+ {
+ return GetSetting(key, default(T), mustExist);
+ }
+
+ public static T? GetSetting(string key, T? defaultValue = default)
+ {
+ return GetSetting(key, defaultValue, false);
+ }
+
+ public static T GetSetting(string key, T defaultValue, bool mustExist)
+ {
+ string? valString = Environment.GetEnvironmentVariable(key);
+
+ if (valString == null)
+ {
+ if (mustExist)
+ {
+ throw new ConfigurationErrorsException($"Setting {key} not found");
+ }
+ return defaultValue;
+ }
+
+ try
+ {
+ return (T)Convert.ChangeType(valString, typeof(T));
+ }
+ catch (Exception ex)
+ {
+ throw new ConfigurationErrorsException($"Settings {key} ('{valString}') cannot be converted to type {typeof(T).Name}", ex);
+ }
+ }
+}
diff --git a/Source/DealerSelection.Common/Data/ConnectionHelper.cs b/Source/DealerSelection.Common/Data/ConnectionHelper.cs
new file mode 100644
index 0000000..ab3c5af
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/ConnectionHelper.cs
@@ -0,0 +1,36 @@
+
+using System.Data.SqlClient;
+using DealerSelection.Common.Configuration;
+
+namespace DealerSelection.Common.Data;
+
+public static class ConnectionHelper
+{
+ public static SqlConnection GetConnectionSync(string cxnName)
+ {
+ SqlConnection cxn = GetConnection(cxnName);
+ cxn.Open();
+ return cxn;
+ }
+
+ public static SqlConnection GetConnectionAsync(string cxnName)
+ {
+ SqlConnection cxn = GetConnection(cxnName);
+ cxn.OpenAsync();
+ return cxn;
+ }
+
+ private static SqlConnection GetConnection(string cxnName)
+ {
+ string cxnString = GetConnectionString(cxnName);
+
+ SqlConnection cxn = new SqlConnection(cxnString);
+ return cxn;
+ }
+
+ public static string GetConnectionString(string cxnName)
+ {
+ string cxnString = ConfigurationHelper.GetConnectionString(cxnName);
+ return cxnString;
+ }
+}
diff --git a/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs
new file mode 100644
index 0000000..2f00975
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs
@@ -0,0 +1,25 @@
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Data.Dapper;
+
+public class RepositoryBaseDapperAsync : RepositoryBaseDIAsync
+{
+ public RepositoryBaseDapperAsync(string cxnName) : base(cxnName)
+ {
+
+ }
+
+ protected async Task OpenCxnWithMappingAsync()
+ {
+ Task cxnTask = OpenCxnAsync();
+ SetTypeMap();
+
+ return await cxnTask;
+ }
+
+ protected void SetTypeMap()
+ {
+ TypeMapHelper.SetTypeMap();
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs
new file mode 100644
index 0000000..b3fbb1e
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs
@@ -0,0 +1,25 @@
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Data.Dapper;
+
+public class RepositoryBaseDapperSync : RepositoryBaseDISync
+{
+ public RepositoryBaseDapperSync(string cxnName) : base(cxnName)
+ {
+
+ }
+
+ protected SqlConnection OpenCxnWithMappingSync()
+ {
+ SqlConnection cxn = OpenCxnSync();
+ SetTypeMap();
+
+ return cxn;
+ }
+
+ protected void SetTypeMap()
+ {
+ TypeMapHelper.SetTypeMap();
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs b/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs
new file mode 100644
index 0000000..ce5f7ea
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs
@@ -0,0 +1,30 @@
+using DealerSelection.Common.Entity;
+using Dapper;
+using System.Reflection;
+
+namespace DealerSelection.Common.Data.Dapper;
+
+public static class TypeMapHelper
+{
+ public static void SetTypeMap()
+ {
+ CustomPropertyTypeMap map = new CustomPropertyTypeMap(
+ typeof(T),
+ PropertySelector);
+ SqlMapper.SetTypeMap(typeof(T), map);
+ }
+ private static PropertyInfo PropertySelector(Type type, string columnName)
+ {
+ PropertyInfo[] properties = type.GetProperties();
+ return properties.FirstOrDefault(
+ prop => prop.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)
+ || columnName.Equals(GetColumnFromAttribute(prop), StringComparison.OrdinalIgnoreCase));
+ }
+ public static string GetColumnFromAttribute(MemberInfo member)
+ {
+ if (member == null) return null;
+ FieldMapAttribute attrib = (FieldMapAttribute)Attribute.GetCustomAttribute(
+ member, typeof(FieldMapAttribute), true);
+ return attrib?.DbFieldName;
+ }
+}
diff --git a/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs b/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs
new file mode 100644
index 0000000..aaaef1a
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs
@@ -0,0 +1,35 @@
+using DealerSelection.Common.Exceptions;
+using DealerSelection.Common.Interfaces.Data;
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Data;
+
+public abstract class RepositoryBaseDIAsync : RepositoryDIBase, IRepositoryDIAsync
+{
+ public RepositoryBaseDIAsync(string cxnName) : base(cxnName)
+ {
+
+ }
+
+ public async Task OpenCxnAsync()
+ {
+ SqlConnection cxn = new SqlConnection(CxnString);
+ try
+ {
+ await cxn.OpenAsync();
+ }
+ catch (SqlException ex)
+ {
+ foreach(SqlError error in ex.Errors)
+ {
+ if(error.Number == 53)
+ {
+ throw new DbConnectionException($"DB Connection error for CxnString: {CxnString}. Exception: {ex}");
+ }
+ }
+ throw;
+ }
+
+ return cxn;
+ }
+}
diff --git a/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs b/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs
new file mode 100644
index 0000000..31c3022
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs
@@ -0,0 +1,35 @@
+using DealerSelection.Common.Exceptions;
+using DealerSelection.Common.Interfaces.Data;
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Data;
+
+public abstract class RepositoryBaseDISync : RepositoryDIBase, IRepositoryDISync
+{
+ public RepositoryBaseDISync(string cxnName) : base(cxnName)
+ {
+
+ }
+
+ public SqlConnection OpenCxnSync()
+ {
+ SqlConnection cxn = new SqlConnection(CxnString);
+ try
+ {
+ cxn.Open();
+ }
+ catch (SqlException ex)
+ {
+ foreach(SqlError error in ex.Errors)
+ {
+ if(error.Number == 53)
+ {
+ throw new DbConnectionException($"DB Connection error for CxnString: {CxnString}. Exception: {ex}");
+ }
+ }
+ throw;
+ }
+
+ return cxn;
+ }
+}
diff --git a/Source/DealerSelection.Common/Data/RepositoryDIBase.cs b/Source/DealerSelection.Common/Data/RepositoryDIBase.cs
new file mode 100644
index 0000000..4cfc709
--- /dev/null
+++ b/Source/DealerSelection.Common/Data/RepositoryDIBase.cs
@@ -0,0 +1,11 @@
+
+namespace DealerSelection.Common.Data;
+
+public abstract class RepositoryDIBase
+{
+ public string CxnString { get; }
+ protected RepositoryDIBase(string cxnName)
+ {
+ CxnString = ConnectionHelper.GetConnectionString(cxnName);
+ }
+}
diff --git a/Source/DealerSelection.Common/DealerSelection.Common.csproj b/Source/DealerSelection.Common/DealerSelection.Common.csproj
new file mode 100644
index 0000000..507e881
--- /dev/null
+++ b/Source/DealerSelection.Common/DealerSelection.Common.csproj
@@ -0,0 +1,56 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+ 1701;1702;8603;1822;8602;8604
+
+
+
+ 1701;1702;8603;1822;8602;8604
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+ Never
+
+
+
+
diff --git a/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs b/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs
new file mode 100644
index 0000000..ee0e645
--- /dev/null
+++ b/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs
@@ -0,0 +1,24 @@
+namespace DealerSelection.Common.Entity;
+
+///
+/// An Attribute that provides a mapping between a property on an object and a fields in a database table.
+///
+[AttributeUsage(AttributeTargets.Property)]
+public sealed class FieldMapAttribute : Attribute
+{
+ readonly string _dbFieldName;
+
+ ///
+ /// Initialize a new FieldMapAttribute
+ ///
+ /// Name of database field that this property represents
+ public FieldMapAttribute(string dbFieldName)
+ {
+ _dbFieldName = dbFieldName;
+ }
+
+ ///
+ /// Name of field that the perperty this attribute is attached to is mapped to.
+ ///
+ public string DbFieldName => _dbFieldName;
+}
diff --git a/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs b/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs
new file mode 100644
index 0000000..df80a1f
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class AuthorizationException : ExceptionBase
+{
+ public AuthorizationException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs b/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs
new file mode 100644
index 0000000..07df4ab
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class DataNotFoundException : ExceptionBase
+{
+ public DataNotFoundException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs b/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs
new file mode 100644
index 0000000..6ee8d8c
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs
@@ -0,0 +1,15 @@
+
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class DbConnectionException : ExceptionBase
+{
+ public DbConnectionException(string message) : base(message)
+ {
+ }
+
+ public DbConnectionException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/DuplicateException.cs b/Source/DealerSelection.Common/Exceptions/DuplicateException.cs
new file mode 100644
index 0000000..c7a988c
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/DuplicateException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class DuplicateException : ExceptionBase
+{
+ public DuplicateException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/NullValueException.cs b/Source/DealerSelection.Common/Exceptions/NullValueException.cs
new file mode 100644
index 0000000..c6576d5
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/NullValueException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class NullValueException : ExceptionBase
+{
+ public NullValueException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs b/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs
new file mode 100644
index 0000000..40bc6fd
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class PartialSuccessException : ExceptionBase
+{
+ public PartialSuccessException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Exceptions/ValidationException.cs b/Source/DealerSelection.Common/Exceptions/ValidationException.cs
new file mode 100644
index 0000000..b996784
--- /dev/null
+++ b/Source/DealerSelection.Common/Exceptions/ValidationException.cs
@@ -0,0 +1,8 @@
+using DealerSelection.Common.CommonBaseClass;
+
+namespace DealerSelection.Common.Exceptions;
+
+public class ValidationException : ExceptionBase
+{
+ public ValidationException(string message) : base(message) { }
+}
diff --git a/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs b/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs
new file mode 100644
index 0000000..69ff2b6
--- /dev/null
+++ b/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs
@@ -0,0 +1,8 @@
+namespace DealerSelection.Common.Helpers;
+
+public class SwaggerCfg
+{
+ public string? Name { get; set; }
+ public string? Title { get; set; }
+ public string? Description { get; set; }
+}
diff --git a/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs b/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs
new file mode 100644
index 0000000..651ba58
--- /dev/null
+++ b/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs
@@ -0,0 +1,38 @@
+namespace DealerSelection.Common.Helpers;
+
+public class SwashbuckleSchemaHelper
+{
+ private readonly Dictionary _schemaNameRepetition = new ();
+
+ ///
+ /// Eliminate the case where more than one method returns the same type in different controllers
+ /// swagger documentation to fail
+ ///
+ ///
+ ///
+ public string GetSchemaId(Type modelType)
+ {
+ string id = DefaultSchemaIdSelector (modelType);
+
+ if(!_schemaNameRepetition.ContainsKey(id))
+ _schemaNameRepetition.Add(id, 0);
+
+ int count = _schemaNameRepetition[id] + 1;
+ _schemaNameRepetition[id] = count;
+
+ return $"{id}{(count > 1 ? count.ToString() : "")}";
+ }
+
+ private string DefaultSchemaIdSelector(Type modelType)
+ {
+ if (!modelType.IsConstructedGenericType)
+ return modelType.Name.Replace("[]", "Array");
+
+ string prefix = modelType.GetGenericArguments()
+ .Select(genericArg => DefaultSchemaIdSelector(genericArg))
+ .Aggregate((previous, current) => previous + current);
+
+ return prefix + modelType.Name.Split('`').First();
+ }
+
+}
diff --git a/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs b/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs
new file mode 100644
index 0000000..191d681
--- /dev/null
+++ b/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs
@@ -0,0 +1,21 @@
+using DealerSelection.Common.Interfaces.HttpClient;
+
+namespace DealerSelection.Common.HttpClient;
+
+public class MyHttpClientHandler : IHttpClientHandler
+{
+ public System.Net.Http.HttpClient GetHttpClient()
+ {
+ var handler = new SocketsHttpHandler
+ {
+ PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes
+ };
+
+ System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(handler);
+
+ client.DefaultRequestHeaders.Accept.Clear();
+ client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
+
+ return client;
+ }
+}
diff --git a/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs
new file mode 100644
index 0000000..0ba6315
--- /dev/null
+++ b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs
@@ -0,0 +1,9 @@
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Interfaces.Data;
+
+public interface IRepositoryDIAsync
+{
+ string CxnString { get; }
+ Task OpenCxnAsync();
+}
diff --git a/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs
new file mode 100644
index 0000000..f6f5d0b
--- /dev/null
+++ b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs
@@ -0,0 +1,9 @@
+using System.Data.SqlClient;
+
+namespace DealerSelection.Common.Interfaces.Data;
+
+public interface IRepositoryDISync
+{
+ string CxnString { get; }
+ SqlConnection OpenCxnSync();
+}
diff --git a/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs b/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs
new file mode 100644
index 0000000..878d9be
--- /dev/null
+++ b/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs
@@ -0,0 +1,8 @@
+
+
+namespace DealerSelection.Common.Interfaces.HttpClient;
+
+public interface IHttpClientHandler
+{
+ System.Net.Http.HttpClient GetHttpClient();
+}
diff --git a/Source/DealerSelection.Common/Logging/ApiInfo.cs b/Source/DealerSelection.Common/Logging/ApiInfo.cs
new file mode 100644
index 0000000..95ca810
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/ApiInfo.cs
@@ -0,0 +1,24 @@
+namespace DealerSelection.Common.Logging;
+
+public class ApiInfo
+{
+ public RequestInfo RequestInfo { get; set; }
+ //public CustomInfo CustomInfo { get; set; }
+ public ResponseInfo ResponseInfo { get; set; }
+ public ApiInfo(string httpMethod, string uriAccessed, string hostName, DateTime startDate)
+ {
+ RequestInfo = new RequestInfo(hostName, httpMethod, uriAccessed, startDate);
+ }
+
+ public override string ToString()
+ {
+ return $"WebAPI {nameof(RequestInfo)}: {RequestInfo}, " +
+ //$"{nameof(CustomInfo)}: {CustomInfo}, " +
+ $"{nameof(ResponseInfo)}: {ResponseInfo}";
+ }
+
+ public bool IsValid()
+ {
+ return RequestInfo.BuId.GetValueOrDefault() > 0;
+ }
+}
diff --git a/Source/DealerSelection.Common/Logging/AzureLogHelper.cs b/Source/DealerSelection.Common/Logging/AzureLogHelper.cs
new file mode 100644
index 0000000..cbaa555
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/AzureLogHelper.cs
@@ -0,0 +1,82 @@
+using DealerSelection.Common.Configuration;
+using Newtonsoft.Json;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace DealerSelection.Common.Logging;
+
+public static class AzureLogHelper
+{
+ private static string aZureWorkspaceId = ConfigurationHelper.GetSetting("aZureWorkspaceId", true);
+ private static string aZureSharedKey = ConfigurationHelper.GetSetting("aZureSharedKey", true);
+ private static string aZureLogType = ConfigurationHelper.GetSetting("aZureLogType", true);
+ private static string aZureApiVersion = ConfigurationHelper.GetSetting("aZureApiVersion", true);
+
+ public static void LogMessage(string message)
+ {
+ try
+ {
+ string azureLog = GetAzureLogFormatLog(message);
+ string requestUriString = $"https://{aZureWorkspaceId}.ods.opinsights.azure.com/api/logs?api-version={aZureApiVersion}";
+ DateTime dateTime = DateTime.UtcNow;
+ string dateString = dateTime.ToString("r");
+ string signature = GetSignature("POST", azureLog.Length, "application/json", dateString, "/api/logs");
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUriString);
+ request.ContentType = "application/json";
+ request.Method = "POST";
+ request.Headers["Log-Type"] = aZureLogType;
+ request.Headers["x-ms-date"] = dateString;
+ request.Headers["Authorization"] = signature;
+ byte[] content = Encoding.UTF8.GetBytes(azureLog);
+ using (Stream requestStreamAsync = request.GetRequestStream())
+ {
+ requestStreamAsync.Write(content, 0, content.Length);
+ }
+ using (HttpWebResponse responseAsync = (HttpWebResponse)request.GetResponse())
+ {
+ if (responseAsync.StatusCode != HttpStatusCode.OK && responseAsync.StatusCode != HttpStatusCode.Accepted)
+ {
+ Stream responseStream = responseAsync.GetResponseStream();
+ if (responseStream != null)
+ {
+ using (StreamReader streamReader = new StreamReader(responseStream))
+ {
+ // throw new Exception(streamReader.ReadToEnd());
+ }
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // throw new UnexpectedDataException($" Bajaj Booking LogMessage: ", ex);
+ }
+ }
+
+ private static string GetAzureLogFormatLog(string inputMessage)
+ {
+ string message = string.Empty;
+ if (!string.IsNullOrWhiteSpace(inputMessage))
+ {
+ message = JsonConvert.SerializeObject(
+ new
+ {
+ id = Guid.NewGuid().ToString(),
+ datetime = DateTime.Now,
+ message = inputMessage
+ }).ToString();
+ }
+ return message;
+ }
+
+ private static string GetSignature(string method, int contentLength, string contentType, string date, string resource)
+ {
+ string message = $"{method}\n{contentLength}\n{contentType}\nx-ms-date:{date}\n{resource}";
+ byte[] bytes = Encoding.UTF8.GetBytes(message);
+ using (HMACSHA256 encryptor = new HMACSHA256(Convert.FromBase64String(aZureSharedKey)))
+ {
+ return $"SharedKey {aZureWorkspaceId}:{Convert.ToBase64String(encryptor.ComputeHash(bytes))}";
+ }
+ }
+}
diff --git a/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs b/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs
new file mode 100644
index 0000000..a8fe9bc
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs
@@ -0,0 +1,28 @@
+
+using Microsoft.Extensions.Primitives;
+
+namespace DealerSelection.Common.Logging;
+
+public class HttpHeaderHelper
+{
+ public static int? ExtractInt(string key, List> headers)
+ {
+ int? res = null;
+ string? resString = Extract(key, headers);
+ if (resString == null)
+ {
+ if(int.TryParse(resString, out int resTemp))
+ res = resTemp;
+ }
+ return res;
+ }
+
+ public static string? Extract(string key, List> headers)
+ {
+ string? res = null;
+ KeyValuePair header = headers.FirstOrDefault(h=> h.Key == key);
+ if (header.Value.Any())
+ res = header.Value.FirstOrDefault();
+ return res;
+ }
+}
diff --git a/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs b/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs
new file mode 100644
index 0000000..5035cbb
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs
@@ -0,0 +1,127 @@
+
+using iTextSharp.text.log;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.IO;
+
+namespace DealerSelection.Common.Logging;
+
+public class LoggingMiddleware
+{
+ public const string Key = "LoggingMiddlewareCfg";
+ private const int ReadChunkBufferLength = 4096;
+ private const int MaxContentLength = 10 * 1024 * 1024; //10MB
+ private RecyclableMemoryStreamManager MemoryStreamManager { get; set; } = null;
+ private readonly RequestDelegate RequestDelegate;
+ enum ErrorTypes
+ {
+ Validation,
+ Error
+ };
+
+ public LoggingMiddleware(RequestDelegate requestDelegate)
+ {
+ RequestDelegate = requestDelegate;
+
+ MemoryStreamManager = new RecyclableMemoryStreamManager();
+ }
+
+ public async Task Invoke(HttpContext context, ILogger logger)
+ {
+ try
+ {
+ ApiInfo loggingInfo = await ExtractInfoFromRequest(context.Request);
+
+ Stream originalBodyStream = context.Request.Body;
+ using MemoryStream responseBody = MemoryStreamManager.GetStream();
+ context.Response.Body = responseBody;
+
+ await RequestDelegate(context);
+
+ ExtractMessageHeaderIntoInfo(loggingInfo, context.Request);
+
+ if(await ExtractResponseInfo(loggingInfo, context.Response, originalBodyStream, logger))
+ {
+ //logger.Info(loggingInfo.ToString());
+ AzureLogHelper.LogMessage($"Api Incoming: {loggingInfo.ToString()}");
+ }
+ }
+ catch { }
+ }
+
+ private async Task ExtractInfoFromRequest(HttpRequest request)
+ {
+ ApiInfo info = new ApiInfo(request.Method, request.GetDisplayUrl(),Environment.MachineName,DateTime.Now);
+
+ if(request.ContentLength.GetValueOrDefault() > 0)
+ {
+ request.EnableBuffering();
+
+ using MemoryStream requestStream = MemoryStreamManager.GetStream();
+ await request.Body.CopyToAsync(requestStream);
+ info.RequestInfo.ContentBody = await ReadStreamInChunks(requestStream);
+
+ request.Body.Position = 0;
+ }
+ return info;
+ }
+
+ private async Task ReadStreamInChunks(Stream stream)
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ await using StringWriter textWriter = new StringWriter();
+ using StreamReader reader = new StreamReader(stream);
+ char[] readChunk = new char[ReadChunkBufferLength];
+ int readChunkLength;
+ do
+ {
+ readChunkLength = await reader.ReadBlockAsync(readChunk, 0, ReadChunkBufferLength);
+ await textWriter.WriteAsync(readChunk, 0, readChunkLength);
+ } while (readChunkLength > 0);
+ return textWriter.ToString();
+ }
+
+ private async Task ExtractResponseInfo(ApiInfo loggingInfo, HttpResponse response, Stream originalBodyStream, ILogger logger)
+ {
+ //loggingInfo.CustomInfo = new CustomInfo(response);
+ if(loggingInfo.IsValid())
+ {
+ try
+ {
+ loggingInfo.ResponseInfo = new ResponseInfo(response);
+ response.Body.Seek(0, SeekOrigin.Begin);
+
+ if(response.Body.Length < MaxContentLength)
+ loggingInfo.ResponseInfo.ContentBody = await new StreamReader(response.Body).ReadToEndAsync();
+ else
+ loggingInfo.ResponseInfo.ContentBody = $"Size {response.Body.Length} too large to retrieve";
+ }
+ catch (Exception ex)
+ {
+ logger.Error($"Exception logging request {@loggingInfo}, error {@ex}");
+ return false;
+ }
+
+ loggingInfo.ResponseInfo.ContentType = response.Headers.ContentType.Any() ? string.Join(",", response.Headers.ContentType) : null;
+ }
+ response.Body.Seek(0, SeekOrigin.Begin);
+
+ await response.Body.CopyToAsync(originalBodyStream);
+ return loggingInfo.IsValid();
+ }
+
+
+ private void ExtractMessageHeaderIntoInfo(ApiInfo apiInfo, HttpRequest request)
+ {
+ //List> headers = request.Headers.ToList();
+ //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers);
+ //apiInfo.RequestInfo.RecordId = HttpHeaderHelper.ExtractInt(CustomInfo.RecordId, headers);
+ //apiInfo.RequestInfo.SecurityContext = HttpHeaderHelper.ExtractInt(CustomInfo.SecurityContext, headers);
+ //apiInfo.RequestInfo.InnerException = HttpHeaderHelper.ExtractInt(CustomInfo.InnerException, headers);
+ //apiInfo.RequestInfo.ExceptionStack = HttpHeaderHelper.ExtractInt(CustomInfo.ExceptionStack, headers);
+ //apiInfo.RequestInfo.RealException = HttpHeaderHelper.ExtractInt(CustomInfo.RealException, headers);
+ //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers);
+ //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers);
+
+ }
+}
diff --git a/Source/DealerSelection.Common/Logging/RequestInfo.cs b/Source/DealerSelection.Common/Logging/RequestInfo.cs
new file mode 100644
index 0000000..3394292
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/RequestInfo.cs
@@ -0,0 +1,42 @@
+
+namespace DealerSelection.Common.Logging;
+
+public class RequestInfo
+{
+ public RequestInfo(string hostName, string httpMethod, string uri, DateTime startDate)
+ {
+ HostName = hostName;
+ HttpMethod = httpMethod;
+ Uri = uri;
+ StartDate = startDate;
+ }
+
+ public string HostName { get; set; }
+ public string HttpMethod { get; set; }
+ public string Uri { get; set; }
+ public DateTime? StartDate { get; set; }
+ public int? RecordId { get; set; }
+ public int? BuId { get; set; }
+ public string? SecurityContext { get; set; }
+ public string? ContentBody { get; set; }
+ public string? ExceptionStack { get; set;}
+ public string? RealException { get; set; }
+ public string? InnerException { get; set; }
+
+ public override string ToString()
+ {
+ return $"{nameof(BuId)}:{ BuId},{nameof(RecordId)}:{RecordId},{nameof(HostName)}:{HostName}," +
+ $"{nameof(HttpMethod)}:{HttpMethod},{nameof(Uri)}:{Uri},{nameof(StartDate)}:{StartDate}," +
+ $"{nameof(SecurityContext)}:{SecurityContext},{nameof(ContentBody)}:{ContentBody}," +
+ $"{nameof(ExceptionStack)}:{ExceptionStack},{nameof(RealException)}:{RealException},{nameof(InnerException)}:{InnerException}";
+ }
+
+ public string BuildRequestData()
+ {
+ if(string.IsNullOrWhiteSpace(ContentBody))
+ {
+ return Uri;
+ }
+ return $"{Uri} with {ContentBody}";
+ }
+}
diff --git a/Source/DealerSelection.Common/Logging/ResponseInfo.cs b/Source/DealerSelection.Common/Logging/ResponseInfo.cs
new file mode 100644
index 0000000..aa4c878
--- /dev/null
+++ b/Source/DealerSelection.Common/Logging/ResponseInfo.cs
@@ -0,0 +1,37 @@
+
+using Microsoft.AspNetCore.Http;
+using System.Net;
+
+namespace DealerSelection.Common.Logging;
+
+public class ResponseInfo
+{
+ public ResponseInfo(HttpResponse response)
+ {
+ StatusCode = (HttpStatusCode)response.StatusCode;
+
+ if (IsSuccessStatusCode)
+ IsSuccess = true;
+ else if (StatusCode >= HttpStatusCode.InternalServerError)
+ IsSuccess = false;
+ else
+ IsSuccess = null;
+
+ TimeStamp = DateTime.Now;
+ }
+
+ public bool IsSuccessStatusCode => (int)StatusCode >= 200 && (int)StatusCode <= 299;
+ public bool? IsSuccess { get; }
+ public HttpStatusCode StatusCode { get; }
+ public DateTime TimeStamp { get; }
+ public string? ContentBody { get; set; }
+ public string? ContentType { get; set; }
+
+ public override string ToString()
+ {
+ return $"{nameof(StatusCode)}: {StatusCode}, " +
+ $"{nameof(TimeStamp)}: {TimeStamp}, " +
+ $"{nameof(ContentType)}: {ContentType} "
+ + (string.IsNullOrWhiteSpace(ContentBody)? null : $", {nameof(ContentBody)}: {ContentBody} ");
+ }
+}
diff --git a/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs b/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs
new file mode 100644
index 0000000..c314540
--- /dev/null
+++ b/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs
@@ -0,0 +1,34 @@
+using Microsoft.AspNetCore.Http;
+
+namespace DealerSelection.Common.Middleware;
+
+public class SwaggerRootRoutingMiddleware
+{
+ public const string SwaggerUrl = "help/ui";
+ private readonly RequestDelegate _requestDelegate;
+ private string PathBase { get; }
+
+ public SwaggerRootRoutingMiddleware(RequestDelegate requestDelegate)
+ {
+ _requestDelegate = requestDelegate;
+ PathBase = "/Booking/1.0";
+ }
+
+ public async Task Invoke(HttpContext context)
+
+ {
+ if(context.Request.Method == "GET" && context.Request.Path.Value!.Contains("/index.html", StringComparison.OrdinalIgnoreCase)
+ && !context.Request.Path.Value.Contains($"{SwaggerUrl}/index.html", StringComparison.OrdinalIgnoreCase))
+ {
+
+#if DEBUG
+ context.Response.Redirect($"{SwaggerUrl}/index.html");
+#else
+ context.Response.Redirect($"{PathBase}/{SwaggerUrl}/index.html");
+#endif
+ return;
+ }
+
+ await _requestDelegate(context);
+ }
+}
diff --git a/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs b/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs
new file mode 100644
index 0000000..b90ad10
--- /dev/null
+++ b/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs
@@ -0,0 +1,31 @@
+namespace DealerSelection.Common.Profiler
+{
+ public class PerformanceProfiler : IDisposable
+ {
+ private bool disposed;
+
+ public PerformanceProfiler(string operationName)
+ {
+ Profiler.StartOperation($"Custom - {operationName}");
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ Profiler.EndOperation();
+ }
+
+ disposed = true;
+ }
+ }
+ }
+}
diff --git a/Source/DealerSelection.Common/Profiler/Profiler.cs b/Source/DealerSelection.Common/Profiler/Profiler.cs
new file mode 100644
index 0000000..7d71df0
--- /dev/null
+++ b/Source/DealerSelection.Common/Profiler/Profiler.cs
@@ -0,0 +1,19 @@
+using System.Diagnostics;
+
+namespace DealerSelection.Common.Profiler
+{
+ public static class Profiler
+ {
+ private static Stopwatch watch;
+ public static void StartOperation(string operationName)
+ {
+ watch = System.Diagnostics.Stopwatch.StartNew();
+ }
+ public static void EndOperation()
+ {
+ watch.Stop();
+ var timeToExecute = watch.ElapsedMilliseconds;
+
+ }
+ }
+}
diff --git a/Source/DealerSelection.DependencyInjection/ApiRegistry.cs b/Source/DealerSelection.DependencyInjection/ApiRegistry.cs
new file mode 100644
index 0000000..96aff78
--- /dev/null
+++ b/Source/DealerSelection.DependencyInjection/ApiRegistry.cs
@@ -0,0 +1,35 @@
+using DealerSelection.Api;
+using DealerSelection.Api.CommonUtil;
+using DealerSelection.Api.Interface;
+using DealerSelection.Common.HttpClient;
+using DealerSelection.Common.Interfaces.HttpClient;
+using Lamar;
+
+namespace DealerSelection.DependencyInjection;
+
+public class ApiRegistry : ServiceRegistry
+{
+ public ApiRegistry()
+ {
+
+ For()
+ .Use()
+ .Singleton();
+
+ For()
+ .Use()
+ .Singleton();
+
+ For()
+ .Use()
+ .Singleton();
+
+ For()
+ .Use()
+ .Singleton();
+ For()
+ .Use()
+ .Singleton();
+
+ }
+}
diff --git a/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj b/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj
new file mode 100644
index 0000000..db4a522
--- /dev/null
+++ b/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs b/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs
new file mode 100644
index 0000000..2d17d40
--- /dev/null
+++ b/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs
@@ -0,0 +1,11 @@
+using Lamar;
+namespace DealerSelection.DependencyInjection;
+
+public class DependencyInjectionBootStrapper : ServiceRegistry
+{
+ public DependencyInjectionBootStrapper()
+ {
+ IncludeRegistry();
+ IncludeRegistry();
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs b/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs
new file mode 100644
index 0000000..8b8b1d2
--- /dev/null
+++ b/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs
@@ -0,0 +1,37 @@
+using Lamar;
+
+using InfoBipRepo = DealerSelection.Api.Infrastructure.InfoBip;
+using MulesoftRepo = DealerSelection.Api.Infrastructure.Mulesoft;
+using AssignDealerRepo = DealerSelection.Api.Infrastructure.AssignDealer;
+using Customerdetail = DealerSelection.Api.Infrastructure.CustomerDetail;
+using JwtRepo = DealerSelection.Api.Infrastructure.Jwt;
+namespace DealerSelection.DependencyInjection;
+
+public class InfrastructureRegistry : ServiceRegistry
+{
+ public InfrastructureRegistry()
+ {
+
+ For()
+ .Use()
+ .Ctor().Is("BOOKING")
+ .Transient();
+
+ For()
+ .Use()
+ .Ctor().Is("BOOKING")
+ .Transient();
+
+ For()
+ .Use()
+ .Ctor().Is("BOOKING")
+ .Transient();
+
+ For()
+ .Use()
+ .Ctor().Is("BOOKING")
+ .Transient();
+
+ }
+
+}
diff --git a/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs b/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs
new file mode 100644
index 0000000..7dd09ab
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs
@@ -0,0 +1,7 @@
+
+namespace DealerSelection.Api.Infrastructure.AssignDealer;
+
+public interface IAssignDealerRepository
+{
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs b/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs
new file mode 100644
index 0000000..abff6b9
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs
@@ -0,0 +1,17 @@
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Data.Dapper;
+using Dapper;
+using Microsoft.Extensions.Logging;
+using System.Data;
+using System.Data.SqlClient;
+namespace DealerSelection.Api.Infrastructure.AssignDealer;
+
+public class Repository : RepositoryBaseDapperAsync, IAssignDealerRepository
+{
+ private readonly ILogger _logger;
+ public Repository(string cxnName, ILogger logger) : base(cxnName)
+ {
+ _logger = logger;
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs
new file mode 100644
index 0000000..a45e7c7
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs
@@ -0,0 +1,26 @@
+using DealerSelection.Api.Models;
+
+namespace DealerSelection.Api.Infrastructure.CustomerDetail;
+
+public class CustomerDealerInfoRequestDto
+{
+ public int BuId { get; set; }
+ public int RecordId { get; set; }
+ public int MobileNumber { get; set; }
+ public string ModelCode { get; set; }
+ public string ModelName { get; set; }
+ public string ModelVariant { get; set; }
+ public string DealerName { get; set; }
+ public string DealerCode { get; set; }
+ public string PinCode { get; set; }
+ public string Latitude { get; set; }
+ public string Longitude { get; set; }
+ public DealerSelectionJobStatus DealerSelectionJobStatus { get; set; }
+
+ public string RequestDetail()
+ {
+ return $"BuId: {BuId}, RecordId: {RecordId}, MobileNumber: {MobileNumber}, ModelCode: {ModelCode}, " +
+ $"ModelName:{ModelName}, ModelVariant:{ModelVariant}, DealerName: {DealerName}, DealerCode: {DealerCode}, "+
+ $"PinCode: {PinCode}, Latitude: {Latitude}, Longitude: {Longitude}, DealerSelectionJobStatus: {DealerSelectionJobStatus}";
+ }
+}
diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs
new file mode 100644
index 0000000..0abd3cd
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs
@@ -0,0 +1,13 @@
+using DealerSelection.Api.Infrastructure.Mulesoft;
+using DealerSelection.Api.Models;
+
+namespace DealerSelection.Api.Infrastructure.CustomerDetail;
+
+public interface IRepository
+{
+ Task UpdateDealerDetail(CustomerDealerInfoRequestDto customerInfo);
+ // Task GetCustomerData();
+ Task GetCustomerData(int buid, int recordId);
+ Task IsDuplicateMobileNumber(int mobileNumber);
+ Task UpdateDealerSelectionJobStatus(int buId, int recordId, int mobileNumber, DealerSelectionJobStatus dealerSelectionJobStatus);
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs
new file mode 100644
index 0000000..8196f16
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs
@@ -0,0 +1,116 @@
+using Dapper;
+using DealerSelection.Api.Infrastructure.Mulesoft;
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Data.Dapper;
+using DealerSelection.Common.Exceptions;
+using Microsoft.Extensions.Logging;
+using System.Data;
+using System.Data.SqlClient;
+
+namespace DealerSelection.Api.Infrastructure.CustomerDetail;
+
+public class Repository : RepositoryBaseDapperAsync, IRepository
+{
+ private readonly ILogger _logger;
+ public Repository(string cxnName, ILogger logger) : base(cxnName)
+ {
+ _logger = logger;
+ }
+
+
+ public async Task UpdateDealerDetail(CustomerDealerInfoRequestDto dto)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ int receivedBookingId = await cxn.ExecuteScalarAsync(Procedure.UpdateDealerDetails,
+ new
+ {
+ dto.BuId,
+ dto.RecordId,
+ dto.MobileNumber,
+ dto.ModelCode,
+ dto.ModelName,
+ dto.ModelVariant,
+ dto.DealerName,
+ dto.DealerCode,
+ dto.PinCode,
+ dto.Latitude,
+ dto.Longitude,
+ dto.DealerSelectionJobStatus
+ },
+ commandType: CommandType.StoredProcedure);
+ return receivedBookingId;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"BU:- {dto.BuId}. Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {dto.RequestDetail()}.", ex.StackTrace);
+ throw new UnexpectedDataException($"Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {dto.RequestDetail()}.", ex);
+ }
+ }
+
+ public async Task GetCustomerData(int buId, int recordId)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ IEnumerable cusotmerInfo = await cxn.QueryAsync(Procedure.GetCustomerDataForJob,
+ commandType: CommandType.StoredProcedure);
+ return cusotmerInfo.ToList().FirstOrDefault();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {customerInfo.RequestDetail()}.", ex.StackTrace);
+ throw new UnexpectedDataException($"Error at Repository:CustomerDetail in UpdateDealerDetail for Request: ", ex);
+ }
+ }
+
+ public async Task IsDuplicateMobileNumber(int mobileNumber)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ bool isDuplicate = await cxn.QueryFirstAsync(Procedure.IsDuplicateMobileNumber,
+ new
+ {
+ mobileNumber
+ },
+ commandType: CommandType.StoredProcedure);
+ return isDuplicate;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Error at Repository:CustomerDetail in IsDuplicateMobileNumber for MobileNumber: {mobileNumber}. ErrorMessage", ex.StackTrace);
+ throw new DuplicateException($"Error at Repository:CustomerDetail in IsDuplicateMobileNumber for MobileNumber: {mobileNumber}.");
+ }
+ }
+
+
+ public async Task UpdateDealerSelectionJobStatus(int buId, int recordId, int mobileNumber, DealerSelectionJobStatus dealerSelectionJobStatus)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ await cxn.QueryFirstAsync(Procedure.UpdateDealerSelectionJobStatus,
+ new
+ {
+ buId, recordId, mobileNumber, dealerSelectionJobStatus
+ },
+ commandType: CommandType.StoredProcedure);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Error at Repository:CustomerDetail in UpdateDealerSelectionJobStatus for BuId: {buId}, RecordId: {recordId}, MobileNumber: {mobileNumber}, DealerSelectionJobStatus: {dealerSelectionJobStatus}. ErrorMessage", ex.StackTrace);
+ throw new DuplicateException($"Error at Repository:CustomerDetail in UpdateDealerSelectionJobStatus for BuId: {buId}, RecordId: {recordId}, MobileNumber: {mobileNumber}, DealerSelectionJobStatus: {dealerSelectionJobStatus}");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj b/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj
new file mode 100644
index 0000000..cc1c4f4
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj
@@ -0,0 +1,37 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+ 1701;1702;8618;8603
+
+
+
+ 1701;1702;8618;8603
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs b/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs
new file mode 100644
index 0000000..3f626a1
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs
@@ -0,0 +1,6 @@
+namespace DealerSelection.Api.Infrastructure.InfoBip;
+
+public interface IRepository
+{
+ Task SaveResponse(int buId, string strMobile, string request_name, string api_request, string api_response, string error_message);
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs b/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs
new file mode 100644
index 0000000..1bfb404
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs
@@ -0,0 +1,45 @@
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Data.Dapper;
+using Dapper;
+using Microsoft.Extensions.Logging;
+using System.Data;
+using System.Data.SqlClient;
+
+
+namespace DealerSelection.Api.Infrastructure.InfoBip;
+
+public class Repository : RepositoryBaseDapperAsync, IRepository
+{
+ private readonly ILogger _logger;
+ public Repository(string cxnName, ILogger logger) : base(cxnName)
+ {
+ _logger = logger;
+ }
+
+ public async Task SaveResponse(int buId, string strMobile, string request_name, string api_request, string api_response, string error_message)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ await cxn.ExecuteScalarAsync(@"insert into tbl_infobip_api_response(request_name,api_request,api_response,error_message)
+ values(@request_name,@api_request,@api_response,@error_message)",
+ new
+ {
+ request_name,
+ api_request,
+ api_response,
+ error_message
+ },
+ commandType: CommandType.Text);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + buId.ToString() + $"Error at Repository:InfoBip in SaveResponse for BuId: {buId}, Mobile: {strMobile}," +
+ $"request_name: {request_name}, api_request: {api_request}, api_response: {api_response}, error_message: {error_message}." + ex.Message.ToString());
+ throw new UnexpectedDataException($"Error at Repository:InfoBip in SaveResponse for BuId: {buId}, Mobile: {strMobile}," +
+ $"request_name: {request_name}, api_request: {api_request}, api_response: {api_response}, error_message: {error_message}.", ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs b/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs
new file mode 100644
index 0000000..dc4110a
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs
@@ -0,0 +1,14 @@
+
+namespace DealerSelection.Api.Infrastructure.Jwt;
+
+public class AuthValidateModelDto
+{
+ public string ClientId { get; set; }
+ public string SecretId { get; set; }
+ public string BuId { get; set; }
+}
+
+public class TokenModel
+{
+ public string Token { get; set; }
+}
diff --git a/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs b/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs
new file mode 100644
index 0000000..d9b732e
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs
@@ -0,0 +1,9 @@
+using DealerSelection.Api.Models;
+namespace DealerSelection.Api.Infrastructure.Jwt;
+
+public interface IJwtRepository
+{
+ Task GenerateToken(AuthModel user);
+ Task Authenticate(AuthValidateModelDto userLogin);
+ Task IsTokenExpired(string tokenValue);
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs b/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs
new file mode 100644
index 0000000..1e00bce
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs
@@ -0,0 +1,23 @@
+using DealerSelection.Api.Models;
+
+
+namespace DealerSelection.Api.Infrastructure.Jwt;
+
+public class JwtRepository : IJwtRepository
+{
+
+ public Task Authenticate(AuthValidateModelDto userLogin)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task GenerateToken(AuthModel user)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task IsTokenExpired(string tokenValue)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs b/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs
new file mode 100644
index 0000000..27b4f04
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs
@@ -0,0 +1,26 @@
+
+namespace DealerSelection.Api.Infrastructure.Mulesoft;
+
+public class DealerDetailDto
+{
+ public int BuId { get; set; }
+ public string DealerCode { get; set; }
+ public string Address1 { get; set; }
+ public string Address2 { get; set; }
+ public string City { get; set; }
+ public string State { get; set; }
+ public string Zip { get; set; }
+ public string DisplayName { get; set; }
+ public string ContactCard { get; set; }
+ public string SalesPersonMail { get; set; }
+ public string SaleMobileNumber { get; set; }
+ public string EcomSalesAddress { get; set; }
+
+ public string RequestDetail()
+ {
+ return $"BuId: {BuId}, DealerCode: {DealerCode}, Address1: {Address1}, Address2: {Address2}, City: {City}, State: {State}, " +
+ $"Zip: {Zip}, DisplayName: {DisplayName}, ContactCard: {ContactCard}, SalesPersonMail: {SalesPersonMail}, " +
+ $"SaleMobileNumber: {SaleMobileNumber}, EcomSalesAddress: {EcomSalesAddress}.";
+ }
+}
+
diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs b/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs
new file mode 100644
index 0000000..3a33a17
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs
@@ -0,0 +1,10 @@
+
+namespace DealerSelection.Api.Infrastructure.Mulesoft;
+
+public interface IRepository
+{
+ Task GetCustomerInfo(int buId, string bookingId);
+ Task UpdateMulesoftResponse(int buId,int recordId,string bookingId,string message,string isSuccessBooking, LeadData leadData);
+ Task InsertAndUpdateDealerRecord(DealerDetailDto dto);
+ Task> GetDataForLsqPush(int buId);
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs b/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs
new file mode 100644
index 0000000..00ca14f
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs
@@ -0,0 +1,46 @@
+
+using System;
+
+namespace DealerSelection.Api.Infrastructure.Mulesoft;
+
+public class MulesoftCustomerInfoDto
+{
+ public int BuId { get; set; }
+ public string BuName { get; set; }
+ public int RecordId { get; set; }
+ public string BookingId { get; set; }
+ public string CustomerName { get; set; }
+ public string MobileNumber { get; set; }
+ public string ModelCode { get; set; }
+ public string ModelName { get; set; }
+ public string ColorCode { get; set; }
+ public string DealerCode { get; set; }
+ public string DealerName { get; set; }
+ public bool IsRegisterInterestRequest { get; set; }
+ public string PinCode { get; set; }
+ public string UtmCustomDetails1 { get; set; }
+ public string UtmCustomDetails2 { get; set; }
+ public string Status { get; set; }
+ public string CCTransactionId { get; set; }
+ public string ReceiptId { get; set; }
+ public string AmountPaid { get; set; }
+ public string ReferralUrl { get; set; }
+
+ public bool IsWhatsappOptIn { get; set; }
+ public int LeadTransferred { get; set; }
+ public string CustomerLat { get; set; }
+ public string CustomerLong { get; set; }
+
+
+}
+
+public class LeadData
+{
+ public string Lead_transferred { get; set; }
+ public string Lead_status { get; set; }
+ public string Opportunity_id { get; set; }
+ public string Prospect_id { get; set; }
+ public string ApiResponse { get; set; }
+ public string LeadResponseStatus { get; set; }
+}
+
diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs b/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs
new file mode 100644
index 0000000..601fe7f
--- /dev/null
+++ b/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs
@@ -0,0 +1,134 @@
+using DealerSelection.Api.Models;
+using DealerSelection.Common.Data.Dapper;
+using Dapper;
+using Microsoft.Extensions.Logging;
+using System.Data;
+using System.Data.SqlClient;
+namespace DealerSelection.Api.Infrastructure.Mulesoft;
+
+public class Repository : RepositoryBaseDapperAsync, IRepository
+{
+ private readonly ILogger _logger;
+ public Repository(string cxnName, ILogger logger) : base(cxnName)
+ {
+ _logger = logger;
+ }
+
+ public async Task GetCustomerInfo(int buId, string bookingId)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnWithMappingAsync())
+ {
+ IEnumerable cusotmerInfo = await cxn.QueryAsync(Procedure.GetCustomerInfoOnBookingId,
+ new
+ {
+ buId,
+ bookingId
+ },
+ commandType: CommandType.StoredProcedure);
+ return cusotmerInfo.ToList().FirstOrDefault();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + buId.ToString() + " Error at Repository:Mulesoft in GetCustomerInfo." + ex.Message.ToString());
+ throw new UnexpectedDataException($"Error at Repository:Mulesoft in GetCustomerInfo for BuId: {buId} and BookingId: {bookingId}.", ex);
+ }
+ }
+
+ public async Task UpdateMulesoftResponse(int buId, int recordId, string bookingId, string message, string isSuccessBooking, LeadData leadData)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnWithMappingAsync())
+ {
+ await cxn.QueryAsync(Procedure.InsertLSQDetail,
+ new
+ {
+ buId,
+ recordId,
+ bookingId,
+ lead_Transferred = leadData.Lead_transferred,
+ lead_Status = leadData.Lead_status,
+ api_Request = message,
+ api_Response = leadData.ApiResponse,
+ lSQProspectId = leadData.Prospect_id,
+ lSQOpportunityId = leadData.Opportunity_id,
+ isSuccessBooking
+ },
+ commandType: CommandType.StoredProcedure);
+ }
+ }
+ catch (Exception ex)
+ {
+
+ _logger.LogError("BU:- " + buId.ToString() + $"Error at Repository:Mulesoft in UpdateMulesoftResponse for buId: {buId}, recordId: {recordId}, " +
+ $"leadData.Lead_transferred: {leadData.Lead_transferred}, message: {message},leadData.ApiResponse: {leadData.ApiResponse}, " +
+ $"leadData.Prospect_id:{leadData.Prospect_id}, leadData.Opportunity_id: {leadData.Opportunity_id}, " +
+ $"isSuccessBooking: {isSuccessBooking} " + ex.Message.ToString());
+
+ throw new UnexpectedDataException($"Error at Repository:Mulesoft in UpdateMulesoftResponse for buId: {buId}, recordId: {recordId}, " +
+ $"leadData.Lead_transferred: {leadData.Lead_transferred}, message: {message},leadData.ApiResponse: {leadData.ApiResponse}, " +
+ $"leadData.Prospect_id:{leadData.Prospect_id}, leadData.Opportunity_id: {leadData.Opportunity_id}, " +
+ $"isSuccessBooking: {isSuccessBooking} ", ex);
+ }
+ }
+
+ public async Task InsertAndUpdateDealerRecord(DealerDetailDto dto)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnWithMappingAsync())
+ {
+ await cxn.QueryAsync(Procedure.InsertUpdateDealerDetail,
+ new
+ {
+ dto.BuId,
+ dto.DealerCode,
+ dto.Address1,
+ dto.Address2,
+ dto.City,
+ dto.State,
+ dto.Zip,
+ dto.DisplayName,
+ dto.ContactCard,
+ dto.SalesPersonMail,
+ dto.SaleMobileNumber,
+ dto.EcomSalesAddress
+
+ },
+ commandType: CommandType.StoredProcedure);
+
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + dto.BuId.ToString() + " Error at Repository:Mulesoft in InsertAndUpdateDealerRecord for InfoBip Request: {dto.RequestDetail()}" + ex.Message.ToString());
+ throw new UnexpectedDataException($"Error at Repository:Mulesoft in InsertAndUpdateDealerRecord for InfoBip Request: {dto.RequestDetail()}", ex);
+ }
+ }
+
+ public async Task> GetDataForLsqPush(int buId)
+ {
+ try
+ {
+ using (SqlConnection cxn = await OpenCxnAsync())
+ {
+ IEnumerable lsqDto = await cxn.QueryAsync(Procedure.GetDataForLsqPush,
+ new
+ {
+ buId
+ },
+ commandType: CommandType.StoredProcedure);
+ return lsqDto.ToList();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("BU:- " + buId.ToString() + "Error at Repository:Mulesoft in GetDataForLsqPush " + ex.Message.ToString());
+ throw new UnexpectedDataException($"Error at Repository:Mulesoft in GetDataForLsqPush for BuId: {buId}.", ex);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj b/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj
new file mode 100644
index 0000000..860db1c
--- /dev/null
+++ b/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+