mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Simplifying implementation of status switch
This commit is contained in:
@@ -465,48 +465,31 @@ namespace BTCPayServer.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("{payReqId}/changestate/{newState}")]
|
[HttpPost("{payReqId}/complete")]
|
||||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyPaymentRequests)]
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyPaymentRequests)]
|
||||||
public async Task<IActionResult> ChangePaymentRequestState(string payReqId, string newState)
|
public async Task<IActionResult> TogglePaymentRequestCompleted(string payReqId)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(payReqId) || string.IsNullOrWhiteSpace(newState))
|
if (string.IsNullOrWhiteSpace(payReqId))
|
||||||
{
|
{
|
||||||
return BadRequest("Invalid parameters");
|
return BadRequest("Invalid parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
var paymentRequest = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId());
|
var paymentRequest = await _PaymentRequestRepository.FindPaymentRequest(payReqId, GetUserId());
|
||||||
var model = new PaymentRequestStateChangeModel();
|
|
||||||
if (paymentRequest == null)
|
if (paymentRequest == null)
|
||||||
{
|
{
|
||||||
model.NotFound = true;
|
return NotFound();
|
||||||
return NotFound(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newState == "completed")
|
if (paymentRequest.Status != PaymentRequestStatus.Pending)
|
||||||
{
|
{
|
||||||
await _PaymentRequestRepository.UpdatePaymentRequestStatus(payReqId, PaymentRequestStatus.Completed);
|
return BadRequest("Invalid payment request status. Only pending payment requests can be marked as completed.");
|
||||||
model.StatusString = "Settled";
|
|
||||||
}
|
|
||||||
else if (newState == "expired")
|
|
||||||
{
|
|
||||||
await _PaymentRequestRepository.UpdatePaymentRequestStatus(payReqId, PaymentRequestStatus.Expired);
|
|
||||||
model.StatusString = "Expired";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return BadRequest($"Invalid state: {newState}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Json(model);
|
await _PaymentRequestRepository.UpdatePaymentRequestStatus(payReqId, PaymentRequestStatus.Completed);
|
||||||
|
|
||||||
|
return RedirectToAction("GetPaymentRequests", new { storeId = paymentRequest.StoreDataId });
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PaymentRequestStateChangeModel
|
|
||||||
{
|
|
||||||
public bool NotFound { get; set; }
|
|
||||||
public string? StatusString { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private string GetUserId() => _UserManager.GetUserId(User);
|
private string GetUserId() => _UserManager.GetUserId(User);
|
||||||
|
|
||||||
private StoreData GetCurrentStore() => HttpContext.GetStoreData();
|
private StoreData GetCurrentStore() => HttpContext.GetStoreData();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{
|
{
|
||||||
private int CountArrayFilter(string type) =>
|
private int CountArrayFilter(string type) =>
|
||||||
Model.Search.ContainsFilter(type) ? Model.Search.GetFilterArray(type).Length : 0;
|
Model.Search.ContainsFilter(type) ? Model.Search.GetFilterArray(type).Length : 0;
|
||||||
|
|
||||||
private bool HasArrayFilter(string type, string key = null) =>
|
private bool HasArrayFilter(string type, string key = null) =>
|
||||||
Model.Search.ContainsFilter(type) && (key is null || Model.Search.GetFilterArray(type).Contains(key));
|
Model.Search.ContainsFilter(type) && (key is null || Model.Search.GetFilterArray(type).Contains(key));
|
||||||
|
|
||||||
@@ -121,7 +121,9 @@
|
|||||||
@item.Status
|
@item.Status
|
||||||
</span>
|
</span>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button type="button" class="dropdown-item lh-base" data-payment-request-id="@item.Id" data-new-state="completed">Mark as settled</button>
|
<form asp-action="TogglePaymentRequestCompleted" asp-route-payReqId="@item.Id" method="post">
|
||||||
|
<button type="submit" class="dropdown-item lh-base">Mark as settled</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -136,14 +138,14 @@
|
|||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<div class="d-inline-flex align-items-center gap-3">
|
<div class="d-inline-flex align-items-center gap-3">
|
||||||
<a asp-action="ViewPaymentRequest" asp-route-payReqId="@item.Id" id="PaymentRequest-@item.Id" target="_blank" text-translate="true">View</a>
|
<a asp-action="ViewPaymentRequest" asp-route-payReqId="@item.Id" id="PaymentRequest-@item.Id" target="_blank" text-translate="true">View</a>
|
||||||
<button type="button" class="btn btn-link p-0 clipboard-button"
|
<button type="button" class="btn btn-link p-0 clipboard-button"
|
||||||
data-clipboard="@CallbackGenerator.PaymentRequestByIdLink(item.Id, this.Context.Request)"
|
data-clipboard="@CallbackGenerator.PaymentRequestByIdLink(item.Id, this.Context.Request)"
|
||||||
title="Copy Link">
|
title="Copy Link">
|
||||||
<vc:icon symbol="actions-copy" />
|
<vc:icon symbol="actions-copy" />
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button class="btn btn-link dropdown-toggle p-0 dropdown-toggle-no-caret text-body" type="button" data-bs-toggle="dropdown" aria-expanded="false" id="ToggleActions-@item.Id">
|
<button class="btn btn-link dropdown-toggle p-0 dropdown-toggle-no-caret text-body" type="button" data-bs-toggle="dropdown" aria-expanded="false" id="ToggleActions-@item.Id">
|
||||||
<vc:icon symbol="dots" />
|
<vc:icon symbol="dots" />
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="actionDropdown">
|
<ul class="dropdown-menu" aria-labelledby="actionDropdown">
|
||||||
<li><a class="dropdown-item" permission="@Policies.CanViewInvoices" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@item.StoreId" asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(item.Id)}")" text-translate="true">Invoices</a></li>
|
<li><a class="dropdown-item" permission="@Policies.CanViewInvoices" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@item.StoreId" asp-route-searchterm="@($"orderid:{PaymentRequestRepository.GetOrderIdForPaymentRequest(item.Id)}")" text-translate="true">Invoices</a></li>
|
||||||
@@ -168,7 +170,3 @@ else
|
|||||||
There are no payment requests matching your criteria.
|
There are no payment requests matching your criteria.
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
<script>
|
|
||||||
window.storeId = '@storeId';
|
|
||||||
</script>
|
|
||||||
@@ -151,7 +151,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
setStickyHeaderHeight();
|
setStickyHeaderHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize timezone offset value if field is present in page
|
// initialize timezone offset value if field is present in page
|
||||||
const $timezoneOffset = document.getElementById("TimezoneOffset");
|
const $timezoneOffset = document.getElementById("TimezoneOffset");
|
||||||
const timezoneOffset = new Date().getTimezoneOffset();
|
const timezoneOffset = new Date().getTimezoneOffset();
|
||||||
@@ -161,7 +161,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
formatDateTimes();
|
formatDateTimes();
|
||||||
|
|
||||||
initLabelManagers();
|
initLabelManagers();
|
||||||
|
|
||||||
function updateTimeAgo(){
|
function updateTimeAgo(){
|
||||||
var timeagoElements = $("[data-timeago-unixms]");
|
var timeagoElements = $("[data-timeago-unixms]");
|
||||||
timeagoElements.each(function () {
|
timeagoElements.each(function () {
|
||||||
@@ -171,7 +171,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
setTimeout(updateTimeAgo, 1000);
|
setTimeout(updateTimeAgo, 1000);
|
||||||
}
|
}
|
||||||
updateTimeAgo();
|
updateTimeAgo();
|
||||||
|
|
||||||
// intializing date time pickers
|
// intializing date time pickers
|
||||||
$(".flatdtpicker").each(function () {
|
$(".flatdtpicker").each(function () {
|
||||||
var element = $(this);
|
var element = $(this);
|
||||||
@@ -259,7 +259,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (!!$button.innerHTML.match('#actions-hide')) $button.innerHTML = $button.innerHTML.replace('#actions-hide', '#actions-show');
|
if (!!$button.innerHTML.match('#actions-hide')) $button.innerHTML = $button.innerHTML.replace('#actions-hide', '#actions-show');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Invoice Status
|
// Invoice Status
|
||||||
delegate('click', '[data-invoice-state-badge] [data-invoice-id][data-new-state]', async e => {
|
delegate('click', '[data-invoice-state-badge] [data-invoice-id][data-new-state]', async e => {
|
||||||
const $button = e.target
|
const $button = e.target
|
||||||
@@ -277,23 +277,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Payment Request Status
|
|
||||||
delegate('click', '[data-payment-request-state-badge] [data-payment-request-id][data-new-state]', async e => {
|
|
||||||
const $button = e.target
|
|
||||||
const $badge = $button.closest('[data-payment-request-state-badge]')
|
|
||||||
const { paymentRequestId, newState } = $button.dataset
|
|
||||||
|
|
||||||
$badge.classList.add('pe-none'); // disable further interaction
|
|
||||||
const response = await fetch(`${baseUrl}/payment-requests/${paymentRequestId}/changestate/${newState}`, { method: 'POST' })
|
|
||||||
if (response.ok) {
|
|
||||||
const { statusString } = await response.json()
|
|
||||||
$badge.outerHTML = `<div class="badge badge-${newState}" data-payment-request-state-badge="${paymentRequestId}">${statusString}</div>`
|
|
||||||
} else {
|
|
||||||
$badge.classList.remove('pe-none');
|
|
||||||
alert("Payment request state update failed");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Time Format
|
// Time Format
|
||||||
delegate('click', '.switch-time-format', switchTimeFormat);
|
delegate('click', '.switch-time-format', switchTimeFormat);
|
||||||
|
|
||||||
@@ -319,7 +302,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
document.documentElement.setAttribute(SENSITIVE_INFO_DATA_ATTR, 'true');
|
document.documentElement.setAttribute(SENSITIVE_INFO_DATA_ATTR, 'true');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Currency Selection: Remove the current input value once the element is focused, so that the user gets to
|
// Currency Selection: Remove the current input value once the element is focused, so that the user gets to
|
||||||
// see the available options. If no selection or change is made, reset it to the previous value on blur.
|
// see the available options. If no selection or change is made, reset it to the previous value on blur.
|
||||||
// Note: Use focusin/focusout instead of focus/blur, because the latter do not bubble up and delegate won't work.
|
// Note: Use focusin/focusout instead of focus/blur, because the latter do not bubble up and delegate won't work.
|
||||||
@@ -331,7 +314,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (!e.target.value) e.target.value = e.target.getAttribute('placeholder')
|
if (!e.target.value) e.target.value = e.target.getAttribute('placeholder')
|
||||||
e.target.removeAttribute('placeholder')
|
e.target.removeAttribute('placeholder')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Offcanvas navigation
|
// Offcanvas navigation
|
||||||
const mainMenuToggle = document.getElementById('mainMenuToggle')
|
const mainMenuToggle = document.getElementById('mainMenuToggle')
|
||||||
if (mainMenuToggle) {
|
if (mainMenuToggle) {
|
||||||
@@ -342,7 +325,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
mainMenuToggle.setAttribute('aria-expanded', 'false')
|
mainMenuToggle.setAttribute('aria-expanded', 'false')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menu collapses
|
// Menu collapses
|
||||||
const mainNav = document.getElementById('mainNav')
|
const mainNav = document.getElementById('mainNav')
|
||||||
if (mainNav) {
|
if (mainNav) {
|
||||||
@@ -361,7 +344,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
window.localStorage.setItem(COLLAPSED_KEY, JSON.stringify(collapsed))
|
window.localStorage.setItem(COLLAPSED_KEY, JSON.stringify(collapsed))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mass Action Tables
|
// Mass Action Tables
|
||||||
const updateSelectedCount = ($table) => {
|
const updateSelectedCount = ($table) => {
|
||||||
const selectedCount = document.querySelectorAll('.mass-action-select:checked').length;
|
const selectedCount = document.querySelectorAll('.mass-action-select:checked').length;
|
||||||
|
|||||||
Reference in New Issue
Block a user