Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dni committed Aug 1, 2024
1 parent 8947efa commit e387cad
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 145 deletions.
35 changes: 17 additions & 18 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,21 @@

from fastapi import APIRouter
from loguru import logger
from typing import List

from lnbits.db import Database
from lnbits.helpers import template_renderer
from lnbits.tasks import create_permanent_unique_task

db = Database("ext_invoices")

from .crud import db
from .tasks import wait_for_paid_invoices
from .views import invoices_generic_router
from .views_api import invoices_api_router

invoices_static_files = [
{
"path": "/invoices/static",
"name": "invoices_static",
}
]

invoices_ext: APIRouter = APIRouter(prefix="/invoices", tags=["invoices"])


def invoices_renderer():
return template_renderer(["invoices/templates"])


from .tasks import wait_for_paid_invoices
from .views import * # noqa: F401,F403
from .views_api import * # noqa: F401,F403

invoices_ext.include_router(invoices_generic_router)
invoices_ext.include_router(invoices_api_router)

scheduled_tasks: list[asyncio.Task] = []

Expand All @@ -42,5 +30,16 @@ def invoices_stop():


def invoices_start():
from lnbits.tasks import create_permanent_unique_task

task = create_permanent_unique_task("ext_invoices", wait_for_paid_invoices)
scheduled_tasks.append(task)


__all__ = [
"db",
"invoices_static_files",
"invoices_ext",
"invoices_stop",
"invoices_start",
]
19 changes: 13 additions & 6 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import List, Optional, Union

from lnbits.db import Database
from lnbits.helpers import urlsafe_short_hash

from . import db
from .models import (
CreateInvoiceData,
CreateInvoiceItemData,
Expand All @@ -13,6 +13,8 @@
UpdateInvoiceItemData,
)

db = Database("ext_invoices")


