mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Add ability to move a payout from InProgress to AwaitingPayment (#6564)
This commit is contained in:
@@ -113,7 +113,6 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("Title")).SendKeys("Pay123");
|
||||
s.Driver.FindElement(By.Id("Amount")).SendKeys("700");
|
||||
new SelectElement(s.Driver.FindElement(By.Id("FormId"))).SelectByValue("Email");
|
||||
s.Driver.TakeScreenshot().SaveAsFile("C:\\Users\\NicolasDorier\\Downloads\\chromedriver-win64\\1.png");
|
||||
s.ClickPagePrimary();
|
||||
|
||||
s.Driver.FindElement(By.XPath("//a[starts-with(@id, 'Edit-')]")).Click();
|
||||
@@ -2175,6 +2174,55 @@ namespace BTCPayServer.Tests
|
||||
Assert.Contains("PP1 Edited", s.Driver.PageSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
public async Task CanUseAwaitProgressForInProgressPayout()
|
||||
{
|
||||
using var s = CreateSeleniumTester();
|
||||
await s.StartAsync();
|
||||
s.RegisterNewUser(true);
|
||||
s.CreateNewStore();
|
||||
s.GenerateWallet(isHotWallet: true);
|
||||
await s.FundStoreWallet(denomination: 50.0m);
|
||||
|
||||
s.GoToStore(s.StoreId, StoreNavPages.PayoutProcessors);
|
||||
s.Driver.FindElement(By.Id("Configure-BTC-CHAIN")).Click();
|
||||
s.Driver.SetCheckbox(By.Id("ProcessNewPayoutsInstantly"), true);
|
||||
s.ClickPagePrimary();
|
||||
|
||||
s.GoToStore(s.StoreId, StoreNavPages.PullPayments);
|
||||
s.ClickPagePrimary();
|
||||
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
|
||||
s.Driver.FindElement(By.Id("Amount")).Clear();
|
||||
s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0");
|
||||
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
|
||||
s.ClickPagePrimary();
|
||||
|
||||
s.Driver.FindElement(By.LinkText("View")).Click();
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last());
|
||||
|
||||
var address = await s.Server.ExplorerNode.GetNewAddressAsync();
|
||||
s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString() + Keys.Enter);
|
||||
s.GoToStore(s.StoreId, StoreNavPages.Payouts);
|
||||
s.Driver.FindElement(By.Id("InProgress-view")).Click();
|
||||
|
||||
// Waiting for the payment processor to process the payment
|
||||
int i = 0;
|
||||
while (!s.Driver.PageSource.Contains("mass-action-select-all"))
|
||||
{
|
||||
s.Driver.Navigate().Refresh();
|
||||
i++;
|
||||
Thread.Sleep(1000);
|
||||
if (i > 10)
|
||||
break;
|
||||
}
|
||||
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||
|
||||
s.Driver.FindElement(By.Id("InProgress-mark-awaiting-payment")).Click();
|
||||
s.Driver.FindElement(By.Id("AwaitingPayment-view")).Click();
|
||||
Assert.Contains("PP1", s.Driver.PageSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
|
||||
@@ -439,7 +439,28 @@ namespace BTCPayServer.Controllers
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case "mark-awaiting-payment":
|
||||
await using (var context = _dbContextFactory.CreateContext())
|
||||
{
|
||||
var payouts = (await PullPaymentHostedService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
|
||||
{
|
||||
States = new[] { PayoutState.InProgress },
|
||||
Stores = new[] { storeId },
|
||||
PayoutIds = payoutIds
|
||||
}, context));
|
||||
foreach (var payout in payouts)
|
||||
{
|
||||
payout.State = PayoutState.AwaitingPayment;
|
||||
payout.Proof = null;
|
||||
}
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Message = "Payout payments have been marked as awaiting payment",
|
||||
Severity = StatusMessageModel.StatusSeverity.Success
|
||||
});
|
||||
break;
|
||||
case "cancel":
|
||||
await _pullPaymentService.Cancel(
|
||||
new PullPaymentHostedService.CancelRequest(payoutIds, new[] { storeId }));
|
||||
|
||||
@@ -339,61 +339,22 @@ public class BitcoinLikePayoutHandler : IPayoutHandler, IHasNetwork
|
||||
{
|
||||
var proof = ParseProof(payout) as PayoutTransactionOnChainBlob;
|
||||
var payoutBlob = payout.GetBlob(this._jsonSerializerSettings);
|
||||
if (proof is null || proof.Accounted is false)
|
||||
{
|
||||
if (proof?.Accounted is not true)
|
||||
continue;
|
||||
}
|
||||
foreach (var txid in proof.Candidates.ToList())
|
||||
{
|
||||
var explorer = _explorerClientProvider.GetExplorerClient(Network.CryptoCode);
|
||||
var tx = await explorer.GetTransactionAsync(txid);
|
||||
if (tx is null)
|
||||
{
|
||||
proof.Candidates.Remove(txid);
|
||||
}
|
||||
else if (tx.Confirmations >= payoutBlob.MinimumConfirmation)
|
||||
continue;
|
||||
if (tx.Confirmations >= payoutBlob.MinimumConfirmation)
|
||||
{
|
||||
payout.State = PayoutState.Completed;
|
||||
proof.TransactionId = tx.TransactionHash;
|
||||
updatedPayouts.Add(payout);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rebroadcasted = await explorer.BroadcastAsync(tx.Transaction);
|
||||
if (rebroadcasted.RPCCode == RPCErrorCode.RPC_TRANSACTION_ERROR ||
|
||||
rebroadcasted.RPCCode == RPCErrorCode.RPC_TRANSACTION_REJECTED)
|
||||
{
|
||||
proof.Candidates.Remove(txid);
|
||||
}
|
||||
else
|
||||
{
|
||||
payout.State = PayoutState.InProgress;
|
||||
proof.TransactionId = tx.TransactionHash;
|
||||
updatedPayouts.Add(payout);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (proof.TransactionId is not null && !proof.Candidates.Contains(proof.TransactionId))
|
||||
{
|
||||
proof.TransactionId = null;
|
||||
}
|
||||
|
||||
if (proof.Candidates.Count == 0)
|
||||
{
|
||||
if (payout.State != PayoutState.AwaitingPayment)
|
||||
{
|
||||
updatedPayouts.Add(payout);
|
||||
}
|
||||
payout.State = PayoutState.AwaitingPayment;
|
||||
}
|
||||
else if (proof.TransactionId is null)
|
||||
{
|
||||
proof.TransactionId = proof.Candidates.First();
|
||||
}
|
||||
|
||||
if (payout.State == PayoutState.Completed)
|
||||
proof.Candidates = null;
|
||||
SetProofBlob(payout, proof);
|
||||
|
||||
@@ -39,11 +39,11 @@
|
||||
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
|
||||
@if (conf.Value is null)
|
||||
{
|
||||
<a href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)" text-translate="true">Configure</a>
|
||||
<a id="Configure-@conf.Key" href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)" text-translate="true">Configure</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)" text-translate="true">Modify</a>
|
||||
<a id="Configure-@conf.Key" href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)" text-translate="true">Modify</a>
|
||||
|
||||
@if (await processorsView.Factory.CanRemove())
|
||||
{
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
stateActions.Add(("cancel", StringLocalizer["Cancel"]));
|
||||
stateActions.Add(("mark-paid", StringLocalizer["Mark as already paid"]));
|
||||
break;
|
||||
case PayoutState.InProgress:
|
||||
stateActions.Add(("mark-awaiting-payment", StringLocalizer["Mark as awaiting payment"]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user