2018-08-30 18:34:39 +02:00
|
|
|
|
using System;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using System.Collections.Generic;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
using System.Linq;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using BTCPayServer.Data;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using BTCPayServer.Logging;
|
|
|
|
|
using BTCPayServer.Models;
|
|
|
|
|
using BTCPayServer.Payments;
|
|
|
|
|
using BTCPayServer.Rating;
|
|
|
|
|
using BTCPayServer.Security;
|
2017-10-20 21:06:37 +02:00
|
|
|
|
using BTCPayServer.Services.Invoices;
|
2017-09-15 09:06:57 +02:00
|
|
|
|
using BTCPayServer.Services.Rates;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using BTCPayServer.Services.Stores;
|
2017-09-15 09:06:57 +02:00
|
|
|
|
using BTCPayServer.Services.Wallets;
|
2018-11-06 08:08:42 +01:00
|
|
|
|
using BTCPayServer.Validation;
|
2018-08-30 18:34:39 +02:00
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using NBitcoin;
|
|
|
|
|
using NBitpayClient;
|
|
|
|
|
using Newtonsoft.Json;
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Controllers
|
|
|
|
|
{
|
2017-10-27 10:53:04 +02:00
|
|
|
|
public partial class InvoiceController : Controller
|
|
|
|
|
{
|
|
|
|
|
InvoiceRepository _InvoiceRepository;
|
2018-07-12 10:38:21 +02:00
|
|
|
|
ContentSecurityPolicies _CSP;
|
2018-08-22 09:53:40 +02:00
|
|
|
|
RateFetcher _RateProvider;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
StoreRepository _StoreRepository;
|
|
|
|
|
UserManager<ApplicationUser> _UserManager;
|
2017-10-27 11:58:43 +02:00
|
|
|
|
private CurrencyNameTable _CurrencyNameTable;
|
2017-12-17 11:58:55 +01:00
|
|
|
|
EventAggregator _EventAggregator;
|
2017-12-21 07:52:04 +01:00
|
|
|
|
BTCPayNetworkProvider _NetworkProvider;
|
2018-02-20 04:45:04 +01:00
|
|
|
|
private readonly BTCPayWalletProvider _WalletProvider;
|
|
|
|
|
IServiceProvider _ServiceProvider;
|
|
|
|
|
public InvoiceController(
|
|
|
|
|
IServiceProvider serviceProvider,
|
|
|
|
|
InvoiceRepository invoiceRepository,
|
2017-10-27 11:58:43 +02:00
|
|
|
|
CurrencyNameTable currencyNameTable,
|
2017-10-27 10:53:04 +02:00
|
|
|
|
UserManager<ApplicationUser> userManager,
|
2018-08-22 09:53:40 +02:00
|
|
|
|
RateFetcher rateProvider,
|
2017-10-27 10:53:04 +02:00
|
|
|
|
StoreRepository storeRepository,
|
2017-12-17 11:58:55 +01:00
|
|
|
|
EventAggregator eventAggregator,
|
2018-02-20 04:45:04 +01:00
|
|
|
|
BTCPayWalletProvider walletProvider,
|
2018-07-12 10:38:21 +02:00
|
|
|
|
ContentSecurityPolicies csp,
|
2018-02-20 04:45:04 +01:00
|
|
|
|
BTCPayNetworkProvider networkProvider)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
2018-02-20 04:45:04 +01:00
|
|
|
|
_ServiceProvider = serviceProvider;
|
2017-10-27 11:58:43 +02:00
|
|
|
|
_CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable));
|
2017-10-27 10:53:04 +02:00
|
|
|
|
_StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository));
|
|
|
|
|
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
2018-05-02 20:32:42 +02:00
|
|
|
|
_RateProvider = rateProvider ?? throw new ArgumentNullException(nameof(rateProvider));
|
2017-10-27 10:53:04 +02:00
|
|
|
|
_UserManager = userManager;
|
2017-12-17 11:58:55 +01:00
|
|
|
|
_EventAggregator = eventAggregator;
|
2017-12-21 07:52:04 +01:00
|
|
|
|
_NetworkProvider = networkProvider;
|
2018-02-20 04:45:04 +01:00
|
|
|
|
_WalletProvider = walletProvider;
|
2018-07-12 10:38:21 +02:00
|
|
|
|
_CSP = csp;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2017-12-21 07:52:04 +01:00
|
|
|
|
|
2018-01-17 07:11:05 +01:00
|
|
|
|
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
|
2017-10-27 10:53:04 +02:00
|
|
|
|
{
|
2018-09-08 07:32:26 +02:00
|
|
|
|
if (!store.HasClaim(Policies.CanCreateInvoice.Key))
|
|
|
|
|
throw new UnauthorizedAccessException();
|
2018-07-24 05:19:43 +02:00
|
|
|
|
InvoiceLogs logs = new InvoiceLogs();
|
|
|
|
|
logs.Write("Creation of invoice starting");
|
2017-10-27 10:53:04 +02:00
|
|
|
|
var entity = new InvoiceEntity
|
|
|
|
|
{
|
2018-01-06 10:57:56 +01:00
|
|
|
|
InvoiceTime = DateTimeOffset.UtcNow
|
2017-10-27 10:53:04 +02:00
|
|
|
|
};
|
2018-01-06 10:57:56 +01:00
|
|
|
|
|
2017-12-21 07:52:04 +01:00
|
|
|
|
var storeBlob = store.GetStoreBlob();
|
2017-10-27 10:53:04 +02:00
|
|
|
|
Uri notificationUri = Uri.IsWellFormedUriString(invoice.NotificationURL, UriKind.Absolute) ? new Uri(invoice.NotificationURL, UriKind.Absolute) : null;
|
|
|
|
|
if (notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
|
|
|
|
|
notificationUri = null;
|
|
|
|
|
EmailAddressAttribute emailValidator = new EmailAddressAttribute();
|
2018-01-17 07:11:05 +01:00
|
|
|
|
entity.ExpirationTime = entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration);
|
2017-12-03 06:43:52 +01:00
|
|
|
|
entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
entity.OrderId = invoice.OrderId;
|
|
|
|
|
entity.ServerUrl = serverUrl;
|
2018-01-07 20:14:35 +01:00
|
|
|
|
entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications;
|
|
|
|
|
entity.ExtendedNotifications = invoice.ExtendedNotifications;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
entity.NotificationURL = notificationUri?.AbsoluteUri;
|
2018-10-12 03:09:13 +02:00
|
|
|
|
entity.NotificationEmail = invoice.NotificationEmail;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
entity.BuyerInformation = Map<Invoice, BuyerInformation>(invoice);
|
2018-05-04 16:15:34 +02:00
|
|
|
|
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
//Another way of passing buyer info to support
|
|
|
|
|
FillBuyerInfo(invoice.Buyer, entity.BuyerInformation);
|
|
|
|
|
if (entity?.BuyerInformation?.BuyerEmail != null)
|
|
|
|
|
{
|
|
|
|
|
if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail))
|
|
|
|
|
throw new BitpayHttpException(400, "Invalid email");
|
|
|
|
|
entity.RefundMail = entity.BuyerInformation.BuyerEmail;
|
|
|
|
|
}
|
|
|
|
|
entity.ProductInformation = Map<Invoice, ProductInformation>(invoice);
|
|
|
|
|
entity.RedirectURL = invoice.RedirectURL ?? store.StoreWebsite;
|
2018-05-24 16:54:48 +02:00
|
|
|
|
if (!Uri.IsWellFormedUriString(entity.RedirectURL, UriKind.Absolute))
|
|
|
|
|
entity.RedirectURL = null;
|
|
|
|
|
|
2018-12-10 13:48:28 +01:00
|
|
|
|
entity.Status = InvoiceStatus.New;
|
2017-10-27 10:53:04 +02:00
|
|
|
|
entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);
|
2017-11-12 15:23:21 +01:00
|
|
|
|
|
2018-05-02 20:32:42 +02:00
|
|
|
|
HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>();
|
|
|
|
|
var rules = storeBlob.GetRateRules(_NetworkProvider);
|
2018-07-27 13:37:16 +02:00
|
|
|
|
var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()
|
2018-05-02 20:32:42 +02:00
|
|
|
|
foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider)
|
2018-07-27 13:37:16 +02:00
|
|
|
|
.Where(s => !excludeFilter.Match(s.PaymentId))
|
|
|
|
|
.Select(c => _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode))
|
2018-05-02 20:32:42 +02:00
|
|
|
|
.Where(c => c != null))
|
|
|
|
|
{
|
|
|
|
|
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, invoice.Currency));
|
|
|
|
|
if (storeBlob.LightningMaxValue != null)
|
|
|
|
|
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, storeBlob.LightningMaxValue.Currency));
|
|
|
|
|
if (storeBlob.OnChainMinValue != null)
|
|
|
|
|
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, storeBlob.OnChainMinValue.Currency));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rateRules = storeBlob.GetRateRules(_NetworkProvider);
|
|
|
|
|
var fetchingByCurrencyPair = _RateProvider.FetchRates(currencyPairsToFetch, rateRules);
|
|
|
|
|
|
2018-07-24 05:19:43 +02:00
|
|
|
|
var fetchingAll = WhenAllFetched(logs, fetchingByCurrencyPair);
|
2018-03-28 15:37:01 +02:00
|
|
|
|
var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider)
|
2018-07-27 13:37:16 +02:00
|
|
|
|
.Where(s => !excludeFilter.Match(s.PaymentId))
|
2018-03-28 15:37:01 +02:00
|
|
|
|
.Select(c =>
|
|
|
|
|
(Handler: (IPaymentMethodHandler)_ServiceProvider.GetService(typeof(IPaymentMethodHandler<>).MakeGenericType(c.GetType())),
|
|
|
|
|
SupportedPaymentMethod: c,
|
|
|
|
|
Network: _NetworkProvider.GetNetwork(c.PaymentId.CryptoCode)))
|
|
|
|
|
.Where(c => c.Network != null)
|
|
|
|
|
.Select(o =>
|
|
|
|
|
(SupportedPaymentMethod: o.SupportedPaymentMethod,
|
2018-07-24 05:19:43 +02:00
|
|
|
|
PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler, o.SupportedPaymentMethod, o.Network, entity, store, logs)))
|
2018-03-28 15:37:01 +02:00
|
|
|
|
.ToList();
|
2018-03-25 18:57:44 +02:00
|
|
|
|
List<ISupportedPaymentMethod> supported = new List<ISupportedPaymentMethod>();
|
2018-03-28 15:37:01 +02:00
|
|
|
|
var paymentMethods = new PaymentMethodDictionary();
|
|
|
|
|
foreach (var o in supportedPaymentMethods)
|
2018-02-20 04:45:04 +01:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
var paymentMethod = await o.PaymentMethod;
|
|
|
|
|
if (paymentMethod == null)
|
|
|
|
|
continue;
|
|
|
|
|
supported.Add(o.SupportedPaymentMethod);
|
|
|
|
|
paymentMethods.Add(paymentMethod);
|
2018-03-25 18:57:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 15:37:01 +02:00
|
|
|
|
if (supported.Count == 0)
|
2018-03-25 18:57:44 +02:00
|
|
|
|
{
|
2018-03-28 15:37:01 +02:00
|
|
|
|
StringBuilder errors = new StringBuilder();
|
|
|
|
|
errors.AppendLine("No payment method available for this store");
|
2018-07-24 05:19:43 +02:00
|
|
|
|
foreach (var error in logs.ToList())
|
2018-03-28 15:37:01 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
errors.AppendLine(error.ToString());
|
2018-03-28 15:37:01 +02:00
|
|
|
|
}
|
|
|
|
|
throw new BitpayHttpException(400, errors.ToString());
|
2017-12-21 07:52:04 +01:00
|
|
|
|
}
|
2018-03-25 18:57:44 +02:00
|
|
|
|
|
|
|
|
|
entity.SetSupportedPaymentMethods(supported);
|
|
|
|
|
entity.SetPaymentMethods(paymentMethods);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
entity.PosData = invoice.PosData;
|
2018-07-24 05:19:43 +02:00
|
|
|
|
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, logs, _NetworkProvider);
|
|
|
|
|
await fetchingAll;
|
2018-06-21 07:15:36 +02:00
|
|
|
|
_EventAggregator.Publish(new Events.InvoiceEvent(entity.EntityToDTO(_NetworkProvider), 1001, "invoice_created"));
|
2017-12-21 07:52:04 +01:00
|
|
|
|
var resp = entity.EntityToDTO(_NetworkProvider);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
|
2018-07-24 05:19:43 +02:00
|
|
|
|
private Task WhenAllFetched(InvoiceLogs logs, Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair)
|
2018-03-28 15:37:01 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
return Task.WhenAll(fetchingByCurrencyPair.Select(async pair =>
|
2018-03-28 16:15:10 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
var rateResult = await pair.Value;
|
|
|
|
|
logs.Write($"{pair.Key}: The rating rule is {rateResult.Rule}");
|
|
|
|
|
logs.Write($"{pair.Key}: The evaluated rating rule is {rateResult.EvaluatedRule}");
|
|
|
|
|
if (rateResult.Errors.Count != 0)
|
|
|
|
|
{
|
|
|
|
|
var allRateRuleErrors = string.Join(", ", rateResult.Errors.ToArray());
|
|
|
|
|
logs.Write($"{pair.Key}: Rate rule error ({allRateRuleErrors})");
|
|
|
|
|
}
|
2018-08-22 17:24:33 +02:00
|
|
|
|
foreach (var ex in rateResult.ExchangeExceptions)
|
2018-07-24 05:19:43 +02:00
|
|
|
|
{
|
2018-08-22 17:24:33 +02:00
|
|
|
|
logs.Write($"{pair.Key}: Exception reaching exchange {ex.ExchangeName} ({ex.Exception.Message})");
|
2018-07-24 05:19:43 +02:00
|
|
|
|
}
|
|
|
|
|
}).ToArray());
|
|
|
|
|
}
|
2018-04-03 10:39:28 +02:00
|
|
|
|
|
2018-07-24 05:19:43 +02:00
|
|
|
|
private async Task<PaymentMethod> CreatePaymentMethodAsync(Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair, IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network, InvoiceEntity entity, StoreData store, InvoiceLogs logs)
|
|
|
|
|
{
|
|
|
|
|
try
|
2018-04-03 10:39:28 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
var storeBlob = store.GetStoreBlob();
|
2018-08-21 06:54:52 +02:00
|
|
|
|
var preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network);
|
2018-07-24 05:19:43 +02:00
|
|
|
|
var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.ProductInformation.Currency)];
|
2018-07-27 11:04:41 +02:00
|
|
|
|
if (rate.BidAsk == null)
|
2018-07-24 05:19:43 +02:00
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
PaymentMethod paymentMethod = new PaymentMethod();
|
|
|
|
|
paymentMethod.ParentEntity = entity;
|
|
|
|
|
paymentMethod.Network = network;
|
|
|
|
|
paymentMethod.SetId(supportedPaymentMethod.PaymentId);
|
2018-07-27 11:04:41 +02:00
|
|
|
|
paymentMethod.Rate = rate.BidAsk.Bid;
|
2018-08-21 06:54:52 +02:00
|
|
|
|
var paymentDetails = await handler.CreatePaymentMethodDetails(supportedPaymentMethod, paymentMethod, store, network, preparePayment);
|
2018-07-24 05:19:43 +02:00
|
|
|
|
paymentMethod.SetPaymentMethodDetails(paymentDetails);
|
|
|
|
|
|
|
|
|
|
Func<Money, Money, bool> compare = null;
|
|
|
|
|
CurrencyValue limitValue = null;
|
|
|
|
|
string errorMessage = null;
|
|
|
|
|
if (supportedPaymentMethod.PaymentId.PaymentType == PaymentTypes.LightningLike &&
|
|
|
|
|
storeBlob.LightningMaxValue != null)
|
|
|
|
|
{
|
|
|
|
|
compare = (a, b) => a > b;
|
|
|
|
|
limitValue = storeBlob.LightningMaxValue;
|
|
|
|
|
errorMessage = "The amount of the invoice is too high to be paid with lightning";
|
|
|
|
|
}
|
|
|
|
|
else if (supportedPaymentMethod.PaymentId.PaymentType == PaymentTypes.BTCLike &&
|
|
|
|
|
storeBlob.OnChainMinValue != null)
|
2018-03-28 16:15:10 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
compare = (a, b) => a < b;
|
|
|
|
|
limitValue = storeBlob.OnChainMinValue;
|
|
|
|
|
errorMessage = "The amount of the invoice is too low to be paid on chain";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (compare != null)
|
|
|
|
|
{
|
|
|
|
|
var limitValueRate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, limitValue.Currency)];
|
2018-07-27 11:04:41 +02:00
|
|
|
|
if (limitValueRate.BidAsk != null)
|
2018-05-02 20:32:42 +02:00
|
|
|
|
{
|
2018-07-27 11:04:41 +02:00
|
|
|
|
var limitValueCrypto = Money.Coins(limitValue.Value / limitValueRate.BidAsk.Bid);
|
2018-07-24 05:19:43 +02:00
|
|
|
|
if (compare(paymentMethod.Calculate().Due, limitValueCrypto))
|
|
|
|
|
{
|
|
|
|
|
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: {errorMessage}");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2018-05-02 20:32:42 +02:00
|
|
|
|
}
|
2018-03-28 16:15:10 +02:00
|
|
|
|
}
|
2018-07-24 05:19:43 +02:00
|
|
|
|
///////////////
|
2018-03-28 16:15:10 +02:00
|
|
|
|
|
|
|
|
|
|
2018-03-28 15:37:01 +02:00
|
|
|
|
#pragma warning disable CS0618
|
2018-07-24 05:19:43 +02:00
|
|
|
|
if (paymentMethod.GetId().IsBTCOnChain)
|
|
|
|
|
{
|
2019-01-05 05:31:05 +01:00
|
|
|
|
entity.TxFee = paymentMethod.NetworkFee;
|
2018-07-24 05:19:43 +02:00
|
|
|
|
entity.Rate = paymentMethod.Rate;
|
|
|
|
|
entity.DepositAddress = paymentMethod.DepositAddress;
|
|
|
|
|
}
|
|
|
|
|
#pragma warning restore CS0618
|
|
|
|
|
return paymentMethod;
|
|
|
|
|
}
|
|
|
|
|
catch (PaymentMethodUnavailableException ex)
|
2018-03-28 15:37:01 +02:00
|
|
|
|
{
|
2018-07-24 05:19:43 +02:00
|
|
|
|
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})");
|
2018-03-28 15:37:01 +02:00
|
|
|
|
}
|
2018-07-24 05:19:43 +02:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex.ToString()})");
|
|
|
|
|
}
|
|
|
|
|
return null;
|
2018-03-28 15:37:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
private SpeedPolicy ParseSpeedPolicy(string transactionSpeed, SpeedPolicy defaultPolicy)
|
|
|
|
|
{
|
|
|
|
|
if (transactionSpeed == null)
|
|
|
|
|
return defaultPolicy;
|
|
|
|
|
var mappings = new Dictionary<string, SpeedPolicy>();
|
|
|
|
|
mappings.Add("low", SpeedPolicy.LowSpeed);
|
2018-05-11 15:12:45 +02:00
|
|
|
|
mappings.Add("low-medium", SpeedPolicy.LowMediumSpeed);
|
2017-10-27 10:53:04 +02:00
|
|
|
|
mappings.Add("medium", SpeedPolicy.MediumSpeed);
|
|
|
|
|
mappings.Add("high", SpeedPolicy.HighSpeed);
|
|
|
|
|
if (!mappings.TryGetValue(transactionSpeed, out SpeedPolicy policy))
|
|
|
|
|
policy = defaultPolicy;
|
|
|
|
|
return policy;
|
|
|
|
|
}
|
2017-10-23 07:51:21 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
private void FillBuyerInfo(Buyer buyer, BuyerInformation buyerInformation)
|
|
|
|
|
{
|
|
|
|
|
if (buyer == null)
|
|
|
|
|
return;
|
|
|
|
|
buyerInformation.BuyerAddress1 = buyerInformation.BuyerAddress1 ?? buyer.Address1;
|
|
|
|
|
buyerInformation.BuyerAddress2 = buyerInformation.BuyerAddress2 ?? buyer.Address2;
|
|
|
|
|
buyerInformation.BuyerCity = buyerInformation.BuyerCity ?? buyer.City;
|
|
|
|
|
buyerInformation.BuyerCountry = buyerInformation.BuyerCountry ?? buyer.country;
|
|
|
|
|
buyerInformation.BuyerEmail = buyerInformation.BuyerEmail ?? buyer.email;
|
|
|
|
|
buyerInformation.BuyerName = buyerInformation.BuyerName ?? buyer.Name;
|
|
|
|
|
buyerInformation.BuyerPhone = buyerInformation.BuyerPhone ?? buyer.phone;
|
|
|
|
|
buyerInformation.BuyerState = buyerInformation.BuyerState ?? buyer.State;
|
|
|
|
|
buyerInformation.BuyerZip = buyerInformation.BuyerZip ?? buyer.zip;
|
|
|
|
|
}
|
2017-10-13 09:44:55 +02:00
|
|
|
|
|
2017-10-27 10:53:04 +02:00
|
|
|
|
private TDest Map<TFrom, TDest>(TFrom data)
|
|
|
|
|
{
|
|
|
|
|
return JsonConvert.DeserializeObject<TDest>(JsonConvert.SerializeObject(data));
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 08:47:34 +02:00
|
|
|
|
}
|