mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2024-11-20 18:51:05 +01:00
add currency to stalls show products in fiat
This commit is contained in:
parent
b1473fc1a4
commit
11b015e516
@ -148,16 +148,18 @@ async def create_shop_stall(data: createStalls) -> Stalls:
|
||||
id,
|
||||
wallet,
|
||||
name,
|
||||
currency,
|
||||
publickey,
|
||||
relays,
|
||||
shippingzones
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
stall_id,
|
||||
data.wallet,
|
||||
data.name,
|
||||
data.currency,
|
||||
data.publickey,
|
||||
data.relays,
|
||||
data.shippingzones,
|
||||
@ -447,17 +449,31 @@ async def get_shop_chat_by_merchant(ids: List[str]) -> List[ChatMessage]:
|
||||
|
||||
|
||||
async def get_shop_settings(user) -> Optional[ShopSettings]:
|
||||
row = await db.fetchone("SELECT * FROM shop.settings WHERE 'user = ?", (user,))
|
||||
row = await db.fetchone("""SELECT * FROM shop.settings WHERE "user" = ?""", (user,))
|
||||
|
||||
return ShopSettings(**row) if row else None
|
||||
|
||||
|
||||
async def set_shop_settings(user: str, data) -> Optional[ShopSettings]:
|
||||
async def create_shop_settings(user: str, data):
|
||||
await db.execute(
|
||||
f"""
|
||||
"""
|
||||
INSERT INTO shop.settings ("user", currency, fiat_base_multiplier)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(
|
||||
user,
|
||||
data.currency,
|
||||
data.fiat_base_multiplier,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def set_shop_settings(user: str, data):
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE shop.settings
|
||||
SET currency = ?, fiat_base_multiplier = ?
|
||||
WHERE 'user' = ?;
|
||||
WHERE "user" = ?;
|
||||
""",
|
||||
(
|
||||
data.currency,
|
||||
|
@ -21,6 +21,7 @@ async def m001_initial(db):
|
||||
id TEXT PRIMARY KEY,
|
||||
wallet TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
currency TEXT,
|
||||
publickey TEXT,
|
||||
relays TEXT,
|
||||
shippingzones TEXT NOT NULL,
|
||||
|
@ -19,6 +19,7 @@ class Stalls(BaseModel):
|
||||
id: str
|
||||
wallet: str
|
||||
name: str
|
||||
currency: str
|
||||
publickey: Optional[str]
|
||||
relays: Optional[str]
|
||||
shippingzones: str
|
||||
@ -27,6 +28,7 @@ class Stalls(BaseModel):
|
||||
class createStalls(BaseModel):
|
||||
wallet: str = Query(...)
|
||||
name: str = Query(...)
|
||||
currency: str = Query("sat")
|
||||
publickey: str = Query(None)
|
||||
relays: str = Query(None)
|
||||
shippingzones: str = Query(...)
|
||||
@ -38,7 +40,7 @@ class createProduct(BaseModel):
|
||||
categories: str = Query(None)
|
||||
description: str = Query(None)
|
||||
image: str = Query(None)
|
||||
price: int = Query(0, ge=0)
|
||||
price: float = Query(0, ge=0)
|
||||
quantity: int = Query(0, ge=0)
|
||||
|
||||
|
||||
@ -49,19 +51,19 @@ class Products(BaseModel):
|
||||
categories: Optional[str]
|
||||
description: Optional[str]
|
||||
image: Optional[str]
|
||||
price: int
|
||||
price: float
|
||||
quantity: int
|
||||
|
||||
|
||||
class createZones(BaseModel):
|
||||
cost: int = Query(0, ge=0)
|
||||
cost: float = Query(0, ge=0)
|
||||
countries: str = Query(...)
|
||||
|
||||
|
||||
class Zones(BaseModel):
|
||||
id: str
|
||||
user: str
|
||||
cost: int
|
||||
cost: float
|
||||
countries: str
|
||||
|
||||
|
||||
|
@ -84,7 +84,11 @@
|
||||
dense
|
||||
v-model.number="productDialog.data.price"
|
||||
type="number"
|
||||
label="Price"
|
||||
:label="'Price (' + currencies.unit + ') *'"
|
||||
:mask="currencies.unit != 'sat' ? '#.##' : '#'"
|
||||
fill-mask="0"
|
||||
reverse-fill-mask
|
||||
:step="currencies.unit != 'sat' ? '0.01' : '1'"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
@ -142,9 +146,13 @@
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
:label="'Amount (' + currencies.unit + ') *'"
|
||||
:mask="currencies.unit != 'sat' ? '#.##' : '#'"
|
||||
fill-mask="0"
|
||||
reverse-fill-mask
|
||||
:step="currencies.unit != 'sat' ? '0.01' : '1'"
|
||||
type="number"
|
||||
v-model.trim="zoneDialog.data.cost"
|
||||
label="Cost (sats)"
|
||||
></q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
|
@ -188,6 +188,9 @@
|
||||
}
|
||||
const mapProducts = obj => {
|
||||
obj._data = _.clone(obj)
|
||||
if ('{{ currency }}' != 'sat') {
|
||||
obj.price /= 100
|
||||
}
|
||||
return obj
|
||||
}
|
||||
const mapZone = obj => {
|
||||
@ -545,7 +548,7 @@
|
||||
LNbits.api
|
||||
.request(
|
||||
'PUT',
|
||||
'/shop/api/v1/settings',
|
||||
'/shop/api/v1/settings/' + this.g.user.id,
|
||||
this.g.user.wallets[0].adminkey,
|
||||
data
|
||||
)
|
||||
@ -680,6 +683,7 @@
|
||||
name: this.stallDialog.data.name,
|
||||
wallet: this.stallDialog.data.wallet,
|
||||
publickey: this.stallDialog.data.publickey || this.keys.pubkey,
|
||||
currency: this.currencies.unit,
|
||||
relays: this.stallDialog.data.relays,
|
||||
shippingzones: this.stallDialog.data.shippingzones
|
||||
.map(z => z.split('-')[0].trim())
|
||||
@ -1376,6 +1380,8 @@
|
||||
this.onboarding.showAgain = showOnboard || false
|
||||
this.diagonAlley =
|
||||
this.$q.localStorage.getItem('lnbits.DAmode') || false
|
||||
this.currencies.unit = '{{ currency }}'
|
||||
console.log(this.currencies.unit, '{{currency}}')
|
||||
await this.getCurrencies()
|
||||
this.getStalls()
|
||||
this.getProducts()
|
||||
|
@ -48,7 +48,10 @@
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side>
|
||||
<span> {{p.price}} sats</span>
|
||||
<span>
|
||||
{{unit != 'sat' ? getAmountFormated(p.price) : p.price +
|
||||
'sats'}}</span
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
{% endraw %}
|
||||
@ -112,13 +115,18 @@
|
||||
|
||||
<q-card-section class="q-py-sm">
|
||||
<div>
|
||||
<!-- <div class="text-caption text-green-8 text-weight-bolder">
|
||||
{{ stall.name }}
|
||||
</div> -->
|
||||
<span class="text-h6">{{ item.price }} sats</span
|
||||
><span class="q-ml-sm text-grey-6"
|
||||
>BTC {{ (item.price / 1e8).toFixed(8) }}</span
|
||||
>
|
||||
<span v-if="unit == 'sat'">
|
||||
<span class="text-h6">{{ item.price }} sats</span
|
||||
><span class="q-ml-sm text-grey-6"
|
||||
>BTC {{ (item.price / 1e8).toFixed(8) }}</span
|
||||
>
|
||||
</span>
|
||||
<span v-else>
|
||||
<span class="text-h6">{{ getAmountFormated(item.price) }}</span>
|
||||
<span v-if="exchangeRate" class="q-ml-sm text-grey-6"
|
||||
>({{ getValueInSats(item.price) }} sats)</span
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="q-ml-md text-caption text-green-8 text-weight-bolder q-mt-md"
|
||||
>{{item.quantity}} left</span
|
||||
@ -203,7 +211,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
{% raw %} Total: {{ finalCost }} {% endraw %}
|
||||
{% raw %} Total: {{ unit != 'sat' ? getAmountFormated(finalCost) :
|
||||
finalCost + 'sats' }}
|
||||
<span v-if="unit != 'sat'" class="q-ml-sm text-grey-6"
|
||||
>({{ getValueInSats(finalCost) }} sats)</span
|
||||
>
|
||||
{% endraw %}
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
@ -281,6 +294,8 @@
|
||||
products: [],
|
||||
searchText: null,
|
||||
diagonalley: false,
|
||||
unit: 'sat',
|
||||
exchangeRate: 0,
|
||||
cart: {
|
||||
total: 0,
|
||||
size: 0,
|
||||
@ -334,6 +349,28 @@
|
||||
products: new Map()
|
||||
}
|
||||
},
|
||||
getAmountFormated(amount) {
|
||||
return LNbits.utils.formatCurrency(amount.toFixed(2), this.unit)
|
||||
},
|
||||
async getRates() {
|
||||
if (this.unit == 'sat') return
|
||||
try {
|
||||
let rate = (
|
||||
await LNbits.api.request('POST', '/api/v1/conversion', null, {
|
||||
amount: 1e8,
|
||||
to: this.unit
|
||||
})
|
||||
).data
|
||||
this.exchangeRate = rate[this.unit]
|
||||
console.log(this.exchangeRate)
|
||||
} catch (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
}
|
||||
},
|
||||
getValueInSats(amount) {
|
||||
if (!this.exchangeRate) return 0
|
||||
return Math.ceil((amount / this.exchangeRate) * 1e8)
|
||||
},
|
||||
addToCart(item) {
|
||||
let prod = this.cart.products
|
||||
if (prod.has(item.id)) {
|
||||
@ -382,7 +419,10 @@
|
||||
let data = {
|
||||
...this.checkoutDialog.data,
|
||||
wallet: this.stall.wallet,
|
||||
total: this.finalCost,
|
||||
total:
|
||||
this.unit != 'sat'
|
||||
? this.getValueInSats(this.finalCost)
|
||||
: this.finalCost, // maybe this is better made in Python to allow API ordering?!
|
||||
products: Array.from(this.cart.products, p => {
|
||||
return {product_id: p[0], quantity: p[1].quantity}
|
||||
})
|
||||
@ -448,9 +488,12 @@
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
async created() {
|
||||
this.stall = JSON.parse('{{ stall | tojson }}')
|
||||
this.products = JSON.parse('{{ products | tojson }}')
|
||||
this.unit = this.stall.currency
|
||||
await this.getRates()
|
||||
setInterval(this.getRates, 300000)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
@ -12,7 +12,7 @@ from starlette.responses import HTMLResponse
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists # type: ignore
|
||||
from lnbits.extensions.shop import shop_ext, shop_renderer
|
||||
from lnbits.extensions.shop.models import CreateChatMessage
|
||||
from lnbits.extensions.shop.models import CreateChatMessage, SetSettings
|
||||
from lnbits.extensions.shop.notifier import Notifier
|
||||
|
||||
from .crud import (
|
||||
@ -26,6 +26,8 @@ from .crud import (
|
||||
get_shop_zone,
|
||||
get_shop_zones,
|
||||
update_shop_product_stock,
|
||||
get_shop_settings,
|
||||
create_shop_settings,
|
||||
)
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
@ -33,8 +35,16 @@ templates = Jinja2Templates(directory="templates")
|
||||
|
||||
@shop_ext.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||
settings = await get_shop_settings(user=user.id)
|
||||
|
||||
if not settings:
|
||||
await create_shop_settings(
|
||||
user=user.id, data=SetSettings(currency="sat", fiat_base_multiplier=1)
|
||||
)
|
||||
settings = await get_shop_settings(user.id)
|
||||
return shop_renderer().TemplateResponse(
|
||||
"shop/index.html", {"request": request, "user": user.dict()}
|
||||
"shop/index.html",
|
||||
{"request": request, "user": user.dict(), "currency": settings.currency},
|
||||
)
|
||||
|
||||
|
||||
|
@ -33,6 +33,7 @@ from .crud import (
|
||||
create_shop_product,
|
||||
create_shop_stall,
|
||||
create_shop_zone,
|
||||
create_shop_settings,
|
||||
delete_shop_order,
|
||||
delete_shop_product,
|
||||
delete_shop_stall,
|
||||
@ -102,15 +103,21 @@ async def api_shop_product_create(
|
||||
product_id=None,
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
):
|
||||
# For fiat currencies,
|
||||
# we multiply by data.fiat_base_multiplier (usually 100) to save the value in cents.
|
||||
settings = await get_shop_settings(user=wallet.wallet.user)
|
||||
stall = await get_shop_stall(stall_id=data.stall)
|
||||
if stall.currency != "sat":
|
||||
data.price *= settings.fiat_base_multiplier
|
||||
|
||||
if product_id:
|
||||
product = await get_shop_product(product_id)
|
||||
if not product:
|
||||
return {"message": "Withdraw product does not exist."}
|
||||
return {"message": "Product does not exist."}
|
||||
|
||||
stall = await get_shop_stall(stall_id=product.stall)
|
||||
# stall = await get_shop_stall(stall_id=product.stall)
|
||||
if stall.wallet != wallet.wallet.id:
|
||||
return {"message": "Not your withdraw product."}
|
||||
return {"message": "Not your product."}
|
||||
|
||||
product = await update_shop_product(product_id, **data.dict())
|
||||
else:
|
||||
@ -250,6 +257,8 @@ async def api_shop_orders(
|
||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
||||
|
||||
orders = await get_shop_orders(wallet_ids)
|
||||
if not orders:
|
||||
return
|
||||
orders_with_details = []
|
||||
for order in orders:
|
||||
order = order.dict()
|
||||
@ -472,9 +481,24 @@ async def api_get_settings(wallet: WalletTypeInfo = Depends(require_admin_key)):
|
||||
return settings
|
||||
|
||||
|
||||
@shop_ext.put("/api/v1/settings")
|
||||
@shop_ext.post("/api/v1/settings")
|
||||
@shop_ext.put("/api/v1/settings/{usr}")
|
||||
async def api_set_settings(
|
||||
data: SetSettings, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||
data: SetSettings,
|
||||
usr: str = None,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
):
|
||||
if usr:
|
||||
if usr != wallet.wallet.user:
|
||||
return {"message": "Not your Shop."}
|
||||
|
||||
settings = await get_shop_settings(user=usr)
|
||||
|
||||
if settings.user != wallet.wallet.user:
|
||||
return {"message": "Not your Shop."}
|
||||
|
||||
return await set_shop_settings(usr, data)
|
||||
|
||||
user = wallet.wallet.user
|
||||
return await set_shop_settings(user, data)
|
||||
|
||||
return await create_shop_settings(user, data)
|
||||
|
Loading…
Reference in New Issue
Block a user