fix: store failed orders also

This commit is contained in:
Vlad Stan 2023-07-04 12:11:42 +03:00
parent bb376b43f2
commit acc6ed45c5
3 changed files with 90 additions and 51 deletions

View file

@ -65,11 +65,24 @@ async def create_new_order(
if data.event_id and await get_order_by_event_id(merchant.id, data.event_id): if data.event_id and await get_order_by_event_id(merchant.id, data.event_id):
return None return None
order, invoice = await _build_order_with_payment(
merchant.id, merchant.public_key, data
)
await create_order(merchant.id, order)
return PaymentRequest(
id=data.id, payment_options=[PaymentOption(type="ln", link=invoice)]
)
async def _build_order_with_payment(
merchant_id: str, merchant_public_key: str, data: PartialOrder
):
products = await get_products_by_ids( products = await get_products_by_ids(
merchant.id, [p.product_id for p in data.items] merchant_id, [p.product_id for p in data.items]
) )
data.validate_order_items(products) data.validate_order_items(products)
shipping_zone = await get_zone(merchant.id, data.shipping_id) shipping_zone = await get_zone(merchant_id, data.shipping_id)
assert shipping_zone, f"Shipping zone not found for order '{data.id}'" assert shipping_zone, f"Shipping zone not found for order '{data.id}'"
product_cost_sat, shipping_cost_sat = await data.costs_in_sats( product_cost_sat, shipping_cost_sat = await data.costs_in_sats(
@ -81,10 +94,10 @@ async def create_new_order(
product_ids = [i.product_id for i in data.items] product_ids = [i.product_id for i in data.items]
success, _, message = await compute_products_new_quantity( success, _, message = await compute_products_new_quantity(
merchant.id, product_ids, data.items merchant_id, product_ids, data.items
) )
if not success: if not success:
return PaymentRequest(id=data.id, message=message, payment_options=[]) raise ValueError(message)
payment_hash, invoice = await create_invoice( payment_hash, invoice = await create_invoice(
wallet_id=wallet_id, wallet_id=wallet_id,
@ -93,7 +106,7 @@ async def create_new_order(
extra={ extra={
"tag": "nostrmarket", "tag": "nostrmarket",
"order_id": data.id, "order_id": data.id,
"merchant_pubkey": merchant.public_key, "merchant_pubkey": merchant_public_key,
}, },
) )
@ -108,11 +121,8 @@ async def create_new_order(
total=product_cost_sat + shipping_cost_sat, total=product_cost_sat + shipping_cost_sat,
extra=extra, extra=extra,
) )
await create_order(merchant.id, order)
return PaymentRequest( return order, invoice
id=data.id, payment_options=[PaymentOption(type="ln", link=invoice)]
)
async def update_merchant_to_nostr( async def update_merchant_to_nostr(
@ -284,12 +294,14 @@ async def process_nostr_message(msg: str):
async def create_or_update_order_from_dm( async def create_or_update_order_from_dm(
merchant_id: str, merchant_pubkey: str, dm: DirectMessage merchant_id: str, merchant_pubkey: str, dm: DirectMessage
): ):
type, value = PartialDirectMessage.parse_message(dm.message) type, json_data = PartialDirectMessage.parse_message(dm.message)
if "id" not in value: if "id" not in json_data:
return return
if type == DirectMessageType.CUSTOMER_ORDER: if type == DirectMessageType.CUSTOMER_ORDER:
order = await extract_order_from_dm(merchant_id, merchant_pubkey, dm, value) order = await extract_customer_order_from_dm(
merchant_id, merchant_pubkey, dm, json_data
)
new_order = await create_order(merchant_id, order) new_order = await create_order(merchant_id, order)
if new_order.stall_id == "None" and order.stall_id != "None": if new_order.stall_id == "None" and order.stall_id != "None":
await update_order( await update_order(
@ -303,7 +315,7 @@ async def create_or_update_order_from_dm(
return return
if type == DirectMessageType.PAYMENT_REQUEST: if type == DirectMessageType.PAYMENT_REQUEST:
payment_request = PaymentRequest(**value) payment_request = PaymentRequest(**json_data)
pr = next( pr = next(
(o.link for o in payment_request.payment_options if o.type == "ln"), None (o.link for o in payment_request.payment_options if o.type == "ln"), None
) )
@ -318,31 +330,33 @@ async def create_or_update_order_from_dm(
return return
if type == DirectMessageType.ORDER_PAID_OR_SHIPPED: if type == DirectMessageType.ORDER_PAID_OR_SHIPPED:
order_update = OrderStatusUpdate(**value) order_update = OrderStatusUpdate(**json_data)
if order_update.paid: if order_update.paid:
await update_order_paid_status(order_update.id, True) await update_order_paid_status(order_update.id, True)
if order_update.shipped: if order_update.shipped:
await update_order_shipped_status(merchant_id, order_update.id, True) await update_order_shipped_status(merchant_id, order_update.id, True)
async def extract_order_from_dm( async def extract_customer_order_from_dm(
merchant_id: str, merchant_pubkey: str, dm: DirectMessage, value merchant_id: str, merchant_pubkey: str, dm: DirectMessage, json_data: dict
): ) -> Order:
order_items = [OrderItem(**i) for i in value.get("items", [])] order_items = [OrderItem(**i) for i in json_data.get("items", [])]
products = await get_products_by_ids( products = await get_products_by_ids(
merchant_id, [p.product_id for p in order_items] merchant_id, [p.product_id for p in order_items]
) )
extra = await OrderExtra.from_products(products) extra = await OrderExtra.from_products(products)
order = Order( order = Order(
id=value.get("id"), id=json_data.get("id"),
event_id=dm.event_id, event_id=dm.event_id,
event_created_at=dm.event_created_at, event_created_at=dm.event_created_at,
public_key=dm.public_key, public_key=dm.public_key,
merchant_public_key=merchant_pubkey, merchant_public_key=merchant_pubkey,
shipping_id=value.get("shipping_id", "None"), shipping_id=json_data.get("shipping_id", "None"),
items=order_items, items=order_items,
contact=OrderContact(**value.get("contact")) if value.get("contact") else None, contact=OrderContact(**json_data.get("contact"))
address=value.get("address"), if json_data.get("contact")
else None,
address=json_data.get("address"),
stall_id=products[0].stall_id if len(products) else "None", stall_id=products[0].stall_id if len(products) else "None",
invoice_id="None", invoice_id="None",
total=0, total=0,
@ -413,22 +427,21 @@ async def _handle_outgoing_dms(
async def _handle_incoming_structured_dm( async def _handle_incoming_structured_dm(
merchant: Merchant, dm: DirectMessage, json_data merchant: Merchant, dm: DirectMessage, json_data: dict
) -> Tuple[DirectMessageType, Optional[str]]: ) -> Tuple[DirectMessageType, str]:
try: try:
if dm.type == DirectMessageType.CUSTOMER_ORDER.value and merchant.config.active: if dm.type == DirectMessageType.CUSTOMER_ORDER.value and merchant.config.active:
json_data["public_key"] = dm.public_key json_resp = await _handle_new_order(
json_data["merchant_public_key"] = merchant.public_key merchant.id, merchant.public_key, dm, json_data
json_data["event_id"] = dm.event_id )
json_data["event_created_at"] = dm.event_created_at
json_data = await _handle_new_order(PartialOrder(**json_data)) return DirectMessageType.PAYMENT_REQUEST, json_resp
return DirectMessageType.PAYMENT_REQUEST, json_data
return None
except Exception as ex: except Exception as ex:
logger.warning(ex) logger.warning(ex)
return None
return None, None
async def _persist_dm( async def _persist_dm(
@ -484,29 +497,54 @@ async def _reply_to_structured_dm(
) )
async def _handle_new_order(order: PartialOrder) -> Optional[str]: async def _handle_new_order(
order.validate_order() merchant_id: str, merchant_public_key: str, dm: DirectMessage, json_data: dict
) -> str:
partial_order = PartialOrder(
**{
**json_data,
"merchant_public_key": merchant_public_key,
"public_key": dm.public_key,
"event_id": dm.event_id,
"event_created_at": dm.event_created_at,
}
)
partial_order.validate_order()
try: try:
first_product_id = order.items[0].product_id first_product_id = partial_order.items[0].product_id
wallet_id = await get_wallet_for_product(first_product_id) wallet_id = await get_wallet_for_product(first_product_id)
assert wallet_id, f"Cannot find wallet id for product id: {first_product_id}" assert wallet_id, f"Cannot find wallet id for product id: {first_product_id}"
wallet = await get_wallet(wallet_id) wallet = await get_wallet(wallet_id)
assert wallet, f"Cannot find wallet for product id: {first_product_id}" assert wallet, f"Cannot find wallet for product id: {first_product_id}"
payment_req = await create_new_order(order.merchant_public_key, order) payment_req = await create_new_order(merchant_public_key, partial_order)
except Exception as e: except Exception as e:
payment_req = PaymentRequest(id=order.id, message=str(e), payment_options=[]) payment_req = await create_new_failed_order(
merchant_id, merchant_public_key, dm, json_data, str(e)
)
if payment_req: response = {
response = { "type": DirectMessageType.PAYMENT_REQUEST.value,
"type": DirectMessageType.PAYMENT_REQUEST.value, **payment_req.dict(),
**payment_req.dict(), }
} return json.dumps(response, separators=(",", ":"), ensure_ascii=False)
return json.dumps(response, separators=(",", ":"), ensure_ascii=False)
return None
async def create_new_failed_order(
merchant_id: str,
merchant_public_key: str,
dm: DirectMessage,
json_data: dict,
failed_message: str,
) -> PaymentRequest:
order = await extract_customer_order_from_dm(
merchant_id, merchant_public_key, dm, json_data
)
await create_order(merchant_id, order)
return PaymentRequest(id=order.id, message=failed_message, payment_options=[])
async def _handle_new_customer(event, merchant: Merchant): async def _handle_new_customer(event, merchant: Merchant):

View file

@ -47,17 +47,17 @@
<strong>New order:</strong> <strong>New order:</strong>
</div> </div>
<div v-else-if="dm.message.type === 1"> <div v-else-if="dm.message.type === 1">
<strong>Invoice sent for order: </strong> <strong>Reply sent for order: </strong>
</div> </div>
<div v-else-if="dm.message.type === 2"> <div v-else-if="dm.message.type === 2">
<q-badge v-if="dm.message.paid" color="green">Paid </q-badge> <q-badge v-if="dm.message.paid" color="green">Paid </q-badge>
<q-badge v-if="dm.message.shipped" color="green">Shipped </q-badge> <q-badge v-if="dm.message.shipped" color="green">Shipped </q-badge>
<span v-text="dm.message.message"></span><br>
</div> </div>
<div> <div>
<span v-text="dm.message.id" @click="showOrderDetails(dm.message.id)" <span v-text="dm.message.message"></span>
class="cursor-pointer"></span> <q-badge color="orange">
<span v-text="dm.message.id" @click="showOrderDetails(dm.message.id)" class="cursor-pointer"></span>
</q-badge>
</div> </div>
<q-badge @click="showMessageRawData(index)" class="cursor-pointer">...</q-badge> <q-badge @click="showMessageRawData(index)" class="cursor-pointer">...</q-badge>

View file

@ -17,10 +17,11 @@ async function directMessages(path) {
messagesAsJson: function () { messagesAsJson: function () {
return this.messages.map(m => { return this.messages.map(m => {
try { try {
const message = JSON.parse(m.message)
return { return {
isJson: true, isJson: message.type >= 0,
...m, ...m,
message: JSON.parse(m.message) message
} }
} catch (error) { } catch (error) {
return { return {