123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- using Dfs.WayneChina.PosModelMini;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Logging.Abstractions;
- 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.Text.Json;
- using System.Threading;
- using System.Threading.Tasks;
- namespace VBaoProxyApp.Cloud
- {
- public enum PaymentID
- {
- Cash = 1,
- AliPay = 2,
- WechatPay = 3,
- IC = 4,
- MiniProgram = 5,
- ThirdPartyPay = 6,
- AutoCleared = 7,
- BankCard = 8,
- OutdoorCash = 9,
- IndoorPay = 10,
- AllInPay = 11,
- PumpTest = 12,
- AllInPayV2 = 13,
- WechatQrScan = 20,
- AliPayQrScan = 21,
- CarPlate = 100,
-
-
-
- DriveOff = 400,
-
-
-
- LeaveOff = 401,
-
-
-
- MembershipPay = 500,
-
-
-
- MembershipMobilePay = 501,
- PetroChinaIC = 600,
- }
- public class TrxCreationResponse
- {
- public Guid Id { get; set; }
- }
- public class ServerSideItem
- {
- public string itemId { get; set; }
- public string BarCode { get; set; }
- public string ItemName { get; set; }
- public decimal Price { get; set; }
- public bool IsFuelItem { get; set; }
- public Guid Id { get; set; }
- }
- public class ServerSideTrxItem
- {
- public int LineNum { get; set; }
- public Guid PosItemId { get; set; }
- public ServerSideItem Item { get; set; }
- public double Qty { get; set; }
- public int FuelItemSoldOnPumpId { get; set; }
- public int FuelItemSoldOnPumpNozzleId { get; set; }
- public string FuelItemFdcTransactionSeqNo { get; set; }
- public decimal FuelItemPumpTotalizerVolume { get; set; }
- }
- public enum ServerSideTrxStatus
- {
- Open,
- Finish
- }
- public enum ServerSideTrxType
- {
- Sale = 0,
- Refund = 1,
- Reconciliation = 2,
- Redemption = 3,
- LogOff = 4,
- LogOn = 5,
- EndOfShift = 6,
- EndOfDay = 7,
- Restore = 8,
- FuelDelivery = 9,
- TankDelivery = 10,
- TankReading = 11
- }
- public class ServerSideTrx
- {
- public Guid Id { get; set; }
- public ServerSideTrxType TransactionType { get; set; }
- public DateTime CreatedDateTime { get; set; }
- public Guid TargetBusinessUnitId { get; set; }
- public decimal NetAmount { get; set; }
- public decimal GrossAmount { get; set; }
- public List<ServerSideTrxItem> Items { get; set; }
- public ServerSideTrxStatus TransactionStatus { get; set; }
- }
- public class ClientFuelTrxInfo
- {
- public PosTrxSource Source { get; set; }
- public int Barcode { get; set; }
- public int PumpId { get; set; }
- public int NozzleId { get; set; }
- public int SiteNozzleNo { get; set; }
-
-
-
- public Guid PosItemId { get; set; }
-
-
-
- public decimal Volume { get; set; }
- public decimal Amount { get; set; }
- public decimal PayAmount { get; set; }
- public decimal UnitPrice { get; set; }
- public int SeqNo { get; set; }
-
-
- public DateTime FuelingStartTime { get; set; }
- public DateTime FuelingFinishedTime { get; set; }
- public decimal VolumeTotalizer { get; set; }
-
-
- }
- public class AuthenticationParameter
- {
- public AuthenticationParameter(string grantType, string userName, string password)
- {
- Params.Clear();
- Params.Add("grant_type", grantType);
- Params.Add("username", userName);
- Params.Add("password", password);
- }
- public Dictionary<string, string> Params { get; } = new Dictionary<string, string>();
- }
- public class CloudCredential
- {
- public string UserName { get; set; }
- public string Password { get; set; }
-
-
-
-
- public string ApiGatewayEntryUrl { get; set; }
-
-
-
- public string DeviceSN { get; set; }
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class BusinessUnit
- {
- [JsonProperty("Id")]
- public Guid Id { get; set; }
- [JsonProperty("Name")]
- public string Name { get; set; }
- }
- public class AuthToken
- {
- #region Standard OAuth token format
-
-
-
- [JsonProperty("access_token")]
- public string AccessToken { get; set; }
-
-
-
- [JsonProperty("token_type")]
- public string TokenType { get; set; }
-
-
-
- [JsonProperty("expires_in")]
- public int ExpiresIn { get; set; }
-
-
-
- [JsonProperty("refresh_token")]
- public string RefreshToken { get; set; }
-
-
-
- [JsonProperty("error")]
- public string Error { get; set; }
- [JsonProperty("userName")]
- public string UserName { get; set; }
- [JsonProperty("alias")]
- public string UserAlias { get; set; }
- [JsonProperty("roleNames")]
- public string RoleNames { get; set; }
- [JsonProperty("BusinessUnits")]
- public string BusinessUnitsJsonString { get; set; }
- public IList<BusinessUnit> BusinessUnitList { get; set; }
- #endregion
- #region Custom extension
-
-
-
- public DateTime TokenRetrievedTime { get; set; }
-
-
-
-
- public bool IsTokenValid()
- {
-
-
- if (DateTime.Now + new TimeSpan(0, 5, 0) < TokenRetrievedTime + new TimeSpan(0, 0, ExpiresIn))
- return true;
- return false;
- }
- #endregion
- }
- public class CloudHelper
- {
- public CloudCredential Credential { get; set; }
- public ILogger Logger { get; set; } = NullLogger.Instance;
- public int Id { get; }
- private string grantType = "password";
- private string tokenAuthPath = "token";
- private string authScheme = "bearer";
- private HttpClient _client = new HttpClient();
- private AuthToken currentAuthToken = null;
- private static CloudHelper instance = new CloudHelper();
- public static CloudHelper Default { get; } = instance;
- private CloudHelper()
- {
- }
- private async Task RefreshAuthTokenAsync(string userName, string password)
- {
- this.Logger.LogDebug("GetTokenAsync...");
- _client.DefaultRequestHeaders.Clear();
- string tokenUrl = string.Concat(this.Credential.ApiGatewayEntryUrl, "/", tokenAuthPath);
- var formParam = new AuthenticationParameter(grantType, userName, password);
- var response = await _client.PostAsync(tokenUrl, new FormUrlEncodedContent(formParam.Params)).ConfigureAwait(false);
- this.Logger.LogDebug($"Response for getting token, Response==null? {response == null}");
- if (response != null && response.IsSuccessStatusCode)
- {
- var resultStr = await response.Content.ReadAsStringAsync();
- this.currentAuthToken = JsonConvert.DeserializeObject<AuthToken>(resultStr);
- if (!string.IsNullOrEmpty(this.currentAuthToken.BusinessUnitsJsonString))
- {
- this.currentAuthToken.BusinessUnitList = JsonConvert.DeserializeObject<IList<BusinessUnit>>(currentAuthToken.BusinessUnitsJsonString);
- return;
- }
- }
- throw new InvalidOperationException($"GetAuthTokenAsync failed(serverUrl: {tokenUrl}, username/pwd: {userName ?? ""}/{password ?? ""}) due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
-
-
-
-
-
- public async Task<T> GeLastTrxWithOpenStatusByUserNameAsync<T>()
- {
- if (this.currentAuthToken == null)
- await this.RefreshAuthTokenAsync(this.Credential.UserName, this.Credential.Password);
- string targetUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/api/transactions/?searchType=lastOpenSaleTrx&searchValue0=userName&searchValue1=", this.Credential.UserName);
- _client.DefaultRequestHeaders.Clear();
- _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, this.currentAuthToken.AccessToken);
- this.Logger.LogDebug($"{_client.DefaultRequestHeaders.Authorization.Scheme}, {_client.DefaultRequestHeaders.Authorization.Parameter}");
-
-
- _client.DefaultRequestHeaders.Add("DeviceSN", this.Credential.DeviceSN);
- var response = await _client.GetAsync(targetUrl).ConfigureAwait(false);
- if (response != null && response.IsSuccessStatusCode)
- {
- var resultStr = await response.Content.ReadAsStringAsync();
- if (string.IsNullOrEmpty(resultStr)) return default(T);
- var jd = JsonDocument.Parse(resultStr);
- return JsonConvert.DeserializeObject<T>(resultStr);
-
- }
- throw new InvalidOperationException($"GeLastOpenTrxByUserNameAsync failed(serverUrl: {targetUrl}, userName: {this.Credential.UserName ?? ""}, deviceSN: {this.Credential?.DeviceSN ?? ""}) due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
- public async Task<PosItem> GetPosItemAsync(string itemId)
- {
- if (this.currentAuthToken == null)
- await this.RefreshAuthTokenAsync(this.Credential.UserName, this.Credential.Password);
- string productItemUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/api/Products/", "itemId/");
- this.Logger.LogDebug("GetPosItemAsync...");
- _client.DefaultRequestHeaders.Clear();
- _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, this.currentAuthToken.AccessToken);
- this.Logger.LogDebug($"{_client.DefaultRequestHeaders.Authorization.Scheme}, {_client.DefaultRequestHeaders.Authorization.Parameter}");
-
-
- _client.DefaultRequestHeaders.Add("DeviceSN", this.Credential.DeviceSN);
-
-
-
- var productUrl = string.Concat(productItemUrl, itemId);
- this.Logger.LogDebug($"item url: {productUrl}");
- var response = await _client.GetAsync(productUrl).ConfigureAwait(false);
- if (response != null && response.IsSuccessStatusCode)
- {
- var resultStr = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<PosItem>(resultStr);
- }
- throw new InvalidOperationException($"GetPosItemAsync failed(serverUrl: {productItemUrl}, itemId: {itemId}, deviceSN: {this.Credential?.DeviceSN ?? ""}) due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
- public async Task<JsonElement> GetAccountIdByVBaoBeaconIdAsync(string beaconId)
- {
- if (this.currentAuthToken == null)
- await this.RefreshAuthTokenAsync(this.Credential.UserName, this.Credential.Password);
- string targetUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/userinfo/", "vBaoId?vBaoId=", beaconId);
- _client.DefaultRequestHeaders.Clear();
- _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, this.currentAuthToken.AccessToken);
- this.Logger.LogDebug($"{_client.DefaultRequestHeaders.Authorization.Scheme}, {_client.DefaultRequestHeaders.Authorization.Parameter}");
-
-
- _client.DefaultRequestHeaders.Add("DeviceSN", this.Credential.DeviceSN);
- var response = await _client.GetAsync(targetUrl).ConfigureAwait(false);
- if (response != null && response.IsSuccessStatusCode)
- {
- var resultStr = await response.Content.ReadAsStringAsync();
- var jd = JsonDocument.Parse(resultStr);
- return jd.RootElement.GetProperty("result");
- }
- throw new InvalidOperationException($"GetAccountIdByVBaoBeaconIdAsync failed due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
- public async Task<Guid> CreateTransactionAsync(ClientFuelTrxInfo clientFuelTrxInfo, string trxComment)
- {
- if (this.currentAuthToken == null)
- await this.RefreshAuthTokenAsync(this.Credential.UserName, this.Credential.Password);
- Guid trxId = Guid.Empty;
- var trxUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/api/transactions/");
- var clientPosTrx = new ClientPosTrx
- {
- RequestingCreationTimeInPosClient = DateTime.Now,
- Type = PosTrxType.Sale,
- Source = clientFuelTrxInfo.Source,
- Items = new List<ClientRingUpPosItem>
- {
- new ClientRingUpPosItem
- {
- PosItemUniqueId = clientFuelTrxInfo.PosItemId,
- Qty = clientFuelTrxInfo.Volume,
- ClientRingUpTime = DateTime.Now,
- FuelItemSoldOnPumpId = clientFuelTrxInfo.PumpId,
- FuelItemSoldOnPumpNozzleId = clientFuelTrxInfo.SiteNozzleNo,
- FuelItemOriginalGrossAmount = clientFuelTrxInfo.Amount,
- FuelItemFdcTransactionSeqNo = Convert.ToString(clientFuelTrxInfo.SeqNo),
- fuelItemTransactionEndTime = clientFuelTrxInfo.FuelingFinishedTime,
- TransactionComment = trxComment,
- FuelItemPumpTotalizerVolume = clientFuelTrxInfo.VolumeTotalizer
- }
- }
- };
- _client.DefaultRequestHeaders.Clear();
- _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, currentAuthToken.AccessToken);
- _client.DefaultRequestHeaders.Add("DeviceSN", this.Credential.DeviceSN);
-
- var response = await _client.PostAsJsonAsync(trxUrl, clientPosTrx).ConfigureAwait(false);
- if (response != null && response.IsSuccessStatusCode)
- {
- var resultStr = await response.Content.ReadAsStringAsync();
- var trxCreationResponse = JsonConvert.DeserializeObject<TrxCreationResponse>(resultStr);
- return trxCreationResponse.Id;
- }
- throw new InvalidOperationException($"CreateTransactionAsync failed(serverUrl: {trxUrl}, trx volume: {clientFuelTrxInfo?.Volume ?? -1 }, deviceSN: {this.Credential?.DeviceSN ?? ""}) due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
- public async Task<bool> CommitTransactionAsync(Guid trxId, PosTrxMop posTrxMop, string accountId)
- {
- if (this.currentAuthToken == null)
- await this.RefreshAuthTokenAsync(this.Credential.UserName, this.Credential.Password);
- string targetUrl = "";
- if (string.IsNullOrEmpty(accountId))
- targetUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/api/transactions/", trxId, "/payment");
- else
- targetUrl = string.Concat(this.Credential.ApiGatewayEntryUrl + "/api/transactions/", trxId, "/payment?accountId=", accountId);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- _client.DefaultRequestHeaders.Clear();
- _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, currentAuthToken.AccessToken);
- _client.DefaultRequestHeaders.Add("DeviceSN", this.Credential.DeviceSN);
-
- var response = await _client.PostAsJsonAsync(targetUrl, posTrxMop).ConfigureAwait(false);
- if (response != null && response.IsSuccessStatusCode)
- return true;
- throw new InvalidOperationException($"CommitTransactionAsync failed(serverUrl: {targetUrl}, deviceSN: {this.Credential?.DeviceSN ?? ""}) due to response with code: {response?.StatusCode.ToString() ?? "-1"}, message: {response?.ReasonPhrase ?? ""}");
- }
- }
- }
|