mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Add ability to set invoice status from details page (#2923)
* Add ability to set invoice status from details page * Remove unnecessary "using" statements * Add print styles * Fix Safari issues * Simplify JS * Update status badge class names * Update dropdown toggle padding * Adjust dropdown menu padding
This commit is contained in:
@@ -13,16 +13,12 @@ using BTCPayServer.Abstractions.Models;
|
|||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.Logging;
|
|
||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Models;
|
|
||||||
using BTCPayServer.Models.InvoicingModels;
|
using BTCPayServer.Models.InvoicingModels;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Lightning;
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Rating;
|
using BTCPayServer.Rating;
|
||||||
using BTCPayServer.Security;
|
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Invoices.Export;
|
using BTCPayServer.Services.Invoices.Export;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
@@ -104,6 +100,7 @@ namespace BTCPayServer.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
||||||
|
var invoiceState = invoice.GetInvoiceState();
|
||||||
var model = new InvoiceDetailsModel()
|
var model = new InvoiceDetailsModel()
|
||||||
{
|
{
|
||||||
StoreId = store.Id,
|
StoreId = store.Id,
|
||||||
@@ -111,7 +108,7 @@ namespace BTCPayServer.Controllers
|
|||||||
StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }),
|
StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }),
|
||||||
PaymentRequestLink = Url.Action(nameof(PaymentRequestController.ViewPaymentRequest), "PaymentRequest", new { id = invoice.Metadata.PaymentRequestId }),
|
PaymentRequestLink = Url.Action(nameof(PaymentRequestController.ViewPaymentRequest), "PaymentRequest", new { id = invoice.Metadata.PaymentRequestId }),
|
||||||
Id = invoice.Id,
|
Id = invoice.Id,
|
||||||
State = invoice.GetInvoiceState().ToString(),
|
State = invoiceState.ToString(),
|
||||||
TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" :
|
TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" :
|
||||||
invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" :
|
invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" :
|
||||||
invoice.SpeedPolicy == SpeedPolicy.LowMediumSpeed ? "low-medium" :
|
invoice.SpeedPolicy == SpeedPolicy.LowMediumSpeed ? "low-medium" :
|
||||||
@@ -129,11 +126,13 @@ namespace BTCPayServer.Controllers
|
|||||||
Events = invoice.Events,
|
Events = invoice.Events,
|
||||||
PosData = PosDataParser.ParsePosData(invoice.Metadata.PosData),
|
PosData = PosDataParser.ParsePosData(invoice.Metadata.PosData),
|
||||||
Archived = invoice.Archived,
|
Archived = invoice.Archived,
|
||||||
CanRefund = CanRefund(invoice.GetInvoiceState()),
|
CanRefund = CanRefund(invoiceState),
|
||||||
ShowCheckout = invoice.Status == InvoiceStatusLegacy.New,
|
ShowCheckout = invoice.Status == InvoiceStatusLegacy.New,
|
||||||
Deliveries = (await _InvoiceRepository.GetWebhookDeliveries(invoiceId))
|
Deliveries = (await _InvoiceRepository.GetWebhookDeliveries(invoiceId))
|
||||||
.Select(c => new Models.StoreViewModels.DeliveryViewModel(c))
|
.Select(c => new Models.StoreViewModels.DeliveryViewModel(c))
|
||||||
.ToList()
|
.ToList(),
|
||||||
|
CanMarkInvalid = invoiceState.CanMarkInvalid(),
|
||||||
|
CanMarkComplete = invoiceState.CanMarkComplete(),
|
||||||
};
|
};
|
||||||
model.Addresses = invoice.HistoricalAddresses.Select(h =>
|
model.Addresses = invoice.HistoricalAddresses.Select(h =>
|
||||||
new InvoiceDetailsModel.AddressModel
|
new InvoiceDetailsModel.AddressModel
|
||||||
|
|||||||
@@ -126,5 +126,8 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||||||
public bool Archived { get; set; }
|
public bool Archived { get; set; }
|
||||||
public bool CanRefund { get; set; }
|
public bool CanRefund { get; set; }
|
||||||
public bool ShowCheckout { get; set; }
|
public bool ShowCheckout { get; set; }
|
||||||
|
public bool CanMarkComplete { get; set; }
|
||||||
|
public bool CanMarkInvalid { get; set; }
|
||||||
|
public bool CanMarkStatus => CanMarkComplete || CanMarkInvalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,38 @@
|
|||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@section PageFootContent {
|
||||||
|
<script>
|
||||||
|
function changeInvoiceState(invoiceId, newState) {
|
||||||
|
var toggleButton = $("#markStatusDropdownMenuButton");
|
||||||
|
toggleButton.attr("disabled", "disabled");
|
||||||
|
|
||||||
|
$.post(invoiceId + "/changestate/" + newState)
|
||||||
|
.done(function (data) {
|
||||||
|
var alertClassModifier = {
|
||||||
|
"complete (marked)": 'success',
|
||||||
|
"invalid (marked)": 'danger'
|
||||||
|
}[data.statusString];
|
||||||
|
var statusHtml = "<span class='fs-6 fw-normal badge bg-" + alertClassModifier + "'>" + data.statusString + " <span class='fa fa-check'></span></span>"
|
||||||
|
toggleButton.replaceWith(statusHtml);
|
||||||
|
})
|
||||||
|
.fail(function () {
|
||||||
|
toggleButton.removeAttr("disabled");
|
||||||
|
alert("Invoice state update failed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
$("[data-change-invoice-status-button]").click(function (e) {
|
||||||
|
var id = e.currentTarget.getAttribute('data-id');
|
||||||
|
var status = e.currentTarget.getAttribute('data-status');
|
||||||
|
|
||||||
|
changeInvoiceState(id, status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
<section class="invoice-details">
|
<section class="invoice-details">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<partial name="_StatusMessage" />
|
<partial name="_StatusMessage" />
|
||||||
@@ -19,7 +51,6 @@
|
|||||||
<h2 class="col-xs-12 col-lg-6 mb-4 mb-lg-0">@ViewData["Title"]</h2>
|
<h2 class="col-xs-12 col-lg-6 mb-4 mb-lg-0">@ViewData["Title"]</h2>
|
||||||
<div class="col-xs-12 col-lg-6 mb-2 mb-lg-0 text-lg-end">
|
<div class="col-xs-12 col-lg-6 mb-2 mb-lg-0 text-lg-end">
|
||||||
<div class="d-inline-flex">
|
<div class="d-inline-flex">
|
||||||
|
|
||||||
@if (Model.ShowCheckout)
|
@if (Model.ShowCheckout)
|
||||||
{
|
{
|
||||||
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap ms-2" asp-route-invoiceId="@Model.Id">
|
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap ms-2" asp-route-invoiceId="@Model.Id">
|
||||||
@@ -92,7 +123,33 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>State</th>
|
<th>State</th>
|
||||||
<td>@Model.State</td>
|
<td>
|
||||||
|
@if (Model.CanMarkStatus)
|
||||||
|
{
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-secondary btn-sm dropdown-toggle py-1 px-2" type="button" id="markStatusDropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
@Model.State
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="markStatusDropdownMenuButton">
|
||||||
|
@if (Model.CanMarkInvalid)
|
||||||
|
{
|
||||||
|
<a class="dropdown-item" href="#" data-id="@Model.Id" data-status="invalid" data-change-invoice-status-button>
|
||||||
|
Mark as invalid <span class="fa fa-times"></span>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
@if (Model.CanMarkComplete)
|
||||||
|
{
|
||||||
|
<a class="dropdown-item" href="#" data-id="@Model.Id" data-status="complete" data-change-invoice-status-button>
|
||||||
|
Mark as complete <span class="fa fa-check-circle"></span>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@Model.State
|
||||||
|
}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Created date</th>
|
<th>Created date</th>
|
||||||
|
|||||||
@@ -337,6 +337,17 @@ h2 small .fa-question-circle-o {
|
|||||||
.toasted-container {
|
.toasted-container {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
#markStatusDropdownMenuButton {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0 !important;
|
||||||
|
color: inherit;
|
||||||
|
font-weight: var(--btcpay-font-weight-normal);
|
||||||
|
font-size: var(--btcpay-body-font-size);
|
||||||
|
}
|
||||||
|
#markStatusDropdownMenuButton::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Richtext editor */
|
/* Richtext editor */
|
||||||
|
|||||||
Reference in New Issue
Block a user