DiscountServiceClient.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using Dfs.WayneChina.CardTrxManager;
  2. using Dfs.WayneChina.CardTrxManager.TrxSubmitter;
  3. using Newtonsoft.Json;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Net.Http;
  8. using System.Net.Http.Headers;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. namespace Dfs.WayneChina.IPosPlus.ServiceClient
  13. {
  14. public class DiscountServiceClient
  15. {
  16. #region Fields
  17. private string grantType = "password";
  18. private string authScheme = "bearer";
  19. private string authServicePath = "token";
  20. private HttpClient httpClient = new HttpClient();
  21. private AuthToken currentAuthToken;
  22. private CloudCredential cloudCredential;
  23. private string promotionCategories = string.Empty;
  24. // Make periodic check to make sure the token is valid.
  25. private System.Timers.Timer timer;
  26. private IPosPlusApp posApp;
  27. private int count = 0;
  28. private int discountTimeout = 3;
  29. #endregion
  30. #region Logger
  31. private NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("IPosPlusApp");
  32. #endregion
  33. #region Constructor
  34. public DiscountServiceClient(IPosPlusApp posApp, CloudCredential cloudCredential, string promoCats, int discountTimeout)
  35. {
  36. this.posApp = posApp;
  37. this.cloudCredential = cloudCredential;
  38. promotionCategories = promoCats;
  39. this.discountTimeout = discountTimeout;
  40. timer = new System.Timers.Timer();
  41. timer.Interval = 30000;
  42. timer.Elapsed += Timer_Elapsed;
  43. timer.Enabled = true;
  44. }
  45. private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  46. {
  47. InfoLog("Checking token validity");
  48. if (currentAuthToken == null)
  49. {
  50. await GetToken();
  51. }
  52. else if (currentAuthToken != null && currentAuthToken.IsTokenValid())
  53. {
  54. InfoLog("We already have a valid token");
  55. }
  56. else
  57. {
  58. await GetToken();
  59. }
  60. }
  61. #endregion
  62. #region Public Methods
  63. public async Task<DiscountResponse> CalculatDiscount(DiscountRequest discountRequest)
  64. {
  65. var cancellationTokenSource = new CancellationTokenSource();
  66. cancellationTokenSource.CancelAfter(discountTimeout*1000);
  67. if (currentAuthToken != null && currentAuthToken.IsTokenValid())
  68. {
  69. //httpClient.DefaultRequestHeaders.Clear();
  70. httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, currentAuthToken.AccessToken);
  71. if (!httpClient.DefaultRequestHeaders.Contains("CurrentBuId"))
  72. httpClient.DefaultRequestHeaders.Add("CurrentBuId", currentAuthToken.BusinessUnitList.First().Id.ToString());
  73. if (!httpClient.DefaultRequestHeaders.Contains("ProxyType"))
  74. httpClient.DefaultRequestHeaders.Add("ProxyType", "Discount");
  75. string discountUrl = string.Concat(cloudCredential.DiscountServiceBaseUrl, "api/marketing/", "pos/discount/conformRules");
  76. var posTrxRequest = new PromotionRequest()
  77. {
  78. AccountId = "",
  79. OwnerId = currentAuthToken.BusinessUnitList.First().Id, //Guid.Parse(cloudCredential.CurrentBuId),
  80. Id = new Guid(),
  81. Amount = 0,
  82. Created = discountRequest.TimeStamp,
  83. AccountIcCardNo = discountRequest.CardNo,
  84. Items = new List<PromotionRequestItem>()
  85. {
  86. new PromotionRequestItem()
  87. {
  88. Id = new Guid(),
  89. // so this item should be applied
  90. Barcode = discountRequest.Barcode,
  91. Category= promotionCategories,
  92. LineItemId = Guid.NewGuid(),
  93. Name = posApp?.GetFuelName(Convert.ToInt32(discountRequest.Barcode)),//"油品",
  94. Price = discountRequest.UnitPrice,
  95. Quantity = Math.Round(discountRequest.Volume * 1.00m, 2),
  96. Amount = Math.Round(discountRequest.FillingAmount * 1.00m, 2)
  97. },
  98. },
  99. Payments = new List<Payment>()
  100. {
  101. new Payment()
  102. {
  103. Name = "IC",
  104. Value = Math.Round(discountRequest.FillingAmount * 1.00m, 2)//discountRequest.FillingAmount
  105. }
  106. },
  107. CouponUidList = new List<string>(),
  108. DiscountUidList = new List<string>()
  109. };
  110. var requestLog = JsonConvert.SerializeObject(posTrxRequest);
  111. InfoLog("Posting request: " + requestLog);
  112. CancellationTokenSource cts = new CancellationTokenSource();
  113. try
  114. {
  115. var discountResponse = await httpClient
  116. .PostAsJsonAsync(discountUrl, posTrxRequest, cancellationTokenSource.Token)
  117. .ConfigureAwait(false);
  118. if (discountResponse.IsSuccessStatusCode)
  119. {
  120. var response = await discountResponse.Content.ReadAsStringAsync();
  121. InfoLog("Received success response: " + response);
  122. var result = JsonConvert.DeserializeObject<DiscountForTrx>(response);
  123. if (result == null || result != null && result.data == null)
  124. {
  125. InfoLog("Oops, the reiceved response body is empty!");
  126. return new DiscountResponse { PayAmount = discountRequest.FillingAmount };
  127. }
  128. if (result != null && result.data != null && result.data.discounts != null)
  129. {
  130. InfoLog($"Data: {result.data}, Amount after discount: {result.data.discounts.amountAfterDiscount}");
  131. }
  132. decimal payAmount = 0M;
  133. if (result != null && result.data != null && result.data.discounts != null && result.data.discounts.amountAfterDiscount != 0)
  134. {
  135. InfoLog("Could get a discount");
  136. payAmount = Convert.ToDecimal(result.data.discounts.amountAfterDiscount);
  137. }
  138. return new DiscountResponse
  139. {
  140. PayAmount = payAmount == 0 ? discountRequest.FillingAmount : payAmount
  141. };
  142. }
  143. else
  144. {
  145. var response = await discountResponse.Content.ReadAsStringAsync();
  146. InfoLog("Received failed response: " + response);
  147. }
  148. }
  149. catch (TaskCanceledException tcEx)
  150. {
  151. InfoLog($"Exception: {tcEx}");
  152. }
  153. catch (Exception ex)
  154. {
  155. InfoLog(ex.ToString());
  156. }
  157. return null;
  158. }
  159. else
  160. {
  161. if (count > 3)
  162. {
  163. count = 0;
  164. return null;
  165. }
  166. else
  167. {
  168. await GetToken();
  169. InfoLog("Should have a valid token now, re-calculate discount...");
  170. return await CalculatDiscount(discountRequest);
  171. }
  172. }
  173. }
  174. #endregion
  175. #region Private Methods
  176. private async Task<AuthToken> GetTokenAsync(string userName, string password, string baseUrl)
  177. {
  178. var cancellationTokenSource = new CancellationTokenSource();
  179. cancellationTokenSource.CancelAfter(7000);
  180. InfoLog("start to get token");
  181. currentAuthToken = null;
  182. httpClient.DefaultRequestHeaders.Clear();
  183. string tokenUrl = string.Concat(baseUrl, authServicePath);
  184. var formParam = new AuthenticationParameter(grantType, userName, password);
  185. try
  186. {
  187. var response = await httpClient
  188. .PostAsync(tokenUrl, new FormUrlEncodedContent(formParam.Params), cancellationTokenSource.Token)
  189. .ConfigureAwait(false);
  190. InfoLog($"GetToken, StatusCode: {response.StatusCode}");
  191. if (response.IsSuccessStatusCode)
  192. {
  193. await response.Content.ReadAsStringAsync().ContinueWith(x =>
  194. {
  195. currentAuthToken = JsonConvert.DeserializeObject<AuthToken>(x?.Result);
  196. currentAuthToken.TokenRetrievedTime = DateTime.Now;
  197. if (!string.IsNullOrEmpty(currentAuthToken.BusinessUnitsJsonString))
  198. {
  199. currentAuthToken.BusinessUnitList =
  200. JsonConvert.DeserializeObject<IList<BusinessUnit>>(currentAuthToken.BusinessUnitsJsonString);
  201. }
  202. });
  203. }
  204. else
  205. {
  206. var content = await response.Content.ReadAsStringAsync();
  207. response.Content?.Dispose();
  208. }
  209. return currentAuthToken;
  210. }
  211. catch (AggregateException aggregateException)
  212. {
  213. foreach (var exception in aggregateException.InnerExceptions)
  214. {
  215. InfoLog(exception.ToString());
  216. }
  217. }
  218. catch (Exception ex)
  219. {
  220. InfoLog("Exception in getting token: " + ex.ToString());
  221. }
  222. return null;
  223. }
  224. private async Task GetToken()
  225. {
  226. count++;
  227. InfoLog($"count: {count}, username: {cloudCredential.UserName}, password: {cloudCredential}, url: {cloudCredential.AuthServiceBaseUrl}");
  228. currentAuthToken = await GetTokenAsync(cloudCredential.UserName, cloudCredential.Password, cloudCredential.AuthServiceBaseUrl);
  229. }
  230. private void InfoLog(string log)
  231. {
  232. logger.Info("\t" + "Discount service client, " + log);
  233. }
  234. #endregion
  235. }
  236. }