Adds settle receivable functionality

Implements a "Settle Receivable" feature for super users to record manual payments from users who owe money.

Introduces a dialog for inputting payment details (amount, method, description, reference), triggers an API call to record the transaction, and updates user balances and transaction history.

This is for non-lightning payments like cash, bank transfers, or checks.
This commit is contained in:
padreug 2025-10-23 02:57:21 +02:00
parent d06f46a63c
commit 1412359172
4 changed files with 278 additions and 1 deletions

View file

@ -162,7 +162,8 @@
:rows="allUserBalances"
:columns="[
{name: 'user', label: 'User', field: 'username', align: 'left'},
{name: 'balance', label: 'Amount Owed', field: 'balance', align: 'right'}
{name: 'balance', label: 'Amount Owed', field: 'balance', align: 'right'},
{name: 'actions', label: 'Actions', align: 'center'}
]"
row-key="user_id"
hide-pagination
@ -189,6 +190,21 @@
</div>
</q-td>
</template>
<template v-slot:body-cell-actions="props">
<q-td :props="props">
<q-btn
v-if="props.row.balance < 0"
flat
dense
size="sm"
color="primary"
icon="payments"
@click="showSettleReceivableDialog(props.row)"
>
<q-tooltip>Settle receivable (user pays)</q-tooltip>
</q-btn>
</q-td>
</template>
</q-table>
</q-card-section>
</q-card>
@ -1108,4 +1124,83 @@
</q-card>
</q-dialog>
<!-- Settle Receivable Dialog (Super User Only) -->
<q-dialog v-model="settleReceivableDialog.show" position="top">
<q-card class="q-pa-md" style="min-width: 400px">
<q-form @submit="submitSettleReceivable">
<h6 class="q-my-none q-mb-md">Settle Receivable</h6>
<div class="q-mb-md">
<div class="text-subtitle2">User</div>
<div>{% raw %}{{ settleReceivableDialog.username }}{% endraw %}</div>
<div class="text-caption text-grey">{% raw %}{{ settleReceivableDialog.user_id }}{% endraw %}</div>
</div>
<div class="q-mb-md">
<div class="text-subtitle2">Amount Owed</div>
<div class="text-negative text-h6">{% raw %}{{ formatSats(settleReceivableDialog.maxAmount) }}{% endraw %} sats</div>
</div>
<q-input
filled
dense
v-model.number="settleReceivableDialog.amount"
type="number"
label="Settlement Amount (sats) *"
hint="Amount user is paying (max: owed amount)"
:max="settleReceivableDialog.maxAmount"
:rules="[
val => val !== null && val !== undefined && val !== '' || 'Amount is required',
val => val > 0 || 'Amount must be positive',
val => val <= settleReceivableDialog.maxAmount || 'Cannot exceed owed amount'
]"
></q-input>
<q-select
filled
dense
v-model="settleReceivableDialog.payment_method"
:options="[
{label: 'Cash', value: 'cash'},
{label: 'Bank Transfer', value: 'bank_transfer'},
{label: 'Check', value: 'check'},
{label: 'Other', value: 'other'}
]"
option-label="label"
option-value="value"
emit-value
map-options
label="Payment Method *"
:rules="[val => !!val || 'Payment method is required']"
></q-select>
<q-input
filled
dense
v-model="settleReceivableDialog.description"
type="text"
label="Description *"
hint="Description of the payment"
:rules="[val => !!val || 'Description is required']"
></q-input>
<q-input
filled
dense
v-model="settleReceivableDialog.reference"
type="text"
label="Reference (optional)"
hint="Receipt number, transaction ID, etc."
></q-input>
<div class="row q-mt-md q-gutter-sm">
<q-btn unelevated color="primary" type="submit" :loading="settleReceivableDialog.loading">
Settle Receivable
</q-btn>
<q-btn v-close-popup flat color="grey">Cancel</q-btn>
</div>
</q-form>
</q-card>
</q-dialog>
{% endblock %}