Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make taxes work #86

Merged
merged 23 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,12 @@ On the regular TPoS you can also add value to a total. Enter a value and click t
![atm withdraw](https://i.imgur.com/rYXtn93.png)
6. After successful withdraw, the green check will show and TPOS exists ATM mode\
![atm success](https://i.imgur.com/FaHltvW.png)

## Tax settings

For tax settings, by default tax is included in the price. You'll need to set a default tax rate in percentage (ex: 13). If items have a tax value, as some products may have different tax (VAT usually), it overides the default value.

- **Tax Exclusive means tax is applied on top of the unit price.**
- **Tax Inclusive means the unit price includes tax.**

When using the normal keypad PoS, the default tax value is used, and tax value is always included in the value.
5 changes: 3 additions & 2 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import List, Optional, Union

from loguru import logger

from lnbits.helpers import urlsafe_short_hash

from . import db
from .models import CreateTposData, TPoS, TPoSClean, LNURLCharge
from loguru import logger
from .models import CreateTposData, LNURLCharge, TPoS, TPoSClean


async def get_current_timestamp():
Expand Down
21 changes: 17 additions & 4 deletions migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async def m005_initial(db):
Initial withdraws table.
"""
await db.execute(
f"""
"""
CREATE TABLE tpos.withdraws (
id TEXT PRIMARY KEY,
tpos_id TEXT NOT NULL,
Expand Down Expand Up @@ -108,10 +108,23 @@ async def m007_atm_premium(db):
await db.execute("ALTER TABLE tpos.pos ADD COLUMN withdrawpremium FLOAT;")



async def m008_atm_time_option_and_pin_toggle(db):
"""
Add a time mins/sec and pin toggle
"""
await db.execute("ALTER TABLE tpos.pos ADD COLUMN withdrawtimeopt TEXT DEFAULT 'mins';")
await db.execute("ALTER TABLE tpos.pos ADD COLUMN withdrawpindisabled BOOL NOT NULL DEFAULT false;")
await db.execute(
"ALTER TABLE tpos.pos ADD COLUMN withdrawtimeopt TEXT DEFAULT 'mins';"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use underscore for column names?

)
await db.execute(
"ALTER TABLE tpos.pos ADD COLUMN withdrawpindisabled BOOL NOT NULL DEFAULT false;"
)


async def m009_tax_inclusive(db):
"""
Add tax_inclusive column
"""
await db.execute(
"ALTER TABLE tpos.pos ADD COLUMN tax_inclusive BOOL NOT NULL DEFAULT true;"
)
await db.execute("ALTER TABLE tpos.pos ADD COLUMN tax_default FLOAT DEFAULT 0;")
48 changes: 18 additions & 30 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from sqlite3 import Row
from typing import Optional, Any, List
from typing import List, Optional

from fastapi import Request
from lnurl import Lnurl, LnurlWithdrawResponse
from lnurl import encode as lnurl_encode
from lnurl.models import ClearnetUrl, MilliSatoshi
from pydantic import BaseModel, Field
from lnurl.types import ClearnetUrl, MilliSatoshi
from pydantic import BaseModel, Field, validator


class CreateTposData(BaseModel):
Expand All @@ -22,32 +22,8 @@ class CreateTposData(BaseModel):
withdrawbtwn: int = Field(10, ge=1)
withdrawpremium: float = Field(None)
withdrawpindisabled: bool = Field(False)


class TPoS(BaseModel):
id: str
wallet: str
name: str
currency: str
tip_options: Optional[str]
tip_wallet: Optional[str]
withdrawlimit: Optional[int]
withdrawpin: Optional[int]
withdrawamt: int
withdrawtime: int
withdrawtimeopt: Optional[str]
withdrawbtwn: int
withdrawpremium: Optional[float]
withdrawpindisabled: Optional[bool]
items: Optional[str]

@classmethod
def from_row(cls, row: Row) -> "TPoS":
return cls(**dict(row))

@property
def withdrawamtposs(self) -> int:
return self.withdrawlimit - self.withdrawamt if self.withdrawlimit else 0
tax_inclusive: bool = Field(True)
tax_default: float = Field(None)


class TPoSClean(BaseModel):
Expand All @@ -63,6 +39,8 @@ class TPoSClean(BaseModel):
withdrawpremium: Optional[float]
withdrawpindisabled: Optional[bool]
items: Optional[str]
tax_inclusive: bool
tax_default: Optional[float]

@classmethod
def from_row(cls, row: Row) -> "TPoSClean":
Expand All @@ -73,6 +51,12 @@ def withdrawamtposs(self) -> int:
return self.withdrawlimit - self.withdrawamt if self.withdrawlimit else 0


class TPoS(TPoSClean, BaseModel):
wallet: str
tip_wallet: Optional[str]
withdrawpin: Optional[int]


class LNURLCharge(BaseModel):
id: str
tpos_id: str
Expand Down Expand Up @@ -120,10 +104,14 @@ class Item(BaseModel):
price: float
title: str
description: Optional[str]
tax: Optional[float] = 0.0
tax: Optional[float] = Field(0, ge=0.0)
disabled: bool = False
categories: Optional[List[str]] = []

@validator("tax", pre=True, always=True)
def set_default_tax(cls, v):
return v or 0


class CreateUpdateItemData(BaseModel):
items: List[Item]
53 changes: 53 additions & 0 deletions static/components/item-list/item-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<div style="margin-bottom: 200px">
<q-separator></q-separator>
<q-list separator padding>
<q-item v-for="item in items" :key="item.id" class="q-py-md">
<q-item-section avatar top>
<q-avatar>
<img v-if="item.image" class="responsive-img" :src="item.image" />
<q-icon v-else color="primary" name="sell"></q-icon>
</q-avatar>
</q-item-section>

<q-item-section class="col-4">
<q-item-label class="ellipsis"
><span
class="text-body text-weight-bold text-uppercase"
v-text="item.title"
></span
></q-item-label>
<q-item-label lines="1">
<span
class="text-weight-medium ellipsis"
v-text="item.description"
></span>
</q-item-label>
</q-item-section>

<q-item-section top>
<q-item-label lines="1">
<span class="text-weight-bold" v-text="item.formattedPrice"></span>
</q-item-label>
<q-item-label caption lines="1">
<i
><span
v-text="`tax ${inclusive ? 'incl.' : 'excl.'} ${item.tax ? item.tax + '%' : ''}`"
></span
></i>
</q-item-label>
<q-item-label v-if="!inclusive" lines="1" class="q-mt-xs">
<span
v-text="`Price w/ tax: ${format(item.price * (1 + item.tax * 0.01), currency)}`"
></span>
</q-item-label>
</q-item-section>

<q-item-section side>
<div class="text-grey-8 q-gutter-sm">
<q-btn round color="green" icon="add" @click="addToCart(item)" />
</div>
</q-item-section>
</q-item>
</q-list>
<q-separator></q-separator>
</div>
20 changes: 20 additions & 0 deletions static/components/item-list/item-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
async function itemList(path) {
const template = await loadTemplateAsync(path)

Vue.component('item-list', {
name: 'item-list',
props: ['items', 'inclusive', 'format', 'currency', 'add-product'],
template,

data: function () {
return {}
},
computed: {},
methods: {
addToCart(item) {
this.$emit('add-product', item)
}
},
created() {}
})
}
Loading