using Dfs.WayneChina.CardTrxManager; using Dfs.WayneChina.CardTrxManager.TrxSubmitter; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Dfs.WayneChina.IPosPlus.ServiceClient { public class DiscountServiceClient { #region Fields private string grantType = "password"; private string authScheme = "bearer"; private string authServicePath = "token"; private HttpClient httpClient = new HttpClient(); private AuthToken currentAuthToken; private CloudCredential cloudCredential; private string promotionCategories = string.Empty; // Make periodic check to make sure the token is valid. private System.Timers.Timer timer; private IPosPlusApp posApp; private int count = 0; private int discountTimeout = 3; #endregion #region Logger private NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("IPosPlusApp"); #endregion #region Constructor public DiscountServiceClient(IPosPlusApp posApp, CloudCredential cloudCredential, string promoCats, int discountTimeout) { this.posApp = posApp; this.cloudCredential = cloudCredential; promotionCategories = promoCats; this.discountTimeout = discountTimeout; timer = new System.Timers.Timer(); timer.Interval = 30000; timer.Elapsed += Timer_Elapsed; timer.Enabled = true; } private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { InfoLog("Checking token validity"); if (currentAuthToken == null) { await GetToken(); } else if (currentAuthToken != null && currentAuthToken.IsTokenValid()) { InfoLog("We already have a valid token"); } else { await GetToken(); } } #endregion #region Public Methods public async Task CalculatDiscount(DiscountRequest discountRequest) { var cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.CancelAfter(discountTimeout*1000); if (currentAuthToken != null && currentAuthToken.IsTokenValid()) { //httpClient.DefaultRequestHeaders.Clear(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, currentAuthToken.AccessToken); if (!httpClient.DefaultRequestHeaders.Contains("CurrentBuId")) httpClient.DefaultRequestHeaders.Add("CurrentBuId", currentAuthToken.BusinessUnitList.First().Id.ToString()); if (!httpClient.DefaultRequestHeaders.Contains("ProxyType")) httpClient.DefaultRequestHeaders.Add("ProxyType", "Discount"); string discountUrl = string.Concat(cloudCredential.DiscountServiceBaseUrl, "api/marketing/", "pos/discount/conformRules"); var posTrxRequest = new PromotionRequest() { AccountId = "", OwnerId = currentAuthToken.BusinessUnitList.First().Id, //Guid.Parse(cloudCredential.CurrentBuId), Id = new Guid(), Amount = 0, Created = discountRequest.TimeStamp, AccountIcCardNo = discountRequest.CardNo, Items = new List() { new PromotionRequestItem() { Id = new Guid(), // so this item should be applied Barcode = discountRequest.Barcode, Category= promotionCategories, LineItemId = Guid.NewGuid(), Name = posApp?.GetFuelName(Convert.ToInt32(discountRequest.Barcode)),//"油品", Price = discountRequest.UnitPrice, Quantity = Math.Round(discountRequest.Volume * 1.00m, 2), Amount = Math.Round(discountRequest.FillingAmount * 1.00m, 2) }, }, Payments = new List() { new Payment() { Name = "IC", Value = Math.Round(discountRequest.FillingAmount * 1.00m, 2)//discountRequest.FillingAmount } }, CouponUidList = new List(), DiscountUidList = new List() }; var requestLog = JsonConvert.SerializeObject(posTrxRequest); InfoLog("Posting request: " + requestLog); CancellationTokenSource cts = new CancellationTokenSource(); try { var discountResponse = await httpClient .PostAsJsonAsync(discountUrl, posTrxRequest, cancellationTokenSource.Token) .ConfigureAwait(false); if (discountResponse.IsSuccessStatusCode) { var response = await discountResponse.Content.ReadAsStringAsync(); InfoLog("Received success response: " + response); var result = JsonConvert.DeserializeObject(response); if (result == null || result != null && result.data == null) { InfoLog("Oops, the reiceved response body is empty!"); return new DiscountResponse { PayAmount = discountRequest.FillingAmount }; } if (result != null && result.data != null && result.data.discounts != null) { InfoLog($"Data: {result.data}, Amount after discount: {result.data.discounts.amountAfterDiscount}"); } decimal payAmount = 0M; if (result != null && result.data != null && result.data.discounts != null && result.data.discounts.amountAfterDiscount != 0) { InfoLog("Could get a discount"); payAmount = Convert.ToDecimal(result.data.discounts.amountAfterDiscount); } return new DiscountResponse { PayAmount = payAmount == 0 ? discountRequest.FillingAmount : payAmount }; } else { var response = await discountResponse.Content.ReadAsStringAsync(); InfoLog("Received failed response: " + response); } } catch (TaskCanceledException tcEx) { InfoLog($"Exception: {tcEx}"); } catch (Exception ex) { InfoLog(ex.ToString()); } return null; } else { if (count > 3) { count = 0; return null; } else { await GetToken(); InfoLog("Should have a valid token now, re-calculate discount..."); return await CalculatDiscount(discountRequest); } } } #endregion #region Private Methods private async Task GetTokenAsync(string userName, string password, string baseUrl) { var cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.CancelAfter(7000); InfoLog("start to get token"); currentAuthToken = null; httpClient.DefaultRequestHeaders.Clear(); string tokenUrl = string.Concat(baseUrl, authServicePath); var formParam = new AuthenticationParameter(grantType, userName, password); try { var response = await httpClient .PostAsync(tokenUrl, new FormUrlEncodedContent(formParam.Params), cancellationTokenSource.Token) .ConfigureAwait(false); InfoLog($"GetToken, StatusCode: {response.StatusCode}"); if (response.IsSuccessStatusCode) { await response.Content.ReadAsStringAsync().ContinueWith(x => { currentAuthToken = JsonConvert.DeserializeObject(x?.Result); currentAuthToken.TokenRetrievedTime = DateTime.Now; if (!string.IsNullOrEmpty(currentAuthToken.BusinessUnitsJsonString)) { currentAuthToken.BusinessUnitList = JsonConvert.DeserializeObject>(currentAuthToken.BusinessUnitsJsonString); } }); } else { var content = await response.Content.ReadAsStringAsync(); response.Content?.Dispose(); } return currentAuthToken; } catch (AggregateException aggregateException) { foreach (var exception in aggregateException.InnerExceptions) { InfoLog(exception.ToString()); } } catch (Exception ex) { InfoLog("Exception in getting token: " + ex.ToString()); } return null; } private async Task GetToken() { count++; InfoLog($"count: {count}, username: {cloudCredential.UserName}, password: {cloudCredential}, url: {cloudCredential.AuthServiceBaseUrl}"); currentAuthToken = await GetTokenAsync(cloudCredential.UserName, cloudCredential.Password, cloudCredential.AuthServiceBaseUrl); } private void InfoLog(string log) { logger.Info("\t" + "Discount service client, " + log); } #endregion } }