TransactionManagment.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Xml.Serialization;
  8. namespace Dfs.WayneChina.CardTrxManager
  9. {
  10. public class StoreForwardCompletedEventArgs : EventArgs
  11. {
  12. public int PumpdId { get; set; }
  13. public int SeqNo { get; set; }
  14. public int ReleaseToken { get; set; }
  15. }
  16. public class StoreForwardManager
  17. {
  18. static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("PosTrxSubmitter");
  19. private TrxSubmitter.TrxSubmitter submitter;
  20. private TransactionManager transactionManager;
  21. public event EventHandler<StoreForwardCompletedEventArgs> OnStoreForwardCompleted;
  22. private System.Timers.Timer scanTimer;
  23. private int count = 0;
  24. public StoreForwardManager(CloudCredential credential)
  25. {
  26. submitter = new TrxSubmitter.TrxSubmitter(100, credential);
  27. transactionManager = new TransactionManager();
  28. scanTimer = new System.Timers.Timer();
  29. scanTimer.Elapsed += ScanTimer_Elapsed;
  30. scanTimer.Interval = 30000;
  31. }
  32. private async void ScanTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  33. {
  34. scanTimer.Stop();
  35. count++;
  36. var firstFileName = Directory.GetFiles("StoreForward").FirstOrDefault();
  37. if (!string.IsNullOrEmpty(firstFileName))
  38. {
  39. logger.Info($" SF, {count}, found file: {firstFileName}");
  40. var sfTrans = transactionManager.TryLoad(firstFileName);
  41. if (sfTrans != null)
  42. {
  43. logger.Info($" SF, {count}, Transaction reloaded");
  44. var result = await submitter.SubmitTrxAsync(sfTrans);
  45. logger.Info($" SF, {count}, submit result: {result}");
  46. if (result)
  47. {
  48. FuelingDoneItem fuelingDoneItem = (FuelingDoneItem)sfTrans.TransactionItems.FirstOrDefault(t => t is FuelingDoneItem);
  49. if (fuelingDoneItem != null)
  50. {
  51. OnStoreForwardCompleted?.Invoke(this, new StoreForwardCompletedEventArgs
  52. {
  53. PumpdId = fuelingDoneItem.PumpId,
  54. ReleaseToken = fuelingDoneItem.FdcSqNo,
  55. SeqNo = fuelingDoneItem.SeqNo
  56. });
  57. }
  58. try
  59. {
  60. File.Delete(firstFileName);
  61. logger.Info($" SF success, delete file: {firstFileName}");
  62. }
  63. catch (Exception ex)
  64. {
  65. logger.Error("Exception in deleting file " + ex.ToString());
  66. }
  67. }
  68. }
  69. }
  70. scanTimer.Start();
  71. }
  72. public void Start()
  73. {
  74. transactionManager.Init();
  75. scanTimer.Start();
  76. }
  77. }
  78. public class TransactionManager
  79. {
  80. private readonly string storeForwardFolder = "StoreForward";
  81. private readonly string errorFolder = @"StoreForward/Error";
  82. private XmlSerializer xmlSerializer;
  83. static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("PosTrxSubmitter");
  84. public TransactionManager()
  85. {
  86. xmlSerializer = new XmlSerializer(typeof(StoreFowardTransaction), transactionItemTypes);
  87. }
  88. public void Init()
  89. {
  90. if (!Directory.Exists(storeForwardFolder))
  91. Directory.CreateDirectory(storeForwardFolder);
  92. if (!Directory.Exists(errorFolder))
  93. Directory.CreateDirectory(errorFolder);
  94. }
  95. Type[] transactionItemTypes =
  96. {
  97. typeof(TransactionItem),
  98. typeof(TransactionCreatedItem),
  99. typeof(ProductCodeIdentitiedItem),
  100. typeof(FuelingDoneItem),
  101. typeof(CommittedItem)
  102. };
  103. public void SaveTransaction(StoreFowardTransaction transaction)
  104. {
  105. Save(storeForwardFolder, transaction);
  106. }
  107. public StoreFowardTransaction TryLoad(string fileName)
  108. {
  109. try
  110. {
  111. using (var reader = new StreamReader(fileName))
  112. {
  113. var transaction = (StoreFowardTransaction)xmlSerializer.Deserialize(reader);
  114. return transaction;
  115. }
  116. }
  117. catch (Exception ex)
  118. {
  119. logger.Error($"TM: {ex.ToString()}");
  120. }
  121. return null;
  122. }
  123. public void SetTransactionToError(StoreFowardTransaction transaction)
  124. {
  125. Save(errorFolder, transaction);
  126. }
  127. private void Save(string targetLocation, StoreFowardTransaction transaction)
  128. {
  129. FuelingDoneItem fuelingDoneItem =
  130. transaction.TransactionItems.FirstOrDefault(i => i is FuelingDoneItem) as FuelingDoneItem;
  131. if (fuelingDoneItem != null)
  132. {
  133. string fileName = $"Trans_{fuelingDoneItem.PumpId}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.xml";
  134. try
  135. {
  136. using (var sw = new StreamWriter(targetLocation + "/" + fileName))
  137. {
  138. xmlSerializer.Serialize(sw, transaction);
  139. }
  140. }
  141. catch (Exception ex)
  142. {
  143. logger.Error($"TM: {ex.ToString()}");
  144. }
  145. }
  146. else
  147. {
  148. logger.Error("TM: No FuelingDoneItem");
  149. }
  150. }
  151. }
  152. [XmlRoot("SFTrans")]
  153. [XmlInclude(typeof(TransactionItem))]
  154. public class StoreFowardTransaction
  155. {
  156. public StoreFowardTransaction()
  157. {
  158. TransactionItems = new List<TransactionItem>();
  159. }
  160. [XmlArray("Items")]
  161. [XmlArrayItem("TransactionItem")]
  162. public List<TransactionItem> TransactionItems { get; }
  163. public int ErrorItemsCount
  164. {
  165. get
  166. {
  167. int count = 0;
  168. for (int i = 0; i < TransactionItems.Count; i++)
  169. {
  170. if (TransactionItems[i] is ErrorItem)
  171. count++;
  172. }
  173. return count;
  174. }
  175. }
  176. public TransactionState LastState => TransactionItems.OrderBy(t => t.AddedTime).Last().State;
  177. public int FuelingId
  178. {
  179. get
  180. {
  181. var fuelingDoneItem = TransactionItems.FirstOrDefault(t => t is FuelingDoneItem) as FuelingDoneItem;
  182. if (fuelingDoneItem != null)
  183. return fuelingDoneItem.SeqNo;
  184. return 0;
  185. }
  186. }
  187. }
  188. [XmlType("TransactionItem")] // define Type
  189. [XmlInclude(typeof(FuelingDoneItem)),
  190. XmlInclude(typeof(ProductCodeIdentitiedItem)),
  191. XmlInclude(typeof(TransactionCreatedItem)),
  192. XmlInclude(typeof(CommittedItem))]
  193. public class TransactionItem
  194. {
  195. public TransactionItem()
  196. {
  197. AddedTime = DateTime.Now;
  198. }
  199. [XmlAttribute("State")]
  200. public TransactionState State { get; set; }
  201. public DateTime AddedTime { get; set; }
  202. }
  203. public enum TransactionState
  204. {
  205. Unknown,
  206. FuelingDone,
  207. ProductCodeIdentified,
  208. Created,
  209. Committed,
  210. Error
  211. }
  212. [XmlType("FuelingDoneItem")]
  213. public class FuelingDoneItem : TransactionItem
  214. {
  215. public FuelingDoneItem()
  216. {
  217. State = TransactionState.FuelingDone;
  218. }
  219. public int Barcode { get; set; }
  220. public int PumpId { get; set; }
  221. public int NozzleId { get; set; }
  222. public int SiteNozzleNo { get; set; }
  223. public ushort FPosSqNo { get; set; }
  224. public int FdcSqNo { get; set; }
  225. public DateTime TimeStamp { get; set; }
  226. public decimal Volume { get; set; }
  227. public decimal Amount { get; set; }
  228. public decimal PayAmount { get; set; }
  229. public decimal UnitPrice { get; set; }
  230. public int SeqNo { get; set; }
  231. public string CardNo { get; set; }
  232. public decimal CurrentCardBalance { get; set; }
  233. public DateTime FuelingStartTime { get; set; }
  234. public DateTime FuelingFinishedTime { get; set; }
  235. public decimal VolumeTotalizer { get; set; }
  236. public string CardHolder { get; set; }
  237. public string AccountName { get; set; }
  238. }
  239. [XmlType("ProductCodeIdentitiedItem")]
  240. public class ProductCodeIdentitiedItem : TransactionItem
  241. {
  242. public ProductCodeIdentitiedItem()
  243. {
  244. State = TransactionState.ProductCodeIdentified;
  245. }
  246. public Guid ItemId { get; set; }
  247. }
  248. [XmlType("TransactionCreatedItem")]
  249. public class TransactionCreatedItem : TransactionItem
  250. {
  251. public TransactionCreatedItem()
  252. {
  253. State = TransactionState.Created;
  254. }
  255. public Guid TransactionId { get; set; }
  256. }
  257. [XmlType("CommittedItem")]
  258. public class CommittedItem : TransactionItem
  259. {
  260. public CommittedItem()
  261. {
  262. State = TransactionState.Committed;
  263. }
  264. public bool Success { get; set; }
  265. }
  266. [XmlType("ErrorItem")]
  267. public class ErrorItem : TransactionItem
  268. {
  269. public ErrorItem()
  270. {
  271. State = TransactionState.Error;
  272. }
  273. }
  274. }