From 8e36007f56ed9ec058dc142e0619a4f4c7d4615f Mon Sep 17 00:00:00 2001 From: arcbtc Date: Wed, 4 Feb 2026 17:40:00 +0000 Subject: [PATCH 1/3] feat: needed for orders extension --- services.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ tasks.py | 28 ++++++++++++++++++++++++++-- views_api.py | 7 +++++-- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/services.py b/services.py index ae26b2a..ab1cc84 100644 --- a/services.py +++ b/services.py @@ -5,6 +5,7 @@ from lnbits.core.models import User from lnbits.helpers import create_access_token from lnbits.settings import settings +from loguru import logger from .helpers import from_csv, inventory_tags_to_list @@ -118,3 +119,47 @@ def has_omit_tag(item_omit_tags: str | list[str] | None) -> bool: def inventory_available_for_user(user: User | None) -> bool: return bool(user and "inventory" in (user.extensions or [])) + + +async def push_order_to_orders( + user_id: str, + payment, + tpos, + base_url: str | None = None, +) -> None: + details = payment.extra.get("details") or {} + payload = { + "source": "tpos", + "tpos_id": payment.extra.get("tpos_id"), + "tpos_name": tpos.name if tpos else None, + "payment_hash": payment.payment_hash, + "checking_id": payment.checking_id, + "amount_msat": payment.amount, + "fee_msat": payment.fee, + "memo": payment.memo, + "paid_in_fiat": bool(payment.extra.get("paid_in_fiat")), + "currency": details.get("currency"), + "exchange_rate": details.get("exchangeRate") or payment.extra.get("exchangeRate"), + "tax_included": details.get("taxIncluded"), + "tax_value": details.get("taxValue"), + "items": details.get("items") or [], + "notes": payment.extra.get("notes"), + "created_at": payment.time.isoformat() if payment.time else None, + "paid": True, + "shipped": True, + } + + access = create_access_token({"sub": "", "usr": user_id}, token_expire_minutes=1) + params = {} + if base_url: + params["base_url"] = base_url + async with httpx.AsyncClient() as client: + try: + await client.post( + url=f"http://{settings.host}:{settings.port}/orders/api/v1/orders", + headers={"Authorization": f"Bearer {access}"}, + params=params, + json=payload, + ) + except Exception as exc: + logger.warning(f"tpos: failed to push order to orders: {exc}") diff --git a/tasks.py b/tasks.py index be3de17..1d815ea 100644 --- a/tasks.py +++ b/tasks.py @@ -1,5 +1,6 @@ import asyncio +from lnbits.core.crud import get_user_active_extensions_ids, get_wallet from lnbits.core.models import Payment from lnbits.core.services import ( create_invoice, @@ -11,7 +12,7 @@ from loguru import logger from .crud import get_tpos -from .services import deduct_inventory_stock +from .services import deduct_inventory_stock, push_order_to_orders async def wait_for_paid_invoices(): @@ -65,9 +66,14 @@ async def on_invoice_paid(payment: Payment) -> None: await websocket_updater(tpos_id, str(stripped_payment)) + await maybe_push_order(payment, tpos) + inventory_payload = payment.extra.get("inventory") if inventory_payload: - await deduct_inventory_stock(payment.wallet_id, inventory_payload) + try: + await deduct_inventory_stock(payment.wallet_id, inventory_payload) + except Exception as exc: + logger.warning(f"tpos: inventory deduction failed: {exc}") if not tip_amount: # no tip amount @@ -90,3 +96,21 @@ async def on_invoice_paid(payment: Payment) -> None: extra={**payment.extra, "tipSplitted": True}, ) logger.debug(f"tpos: tip invoice paid: {paid_payment.checking_id}") + + +async def maybe_push_order(payment: Payment, tpos) -> None: + wallet = await get_wallet(payment.wallet_id) + if not wallet: + return + + active_extensions = await get_user_active_extensions_ids(wallet.user) + if "orders" not in active_extensions: + return + + details = payment.extra.get("details") or {} + await push_order_to_orders( + wallet.user, + payment, + tpos, + base_url=payment.extra.get("base_url"), + ) diff --git a/views_api.py b/views_api.py index 12f3b65..820f920 100644 --- a/views_api.py +++ b/views_api.py @@ -3,7 +3,7 @@ from typing import Any import httpx -from fastapi import APIRouter, Depends, HTTPException, Query +from fastapi import APIRouter, Depends, HTTPException, Query, Request from lnbits.core.crud import ( get_latest_payments_by_extension, get_standalone_payment, @@ -164,7 +164,9 @@ async def api_tpos_delete( @tpos_api_router.post( "/api/v1/tposs/{tpos_id}/invoices", status_code=HTTPStatus.CREATED ) -async def api_tpos_create_invoice(tpos_id: str, data: CreateTposInvoice) -> Payment: +async def api_tpos_create_invoice( + tpos_id: str, data: CreateTposInvoice, request: Request +) -> Payment: tpos = await get_tpos(tpos_id) if not tpos: @@ -227,6 +229,7 @@ async def api_tpos_create_invoice(tpos_id: str, data: CreateTposInvoice) -> Paym "lnaddress": data.user_lnaddress if data.user_lnaddress else None, "internal_memo": data.internal_memo if data.internal_memo else None, "paid_in_fiat": data.pay_in_fiat, + "base_url": str(request.base_url), } if inventory_payload: extra["inventory"] = inventory_payload.dict() From 67d5d7f99fafb43179c6ca9980ea4c00679d2b28 Mon Sep 17 00:00:00 2001 From: arcbtc Date: Wed, 4 Feb 2026 19:21:50 +0000 Subject: [PATCH 2/3] added weight --- static/js/tpos.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/js/tpos.js b/static/js/tpos.js index 582ccb5..8fb2dad 100644 --- a/static/js/tpos.js +++ b/static/js/tpos.js @@ -787,6 +787,7 @@ window.app = Vue.createApp({ formattedPrice: item.formattedPrice, quantity: item.quantity, title: item.title, + weight_grams: item.weight_grams, tax: item.tax || this.taxDefault, note: item.note || null })), From 0e4c483356a486c1ed2ae97f1cfb2ce522053f38 Mon Sep 17 00:00:00 2001 From: arcbtc Date: Wed, 4 Feb 2026 19:28:42 +0000 Subject: [PATCH 3/3] make --- services.py | 3 ++- tasks.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services.py b/services.py index ab1cc84..b65b4e2 100644 --- a/services.py +++ b/services.py @@ -139,7 +139,8 @@ async def push_order_to_orders( "memo": payment.memo, "paid_in_fiat": bool(payment.extra.get("paid_in_fiat")), "currency": details.get("currency"), - "exchange_rate": details.get("exchangeRate") or payment.extra.get("exchangeRate"), + "exchange_rate": details.get("exchangeRate") + or payment.extra.get("exchangeRate"), "tax_included": details.get("taxIncluded"), "tax_value": details.get("taxValue"), "items": details.get("items") or [], diff --git a/tasks.py b/tasks.py index 1d815ea..5d17ae9 100644 --- a/tasks.py +++ b/tasks.py @@ -107,7 +107,6 @@ async def maybe_push_order(payment: Payment, tpos) -> None: if "orders" not in active_extensions: return - details = payment.extra.get("details") or {} await push_order_to_orders( wallet.user, payment,