From 547c477ce6e1b8c48937a5fae742a002b64e8db3 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Mon, 3 Apr 2023 11:57:55 +0300 Subject: [PATCH] fix: shipping cost; update UI on new order --- crud.py | 6 +++-- helpers.py | 4 +--- migrations.py | 1 + models.py | 18 +++++++++++---- services.py | 23 +++++++++++++++---- .../customer-stall/customer-stall.js | 5 ++-- .../direct-messages/direct-messages.js | 7 ++++++ static/components/order-list/order-list.html | 7 ++++-- static/components/order-list/order-list.js | 5 ++-- static/js/index.js | 3 +-- templates/nostrmarket/index.html | 1 + 11 files changed, 57 insertions(+), 23 deletions(-) diff --git a/crud.py b/crud.py index a4d5fb7..3be6bf6 100644 --- a/crud.py +++ b/crud.py @@ -393,12 +393,13 @@ async def create_order(merchant_id: str, o: Order) -> Order: address, contact_data, extra_data, - order_items, + order_items, + shipping_id, stall_id, invoice_id, total ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(event_id) DO NOTHING """, ( @@ -412,6 +413,7 @@ async def create_order(merchant_id: str, o: Order) -> Order: json.dumps(o.contact.dict() if o.contact else {}), json.dumps(o.extra.dict()), json.dumps([i.dict() for i in o.items]), + o.shipping_id, o.stall_id, o.invoice_id, o.total, diff --git a/helpers.py b/helpers.py index a81f5a5..d3c9f93 100644 --- a/helpers.py +++ b/helpers.py @@ -77,8 +77,6 @@ def copy_x(output, x32, y32, data): def order_from_json(s: str) -> Tuple[Optional[Any], Optional[str]]: try: order = json.loads(s) - return ( - (order, s) if (type(order) is dict) and "items" in order else (None, s) - ) + return (order, s) if (type(order) is dict) and "items" in order else (None, s) except ValueError: return None, s diff --git a/migrations.py b/migrations.py index 27d4e21..f928098 100644 --- a/migrations.py +++ b/migrations.py @@ -86,6 +86,7 @@ async def m001_initial(db): order_items TEXT NOT NULL, address TEXT, total REAL NOT NULL, + shipping_id TEXT NOT NULL, stall_id TEXT NOT NULL, invoice_id TEXT NOT NULL, paid BOOLEAN NOT NULL DEFAULT false, diff --git a/models.py b/models.py index e7565eb..47bc91b 100644 --- a/models.py +++ b/models.py @@ -2,7 +2,7 @@ import json import time from abc import abstractmethod from sqlite3 import Row -from typing import List, Optional +from typing import List, Optional, Tuple from pydantic import BaseModel @@ -313,6 +313,8 @@ class OrderExtra(BaseModel): products: List[ProductOverview] currency: str btc_price: str + shipping_cost: float = 0 + shipping_cost_sat: float = 0 @classmethod async def from_products(cls, products: List[Product]): @@ -329,6 +331,7 @@ class PartialOrder(BaseModel): event_created_at: Optional[int] public_key: str merchant_public_key: str + shipping_id: str items: List[OrderItem] contact: Optional[OrderContact] address: Optional[str] @@ -356,20 +359,25 @@ class PartialOrder(BaseModel): f"Order ({self.id}) has products from different stalls" ) - async def total_sats(self, products: List[Product]) -> float: + async def costs_in_sats( + self, products: List[Product], shipping_cost: float + ) -> Tuple[float, float]: product_prices = {} for p in products: product_prices[p.id] = p - amount: float = 0 # todo + product_cost: float = 0 # todo for item in self.items: price = product_prices[item.product_id].price currency = product_prices[item.product_id].config.currency or "sat" if currency != "sat": price = await fiat_amount_as_satoshis(price, currency) - amount += item.quantity * price + product_cost += item.quantity * price - return amount + if currency != "sat": + shipping_cost = await fiat_amount_as_satoshis(shipping_cost, currency) + + return product_cost, shipping_cost class Order(PartialOrder): diff --git a/services.py b/services.py index 46a3aba..827960b 100644 --- a/services.py +++ b/services.py @@ -20,6 +20,7 @@ from .crud import ( get_products_by_ids, get_stalls, get_wallet_for_product, + get_zone, increment_customer_unread_messages, update_customer_profile, update_order_paid_status, @@ -60,8 +61,12 @@ async def create_new_order( merchant.id, [p.product_id for p in data.items] ) data.validate_order_items(products) + shipping_zone = await get_zone(merchant.id, data.shipping_id) + assert shipping_zone, f"Shipping zone not found for order '{data.id}'" - total_amount = await data.total_sats(products) + product_cost_sat, shipping_cost_sat = await data.costs_in_sats( + products, shipping_zone.cost + ) wallet_id = await get_wallet_for_product(data.items[0].product_id) assert wallet_id, "Missing wallet for order `{data.id}`" @@ -75,7 +80,7 @@ async def create_new_order( payment_hash, invoice = await create_invoice( wallet_id=wallet_id, - amount=round(total_amount), + amount=round(product_cost_sat + shipping_cost_sat), memo=f"Order '{data.id}' for pubkey '{data.public_key}'", extra={ "tag": "nostrmarket", @@ -84,12 +89,16 @@ async def create_new_order( }, ) + extra = await OrderExtra.from_products(products) + extra.shipping_cost_sat = shipping_cost_sat + extra.shipping_cost = shipping_zone.cost + order = Order( **data.dict(), stall_id=products[0].stall_id, invoice_id=payment_hash, - total=total_amount, - extra=await OrderExtra.from_products(products), + total=product_cost_sat + shipping_cost_sat, + extra=extra, ) await create_order(merchant.id, order) await websocketUpdater( @@ -99,6 +108,7 @@ async def create_new_order( "type": "new-order", "stallId": products[0].stall_id, "customerPubkey": data.public_key, + "orderId": order.id, } ), ) @@ -312,6 +322,11 @@ async def _handle_dirrect_message( order["event_created_at"] = event_created_at return await _handle_new_order(PartialOrder(**order)) + await websocketUpdater( + merchant_id, + json.dumps({"type": "new-direct-message", "customerPubkey": from_pubkey}), + ) + return None except Exception as ex: logger.warning(ex) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index aedbac5..b185d83 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -375,8 +375,9 @@ async function customerStall(path) { this.qrCodeDialog.data.message = json.message return cb() } - let payment_request = json.payment_options.find(o => o.type == 'ln') - .link + let payment_request = json.payment_options.find( + o => o.type == 'ln' + ).link if (!payment_request) return this.loading = false this.qrCodeDialog.data.payment_request = payment_request diff --git a/static/components/direct-messages/direct-messages.js b/static/components/direct-messages/direct-messages.js index a16c151..39bc7d3 100644 --- a/static/components/direct-messages/direct-messages.js +++ b/static/components/direct-messages/direct-messages.js @@ -83,6 +83,13 @@ async function directMessages(path) { LNbits.utils.notifyApiError(error) } }, + handleNewMessage: async function (data) { + if (data.customerPubkey === this.activePublicKey) { + await this.getDirectMessages(this.activePublicKey) + } else { + await this.getCustomers() + } + }, showClientOrders: function () { this.$emit('customer-selected', this.activePublicKey) }, diff --git a/static/components/order-list/order-list.html b/static/components/order-list/order-list.html index 594b3d7..3f02776 100644 --- a/static/components/order-list/order-list.html +++ b/static/components/order-list/order-list.html @@ -141,8 +141,11 @@
-
-
Exchange Rate:
+
+
Exchange Rate (1 BTC):
{ - console.log('### t, o', t, item) product = order.extra.products.find(p => p.id === item.product_id) return t + item.quantity * product.price }, 0) diff --git a/static/js/index.js b/static/js/index.js index 29ea63f..2a8c6be 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -113,9 +113,7 @@ const merchant = async () => { const port = location.port ? `:${location.port}` : '' const wsUrl = `${scheme}://${document.domain}${port}/api/v1/ws/${this.merchant.id}` const wsConnection = new WebSocket(wsUrl) - console.log('### waiting for events') wsConnection.onmessage = async e => { - console.log('### e', e) const data = JSON.parse(e.data) if (data.type === 'new-order') { this.$q.notify({ @@ -126,6 +124,7 @@ const merchant = async () => { await this.$refs.orderListRef.addOrder(data) } else if (data.type === 'new-customer') { } else if (data.type === 'new-direct-message') { + await this.$refs.directMessagesRef.handleNewMessage(data) } } } catch (error) { diff --git a/templates/nostrmarket/index.html b/templates/nostrmarket/index.html index 3cf3f96..9064c0c 100644 --- a/templates/nostrmarket/index.html +++ b/templates/nostrmarket/index.html @@ -148,6 +148,7 @@