mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
@@ -104,7 +104,6 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
public abstract class BTCPayNetworkBase
|
public abstract class BTCPayNetworkBase
|
||||||
{
|
{
|
||||||
|
|
||||||
public string CryptoCode { get; internal set; }
|
public string CryptoCode { get; internal set; }
|
||||||
public string BlockExplorerLink { get; internal set; }
|
public string BlockExplorerLink { get; internal set; }
|
||||||
public string DisplayName { get; set; }
|
public string DisplayName { get; set; }
|
||||||
|
|||||||
@@ -225,7 +225,6 @@ namespace BTCPayServer.Controllers
|
|||||||
(1m + (changelly.AmountMarkupPercentage / 100m)))
|
(1m + (changelly.AmountMarkupPercentage / 100m)))
|
||||||
: (decimal?)null;
|
: (decimal?)null;
|
||||||
|
|
||||||
|
|
||||||
var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId];
|
var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId];
|
||||||
var model = new PaymentModel()
|
var model = new PaymentModel()
|
||||||
{
|
{
|
||||||
@@ -244,6 +243,8 @@ namespace BTCPayServer.Controllers
|
|||||||
OrderAmountFiat = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation),
|
OrderAmountFiat = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation),
|
||||||
CustomerEmail = invoice.RefundMail,
|
CustomerEmail = invoice.RefundMail,
|
||||||
RequiresRefundEmail = storeBlob.RequiresRefundEmail,
|
RequiresRefundEmail = storeBlob.RequiresRefundEmail,
|
||||||
|
ShowRecommendedFee = storeBlob.ShowRecommendedFee,
|
||||||
|
FeeRate = paymentMethodDetails.GetFeeRate(),
|
||||||
ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
|
ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds),
|
||||||
MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
|
MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
|
||||||
MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
|
MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ namespace BTCPayServer.Controllers
|
|||||||
vm.HtmlTitle = storeBlob.HtmlTitle;
|
vm.HtmlTitle = storeBlob.HtmlTitle;
|
||||||
vm.SetLanguages(_LangService, storeBlob.DefaultLang);
|
vm.SetLanguages(_LangService, storeBlob.DefaultLang);
|
||||||
vm.RequiresRefundEmail = storeBlob.RequiresRefundEmail;
|
vm.RequiresRefundEmail = storeBlob.RequiresRefundEmail;
|
||||||
|
vm.ShowRecommendedFee = storeBlob.ShowRecommendedFee;
|
||||||
vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? "";
|
vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? "";
|
||||||
vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? "";
|
vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? "";
|
||||||
vm.LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi;
|
vm.LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi;
|
||||||
@@ -421,6 +422,7 @@ namespace BTCPayServer.Controllers
|
|||||||
blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle;
|
blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle;
|
||||||
blob.DefaultLang = model.DefaultLang;
|
blob.DefaultLang = model.DefaultLang;
|
||||||
blob.RequiresRefundEmail = model.RequiresRefundEmail;
|
blob.RequiresRefundEmail = model.RequiresRefundEmail;
|
||||||
|
blob.ShowRecommendedFee = model.ShowRecommendedFee;
|
||||||
blob.OnChainMinValue = onchainMinValue;
|
blob.OnChainMinValue = onchainMinValue;
|
||||||
blob.LightningMaxValue = lightningMaxValue;
|
blob.LightningMaxValue = lightningMaxValue;
|
||||||
blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi;
|
blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace BTCPayServer.Data
|
|||||||
MonitoringExpiration = 1440;
|
MonitoringExpiration = 1440;
|
||||||
PaymentTolerance = 0;
|
PaymentTolerance = 0;
|
||||||
RequiresRefundEmail = true;
|
RequiresRefundEmail = true;
|
||||||
|
ShowRecommendedFee = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use NetworkFeeMode instead")]
|
[Obsolete("Use NetworkFeeMode instead")]
|
||||||
@@ -39,6 +40,8 @@ namespace BTCPayServer.Data
|
|||||||
|
|
||||||
public bool RequiresRefundEmail { get; set; }
|
public bool RequiresRefundEmail { get; set; }
|
||||||
|
|
||||||
|
public bool ShowRecommendedFee { get; set; }
|
||||||
|
|
||||||
CurrencyPair[] _DefaultCurrencyPairs;
|
CurrencyPair[] _DefaultCurrencyPairs;
|
||||||
[JsonProperty("defaultCurrencyPairs", ItemConverterType = typeof(CurrencyPairJsonConverter))]
|
[JsonProperty("defaultCurrencyPairs", ItemConverterType = typeof(CurrencyPairJsonConverter))]
|
||||||
public CurrencyPair[] DefaultCurrencyPairs
|
public CurrencyPair[] DefaultCurrencyPairs
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||||||
public string BtcDue { get; set; }
|
public string BtcDue { get; set; }
|
||||||
public string CustomerEmail { get; set; }
|
public string CustomerEmail { get; set; }
|
||||||
public bool RequiresRefundEmail { get; set; }
|
public bool RequiresRefundEmail { get; set; }
|
||||||
|
public bool ShowRecommendedFee { get; set; }
|
||||||
|
public decimal FeeRate { get; set; }
|
||||||
public int ExpirationSeconds { get; set; }
|
public int ExpirationSeconds { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public string MerchantRefLink { get; set; }
|
public string MerchantRefLink { get; set; }
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||||||
[Display(Name = "Requires a refund email")]
|
[Display(Name = "Requires a refund email")]
|
||||||
public bool RequiresRefundEmail { get; set; }
|
public bool RequiresRefundEmail { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Show recommended fee")]
|
||||||
|
public bool ShowRecommendedFee { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Do not propose on chain payment if the value of the invoice is below...")]
|
[Display(Name = "Do not propose on chain payment if the value of the invoice is below...")]
|
||||||
[MaxLength(20)]
|
[MaxLength(20)]
|
||||||
public string OnChainMinValue { get; set; }
|
public string OnChainMinValue { get; set; }
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
{
|
{
|
||||||
return NextNetworkFee.ToDecimal(MoneyUnit.BTC);
|
return NextNetworkFee.ToDecimal(MoneyUnit.BTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public decimal GetFeeRate() {
|
||||||
|
return FeeRate.SatoshiPerByte;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPaymentDestination(string newPaymentDestination)
|
public void SetPaymentDestination(string newPaymentDestination)
|
||||||
{
|
{
|
||||||
DepositAddress = newPaymentDestination;
|
DepositAddress = newPaymentDestination;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ namespace BTCPayServer.Payments
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
decimal GetNextNetworkFee();
|
decimal GetNextNetworkFee();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Returns recommended fee rate for a transaction
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
decimal GetFeeRate();
|
||||||
|
/// <summary>
|
||||||
/// Change the payment destination (internal plumbing)
|
/// Change the payment destination (internal plumbing)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newPaymentDestination"></param>
|
/// <param name="newPaymentDestination"></param>
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
{
|
{
|
||||||
return 0.0m;
|
return 0.0m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public decimal GetFeeRate() {
|
||||||
|
return 0.0m;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPaymentDestination(string newPaymentDestination)
|
public void SetPaymentDestination(string newPaymentDestination)
|
||||||
{
|
{
|
||||||
BOLT11 = newPaymentDestination;
|
BOLT11 = newPaymentDestination;
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
{
|
{
|
||||||
return NextNetworkFee;
|
return NextNetworkFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public decimal GetFeeRate() {
|
||||||
|
return 0.0m;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPaymentDestination(string newPaymentDestination)
|
public void SetPaymentDestination(string newPaymentDestination)
|
||||||
{
|
{
|
||||||
DepositAddress = newPaymentDestination;
|
DepositAddress = newPaymentDestination;
|
||||||
|
|||||||
@@ -153,7 +153,7 @@
|
|||||||
</component>
|
</component>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="payment-box">
|
<div class="payment-box" v-bind:class="{ 'payment-box--with-recommended-fee': showRecommendedFee && !showEmailForm }">
|
||||||
<div class="bp-view payment manual-flow enter-contact-email" id="emailAddressView" v-bind:class="{ 'active': showEmailForm}">
|
<div class="bp-view payment manual-flow enter-contact-email" id="emailAddressView" v-bind:class="{ 'active': showEmailForm}">
|
||||||
<form class="manual__step-one refund-address-form contact-email-form" id="emailAddressForm" name="emailAddressForm" novalidate="" v-on:submit.prevent="onEmailSubmit">
|
<form class="manual__step-one refund-address-form contact-email-form" id="emailAddressForm" name="emailAddressForm" novalidate="" v-on:submit.prevent="onEmailSubmit">
|
||||||
<div class="manual__step-one__header">
|
<div class="manual__step-one__header">
|
||||||
|
|||||||
@@ -185,6 +185,9 @@
|
|||||||
showEmailForm: function(){
|
showEmailForm: function(){
|
||||||
return this.srvModel.requiresRefundEmail && (!this.srvModel.customerEmail || !this.validateEmail(this.srvModel.customerEmail)) && !this.invoiceUnpayable && !this.invoicePaid;
|
return this.srvModel.requiresRefundEmail && (!this.srvModel.customerEmail || !this.validateEmail(this.srvModel.customerEmail)) && !this.invoiceUnpayable && !this.invoicePaid;
|
||||||
},
|
},
|
||||||
|
showRecommendedFee: function(){
|
||||||
|
return this.srvModel.showRecommendedFee && this.srvModel.feeRate != 0;
|
||||||
|
},
|
||||||
invoiceUnpayable: function(){
|
invoiceUnpayable: function(){
|
||||||
return ["expired", "invalid"].indexOf(this.srvModel.status) >= 0;
|
return ["expired", "invalid"].indexOf(this.srvModel.status) >= 0;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -167,7 +167,13 @@
|
|||||||
</center>
|
</center>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (Model.ShowRecommendedFee) {
|
||||||
|
<div id="recommended-fee" class="recommended-fee" v-bind:class="{ hide: !srvModel.feeRate }">
|
||||||
|
<span>{{$t("Recommended_Fee", srvModel)}}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input asp-for="RedirectAutomatically" type="checkbox" class="form-check-input" />
|
<input asp-for="RedirectAutomatically" type="checkbox" class="form-check-input" />
|
||||||
<label asp-for="RedirectAutomatically" class="form-check-label" ></label>
|
<label asp-for="RedirectAutomatically" class="form-check-label"></label>
|
||||||
<span asp-validation-for="RedirectAutomatically" class="text-danger"></span>
|
<span asp-validation-for="RedirectAutomatically" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input asp-for="ShowRecommendedFee" type="checkbox" class="form-check-input" />
|
||||||
|
<label asp-for="ShowRecommendedFee" class="form-check-label"></label>
|
||||||
|
<p class="form-text text-muted">Fee will be shown for BTC and LTC onchain payments only.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
|
<button name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -9015,6 +9015,10 @@ strong {
|
|||||||
min-height: 393px;
|
min-height: 393px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-box--with-recommended-fee {
|
||||||
|
min-height: 430px;
|
||||||
|
}
|
||||||
|
|
||||||
.paypro {
|
.paypro {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
@@ -9248,6 +9252,20 @@ strong {
|
|||||||
padding-bottom: 40px;
|
padding-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recommended-fee {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #818EA9;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 300;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% - 40px);
|
||||||
|
left: 50%;
|
||||||
|
padding: 0 16px;
|
||||||
|
text-align: center;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.success-message {
|
.success-message {
|
||||||
color: rgba(111, 111, 111, 0.9);
|
color: rgba(111, 111, 111, 0.9);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -47,5 +47,6 @@
|
|||||||
"Pay with CoinSwitch": "Pay with CoinSwitch",
|
"Pay with CoinSwitch": "Pay with CoinSwitch",
|
||||||
"Pay with Changelly": "Pay with Changelly",
|
"Pay with Changelly": "Pay with Changelly",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due."
|
"NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due.",
|
||||||
|
"Recommended_Fee": "Recommended fee: {{feeRate}} sat/byte"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user