Author SHA1 Message Date
alve 362de62e2f 🚪Add logout button 2024-11-28 20:26:31 +01:00
alve ff09985944 🥷 Hide users navigation tab 2024-02-15 19:29:13 +00:00
Emma Eilefsen Glenna d76c911d4b fix rendering of register total 2024-01-25 21:45:17 +01:00
Emma Eilefsen Glenna e60473e7ed fix rendering of user balance 2024-01-25 21:44:03 +01:00
Emma Eilefsen Glenna d596c31353 extract function 2024-01-25 21:43:32 +01:00
Emma Eilefsen Glenna 90558a3a28 add comment 2024-01-25 19:01:45 +00:00
alve 57a6c412d5 💄 Hide trailing decimal zeros 2024-01-25 19:01:45 +00:00
alve 19f58211e7 🗃 Make order sum a decimal field 2024-01-25 19:01:45 +00:00
nikolark 0726754678 💡 add some FIXMEs 2024-01-25 19:01:45 +00:00
nikolark 480fba870a 🗃 Replace float fields with int or decimals 2024-01-25 19:01:45 +00:00
alve ed08c60380 💄Fix favicon path 2023-07-19 19:46:01 +02:00
14 changed files with 133 additions and 29 deletions

No files matched your search

+1
View File
@@ -26,6 +26,7 @@ npm start
- improve product listing (light purple background)
- Stats: products over time
- inventory views
- Stats: Implement users tab
## TODO-old
+2 -1
View File
@@ -1,5 +1,6 @@
from datetime import datetime
from typing import List
from decimal import Decimal
import strawberry
import strawberry_django
@@ -25,7 +26,7 @@ class UserProfile:
balance: auto
image: auto
last_purchase_date: datetime
order_sum_total: float
order_sum_total: Decimal
@strawberry.field()
def top_months(self) -> List[TopMonth]:
+3 -1
View File
@@ -2,9 +2,11 @@ from django import forms
from bbs.models import InventoryTransaction, Product
MAX_DIGITS = 9
DECIMAL_PLACES = 1
class InventoryTransactionForm(forms.ModelForm):
unit_price = forms.FloatField(required=True, localize=True)
unit_price = forms.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, required=True, localize=True)
def __init__(self, *args, **kwargs):
# Only show active products
@@ -0,0 +1,63 @@
# Generated by Django 4.0.2 on 2022-03-05 19:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bbs", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="inventorytransaction",
name="amount",
field=models.IntegerField(verbose_name="Antall"),
),
migrations.AlterField(
model_name="inventorytransaction",
name="unit_price",
field=models.DecimalField(decimal_places=1, max_digits=9, verbose_name="Enhetspris"),
),
migrations.AlterField(
model_name="orderline",
name="unit_price",
field=models.DecimalField(decimal_places=1, max_digits=9, verbose_name="Enhetspris"),
),
migrations.AlterField(
model_name="product",
name="alcohol_percent",
field=models.DecimalField(decimal_places=1, max_digits=9, null=True),
),
migrations.AlterField(
model_name="product",
name="inventory_amount",
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name="product",
name="sale_price_ext",
field=models.DecimalField(decimal_places=1, max_digits=9),
),
migrations.AlterField(
model_name="product",
name="sale_price_int",
field=models.DecimalField(decimal_places=1, max_digits=9),
),
migrations.AlterField(
model_name="product",
name="volume_liter",
field=models.DecimalField(decimal_places=1, max_digits=9, null=True),
),
migrations.AlterField(
model_name="transaction",
name="amount",
field=models.DecimalField(decimal_places=1, max_digits=9),
),
migrations.AlterField(
model_name="userprofile",
name="balance",
field=models.DecimalField(decimal_places=1, default=0, max_digits=9),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2023-06-28 19:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bbs', '0002_alter_inventorytransaction_amount_and_more'),
]
operations = [
migrations.AlterField(
model_name='order',
name='order_sum',
field=models.DecimalField(db_column='sum', decimal_places=1, max_digits=9),
),
]
+20 -12
View File
@@ -2,6 +2,7 @@ import hashlib
from datetime import datetime
from itertools import groupby
from typing import Type
from decimal import Decimal
from django.conf import settings
from django.db import models
@@ -17,6 +18,8 @@ from django.db.models.functions import (
)
EXTERNAL_USER = "Ekstern"
MAX_DIGITS = 9
DECIMAL_PLACES = 1
def _format_counts(per_user):
@@ -36,14 +39,15 @@ def _format_counts(per_user):
class Product(models.Model):
name = models.CharField(max_length=64)
sale_price_int = models.FloatField()
sale_price_ext = models.FloatField()
sale_price_int = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES)
sale_price_ext = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES)
description = models.CharField(max_length=256, blank=True)
volume_liter = models.FloatField(null=True)
alcohol_percent = models.FloatField(null=True)
volume_liter = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, null=True)
alcohol_percent = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, null=True)
image = models.ImageField(upload_to="products", blank=True)
customer_support = models.CharField(max_length=32, blank=True)
inventory_amount = models.FloatField(default=0)
# FIXME: rename to inventory_quantity
inventory_amount = models.IntegerField(default=0)
active = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
@@ -109,7 +113,7 @@ class Order(models.Model):
blank=True,
related_name="orders",
)
order_sum = models.FloatField(db_column="sum")
order_sum = models.DecimalField(db_column="sum", max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES)
created = models.DateTimeField(auto_now_add=True)
objects = OrderManager()
@@ -148,8 +152,10 @@ class OrderLineManager(models.QuerySet):
class OrderLine(models.Model):
order = models.ForeignKey("bbs.Order", on_delete=models.CASCADE, related_name="orderlines")
product = models.ForeignKey("bbs.Product", on_delete=models.CASCADE, related_name="orderlines")
# FIXME: rename to quantity
amount = models.IntegerField()
unit_price = models.FloatField(verbose_name="Enhetspris")
# FIXME: rename to price
unit_price = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, verbose_name="Enhetspris")
objects = OrderLineManager.as_manager()
@@ -168,7 +174,7 @@ class Transaction(models.Model):
"""Money"""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="transactions")
amount = models.FloatField()
amount = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
@@ -189,8 +195,10 @@ class InventoryTransaction(models.Model):
related_name="transactions",
verbose_name="Produkt",
)
amount = models.FloatField(verbose_name="Antall")
unit_price = models.FloatField(verbose_name="Enhetspris")
# FIXME: rename to quantity
amount = models.IntegerField(verbose_name="Antall")
# FIXME: rename to price
unit_price = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, verbose_name="Enhetspris")
comment = models.TextField(verbose_name="Kommentar", blank=True)
created = models.DateTimeField(auto_now_add=True)
@@ -204,7 +212,7 @@ class InventoryTransaction(models.Model):
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile")
balance = models.FloatField(default=0.0)
balance = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=DECIMAL_PLACES, default=0)
image = models.URLField(blank=True)
def last_purchase(self):
@@ -227,7 +235,7 @@ class UserProfile(models.Model):
def product_order_stats(self):
return OrderLine.objects.filter(order__customer__pk=self.pk).product_order_stats()
def order_sum_total(self) -> float:
def order_sum_total(self) -> Decimal:
return Order.objects.filter(customer_id=self.user_id).aggregate(sum=Sum("order_sum"))["sum"] or 0
def image_url(self) -> str:
+1 -1
View File
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<link rel="icon" type="image/svg+xml" href="/src/assets/brick.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap" rel="stylesheet">
+6
View File
@@ -5,6 +5,7 @@ import { NavLink } from "react-router-dom";
import styles from "./Header.module.css";
const ADMIN_URL = `${import.meta.env.VITE_API_URL}/admin/`;
const LOGOUT_URL = `${import.meta.env.VITE_API_URL}/`.replace("://", "://none:none@");
const navLinkStyles = ({ isActive }: { isActive: boolean }) => clsx(styles.navLink, { [styles.active]: isActive });
@@ -48,6 +49,11 @@ export const Header = (): JSX.Element => {
Admin
</a>
</li>
<li>
<a href={LOGOUT_URL} className={styles.navLink}>
Logg ut
</a>
</li>
</ul>
</nav>
</header>
+3 -3
View File
@@ -51,11 +51,11 @@ const Log = () => {
<td>
{(order.orderlines ?? []).map((line) => (
<div key={line.id}>
{line.amount}x {line.product.name}
{Number(line.amount)}x {line.product.name}
</div>
))}
</td>
<td>{order.orderSum}</td>
<td>{Number(order.orderSum)}</td>
</tr>
))}
</tbody>
@@ -104,7 +104,7 @@ const Log = () => {
<td>
{trans.user.firstName} {trans.user.lastName}
</td>
<td>{trans.amount}</td>
<td>{Number(trans.amount)}</td>
</tr>
))}
</tbody>
+3 -3
View File
@@ -15,8 +15,8 @@ const Register = (): JSX.Element => {
loading,
showAll,
setShowAll,
setSelectedUser,
selectedUser,
toggleSelectedUser,
addToOrder,
order,
total,
@@ -36,14 +36,14 @@ const Register = (): JSX.Element => {
<UserCard
key={USER_EXTERNAL}
user={null}
onUser={() => toggleSelectedUser(USER_EXTERNAL)}
onUser={() => setSelectedUser(USER_EXTERNAL)}
active={selectedUser == USER_EXTERNAL}
/>
{users.map((user) => (
<UserCard
key={user.id}
user={user}
onUser={() => toggleSelectedUser(user.id)}
onUser={() => setSelectedUser(user.id)}
active={selectedUser == user.id}
/>
))}
@@ -4,6 +4,7 @@ import { useState } from "react";
import { useToast } from "../../components/ToastProvider";
import { AllProductsDocument, AllUsersDocument, CreateOrderDocument, OrderLineInput, Product } from "../../types";
import { activeUserFilter } from "../../utils/users";
import {formatCurrency} from "../../utils/currency";
const USER_EXTERNAL = "external";
@@ -38,10 +39,6 @@ export const useRegister = () => {
setSelectedUser("");
};
const toggleSelectedUser = (userId: string) => {
setSelectedUser(selectedUser == userId ? "" : userId);
};
const addToOrder = (productId: string) => {
let added = false;
const newOrder = order.map((orderLine: OrderLineInput) => {
@@ -57,7 +54,7 @@ export const useRegister = () => {
setOrder(newOrder);
};
const total = sumTotal(products, order, selectedUser === USER_EXTERNAL);
const total = formatCurrency(sumTotal(products, order, selectedUser === USER_EXTERNAL));
const onSubmit = async () => {
let res;
@@ -98,7 +95,6 @@ export const useRegister = () => {
setShowAll,
setSelectedUser,
selectedUser,
toggleSelectedUser,
addToOrder,
order,
total,
+1 -1
View File
@@ -25,7 +25,7 @@ export const StatsNav = () => (
</NavLink>
</li>
<li>
<NavLink className="disabled" to="/stats/users" title="TODO">
<NavLink className="disabled" to="/stats/users" title="TODO" hidden={true}>
Folk
</NavLink>
</li>
+3 -1
View File
@@ -3,6 +3,7 @@ import React, { MouseEventHandler } from "react";
import { AllUsersQuery } from "../../types";
import styles from "./UserCard.module.css";
import {formatCurrency} from "../../utils/currency";
type UserCardProps = {
user: AllUsersQuery["allUsers"][0] | null;
@@ -13,6 +14,7 @@ type UserCardProps = {
/** If user is null, then it's the special external user */
export const UserCard = ({ user, onUser, active = false }: UserCardProps): JSX.Element => {
const classes = clsx(styles.user, { [styles.active]: active });
const userBalanceString = formatCurrency(Number(user?.profile?.balance));
return (
<button className={classes} onClick={onUser} type="button" title={user?.firstName || "Ekstern"}>
<div className={styles.avatarWrap}>
@@ -27,7 +29,7 @@ export const UserCard = ({ user, onUser, active = false }: UserCardProps): JSX.E
</div>
<div className={styles.meta}>
{user?.firstName || "Ekstern"}
<span className={styles.balance}>{user?.profile?.balance || ""}</span>
<span className={styles.balance}>{userBalanceString}</span>
</div>
</button>
);
+7
View File
@@ -0,0 +1,7 @@
export function formatCurrency(value: number) {
if (isNaN(value)) {
return "";
} else {
return value.toFixed(2).replace(/\.00$/, '');
}
}