feat: handle order paid

This commit is contained in:
Vlad Stan 2023-03-07 13:10:01 +02:00
parent 76af65c148
commit 8094bcaf8a
4 changed files with 93 additions and 13 deletions

27
crud.py
View file

@ -1,5 +1,4 @@
import json import json
import time
from typing import List, Optional from typing import List, Optional
from lnbits.helpers import urlsafe_short_hash from lnbits.helpers import urlsafe_short_hash
@ -9,7 +8,6 @@ from .models import (
Merchant, Merchant,
Order, Order,
PartialMerchant, PartialMerchant,
PartialOrder,
PartialProduct, PartialProduct,
PartialStall, PartialStall,
PartialZone, PartialZone,
@ -380,3 +378,28 @@ async def get_orders_for_stall(user_id: str, stall_id: str) -> List[Order]:
), ),
) )
return [Order.from_row(row) for row in rows] return [Order.from_row(row) for row in rows]
async def update_order_paid_status(order_id: str, paid: bool) -> Optional[Order]:
await db.execute(
f"UPDATE nostrmarket.orders SET paid = ? WHERE id = ?",
(paid, order_id),
)
row = await db.fetchone(
"SELECT * FROM nostrmarket.orders WHERE id = ?",
(order_id,),
)
return Order.from_row(row) if row else None
async def update_order_shipped_status(order_id: str, shipped: bool) -> Optional[Order]:
await db.execute(
f"UPDATE nostrmarket.orders SET shipped = ? WHERE id = ?",
(order_id, shipped),
)
row = await db.fetchone(
"SELECT * FROM nostrmarket.orders WHERE id = ?",
(order_id,),
)
return Order.from_row(row) if row else None

View file

@ -343,6 +343,13 @@ class Order(PartialOrder):
return order return order
class OrderStatusUpdate(BaseModel):
id: str
message: Optional[str]
paid: Optional[bool]
shipped: Optional[bool]
class PaymentOption(BaseModel): class PaymentOption(BaseModel):
type: str type: str
link: str link: str

View file

@ -16,9 +16,10 @@ from .crud import (
get_merchant_by_pubkey, get_merchant_by_pubkey,
get_public_keys_for_merchants, get_public_keys_for_merchants,
get_wallet_for_product, get_wallet_for_product,
update_order_paid_status,
) )
from .helpers import order_from_json from .helpers import order_from_json
from .models import PartialOrder from .models import OrderStatusUpdate, PartialOrder
from .nostr.event import NostrEvent from .nostr.event import NostrEvent
from .nostr.nostr_client import connect_to_nostrclient_ws, publish_nostr_event from .nostr.nostr_client import connect_to_nostrclient_ws, publish_nostr_event
@ -36,7 +37,33 @@ async def on_invoice_paid(payment: Payment) -> None:
if payment.extra.get("tag") != "nostrmarket": if payment.extra.get("tag") != "nostrmarket":
return return
print("### on_invoice_paid", json.dumps(payment)) order_id = payment.extra.get("order_id")
merchant_pubkey = payment.extra.get("merchant_pubkey")
if not order_id or not merchant_pubkey:
return None
await handle_order_paid(order_id, merchant_pubkey)
async def handle_order_paid(order_id: str, merchant_pubkey: str):
try:
order = await update_order_paid_status(order_id, True)
assert order, f"Paid order cannot be found. Order id: {order_id}"
order_status = OrderStatusUpdate(
id=order_id, message="Payment received.", paid=True, shipped=order.shipped
)
merchant = await get_merchant_by_pubkey(merchant_pubkey)
assert merchant, f"Merchant cannot be foud for order {order_id}"
dm_content = json.dumps(
order_status.dict(), separators=(",", ":"), ensure_ascii=False
)
dm_event = merchant.build_dm_event(dm_content, order.pubkey)
await publish_nostr_event(dm_event)
except Exception as ex:
logger.warning(ex)
async def subscribe_to_nostr_client(recieve_event_queue: Queue, send_req_queue: Queue): async def subscribe_to_nostr_client(recieve_event_queue: Queue, send_req_queue: Queue):
@ -60,7 +87,6 @@ async def subscribe_to_nostr_client(recieve_event_queue: Queue, send_req_queue:
# be sure the connection is open # be sure the connection is open
await asyncio.sleep(3) await asyncio.sleep(3)
req = await send_req_queue.get() req = await send_req_queue.get()
print("### req", req)
ws.send(json.dumps(req)) ws.send(json.dumps(req))
except Exception as ex: except Exception as ex:
logger.warning(ex) logger.warning(ex)
@ -100,9 +126,9 @@ async def handle_nip04_message(public_key: str, event: NostrEvent):
assert merchant, f"Merchant not found for public key '{public_key}'" assert merchant, f"Merchant not found for public key '{public_key}'"
clear_text_msg = merchant.decrypt_message(event.content, event.pubkey) clear_text_msg = merchant.decrypt_message(event.content, event.pubkey)
dm_resp = await handle_dirrect_message(event.pubkey, event.id, clear_text_msg) dm_content = await handle_dirrect_message(event.pubkey, event.id, clear_text_msg)
if dm_resp: if dm_content:
dm_event = merchant.build_dm_event(dm_resp, event.pubkey) dm_event = merchant.build_dm_event(dm_content, event.pubkey)
await publish_nostr_event(dm_event) await publish_nostr_event(dm_event)

View file

@ -93,7 +93,7 @@ async def api_get_merchant(
logger.warning(ex) logger.warning(ex)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot create merchant", detail="Cannot get merchant",
) )
@ -108,7 +108,7 @@ async def api_get_zones(wallet: WalletTypeInfo = Depends(get_key_type)) -> List[
logger.warning(ex) logger.warning(ex)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot create merchant", detail="Cannot get zone",
) )
@ -123,7 +123,7 @@ async def api_create_zone(
logger.warning(ex) logger.warning(ex)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot create merchant", detail="Cannot create zone",
) )
@ -149,7 +149,7 @@ async def api_update_zone(
logger.warning(ex) logger.warning(ex)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot create merchant", detail="Cannot update zone",
) )
@ -170,7 +170,7 @@ async def api_delete_zone(zone_id, wallet: WalletTypeInfo = Depends(require_admi
logger.warning(ex) logger.warning(ex)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot create merchant", detail="Cannot delete zone",
) )
@ -463,6 +463,9 @@ async def api_create_order(
): ):
return None return None
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Cannot find merchant!"
products = await get_products_by_ids( products = await get_products_by_ids(
wallet.wallet.user, [p.product_id for p in data.items] wallet.wallet.user, [p.product_id for p in data.items]
) )
@ -480,6 +483,7 @@ async def api_create_order(
extra={ extra={
"tag": "nostrmarket", "tag": "nostrmarket",
"order_id": data.id, "order_id": data.id,
"merchant_pubkey": merchant.public_key,
}, },
) )
@ -538,6 +542,26 @@ async def api_get_orders(wallet: WalletTypeInfo = Depends(get_key_type)):
) )
# @nostrmarket_ext.patch("/api/v1/order/{order_id}")
# async def api_update_order(
# data: OrderStatusUpdate,
# wallet: WalletTypeInfo = Depends(require_admin_key),
# ) -> Zone:
# try:
# zone = await update_order(wallet.wallet.user, data)
# assert zone, "Cannot find updated zone"
# return zone
# except HTTPException as ex:
# raise ex
# except Exception as ex:
# logger.warning(ex)
# raise HTTPException(
# status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
# detail="Cannot update order",
# )
######################################## OTHER ######################################## ######################################## OTHER ########################################