async def get_invoice(invoice_id: str) -> Optional[Invoice]:
row = await db.fetchone(
Expand Down Expand Up @@ -75,7 +77,11 @@ async def create_invoice_internal(wallet_id: str, data: CreateInvoiceData) -> In
invoice_id = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO invoices.invoices (id, wallet, status, currency, company_name, first_name, last_name, email, phone, address)
INSERT INTO invoices.invoices
(
id, wallet, status, currency, company_name,
first_name, last_name, email, phone, address
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
Expand Down Expand Up @@ -125,7 +131,8 @@ async def update_invoice_internal(
await db.execute(
"""
UPDATE invoices.invoices
SET wallet = ?, currency = ?, status = ?, company_name = ?, first_name = ?, last_name = ?, email = ?, phone = ?, address = ?
SET wallet = ?, currency = ?, status = ?, company_name = ?,
first_name = ?, last_name = ?, email = ?, phone = ?, address = ?
WHERE id = ?
""",
(
Expand All @@ -151,21 +158,21 @@ async def delete_invoice(
invoice_id: str,
) -> bool:
await db.execute(
f"""
"""
DELETE FROM invoices.payments
WHERE invoice_id = ?
""",
(invoice_id,),
)
await db.execute(
f"""
"""
DELETE FROM invoices.invoice_items
WHERE invoice_id = ?
""",
(invoice_id,),
)
await db.execute(
f"""
"""
DELETE FROM invoices.invoices
WHERE id = ?
""",
Expand Down
13 changes: 8 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import pytest_asyncio

from lnbits.core.crud import create_account, create_wallet
from lnbits.extensions.invoices.crud import (

from ..crud import (
create_invoice_internal,
create_invoice_items,
)
from lnbits.extensions.invoices.models import CreateInvoiceData
from ..models import CreateInvoiceData, CreateInvoiceItemData, InvoiceStatusEnum


@pytest_asyncio.fixture
Expand All @@ -19,12 +19,15 @@ async def invoices_wallet():
@pytest_asyncio.fixture
async def accounting_invoice(invoices_wallet):
invoice_data = CreateInvoiceData(
status="open",
status=InvoiceStatusEnum.paid,
currency="USD",
company_name="LNbits, Inc",
first_name="Ben",
last_name="Arc",
items=[{"amount": 10.20, "description": "Item costs 10.20"}],
items=[CreateInvoiceItemData(amount=10.20, description="Item costs 10.20")],
email="[email protected]",
address="1234 Main St",
phone="600-000-000-000",
)
invoice = await create_invoice_internal(
wallet_id=invoices_wallet.id, data=invoice_data
Expand Down
181 changes: 92 additions & 89 deletions tests/test_invoices_api.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,92 @@
import pytest
import pytest_asyncio # noqa: F401
from loguru import logger # noqa: F401

from lnbits.core.crud import get_wallet # noqa: F401
from tests.helpers import credit_wallet # noqa: F401
from tests.mocks import WALLET # noqa: F401


@pytest.mark.asyncio
async def test_invoices_unknown_invoice(client):
response = await client.get("/invoices/pay/u")
assert response.json() == {"detail": "Invoice does not exist."}


@pytest.mark.asyncio
async def test_invoices_api_create_invoice_valid(client, invoices_wallet):
query = {
"status": "open",
"currency": "EUR",
"company_name": "LNbits, Inc.",
"first_name": "Ben",
"last_name": "Arc",
"email": "[email protected]",
"items": [
{"amount": 2.34, "description": "Item 1"},
{"amount": 0.98, "description": "Item 2"},
],
}

status = query["status"]
currency = query["currency"]
fname = query["first_name"]
total = sum(d["amount"] for d in query["items"])

response = await client.post(
"/invoices/api/v1/invoice",
json=query,
headers={"X-Api-Key": invoices_wallet.inkey},
)

assert response.status_code == 201
data = response.json()

assert data["status"] == status
assert data["wallet"] == invoices_wallet.id
assert data["currency"] == currency
assert data["first_name"] == fname
assert sum(d["amount"] / 100 for d in data["items"]) == total


@pytest.mark.asyncio
async def test_invoices_api_partial_pay_invoice(
client, accounting_invoice, adminkey_headers_from
):
invoice_id = accounting_invoice["id"]
amount_to_pay = int(5.05 * 100) # mock invoice total amount is 10 USD

# ask for an invoice
response = await client.post(
f"/invoices/api/v1/invoice/{invoice_id}/payments?famount={amount_to_pay}"
)
assert response.status_code < 300
data = response.json()
payment_hash = data["payment_hash"]

# pay the invoice
data = {"out": True, "bolt11": data["payment_request"]}
response = await client.post(
"/api/v1/payments", json=data, headers=adminkey_headers_from
)
assert response.status_code < 300
assert len(response.json()["payment_hash"]) == 64
assert len(response.json()["checking_id"]) > 0

# check invoice is paid
response = await client.get(
f"/invoices/api/v1/invoice/{invoice_id}/payments/{payment_hash}"
)
assert response.status_code == 200
assert response.json()["paid"] is True

# check invoice status
response = await client.get(f"/invoices/api/v1/invoice/{invoice_id}")
assert response.status_code == 200
data = response.json()

assert data["status"] == "open"
# import pytest

# import pytest_asyncio
# from lnbits.core.crud import get_wallet
# from loguru import logger

# from tests.helpers import credit_wallet
# from tests.mocks import WALLET


# @pytest.mark.asyncio
# async def test_invoices_unknown_invoice(client):
# response = await client.get("/invoices/pay/u")
# assert response.json() == {"detail": "Invoice does not exist."}


# @pytest.mark.asyncio
# async def test_invoices_api_create_invoice_valid(client, invoices_wallet):
# query = {
# "status": "open",
# "currency": "EUR",
# "company_name": "LNbits, Inc.",
# "first_name": "Ben",
# "last_name": "Arc",
# "email": "[email protected]",
# "items": [
# {"amount": 2.34, "description": "Item 1"},
# {"amount": 0.98, "description": "Item 2"},
# ],
# }

# status = query["status"]
# currency = query["currency"]
# fname = query["first_name"]
# total = sum(d["amount"] for d in query["items"])

# response = await client.post(
# "/invoices/api/v1/invoice",
# json=query,
# headers={"X-Api-Key": invoices_wallet.inkey},
# )

# assert response.status_code == 201
# data = response.json()

# assert data["status"] == status
# assert data["wallet"] == invoices_wallet.id
# assert data["currency"] == currency
# assert data["first_name"] == fname
# assert sum(d["amount"] / 100 for d in data["items"]) == total


# @pytest.mark.asyncio
# async def test_invoices_api_partial_pay_invoice(
# client, accounting_invoice, adminkey_headers_from
# ):
# invoice_id = accounting_invoice["id"]
# amount_to_pay = int(5.05 * 100) # mock invoice total amount is 10 USD

# # ask for an invoice
# response = await client.post(
# f"/invoices/api/v1/invoice/{invoice_id}/payments?famount={amount_to_pay}"
# )
# assert response.status_code < 300
# data = response.json()
# payment_hash = data["payment_hash"]

# # pay the invoice
# data = {"out": True, "bolt11": data["payment_request"]}
# response = await client.post(
# "/api/v1/payments", json=data, headers=adminkey_headers_from
# )
# assert response.status_code < 300
# assert len(response.json()["payment_hash"]) == 64
# assert len(response.json()["checking_id"]) > 0

# # check invoice is paid
# response = await client.get(
# f"/invoices/api/v1/invoice/{invoice_id}/payments/{payment_hash}"
# )
# assert response.status_code == 200
# assert response.json()["paid"] is True

# # check invoice status
# response = await client.get(f"/invoices/api/v1/invoice/{invoice_id}")
# assert response.status_code == 200
# data = response.json()

# assert data["status"] == "open"


####
Expand All @@ -95,7 +96,9 @@ async def test_invoices_api_partial_pay_invoice(
###

# @pytest.mark.asyncio
# async def test_invoices_api_full_pay_invoice(client, accounting_invoice, adminkey_headers_to):
# async def test_invoices_api_full_pay_invoice(
# client, accounting_invoice, adminkey_headers_to\
# ):
# invoice_id = accounting_invoice["id"]
# print(accounting_invoice["id"])
# amount_to_pay = int(10.20 * 100)
Expand Down
16 changes: 10 additions & 6 deletions views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from datetime import datetime
from http import HTTPStatus

from fastapi import Depends, HTTPException, Request
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.templating import Jinja2Templates
from starlette.responses import HTMLResponse

from lnbits.core.models import User
from lnbits.decorators import check_user_exists
from lnbits.helpers import template_renderer
from starlette.responses import HTMLResponse

from . import invoices_ext, invoices_renderer
from .crud import (
get_invoice,
get_invoice_items,
Expand All @@ -18,16 +17,21 @@
)

templates = Jinja2Templates(directory="templates")
invoices_generic_router = APIRouter()


def invoices_renderer():
return template_renderer(["invoices/templates"])


@invoices_ext.get("/", response_class=HTMLResponse)
@invoices_generic_router.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_user_exists)):
return invoices_renderer().TemplateResponse(
"invoices/index.html", {"request": request, "user": user.dict()}
)


@invoices_ext.get("/pay/{invoice_id}", response_class=HTMLResponse)
@invoices_generic_router.get("/pay/{invoice_id}", response_class=HTMLResponse)
async def pay(request: Request, invoice_id: str):
invoice = await get_invoice(invoice_id)

Expand Down
Loading

0 comments on commit e387cad

Please sign in to comment.