[perf] pending payments check (#3565)
Co-authored-by: dni ⚡ <office@dnilabs.com>
This commit is contained in:
parent
33e2fc2ea8
commit
0910687328
8 changed files with 74 additions and 30 deletions
|
|
@ -179,12 +179,18 @@ async def api_payments_daily_stats(
|
|||
)
|
||||
async def api_payments_paginated(
|
||||
key_info: WalletTypeInfo = Depends(require_invoice_key),
|
||||
recheck_pending: bool = Query(
|
||||
False, description="Force check and update of pending payments."
|
||||
),
|
||||
filters: Filters = Depends(parse_filters(PaymentFilters)),
|
||||
):
|
||||
page = await get_payments_paginated(
|
||||
wallet_id=key_info.wallet.id,
|
||||
filters=filters,
|
||||
)
|
||||
if not recheck_pending:
|
||||
return page
|
||||
|
||||
for payment in page.data:
|
||||
if payment.pending:
|
||||
await update_pending_payment(payment)
|
||||
|
|
|
|||
15
lnbits/db.py
15
lnbits/db.py
|
|
@ -522,7 +522,7 @@ class Filter(BaseModel, Generic[TFilterModel]):
|
|||
if field in model.__fields__:
|
||||
compare_field = model.__fields__[field]
|
||||
values: dict = {}
|
||||
if op in {Operator.EVERY, Operator.ANY}:
|
||||
if op in {Operator.EVERY, Operator.ANY, Operator.INCLUDE, Operator.EXCLUDE}:
|
||||
raw_values = [v for rv in raw_values for v in rv.split(",")]
|
||||
|
||||
for index, raw_value in enumerate(raw_values):
|
||||
|
|
@ -540,14 +540,17 @@ class Filter(BaseModel, Generic[TFilterModel]):
|
|||
prefix = f"{self.table_name}." if self.table_name else ""
|
||||
stmt = []
|
||||
for key in self.values.keys() if self.values else []:
|
||||
clean_key = key.split("__")[0]
|
||||
if self.model and self.model.__fields__[clean_key].type_ == datetime:
|
||||
if self.model and self.model.__fields__[self.field].type_ == datetime:
|
||||
placeholder = compat_timestamp_placeholder(key)
|
||||
stmt.append(f"{prefix}{clean_key} {self.op.as_sql} {placeholder}")
|
||||
stmt.append(f"{prefix}{self.field} {self.op.as_sql} {placeholder}")
|
||||
if self.op in {Operator.INCLUDE, Operator.EXCLUDE}:
|
||||
stmt.append(f":{key}")
|
||||
else:
|
||||
stmt.append(f"{prefix}{clean_key} {self.op.as_sql} :{key}")
|
||||
stmt.append(f"{prefix}{self.field} {self.op.as_sql} :{key}")
|
||||
|
||||
if self.op == Operator.EVERY:
|
||||
if self.op in {Operator.INCLUDE, Operator.EXCLUDE}:
|
||||
statement = f"{prefix}{self.field} {self.op.as_sql} ({', '.join(stmt)})"
|
||||
elif self.op == Operator.EVERY:
|
||||
statement = " AND ".join(stmt)
|
||||
else:
|
||||
statement = " OR ".join(stmt)
|
||||
|
|
|
|||
2
lnbits/static/bundle-components.min.js
vendored
2
lnbits/static/bundle-components.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,6 @@
|
|||
window.app.component('lnbits-payment-list', {
|
||||
template: '#lnbits-payment-list',
|
||||
props: ['update', 'lazy', 'wallet', 'paymentFilter'],
|
||||
props: ['wallet', 'paymentFilter'],
|
||||
mixins: [window.windowMixin],
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -198,6 +198,7 @@ window.app.component('lnbits-payment-list', {
|
|||
this.payments = response.data.data.map(obj => {
|
||||
return LNbits.map.payment(obj)
|
||||
})
|
||||
this.recheckPendingPayments()
|
||||
})
|
||||
.catch(err => {
|
||||
this.paymentsTable.loading = false
|
||||
|
|
@ -244,6 +245,45 @@ window.app.component('lnbits-payment-list', {
|
|||
})
|
||||
.catch(LNbits.utils.notifyApiError)
|
||||
},
|
||||
recheckPendingPayments() {
|
||||
const pendingPayments = this.payments.filter(p => p.status === 'pending')
|
||||
if (pendingPayments.length === 0) return
|
||||
|
||||
const params = [
|
||||
'recheck_pending=true',
|
||||
'checking_id[in]=' + pendingPayments.map(p => p.checking_id).join(',')
|
||||
].join('&')
|
||||
|
||||
LNbits.api
|
||||
.getPayments(this.currentWallet, params)
|
||||
.then(response => {
|
||||
let updatedPayments = 0
|
||||
response.data.data.forEach(updatedPayment => {
|
||||
if (updatedPayment.status !== 'pending') {
|
||||
const index = this.payments.findIndex(
|
||||
p => p.checking_id === updatedPayment.checking_id
|
||||
)
|
||||
if (index !== -1) {
|
||||
this.payments.splice(
|
||||
index,
|
||||
1,
|
||||
LNbits.map.payment(updatedPayment)
|
||||
)
|
||||
updatedPayments += 1
|
||||
}
|
||||
}
|
||||
})
|
||||
if (updatedPayments > 0) {
|
||||
Quasar.Notify.create({
|
||||
type: 'positive',
|
||||
message: this.$t('payment_successful')
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn(err)
|
||||
})
|
||||
},
|
||||
showHoldInvoiceDialog(payment) {
|
||||
this.hodlInvoice.show = true
|
||||
this.hodlInvoice.preimage = ''
|
||||
|
|
@ -423,23 +463,11 @@ window.app.component('lnbits-payment-list', {
|
|||
this.fetchPayments()
|
||||
}
|
||||
},
|
||||
lazy(newVal) {
|
||||
if (newVal === true) this.fetchPayments()
|
||||
},
|
||||
update() {
|
||||
this.fetchPayments()
|
||||
},
|
||||
'g.updatePayments'() {
|
||||
this.fetchPayments()
|
||||
},
|
||||
'g.wallet': {
|
||||
handler(newWallet) {
|
||||
this.fetchPayments()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.lazy === undefined) this.fetchPayments()
|
||||
this.fetchPayments()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ window.PageWallet = {
|
|||
)
|
||||
.then(response => {
|
||||
dismissPaymentMsg()
|
||||
this.updatePayments = !this.updatePayments
|
||||
this.g.updatePayments = !this.g.updatePayments
|
||||
this.parse.show = false
|
||||
if (response.data.status == 'success') {
|
||||
Quasar.Notify.create({
|
||||
|
|
|
|||
|
|
@ -18,12 +18,7 @@
|
|||
//Needed for Vue to create the app on first load (although called on every page, its only loaded once)
|
||||
window.app = Vue.createApp({
|
||||
el: '#vue',
|
||||
mixins: [window.windowMixin],
|
||||
data() {
|
||||
return {
|
||||
updatePayments: false
|
||||
}
|
||||
}
|
||||
mixins: [window.windowMixin]
|
||||
})
|
||||
</script>
|
||||
{%- endmacro %}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@
|
|||
<q-card class="wallet-card">
|
||||
<q-card-section>
|
||||
<lnbits-payment-list
|
||||
:update="updatePayments"
|
||||
:expand-details="expandDetails"
|
||||
:payment-filter="paymentFilter"
|
||||
></lnbits-payment-list>
|
||||
|
|
|
|||
|
|
@ -418,9 +418,22 @@ async def test_get_payments_paginated(client, inkey_fresh_headers_to, fake_payme
|
|||
)
|
||||
assert response.status_code == 200
|
||||
paginated = response.json()
|
||||
assert len(paginated["data"]) == 2
|
||||
data = paginated["data"]
|
||||
assert len(data) == 2
|
||||
assert paginated["total"] == len(fake_data)
|
||||
|
||||
checking_id_list = [payment["checking_id"] for payment in data]
|
||||
params = {"checking_id[in]": ",".join(checking_id_list)}
|
||||
response = await client.get(
|
||||
"/api/v1/payments/paginated",
|
||||
params=params,
|
||||
headers=inkey_fresh_headers_to,
|
||||
)
|
||||
data = response.json()["data"]
|
||||
assert len(data) == 2
|
||||
for payment in data:
|
||||
assert payment["checking_id"] in checking_id_list
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_get_payments_history(client, inkey_fresh_headers_to, fake_payments):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue