-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathCieloApi.cs
532 lines (459 loc) · 19.9 KB
/
CieloApi.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
using Cielo.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Cielo
{
public class CieloApi
{
private readonly static HttpClient _http = new HttpClient();
/// <summary>
/// Tempo para TimeOut da requisição, por default é 60 segundos
/// </summary>
private int _timeOut = 0;
public Merchant Merchant { get; }
public ISerializerJSON SerializerJSON { get; }
public CieloEnvironment Environment { get; }
static CieloApi()
{
_http.DefaultRequestHeaders.ExpectContinue = false;
/*
O proxy pode ser definido no Web.config ou App.config da sua aplicação
*/
}
/// <summary>
///
/// </summary>
/// <param name="environment"></param>
/// <param name="merchant"></param>
/// <param name="serializer">Crie o seu Provider Json</param>
/// <param name="timeOut">Tempo para TimeOut da requisição, por default é 60 segundos</param>
public CieloApi(CieloEnvironment environment, Merchant merchant, ISerializerJSON serializer, int timeOut = 60000, SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls12)
{
Environment = environment;
Merchant = merchant;
SerializerJSON = serializer;
_timeOut = timeOut;
ServicePointManager.SecurityProtocol = securityProtocolType;
}
/// <summary>
///
/// </summary>
/// <param name="merchant"></param>
/// <param name="serializer">Crie o seu Provider Json</param>
/// <param name="timeOut">Tempo para TimeOut da requisição, por default é 60 segundos</param>
public CieloApi(Merchant merchant, ISerializerJSON serializer, int timeOut = 60000)
: this(CieloEnvironment.PRODUCTION, merchant, serializer, timeOut) { }
private IDictionary<string, string> GetHeaders(Guid requestId)
{
return new Dictionary<string, string>
{
{ "RequestId", requestId.ToString() }
};
}
private async Task<HttpResponseMessage> CreateRequestAsync(string resource, Method method = Method.GET, IDictionary<string, string> headers = null)
{
return await CreateRequestAsync<object>(resource, null, method, headers);
}
private async Task<HttpResponseMessage> CreateRequestAsync<T>(string resource, T value, Method method = Method.POST, IDictionary<string, string> headers = null)
{
StringContent content = null;
if (value != null)
{
string json = SerializerJSON.Serialize<T>(value);
content = new StringContent(json, Encoding.UTF8, "application/json");
}
return await ExecuteAsync(resource, headers, method, content);
}
private async Task<HttpResponseMessage> ExecuteAsync(string fullUrl, IDictionary<string, string> headers = null, Method method = Method.POST, StringContent content = null)
{
if (headers == null)
{
headers = new Dictionary<string, string>(2);
}
headers.Add("MerchantId", Merchant.Id.ToString());
headers.Add("MerchantKey", Merchant.Key);
var tokenSource = new CancellationTokenSource(_timeOut);
try
{
HttpMethod httpMethod = null;
if (method == Method.POST)
{
httpMethod = HttpMethod.Post;
if (headers != null)
{
foreach (var item in headers)
{
content.Headers.Add(item.Key, item.Value);
}
}
}
else if (method == Method.GET)
{
httpMethod = HttpMethod.Get;
}
else if (method == Method.PUT)
{
httpMethod = HttpMethod.Put;
}
else if (method == Method.DELETE)
{
httpMethod = HttpMethod.Delete;
}
var request = GetExecute(fullUrl, headers, httpMethod, content);
return await _http.SendAsync(request, tokenSource.Token).ConfigureAwait(false);
}
catch (OperationCanceledException e)
{
throw new CancellationTokenException(e);
}
finally
{
tokenSource.Dispose();
}
}
private static HttpRequestMessage GetExecute(string fullUrl, IEnumerable<KeyValuePair<string, string>> headers, HttpMethod method, StringContent content = null)
{
var request = new HttpRequestMessage(method, fullUrl)
{
Content = content
};
if (method != HttpMethod.Post)
{
foreach (var item in headers)
{
request.Headers.Add(item.Key, item.Value);
}
}
return request;
}
private async Task<T> GetResponseAsync<T>(HttpResponseMessage response)
{
await CheckResponseAsync(response);
return SerializerJSON.Deserialize<T>(response.Content);
}
private async Task CheckResponseAsync(HttpResponseMessage response)
{
if (!response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new CieloException($"Error code {response.StatusCode}.", result, this.SerializerJSON);
}
}
/// <summary>
/// Envia uma transação
/// </summary>
/// <param name="requestId"></param>
/// <param name="transaction"></param>
/// <returns></returns>
public async Task<Transaction> CreateTransactionAsync(Guid requestId, Transaction transaction)
{
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(Environment.GetTransactionUrl("/1/sales/"), transaction, Method.POST, headers);
return await GetResponseAsync<Transaction>(response);
}
/// <summary>
/// Consulta uma transação
/// </summary>
/// <param name="paymentId"></param>
/// <returns></returns>
public async Task<Transaction> GetTransactionAsync(Guid paymentId)
{
return await GetTransactionAsync(Guid.NewGuid(), paymentId);
}
/// <summary>
/// Consulta uma transação
/// </summary>
/// <param name="requestId"></param>
/// <param name="paymentId"></param>
/// <returns></returns>
public async Task<Transaction> GetTransactionAsync(Guid requestId, Guid paymentId)
{
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(Environment.GetQueryUrl($"/1/sales/{paymentId}"), Method.GET, headers);
return await GetResponseAsync<Transaction>(response);
}
/// <summary>
/// Consulta uma transação
/// </summary>
/// <param name="requestId"></param>
/// <param name="paymentId"></param>
/// <returns></returns>
public async Task<ReturnRecurrentPayment> GetRecurrentPaymentAsync(Guid requestId, Guid recurrentPaymentId)
{
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(Environment.GetQueryUrl($"/1/RecurrentPayment/{recurrentPaymentId}"), Method.GET, headers);
return await GetResponseAsync<ReturnRecurrentPayment>(response);
}
/// <summary>
/// Cancela uma transação (parcial ou total)
/// </summary>
/// <param name="requestId"></param>
/// <param name="paymentId"></param>
/// <param name="amount"></param>
/// <returns></returns>
public async Task<ReturnStatus> CancelTransactionAsync(Guid requestId, Guid paymentId, decimal? amount = null)
{
var url = Environment.GetTransactionUrl($"/1/sales/{paymentId}/void");
if (amount.HasValue)
{
url += $"?Amount={NumberHelper.DecimalToInteger(amount)}";
}
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(url, Method.PUT, headers);
return await GetResponseAsync<ReturnStatus>(response);
}
/// <summary>
/// Captura uma transação (parcial ou total)
/// </summary>
/// <param name="requestId"></param>
/// <param name="paymentId"></param>
/// <param name="amount"></param>
/// <param name="serviceTaxAmount"></param>
/// <returns></returns>
public async Task<ReturnStatus> CaptureTransactionAsync(Guid requestId, Guid paymentId, decimal? amount = null, decimal? serviceTaxAmount = null)
{
var url = Environment.GetTransactionUrl($"/1/sales/{paymentId}/capture");
if (amount.HasValue)
{
url += $"?Amount={NumberHelper.DecimalToInteger(amount)}";
}
if (serviceTaxAmount.HasValue)
{
url += $"?SeviceTaxAmount={NumberHelper.DecimalToInteger(serviceTaxAmount)}";
}
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(url, Method.PUT, headers);
return await GetResponseAsync<ReturnStatus>(response);
}
/// <summary>
/// Ativa uma recorrência
/// </summary>
/// <param name="requestId"></param>
/// <param name="recurrentPaymentId"></param>
/// <exception cref="CieloException">Ocorreu algum erro ao tentar alterar a recorrência</exception>
/// <returns></returns>
public async Task<bool> ActivateRecurrentAsync(Guid requestId, Guid recurrentPaymentId)
{
return await ManagerRecurrent(requestId, recurrentPaymentId, true);
}
/// <summary>
/// Desativa uma recorrência
/// </summary>
/// <param name="requestId"></param>
/// <param name="recurrentPaymentId"></param>
/// <exception cref="CieloException">Ocorreu algum erro ao tentar alterar a recorrência</exception>
/// <returns></returns>
public async Task<bool> DeactivateRecurrentAsync(Guid requestId, Guid recurrentPaymentId)
{
return await ManagerRecurrent(requestId, recurrentPaymentId, false);
}
/// <summary>
/// Cria uma Token de um cartão válido ou não.
/// </summary>
/// <param name="requestId"></param>
/// <param name="recurrentPaymentId"></param>
/// <param name="active">Parâmetro que define se uma recorrência será desativada ou ativada novamente</param>
/// <exception cref="CieloException">Ocorreu algum erro ao tentar alterar a recorrência</exception>
/// <returns>Se retornou true é porque a operação foi realizada com sucesso</returns>
public async Task<ReturnStatusLink> CreateTokenAsync(Guid requestId, Card card)
{
card.CustomerName = card.Holder;
card.SecurityCode = string.Empty;
var url = Environment.GetTransactionUrl($"/1/Card");
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(url, card, Method.POST, headers);
//Se tiver errado será levantado uma exceção
return await GetResponseAsync<ReturnStatusLink>(response);
}
/// <summary>
/// Faz pagamento de 1 real e cancela logo em seguida para testar se o cartão é válido.
/// Gera token somente de cartão válido
/// </summary>
/// <param name="requestId"></param>
/// <param name="card"></param>
/// <returns></returns>
public async Task<ReturnStatusLink> CreateTokenValidAsync(Guid requestId, Card creditCard, string softDescriptor = "Validando", Currency currency = Currency.BRL)
{
creditCard.SaveCard = true;
creditCard.CustomerName = creditCard.Holder;
var customer = new Customer(creditCard.CustomerName);
var payment = new Payment(amount: 1,
currency: currency,
paymentType: PaymentType.CreditCard,
installments: 1,
capture: true,
recurrentPayment: null,
softDescriptor: softDescriptor,
card: creditCard,
returnUrl: string.Empty);
var transaction = new Transaction(Guid.NewGuid().ToString(), customer, payment);
var result = await CreateTransactionAsync(requestId, transaction);
var status = result.Payment.GetStatus();
if (status == Status.Authorized || status == Status.PaymentConfirmed)
{
//Cancelando pagamento de 1 REAL
var resultCancel = await CancelTransactionAsync(Guid.NewGuid(), result.Payment.PaymentId.Value, 1);
var status2 = resultCancel.GetStatus();
if (status2 != Status.Voided)
{
return new ReturnStatusLink
{
ReturnCode = resultCancel.ReturnCode,
ReturnMessage = resultCancel.ReturnMessage,
Status = resultCancel.Status,
Links = resultCancel.Links.FirstOrDefault()
};
}
}
else
{
return new ReturnStatusLink
{
ReturnCode = result.Payment.ReturnCode,
ReturnMessage = result.Payment.ReturnMessage,
Status = result.Payment.Status,
Links = result.Payment.Links.FirstOrDefault()
};
}
var token = result.Payment.CreditCard.CardToken.HasValue ? result.Payment.CreditCard.CardToken.Value.ToString() : string.Empty;
var statusLink = new ReturnStatusLink
{
CardToken = token,
ReturnCode = result.Payment.ReturnCode,
ReturnMessage = result.Payment.ReturnMessage,
Status = result.Payment.Status,
Links = result.Payment.Links.FirstOrDefault()
};
return statusLink;
}
/// <summary>
///
/// </summary>
/// <param name="requestId"></param>
/// <param name="recurrentPaymentId"></param>
/// <param name="active">Parâmetro que define se uma recorrência será desativada ou ativada novamente</param>
/// <exception cref="CieloException">Ocorreu algum erro ao tentar alterar a recorrência</exception>
/// <returns>Se retornou true é porque a operação foi realizada com sucesso</returns>
private async Task<bool> ManagerRecurrent(Guid requestId, Guid recurrentPaymentId, bool active)
{
var url = Environment.GetTransactionUrl($"/1/RecurrentPayment/{recurrentPaymentId}/Deactivate");
if (active)
{
//Ativar uma recorrência novamente
url = Environment.GetTransactionUrl($"/1/RecurrentPayment/{recurrentPaymentId}/Reactivate");
}
var headers = GetHeaders(requestId);
var response = await CreateRequestAsync(url, Method.PUT, headers);
//Se tiver errado será levantado uma exceção
await CheckResponseAsync(response);
return true;
}
#region Método Sincronos
/// <summary>
/// Cria uma Token de um cartão válido ou não.
/// </summary>
/// <param name="requestId"></param>
/// <param name="card"></param>
/// <returns></returns>
public ReturnStatusLink CreateToken(Guid requestId, Card card)
{
return RunTask(() =>
{
return CreateTokenAsync(requestId, card);
});
}
public ReturnRecurrentPayment GetRecurrentPayment(Guid requestId, Guid recurrentPaymentId)
{
return RunTask(() =>
{
return GetRecurrentPaymentAsync(requestId, recurrentPaymentId);
});
}
/// <summary>
///
/// </summary>
/// <param name="requestId"></param>
/// <param name="creditCard"></param>
/// <param name="softDescriptor"></param>
/// <param name="currency"></param>
/// <returns></returns>
public ReturnStatusLink CreateTokenValid(Guid requestId, Card creditCard, string softDescriptor = "Validando", Currency currency = Currency.BRL)
{
return RunTask(() =>
{
return CreateTokenValidAsync(requestId, creditCard, softDescriptor, currency);
});
}
public ReturnStatus CaptureTransaction(Guid requestId, Guid paymentId, decimal? amount = null, decimal? serviceTaxAmount = null)
{
return RunTask(() =>
{
return CaptureTransactionAsync(requestId, paymentId, amount, serviceTaxAmount);
});
}
public bool ActivateRecurrent(Guid requestId, Guid recurrentPaymentId)
{
return RunTask(() =>
{
return ActivateRecurrentAsync(requestId, recurrentPaymentId);
});
}
public bool DeactivateRecurrent(Guid requestId, Guid recurrentPaymentId)
{
return RunTask(() =>
{
return DeactivateRecurrentAsync(requestId, recurrentPaymentId);
});
}
public ReturnStatus CancelTransaction(Guid requestId, Guid paymentId, decimal? amount = null)
{
return RunTask(() =>
{
return CancelTransactionAsync(requestId, paymentId, amount);
});
}
public Transaction GetTransaction(Guid requestId, Guid paymentId)
{
return RunTask(() =>
{
return GetTransactionAsync(requestId, paymentId);
});
}
public Transaction GetTransaction(Guid paymentId)
{
return RunTask(() =>
{
return GetTransactionAsync(paymentId);
});
}
public Transaction CreateTransaction(Guid requestId, Transaction transaction)
{
return RunTask(() =>
{
return CreateTransactionAsync(requestId, transaction);
});
}
private static TResult RunTask<TResult>(Func<Task<TResult>> method)
{
try
{
return Task.Run(() => method()).Result;
}
catch (Exception e)
{
if (e.InnerException is CieloException ex)
{
throw ex;
}
throw e;
}
}
#endregion
}
}