feat: filter orders

This commit is contained in:
Vlad Stan 2023-03-29 16:22:05 +03:00
parent 21ecf6c3c7
commit 5b03c324f1
5 changed files with 138 additions and 26 deletions

31
crud.py
View file

@ -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]

View file

@ -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

View file

@ -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()
} }
}) })
} }

View file

@ -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>

View file

@ -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(