/// <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);
            }
        }
Beispiel #4
0
        /// <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);
            }
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        /// <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);
        }