/// <summary> /// Add a payment to an invoice /// </summary> /// <param name="invoiceId"></param> /// <param name="date"></param> /// <param name="paymentData"></param> /// <param name="cryptoCode"></param> /// <param name="accounted"></param> /// <returns>The PaymentEntity or null if already added</returns> public async Task <PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, string cryptoCode, bool accounted = false) { using (var context = _ContextFactory.CreateContext()) { PaymentEntity entity = new PaymentEntity { #pragma warning disable CS0618 CryptoCode = cryptoCode, #pragma warning restore CS0618 ReceivedTime = date.UtcDateTime, Accounted = accounted }; entity.SetCryptoPaymentData(paymentData); PaymentData data = new PaymentData { Id = paymentData.GetPaymentId(), Blob = ToBytes(entity, null), InvoiceDataId = invoiceId, Accounted = accounted }; context.Payments.Add(data); try { await context.SaveChangesAsync().ConfigureAwait(false); } catch (DbUpdateException) { return(null); } // Already exists AddToTextSearch(invoiceId, paymentData.GetSearchTerms()); return(entity); } }
public async Task <PaymentEntity> AddPayment(string invoiceId, Coin receivedCoin) { using (var context = _ContextFactory.CreateContext()) { PaymentEntity entity = new PaymentEntity { Outpoint = receivedCoin.Outpoint, Output = receivedCoin.TxOut, ReceivedTime = DateTime.UtcNow }; PaymentData data = new PaymentData { Id = receivedCoin.Outpoint.ToString(), Blob = ToBytes(entity), InvoiceDataId = invoiceId }; context.Payments.Add(data); await context.SaveChangesAsync().ConfigureAwait(false); AddToTextSearch(invoiceId, receivedCoin.Outpoint.Hash.ToString()); return(entity); } }
public async Task <PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, Coin receivedCoin, string cryptoCode) { using (var context = _ContextFactory.CreateContext()) { PaymentEntity entity = new PaymentEntity { Outpoint = receivedCoin.Outpoint, #pragma warning disable CS0618 Output = receivedCoin.TxOut, CryptoCode = cryptoCode, #pragma warning restore CS0618 ReceivedTime = date.UtcDateTime }; PaymentData data = new PaymentData { Id = receivedCoin.Outpoint.ToString(), Blob = ToBytes(entity), InvoiceDataId = invoiceId }; context.Payments.Add(data); await context.SaveChangesAsync().ConfigureAwait(false); AddToTextSearch(invoiceId, receivedCoin.Outpoint.Hash.ToString()); return(entity); } }
/// <summary> /// Add a payment to an invoice /// </summary> /// <param name="invoiceId"></param> /// <param name="date"></param> /// <param name="paymentData"></param> /// <param name="cryptoCode"></param> /// <param name="accounted"></param> /// <returns>The PaymentEntity or null if already added</returns> public async Task <PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, BTCPayNetworkBase network, bool accounted = false) { using (var context = _ContextFactory.CreateContext()) { var invoice = context.Invoices.Find(invoiceId); if (invoice == null) { return(null); } InvoiceEntity invoiceEntity = ToObject(invoice.Blob); invoiceEntity.PaymentMethodHandlerDictionary = _paymentMethodHandlerDictionary; PaymentMethod paymentMethod = invoiceEntity.GetPaymentMethod(new PaymentMethodId(network.CryptoCode, paymentData.GetPaymentType()), null); IPaymentMethodDetails paymentMethodDetails = paymentMethod.GetPaymentMethodDetails(); PaymentEntity entity = new PaymentEntity { Version = 1, #pragma warning disable CS0618 CryptoCode = network.CryptoCode, #pragma warning restore CS0618 ReceivedTime = date.UtcDateTime, Accounted = accounted, NetworkFee = paymentMethodDetails.GetNextNetworkFee(), PaymentMethodHandlerDictionary = _paymentMethodHandlerDictionary }; entity.SetCryptoPaymentData(paymentData); if (paymentMethodDetails is Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod bitcoinPaymentMethod && bitcoinPaymentMethod.NetworkFeeMode == NetworkFeeMode.MultiplePaymentsOnly && bitcoinPaymentMethod.NextNetworkFee == Money.Zero) { bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.FeeRate.GetFee(100); // assume price for 100 bytes paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod); invoiceEntity.SetPaymentMethod(paymentMethod); invoice.Blob = ToBytes(invoiceEntity, network); } PaymentData data = new PaymentData { Id = paymentData.GetPaymentId(), Blob = ToBytes(entity, null), InvoiceDataId = invoiceId, Accounted = accounted }; context.Payments.Add(data); try { await context.SaveChangesAsync().ConfigureAwait(false); } catch (DbUpdateException) { return(null); } // Already exists AddToTextSearch(invoiceId, paymentData.GetSearchTerms()); return(entity); } }
private InvoiceEntity ToEntity(Data.InvoiceData invoice) { var entity = ToObject(invoice.Blob); PaymentMethodDictionary paymentMethods = null; #pragma warning disable CS0618 entity.Payments = invoice.Payments.Select(p => { var unziped = ZipUtils.Unzip(p.Blob); var cryptoCode = GetCryptoCode(unziped); var network = _Networks.GetNetwork <BTCPayNetworkBase>(cryptoCode); PaymentEntity paymentEntity = null; if (network == null) { paymentEntity = NBitcoin.JsonConverters.Serializer.ToObject <PaymentEntity>(unziped, null); } else { paymentEntity = network.ToObject <PaymentEntity>(unziped); } paymentEntity.Network = network; paymentEntity.Accounted = p.Accounted; // PaymentEntity on version 0 does not have their own fee, because it was assumed that the payment method have fixed fee. // We want to hide this legacy detail in InvoiceRepository, so we fetch the fee from the PaymentMethod and assign it to the PaymentEntity. if (paymentEntity.Version == 0) { if (paymentMethods == null) { paymentMethods = entity.GetPaymentMethods(); } var paymentMethodDetails = paymentMethods.TryGet(paymentEntity.GetPaymentMethodId())?.GetPaymentMethodDetails(); if (paymentMethodDetails != null) // == null should never happen, but we never know. { paymentEntity.NetworkFee = paymentMethodDetails.GetNextNetworkFee(); } } return(paymentEntity); }) .OrderBy(a => a.ReceivedTime).ToList(); #pragma warning restore CS0618 var state = invoice.GetInvoiceState(); entity.ExceptionStatus = state.ExceptionStatus; entity.Status = state.Status; entity.RefundMail = invoice.CustomerEmail; entity.Refundable = invoice.RefundAddresses.Count != 0; if (invoice.HistoricalAddressInvoices != null) { entity.HistoricalAddresses = invoice.HistoricalAddressInvoices.ToArray(); } if (invoice.AddressInvoices != null) { entity.AvailableAddressHashes = invoice.AddressInvoices.Select(a => a.GetAddress() + a.GetpaymentMethodId().ToString()).ToHashSet(); } if (invoice.Events != null) { entity.Events = invoice.Events.OrderBy(c => c.Timestamp).ToList(); } if (!string.IsNullOrEmpty(entity.RefundMail) && string.IsNullOrEmpty(entity.BuyerInformation.BuyerEmail)) { entity.BuyerInformation.BuyerEmail = entity.RefundMail; } return(entity); }
/// <summary> /// Add a payment to an invoice /// </summary> /// <param name="invoiceId"></param> /// <param name="date"></param> /// <param name="paymentData"></param> /// <param name="cryptoCode"></param> /// <param name="accounted"></param> /// <returns>The PaymentEntity or null if already added</returns> public async Task <PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, BTCPayNetworkBase network, bool accounted = false) { await using var context = _applicationDbContextFactory.CreateContext(); var invoice = await context.Invoices.FindAsync(invoiceId); if (invoice == null) { return(null); } InvoiceEntity invoiceEntity = invoice.GetBlob(_btcPayNetworkProvider); PaymentMethod paymentMethod = invoiceEntity.GetPaymentMethod(new PaymentMethodId(network.CryptoCode, paymentData.GetPaymentType())); IPaymentMethodDetails paymentMethodDetails = paymentMethod.GetPaymentMethodDetails(); PaymentEntity entity = new PaymentEntity { Version = 1, #pragma warning disable CS0618 CryptoCode = network.CryptoCode, #pragma warning restore CS0618 ReceivedTime = date.UtcDateTime, Accounted = accounted, NetworkFee = paymentMethodDetails.GetNextNetworkFee(), Network = network }; entity.SetCryptoPaymentData(paymentData); //TODO: abstract if (paymentMethodDetails is Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod bitcoinPaymentMethod && bitcoinPaymentMethod.NetworkFeeMode == NetworkFeeMode.MultiplePaymentsOnly && bitcoinPaymentMethod.NextNetworkFee == Money.Zero) { bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod); invoiceEntity.SetPaymentMethod(paymentMethod); invoice.Blob = InvoiceRepository.ToBytes(invoiceEntity, network); } PaymentData data = new PaymentData { Id = paymentData.GetPaymentId(), Blob = InvoiceRepository.ToBytes(entity, entity.Network), InvoiceDataId = invoiceId, Accounted = accounted }; await context.Payments.AddAsync(data); InvoiceRepository.AddToTextSearch(context, invoice, paymentData.GetSearchTerms()); var alreadyExists = false; try { await context.SaveChangesAsync().ConfigureAwait(false); } catch (DbUpdateException) { alreadyExists = true; } if (alreadyExists) { return(null); } if (paymentData.PaymentConfirmed(entity, invoiceEntity.SpeedPolicy)) { _eventAggregator.Publish(new InvoiceEvent(invoiceEntity, InvoiceEvent.PaymentSettled) { Payment = entity }); } return(entity); }