feat: filter orders
This commit is contained in:
parent
21ecf6c3c7
commit
5b03c324f1
5 changed files with 138 additions and 26 deletions
31
crud.py
31
crud.py
|
|
@ -445,21 +445,34 @@ async def get_order_by_event_id(merchant_id: str, event_id: str) -> Optional[Ord
|
||||||
return Order.from_row(row) if row else None
|
return Order.from_row(row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_orders(merchant_id: str) -> List[Order]:
|
async def get_orders(merchant_id: str, **kwargs) -> List[Order]:
|
||||||
|
q = " AND ".join(
|
||||||
|
[f"{field[0]} = ?" for field in kwargs.items() if field[1] != None]
|
||||||
|
)
|
||||||
|
values = ()
|
||||||
|
if q:
|
||||||
|
q = f"AND {q}"
|
||||||
|
values = (v for v in kwargs.values() if v != None)
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
"SELECT * FROM nostrmarket.orders WHERE merchant_id = ? ORDER BY time DESC",
|
f"SELECT * FROM nostrmarket.orders WHERE merchant_id = ? {q} ORDER BY time DESC",
|
||||||
(merchant_id,),
|
(merchant_id, *values),
|
||||||
)
|
)
|
||||||
return [Order.from_row(row) for row in rows]
|
return [Order.from_row(row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
async def get_orders_for_stall(merchant_id: str, stall_id: str) -> List[Order]:
|
async def get_orders_for_stall(
|
||||||
|
merchant_id: str, stall_id: str, **kwargs
|
||||||
|
) -> List[Order]:
|
||||||
|
q = " AND ".join(
|
||||||
|
[f"{field[0]} = ?" for field in kwargs.items() if field[1] != None]
|
||||||
|
)
|
||||||
|
values = ()
|
||||||
|
if q:
|
||||||
|
q = f"AND {q}"
|
||||||
|
values = (v for v in kwargs.values() if v != None)
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
"SELECT * FROM nostrmarket.orders WHERE merchant_id = ? AND stall_id = ? ORDER BY time DESC",
|
f"SELECT * FROM nostrmarket.orders WHERE merchant_id = ? AND stall_id = ? {q} ORDER BY time DESC",
|
||||||
(
|
(merchant_id, stall_id, *values),
|
||||||
merchant_id,
|
|
||||||
stall_id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return [Order.from_row(row) for row in rows]
|
return [Order.from_row(row) for row in rows]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,45 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="row q-mb-md">
|
<div class="row q-mb-md">
|
||||||
<div class="col">
|
<div class="col-3 q-pr-lg">
|
||||||
|
<q-select
|
||||||
|
v-model="search.publicKey"
|
||||||
|
:options="customers.map(c => ({label: buildCustomerLabel(c), value: c.public_key}))"
|
||||||
|
label="Customer"
|
||||||
|
emit-value
|
||||||
|
class="text-wrap"
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 q-pr-lg">
|
||||||
|
<q-select
|
||||||
|
v-model="search.isPaid"
|
||||||
|
:options="ternaryOptions"
|
||||||
|
label="Paid"
|
||||||
|
emit-value
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 q-pr-lg">
|
||||||
|
<q-select
|
||||||
|
v-model="search.isShipped"
|
||||||
|
:options="ternaryOptions"
|
||||||
|
label="Shipped"
|
||||||
|
emit-value
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
<q-btn
|
<q-btn
|
||||||
unelevated
|
unelevated
|
||||||
color="secondary"
|
|
||||||
outline
|
outline
|
||||||
icon="refresh"
|
icon="search"
|
||||||
@click="getOrders()"
|
@click="getOrders()"
|
||||||
class="float-left"
|
class="float-right"
|
||||||
>Refresh Orders</q-btn
|
>Search Orders</q-btn
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row q-mt-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-table
|
<q-table
|
||||||
flat
|
flat
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,26 @@ async function orderList(path) {
|
||||||
shippingMessage: '',
|
shippingMessage: '',
|
||||||
showShipDialog: false,
|
showShipDialog: false,
|
||||||
filter: '',
|
filter: '',
|
||||||
|
search: {
|
||||||
|
publicKey: '',
|
||||||
|
isPaid: null,
|
||||||
|
isShipped: null
|
||||||
|
},
|
||||||
|
customers: [],
|
||||||
|
ternaryOptions: [
|
||||||
|
{
|
||||||
|
label: 'All',
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Yes',
|
||||||
|
value: 'true'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'No',
|
||||||
|
value: 'false'
|
||||||
|
}
|
||||||
|
],
|
||||||
ordersTable: {
|
ordersTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
|
@ -83,11 +103,22 @@ async function orderList(path) {
|
||||||
getOrders: async function () {
|
getOrders: async function () {
|
||||||
try {
|
try {
|
||||||
const ordersPath = this.stallId
|
const ordersPath = this.stallId
|
||||||
? `/stall/order/${this.stallId}`
|
? `stall/order/${this.stallId}`
|
||||||
: '/order'
|
: 'order'
|
||||||
|
|
||||||
|
const query = []
|
||||||
|
if (this.search.publicKey) {
|
||||||
|
query.push(`pubkey=${this.search.publicKey}`)
|
||||||
|
}
|
||||||
|
if (this.search.isPaid) {
|
||||||
|
query.push(`paid=${this.search.isPaid}`)
|
||||||
|
}
|
||||||
|
if (this.search.isShipped) {
|
||||||
|
query.push(`shipped=${this.search.isShipped}`)
|
||||||
|
}
|
||||||
const {data} = await LNbits.api.request(
|
const {data} = await LNbits.api.request(
|
||||||
'GET',
|
'GET',
|
||||||
'/nostrmarket/api/v1' + ordersPath,
|
`/nostrmarket/api/v1/${ordersPath}?${query.join('&')}`,
|
||||||
this.inkey
|
this.inkey
|
||||||
)
|
)
|
||||||
this.orders = data.map(s => ({...s, expanded: false}))
|
this.orders = data.map(s => ({...s, expanded: false}))
|
||||||
|
|
@ -129,10 +160,35 @@ async function orderList(path) {
|
||||||
},
|
},
|
||||||
customerSelected: function (customerPubkey) {
|
customerSelected: function (customerPubkey) {
|
||||||
this.$emit('customer-selected', customerPubkey)
|
this.$emit('customer-selected', customerPubkey)
|
||||||
|
},
|
||||||
|
getCustomers: async function () {
|
||||||
|
try {
|
||||||
|
const {data} = await LNbits.api.request(
|
||||||
|
'GET',
|
||||||
|
'/nostrmarket/api/v1/customers',
|
||||||
|
this.inkey
|
||||||
|
)
|
||||||
|
this.customers = data
|
||||||
|
} catch (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buildCustomerLabel: function (c) {
|
||||||
|
let label = `${c.profile.name || 'unknown'} ${c.profile.about || ''}`
|
||||||
|
if (c.unread_messages) {
|
||||||
|
label += `[new: ${c.unread_messages}]`
|
||||||
|
}
|
||||||
|
label += ` (${c.public_key.slice(0, 16)}...${c.public_key.slice(
|
||||||
|
c.public_key.length - 16
|
||||||
|
)}`
|
||||||
|
return label
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
await this.getOrders()
|
if (this.stallId) {
|
||||||
|
await this.getOrders()
|
||||||
|
}
|
||||||
|
await this.getCustomers()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,13 @@
|
||||||
<q-card class="q-mt-lg">
|
<q-card class="q-mt-lg">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-2"></div>
|
<div class="col-12">
|
||||||
<div class="col-8"></div>
|
<order-list
|
||||||
<div class="col-2"></div>
|
:adminkey="g.user.wallets[0].adminkey"
|
||||||
|
:inkey="g.user.wallets[0].inkey"
|
||||||
|
@customer-selected="customerSelectedForOrder"
|
||||||
|
></order-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
|
||||||
20
views_api.py
20
views_api.py
|
|
@ -1,6 +1,6 @@
|
||||||
import json
|
import json
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from fastapi.exceptions import HTTPException
|
from fastapi.exceptions import HTTPException
|
||||||
|
|
@ -448,12 +448,17 @@ async def api_get_stall_products(
|
||||||
@nostrmarket_ext.get("/api/v1/stall/order/{stall_id}")
|
@nostrmarket_ext.get("/api/v1/stall/order/{stall_id}")
|
||||||
async def api_get_stall_orders(
|
async def api_get_stall_orders(
|
||||||
stall_id: str,
|
stall_id: str,
|
||||||
|
paid: Optional[bool] = None,
|
||||||
|
shipped: Optional[bool] = None,
|
||||||
|
pubkey: Optional[str] = None,
|
||||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
merchant = await get_merchant_for_user(wallet.wallet.user)
|
merchant = await get_merchant_for_user(wallet.wallet.user)
|
||||||
assert merchant, "Merchant cannot be found"
|
assert merchant, "Merchant cannot be found"
|
||||||
orders = await get_orders_for_stall(merchant.id, stall_id)
|
orders = await get_orders_for_stall(
|
||||||
|
merchant.id, stall_id, paid=paid, shipped=shipped, public_key=pubkey
|
||||||
|
)
|
||||||
return orders
|
return orders
|
||||||
except AssertionError as ex:
|
except AssertionError as ex:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -673,12 +678,19 @@ async def api_get_order(order_id: str, wallet: WalletTypeInfo = Depends(get_key_
|
||||||
|
|
||||||
|
|
||||||
@nostrmarket_ext.get("/api/v1/order")
|
@nostrmarket_ext.get("/api/v1/order")
|
||||||
async def api_get_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_get_orders(
|
||||||
|
paid: Optional[bool] = None,
|
||||||
|
shipped: Optional[bool] = None,
|
||||||
|
pubkey: Optional[str] = None,
|
||||||
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
merchant = await get_merchant_for_user(wallet.wallet.user)
|
merchant = await get_merchant_for_user(wallet.wallet.user)
|
||||||
assert merchant, "Merchant cannot be found"
|
assert merchant, "Merchant cannot be found"
|
||||||
|
|
||||||
orders = await get_orders(merchant.id)
|
orders = await get_orders(
|
||||||
|
merchant_id=merchant.id, paid=paid, shipped=shipped, public_key=pubkey
|
||||||
|
)
|
||||||
return orders
|
return orders
|
||||||
except AssertionError as ex:
|
except AssertionError as ex:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue