Slop/sloppy fixes #1
No files matched your search
@@ -36,7 +36,6 @@ To create the admin during data seeding instead, set `BBS_SEED_ADMIN_PASSWORD` f
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Migrate inventory and report views to the SPA
|
|
||||||
- Stats: Implement users tab
|
- Stats: Implement users tab
|
||||||
|
|
||||||
## TODO-old
|
## TODO-old
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
from decimal import Decimal
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
import strawberry
|
||||||
|
from django.db import transaction
|
||||||
|
from strawberry import ID, Info
|
||||||
|
|
||||||
|
from bbs import models
|
||||||
|
from bbs.api.errors import FieldError, FormErrors
|
||||||
|
from bbs.api.types.inventory import InventoryTransaction
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.input
|
||||||
|
class InventoryTransactionInput:
|
||||||
|
product_id: ID
|
||||||
|
amount: int
|
||||||
|
unit_price: Decimal
|
||||||
|
comment: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.type
|
||||||
|
class CreateInventoryTransactionSuccess:
|
||||||
|
inventory_transaction: InventoryTransaction
|
||||||
|
|
||||||
|
|
||||||
|
CreateInventoryTransactionResponse = Annotated[
|
||||||
|
CreateInventoryTransactionSuccess | FormErrors,
|
||||||
|
strawberry.union("CreateInventoryTransactionResponse"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.mutation
|
||||||
|
@transaction.atomic
|
||||||
|
def create_inventory_transaction(
|
||||||
|
info: Info,
|
||||||
|
data: InventoryTransactionInput,
|
||||||
|
) -> CreateInventoryTransactionResponse:
|
||||||
|
user = info.context.request.user
|
||||||
|
if not user.is_authenticated:
|
||||||
|
message = "Logg inn for å registrere varetransaksjoner."
|
||||||
|
return FormErrors(message=message, fields=[FieldError(field="user", message=message)])
|
||||||
|
|
||||||
|
try:
|
||||||
|
product = models.Product.objects.get(pk=data.product_id, active=True)
|
||||||
|
except (models.Product.DoesNotExist, ValueError):
|
||||||
|
message = "Velg et aktivt produkt."
|
||||||
|
return FormErrors(message=message, fields=[FieldError(field="product_id", message=message)])
|
||||||
|
|
||||||
|
product.inventory_amount += data.amount
|
||||||
|
product.save()
|
||||||
|
inventory_transaction = models.InventoryTransaction.objects.create(
|
||||||
|
user=user,
|
||||||
|
product=product,
|
||||||
|
amount=data.amount,
|
||||||
|
unit_price=data.unit_price,
|
||||||
|
comment=data.comment,
|
||||||
|
)
|
||||||
|
return CreateInventoryTransactionSuccess(inventory_transaction=inventory_transaction)
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.type
|
||||||
|
class InventoryMutations:
|
||||||
|
create_inventory_transaction = create_inventory_transaction
|
||||||
@@ -1,9 +1,113 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import strawberry
|
import strawberry
|
||||||
import strawberry_django
|
import strawberry_django
|
||||||
|
from django.db.models import F, Sum
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from bbs.api.types.inventory import Transaction, TransactionOrdering
|
from bbs import models
|
||||||
|
from bbs.api.types.inventory import (
|
||||||
|
InventoryReport,
|
||||||
|
InventoryReportProduct,
|
||||||
|
InventoryTransaction,
|
||||||
|
InventoryTransactionOrdering,
|
||||||
|
Transaction,
|
||||||
|
TransactionOrdering,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@strawberry.type
|
@strawberry.type
|
||||||
class InventoryQueries:
|
class InventoryQueries:
|
||||||
transaction_list: list[Transaction] = strawberry_django.field(pagination=True, ordering=TransactionOrdering)
|
transaction_list: list[Transaction] = strawberry_django.field(pagination=True, ordering=TransactionOrdering)
|
||||||
|
inventory_transaction_list: list[InventoryTransaction] = strawberry_django.field(
|
||||||
|
pagination=True,
|
||||||
|
ordering=InventoryTransactionOrdering,
|
||||||
|
)
|
||||||
|
|
||||||
|
@strawberry.field
|
||||||
|
def inventory_report(self, start_time: datetime, end_time: datetime) -> InventoryReport:
|
||||||
|
if timezone.is_naive(start_time):
|
||||||
|
start_time = timezone.make_aware(start_time)
|
||||||
|
if timezone.is_naive(end_time):
|
||||||
|
end_time = timezone.make_aware(end_time)
|
||||||
|
if start_time > end_time:
|
||||||
|
raise ValueError("The report start date must not be after the end date.")
|
||||||
|
|
||||||
|
purchases = (
|
||||||
|
models.InventoryTransaction.objects.filter(created__range=(start_time, end_time))
|
||||||
|
.values("product_id", "product__name")
|
||||||
|
.annotate(units=Sum("amount"), value=Sum(F("amount") * F("unit_price")))
|
||||||
|
)
|
||||||
|
sales = (
|
||||||
|
models.OrderLine.objects.filter(order__created__range=(start_time, end_time))
|
||||||
|
.values("product_id", "product__name")
|
||||||
|
.annotate(units=Sum("amount"), value=Sum(F("amount") * F("unit_price")))
|
||||||
|
)
|
||||||
|
|
||||||
|
product_totals = {}
|
||||||
|
for product in purchases:
|
||||||
|
product_totals[product["product_id"]] = {
|
||||||
|
"product_id": product["product_id"],
|
||||||
|
"product_name": product["product__name"],
|
||||||
|
"purchase_units": product["units"] or 0,
|
||||||
|
"purchase_value": product["value"] or Decimal(0),
|
||||||
|
"sales_units": 0,
|
||||||
|
"sales_value": Decimal(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
for product in sales:
|
||||||
|
product_data = product_totals.setdefault(
|
||||||
|
product["product_id"],
|
||||||
|
{
|
||||||
|
"product_id": product["product_id"],
|
||||||
|
"product_name": product["product__name"],
|
||||||
|
"purchase_units": 0,
|
||||||
|
"purchase_value": Decimal(0),
|
||||||
|
"sales_units": 0,
|
||||||
|
"sales_value": Decimal(0),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
product_data["sales_units"] = product["units"] or 0
|
||||||
|
product_data["sales_value"] = product["value"] or Decimal(0)
|
||||||
|
|
||||||
|
product_data = sorted(product_totals.values(), key=lambda product: product["product_name"])
|
||||||
|
inventory_purchases = sum((product["purchase_value"] for product in product_data), Decimal(0))
|
||||||
|
product_sales = sum((product["sales_value"] for product in product_data), Decimal(0))
|
||||||
|
|
||||||
|
deposits = (
|
||||||
|
models.Transaction.objects.filter(created__range=(start_time, end_time)).aggregate(total=Sum("amount"))[
|
||||||
|
"total"
|
||||||
|
]
|
||||||
|
or Decimal(0)
|
||||||
|
)
|
||||||
|
order_purchases = (
|
||||||
|
models.Order.objects.filter(created__range=(start_time, end_time)).aggregate(total=Sum("order_sum"))[
|
||||||
|
"total"
|
||||||
|
]
|
||||||
|
or Decimal(0)
|
||||||
|
)
|
||||||
|
deposits_start = (
|
||||||
|
models.Transaction.objects.filter(created__lt=start_time).aggregate(total=Sum("amount"))["total"]
|
||||||
|
or Decimal(0)
|
||||||
|
)
|
||||||
|
orders_start = (
|
||||||
|
models.Order.objects.filter(created__lt=start_time).aggregate(total=Sum("order_sum"))["total"] or Decimal(0)
|
||||||
|
)
|
||||||
|
deposits_end = (
|
||||||
|
models.Transaction.objects.filter(created__lte=end_time).aggregate(total=Sum("amount"))["total"]
|
||||||
|
or Decimal(0)
|
||||||
|
)
|
||||||
|
orders_end = (
|
||||||
|
models.Order.objects.filter(created__lte=end_time).aggregate(total=Sum("order_sum"))["total"] or Decimal(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
return InventoryReport(
|
||||||
|
products=[InventoryReportProduct(**product) for product in product_data],
|
||||||
|
inventory_purchases=inventory_purchases,
|
||||||
|
product_sales=product_sales,
|
||||||
|
deposits=deposits,
|
||||||
|
order_purchases=order_purchases,
|
||||||
|
balance_at_start=deposits_start - orders_start,
|
||||||
|
balance_at_end=deposits_end - orders_end,
|
||||||
|
)
|
||||||
+2
-1
@@ -2,6 +2,7 @@ import strawberry
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from strawberry.extensions import SchemaExtension
|
from strawberry.extensions import SchemaExtension
|
||||||
|
|
||||||
|
from bbs.api.mutations.inventory import InventoryMutations
|
||||||
from bbs.api.mutations.shop import ShopMutations
|
from bbs.api.mutations.shop import ShopMutations
|
||||||
from bbs.api.mutations.users import UsersMutations
|
from bbs.api.mutations.users import UsersMutations
|
||||||
from bbs.api.queries.inventory import InventoryQueries
|
from bbs.api.queries.inventory import InventoryQueries
|
||||||
@@ -15,7 +16,7 @@ class Query(InventoryQueries, ShopQueries, UsersQueries):
|
|||||||
|
|
||||||
|
|
||||||
@strawberry.type
|
@strawberry.type
|
||||||
class Mutation(ShopMutations, UsersMutations):
|
class Mutation(InventoryMutations, ShopMutations, UsersMutations):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from typing import TYPE_CHECKING, Annotated
|
from typing import TYPE_CHECKING, Annotated
|
||||||
|
|
||||||
import strawberry
|
import strawberry
|
||||||
import strawberry_django
|
import strawberry_django
|
||||||
from strawberry import auto
|
from strawberry import ID, auto
|
||||||
|
|
||||||
from bbs import models
|
from bbs import models
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from .shop import Product
|
||||||
from .users import User
|
from .users import User
|
||||||
|
|
||||||
|
|
||||||
@@ -21,3 +23,40 @@ class Transaction:
|
|||||||
user: Annotated["User", strawberry.lazy(".users")]
|
user: Annotated["User", strawberry.lazy(".users")]
|
||||||
amount: auto
|
amount: auto
|
||||||
created: auto
|
created: auto
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry_django.type(models.InventoryTransaction)
|
||||||
|
class InventoryTransaction:
|
||||||
|
id: auto
|
||||||
|
user: Annotated["User", strawberry.lazy(".users")]
|
||||||
|
product: Annotated["Product", strawberry.lazy(".shop")]
|
||||||
|
amount: auto
|
||||||
|
unit_price: auto
|
||||||
|
comment: auto
|
||||||
|
created: auto
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry_django.order_type(models.InventoryTransaction)
|
||||||
|
class InventoryTransactionOrdering:
|
||||||
|
created: auto
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.type
|
||||||
|
class InventoryReportProduct:
|
||||||
|
product_id: ID
|
||||||
|
product_name: str
|
||||||
|
purchase_units: int
|
||||||
|
purchase_value: Decimal
|
||||||
|
sales_units: int
|
||||||
|
sales_value: Decimal
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry.type
|
||||||
|
class InventoryReport:
|
||||||
|
products: list[InventoryReportProduct]
|
||||||
|
inventory_purchases: Decimal
|
||||||
|
product_sales: Decimal
|
||||||
|
deposits: Decimal
|
||||||
|
order_purchases: Decimal
|
||||||
|
balance_at_start: Decimal
|
||||||
|
balance_at_end: Decimal
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from typing import TYPE_CHECKING, Annotated
|
from typing import TYPE_CHECKING, Annotated
|
||||||
|
|
||||||
import strawberry
|
import strawberry
|
||||||
@@ -24,6 +25,11 @@ class Product:
|
|||||||
image_url: str
|
image_url: str
|
||||||
sale_price_int: auto
|
sale_price_int: auto
|
||||||
sale_price_ext: auto
|
sale_price_ext: auto
|
||||||
|
active: auto
|
||||||
|
inventory_amount: auto
|
||||||
|
updated: auto
|
||||||
|
wholesale_unit_price: Decimal
|
||||||
|
wholesale_value: Decimal
|
||||||
# FIXME: stricter types
|
# FIXME: stricter types
|
||||||
user_counts: JSONScalar
|
user_counts: JSONScalar
|
||||||
|
|
||||||
|
|||||||
+137
-1
@@ -1,8 +1,10 @@
|
|||||||
import pytest # noqa: INP001
|
import pytest # noqa: INP001
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
|
from django.utils import timezone
|
||||||
from strawberry.django.test import GraphQLTestClient
|
from strawberry.django.test import GraphQLTestClient
|
||||||
|
|
||||||
from bbs.models import Order, Product
|
from bbs.models import InventoryTransaction, Order, OrderLine, Product, Transaction
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="gql_client")
|
@pytest.fixture(name="gql_client")
|
||||||
@@ -50,3 +52,137 @@ def test_create_order(product, gql_client):
|
|||||||
assert Order.objects.count() == 1
|
assert Order.objects.count() == 1
|
||||||
o = Order.objects.first()
|
o = Order.objects.first()
|
||||||
assert o.orderlines.first().product.id == product.id
|
assert o.orderlines.first().product.id == product.id
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_inventory_transaction_requires_login(product, gql_client):
|
||||||
|
result = gql_client.query(
|
||||||
|
"""
|
||||||
|
mutation CreateInventoryTransaction($data: InventoryTransactionInput!) {
|
||||||
|
createInventoryTransaction(data: $data) {
|
||||||
|
... on FormErrors { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
variables={"data": {"productId": str(product.id), "amount": 5, "unitPrice": "12.5"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data["createInventoryTransaction"]["message"] == "Logg inn for å registrere varetransaksjoner."
|
||||||
|
product.refresh_from_db()
|
||||||
|
assert product.inventory_amount == 0
|
||||||
|
assert InventoryTransaction.objects.count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_inventory_transaction_updates_stock(product, gql_client, client):
|
||||||
|
user = get_user_model().objects.create_user(username="stock-manager")
|
||||||
|
client.force_login(user)
|
||||||
|
|
||||||
|
result = gql_client.query(
|
||||||
|
"""
|
||||||
|
mutation CreateInventoryTransaction($data: InventoryTransactionInput!) {
|
||||||
|
createInventoryTransaction(data: $data) {
|
||||||
|
... on CreateInventoryTransactionSuccess {
|
||||||
|
inventoryTransaction {
|
||||||
|
amount
|
||||||
|
unitPrice
|
||||||
|
product { id inventoryAmount }
|
||||||
|
user { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
variables={
|
||||||
|
"data": {
|
||||||
|
"productId": str(product.id),
|
||||||
|
"amount": 5,
|
||||||
|
"unitPrice": "12.5",
|
||||||
|
"comment": "Restock",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
transaction = result.data["createInventoryTransaction"]["inventoryTransaction"]
|
||||||
|
assert transaction["amount"] == 5
|
||||||
|
assert transaction["unitPrice"] == "12.5"
|
||||||
|
assert transaction["product"]["inventoryAmount"] == 5
|
||||||
|
assert transaction["user"]["id"] == str(user.id)
|
||||||
|
product.refresh_from_db()
|
||||||
|
assert product.inventory_amount == 5
|
||||||
|
|
||||||
|
|
||||||
|
def test_inventory_report_aggregates_period_data(product, gql_client):
|
||||||
|
user = get_user_model().objects.create_user(username="report-user")
|
||||||
|
InventoryTransaction.objects.create(user=user, product=product, amount=5, unit_price=10)
|
||||||
|
transaction = Transaction.objects.create(user=user, amount=100)
|
||||||
|
order = Order.objects.create(order_sum=30)
|
||||||
|
OrderLine.objects.create(order=order, product=product, amount=2, unit_price=15)
|
||||||
|
start_time = timezone.make_naive(timezone.now() - timezone.timedelta(days=1))
|
||||||
|
end_time = timezone.make_naive(timezone.now() + timezone.timedelta(days=1))
|
||||||
|
|
||||||
|
result = gql_client.query(
|
||||||
|
"""
|
||||||
|
query InventoryReport($startTime: DateTime!, $endTime: DateTime!) {
|
||||||
|
inventoryReport(startTime: $startTime, endTime: $endTime) {
|
||||||
|
products {
|
||||||
|
productId
|
||||||
|
purchaseUnits
|
||||||
|
purchaseValue
|
||||||
|
salesUnits
|
||||||
|
salesValue
|
||||||
|
}
|
||||||
|
inventoryPurchases
|
||||||
|
productSales
|
||||||
|
deposits
|
||||||
|
orderPurchases
|
||||||
|
balanceAtStart
|
||||||
|
balanceAtEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
variables={"startTime": start_time.isoformat(), "endTime": end_time.isoformat()},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
report = result.data["inventoryReport"]
|
||||||
|
assert report["products"] == [
|
||||||
|
{
|
||||||
|
"productId": str(product.id),
|
||||||
|
"purchaseUnits": 5,
|
||||||
|
"purchaseValue": "50",
|
||||||
|
"salesUnits": 2,
|
||||||
|
"salesValue": "30",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
assert report["inventoryPurchases"] == "50"
|
||||||
|
assert report["productSales"] == "30"
|
||||||
|
assert report["deposits"] == "100"
|
||||||
|
assert report["orderPurchases"] == "30"
|
||||||
|
assert report["balanceAtStart"] == "0"
|
||||||
|
assert report["balanceAtEnd"] == "70"
|
||||||
|
assert transaction.amount == 100
|
||||||
|
|
||||||
|
products_result = gql_client.query(
|
||||||
|
"""
|
||||||
|
query InventoryProducts {
|
||||||
|
allProducts {
|
||||||
|
id
|
||||||
|
active
|
||||||
|
inventoryAmount
|
||||||
|
wholesaleUnitPrice
|
||||||
|
wholesaleValue
|
||||||
|
}
|
||||||
|
inventoryTransactionList(ordering: [{created: DESC}], pagination: {limit: 20, offset: 0}) {
|
||||||
|
amount
|
||||||
|
unitPrice
|
||||||
|
product { name }
|
||||||
|
user { firstName lastName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not products_result.errors
|
||||||
|
assert products_result.data["allProducts"][0]["active"]
|
||||||
|
assert products_result.data["inventoryTransactionList"][0]["amount"] == 5
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import pytest # noqa: INP001
|
||||||
|
from django.test import Client
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("path", ["/inventory", "/inventory/add", "/report"])
|
||||||
|
def test_inventory_pages_serve_the_spa_entry(client: Client, path: str):
|
||||||
|
response = client.get(path)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert b'<div id="root"></div>' in b"".join(response.streaming_content)
|
||||||
+7
-5
@@ -7,15 +7,17 @@ from django.views.decorators.csrf import csrf_exempt
|
|||||||
from strawberry.django.views import GraphQLView
|
from strawberry.django.views import GraphQLView
|
||||||
|
|
||||||
from bbs.api.schema import schema
|
from bbs.api.schema import schema
|
||||||
from bbs.views.reports import inventory, inventory_add, report
|
from bbs.views.spa import spa_index
|
||||||
|
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# TODO: migrate reports to SPA
|
path("inventory", spa_index, name="inventory"),
|
||||||
path("inventory/", inventory, name="inventory"),
|
path("inventory/", spa_index),
|
||||||
path("inventory/add/", inventory_add, name="inventory-add"),
|
path("inventory/add", spa_index, name="inventory-add"),
|
||||||
path("report", report, name="report"),
|
path("inventory/add/", spa_index),
|
||||||
|
path("report", spa_index, name="report"),
|
||||||
|
path("report/", spa_index),
|
||||||
path("accounts/login/", LoginView.as_view(), name="django.contrib.auth.views.login"),
|
path("accounts/login/", LoginView.as_view(), name="django.contrib.auth.views.login"),
|
||||||
path(
|
path(
|
||||||
"accounts/logout/",
|
"accounts/logout/",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.contrib.staticfiles import finders
|
||||||
|
from django.http import FileResponse, Http404
|
||||||
|
|
||||||
|
|
||||||
|
def spa_index(_request):
|
||||||
|
index_path = finders.find("index.html")
|
||||||
|
if not index_path:
|
||||||
|
raise Http404("The frontend has not been built.")
|
||||||
|
return FileResponse(Path(index_path).open("rb"), content_type="text/html")
|
||||||
@@ -4,6 +4,9 @@ import { Route, Routes as ReactRouterRoutes } from "react-router-dom";
|
|||||||
const Splash = React.lazy(() => import("./components/Splash"));
|
const Splash = React.lazy(() => import("./components/Splash"));
|
||||||
const UserCreate = React.lazy(() => import("./features/auth/UserCreate"));
|
const UserCreate = React.lazy(() => import("./features/auth/UserCreate"));
|
||||||
const Deposit = React.lazy(() => import("./features/deposit/Deposit"));
|
const Deposit = React.lazy(() => import("./features/deposit/Deposit"));
|
||||||
|
const Inventory = React.lazy(() => import("./features/inventory/Inventory"));
|
||||||
|
const InventoryAdd = React.lazy(() => import("./features/inventory/InventoryAdd"));
|
||||||
|
const InventoryReport = React.lazy(() => import("./features/inventory/InventoryReport"));
|
||||||
const Log = React.lazy(() => import("./features/log/Log"));
|
const Log = React.lazy(() => import("./features/log/Log"));
|
||||||
const Register = React.lazy(() => import("./features/register/Register"));
|
const Register = React.lazy(() => import("./features/register/Register"));
|
||||||
const OrderStats = React.lazy(() => import("./features/stats/OrderStats"));
|
const OrderStats = React.lazy(() => import("./features/stats/OrderStats"));
|
||||||
@@ -16,6 +19,9 @@ export const Routes = (): JSX.Element => (
|
|||||||
<React.Suspense fallback={<div>Loading...</div>}>
|
<React.Suspense fallback={<div>Loading...</div>}>
|
||||||
<ReactRouterRoutes>
|
<ReactRouterRoutes>
|
||||||
<Route path="/deposit" element={<Deposit />} />
|
<Route path="/deposit" element={<Deposit />} />
|
||||||
|
<Route path="/inventory" element={<Inventory />} />
|
||||||
|
<Route path="/inventory/add" element={<InventoryAdd />} />
|
||||||
|
<Route path="/report" element={<InventoryReport />} />
|
||||||
<Route path="/log" element={<Log />} />
|
<Route path="/log" element={<Log />} />
|
||||||
<Route path="/stats" element={<Stats />} />
|
<Route path="/stats" element={<Stats />} />
|
||||||
<Route path="/stats/orders" element={<OrderStats />} />
|
<Route path="/stats/orders" element={<OrderStats />} />
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ export const Header = (): JSX.Element => {
|
|||||||
Logg
|
Logg
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<NavLink to="/inventory" className={navLinkStyles}>
|
||||||
|
Varebeholdning
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<NavLink to="/report" className={navLinkStyles}>
|
||||||
|
Rapport
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<NavLink to="/stats" className={navLinkStyles}>
|
<NavLink to="/stats" className={navLinkStyles}>
|
||||||
Statistikk
|
Statistikk
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
.section {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableWrap {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableWrap table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inactive {
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transactions {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: grid;
|
||||||
|
max-width: 36rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form label {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form textarea,
|
||||||
|
.form select {
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgb(35, 15, 41);
|
||||||
|
color: var(--text);
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form textarea {
|
||||||
|
min-height: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.report {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--sun);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.tableWrap table {
|
||||||
|
min-width: 42rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import { useQuery } from "@apollo/client";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import { GQLError } from "../../components/GQLError";
|
||||||
|
import { InventoryPageDocument } from "../../types";
|
||||||
|
import { formatCurrency } from "../../utils/currency";
|
||||||
|
import { formatTime } from "../../utils/time";
|
||||||
|
import styles from "./Inventory.module.css";
|
||||||
|
|
||||||
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
|
const Inventory = () => {
|
||||||
|
const [offset, setOffset] = useState(0);
|
||||||
|
const { data, loading, error } = useQuery(InventoryPageDocument, {
|
||||||
|
variables: { limit: PAGE_SIZE, offset },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loading) return <div>Loading...</div>;
|
||||||
|
if (error) return <GQLError error={error} />;
|
||||||
|
|
||||||
|
const products = [...(data?.allProducts || [])].sort(
|
||||||
|
(a, b) =>
|
||||||
|
Number(b.active) - Number(a.active) || a.inventoryAmount - b.inventoryAmount || a.name.localeCompare(b.name),
|
||||||
|
);
|
||||||
|
const activeProducts = products.filter((product) => product.active);
|
||||||
|
const transactions = data?.inventoryTransactionList || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Varebeholdning</h2>
|
||||||
|
<div className={styles.summary}>
|
||||||
|
<div>Antall aktive varer: {activeProducts.reduce((total, product) => total + product.inventoryAmount, 0)}</div>
|
||||||
|
<div>
|
||||||
|
Innkjøpsverdi:{" "}
|
||||||
|
{formatCurrency(activeProducts.reduce((total, product) => total + Number(product.wholesaleValue), 0))} kr
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<section className={styles.section}>
|
||||||
|
<div className={styles.summary}>
|
||||||
|
<h3>Varer</h3>
|
||||||
|
<Link className="btn-primary" to="/inventory/add">
|
||||||
|
Registrer varetransaksjon
|
||||||
|
</Link>
|
||||||
|
<Link to="/report">Åpne rapport</Link>
|
||||||
|
</div>
|
||||||
|
<div className={styles.tableWrap}>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Vare</th>
|
||||||
|
<th scope="col">Beholdning</th>
|
||||||
|
<th scope="col">Innkjøpspris</th>
|
||||||
|
<th scope="col">Verdi</th>
|
||||||
|
<th scope="col">I salg</th>
|
||||||
|
<th scope="col">Sist oppdatert</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{products.map((product) => (
|
||||||
|
<tr key={product.id} className={!product.active ? styles.inactive : undefined}>
|
||||||
|
<td>{product.name}</td>
|
||||||
|
<td>{product.inventoryAmount}</td>
|
||||||
|
<td>{formatCurrency(Number(product.wholesaleUnitPrice))} kr</td>
|
||||||
|
<td>{formatCurrency(Number(product.wholesaleValue))} kr</td>
|
||||||
|
<td>{product.active ? "Ja" : "Nei"}</td>
|
||||||
|
<td>{formatTime(product.updated)}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section className={styles.transactions}>
|
||||||
|
<h3>Varetransaksjoner</h3>
|
||||||
|
<div className={styles.tableWrap}>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Når</th>
|
||||||
|
<th scope="col">Vare</th>
|
||||||
|
<th scope="col">Antall</th>
|
||||||
|
<th scope="col">Enhetspris</th>
|
||||||
|
<th scope="col">Hvem</th>
|
||||||
|
<th scope="col">Kommentar</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{transactions.map((transaction) => (
|
||||||
|
<tr key={transaction.id}>
|
||||||
|
<td>{formatTime(transaction.created)}</td>
|
||||||
|
<td>{transaction.product.name}</td>
|
||||||
|
<td>{transaction.amount}</td>
|
||||||
|
<td>{formatCurrency(Number(transaction.unitPrice))} kr</td>
|
||||||
|
<td>
|
||||||
|
{transaction.user.firstName} {transaction.user.lastName}
|
||||||
|
</td>
|
||||||
|
<td>{transaction.comment}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
{!transactions.length && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={6}>Ingen varetransaksjoner ennå.</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div className={styles.pagination}>
|
||||||
|
<button type="button" disabled={offset === 0} onClick={() => setOffset(Math.max(0, offset - PAGE_SIZE))}>
|
||||||
|
Forrige
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={transactions.length < PAGE_SIZE}
|
||||||
|
onClick={() => setOffset(offset + PAGE_SIZE)}
|
||||||
|
>
|
||||||
|
Neste
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Inventory;
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
import { GQLError } from "../../components/GQLError";
|
||||||
|
import { useToast } from "../../components/ToastProvider";
|
||||||
|
import { CreateInventoryTransactionDocument, InventoryProductsDocument } from "../../types";
|
||||||
|
import styles from "./Inventory.module.css";
|
||||||
|
|
||||||
|
const InventoryAdd = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { showToast } = useToast();
|
||||||
|
const { data, loading, error } = useQuery(InventoryProductsDocument);
|
||||||
|
const [createInventoryTransaction, { loading: saving }] = useMutation(CreateInventoryTransactionDocument);
|
||||||
|
const [productId, setProductId] = useState("");
|
||||||
|
const [amount, setAmount] = useState("");
|
||||||
|
const [unitPrice, setUnitPrice] = useState("");
|
||||||
|
const [comment, setComment] = useState("");
|
||||||
|
const products = data?.allProducts || [];
|
||||||
|
|
||||||
|
if (loading) return <div>Loading...</div>;
|
||||||
|
if (error) return <GQLError error={error} />;
|
||||||
|
|
||||||
|
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
try {
|
||||||
|
const result = await createInventoryTransaction({
|
||||||
|
variables: {
|
||||||
|
data: {
|
||||||
|
productId,
|
||||||
|
amount: Number(amount),
|
||||||
|
unitPrice,
|
||||||
|
comment,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const response = result.data?.createInventoryTransaction;
|
||||||
|
if (response?.__typename === "CreateInventoryTransactionSuccess") {
|
||||||
|
showToast(`Registrerte ${amount} stk ${response.inventoryTransaction.product.name}.`);
|
||||||
|
navigate("/inventory");
|
||||||
|
} else if (response?.__typename === "FormErrors") {
|
||||||
|
showToast(response.message, "danger");
|
||||||
|
} else {
|
||||||
|
showToast("Kunne ikke registrere varetransaksjonen.", "danger");
|
||||||
|
}
|
||||||
|
} catch (mutationError) {
|
||||||
|
showToast(
|
||||||
|
mutationError instanceof Error ? mutationError.message : "Kunne ikke registrere varetransaksjonen.",
|
||||||
|
"danger",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Registrer varetransaksjon</h2>
|
||||||
|
<p>
|
||||||
|
Du må være innlogget for å registrere varer. <a href="/accounts/login/">Logg inn</a>.
|
||||||
|
</p>
|
||||||
|
<form className={styles.form} onSubmit={onSubmit}>
|
||||||
|
<label>
|
||||||
|
Vare
|
||||||
|
<select required value={productId} onChange={(event) => setProductId(event.target.value)}>
|
||||||
|
<option value="">Velg vare</option>
|
||||||
|
{products.map((product) => (
|
||||||
|
<option key={product.id} value={product.id}>
|
||||||
|
{product.name} ({product.inventoryAmount} på lager)
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Antall
|
||||||
|
<input required type="number" step="1" value={amount} onChange={(event) => setAmount(event.target.value)} />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Innkjøpspris per enhet (kr)
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
step="0.1"
|
||||||
|
type="number"
|
||||||
|
value={unitPrice}
|
||||||
|
onChange={(event) => setUnitPrice(event.target.value)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Kommentar
|
||||||
|
<textarea value={comment} onChange={(event) => setComment(event.target.value)} />
|
||||||
|
</label>
|
||||||
|
<div className={styles.summary}>
|
||||||
|
<button type="submit" className="primary" disabled={saving || !products.length}>
|
||||||
|
{saving ? "Lagrer..." : "Registrer"}
|
||||||
|
</button>
|
||||||
|
<Link to="/inventory">Avbryt</Link>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{!products.length && <p>Ingen aktive varer å registrere.</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InventoryAdd;
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import { useQuery } from "@apollo/client";
|
||||||
|
import { format, subDays } from "date-fns";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { GQLError } from "../../components/GQLError";
|
||||||
|
import { InventoryReportDocument } from "../../types";
|
||||||
|
import { formatCurrency } from "../../utils/currency";
|
||||||
|
import styles from "./Inventory.module.css";
|
||||||
|
|
||||||
|
const today = () => format(new Date(), "yyyy-MM-dd");
|
||||||
|
const monthAgo = () => format(subDays(new Date(), 30), "yyyy-MM-dd");
|
||||||
|
const timestampAt = (date: string, endOfDay = false) => `${date}T${endOfDay ? "23:59:59.999999" : "00:00:00"}`;
|
||||||
|
|
||||||
|
const InventoryReport = () => {
|
||||||
|
const [startDate, setStartDate] = useState(monthAgo);
|
||||||
|
const [endDate, setEndDate] = useState(today);
|
||||||
|
const [appliedRange, setAppliedRange] = useState({ startDate: monthAgo(), endDate: today() });
|
||||||
|
const invalidRange = startDate > endDate;
|
||||||
|
const { data, loading, error } = useQuery(InventoryReportDocument, {
|
||||||
|
variables: {
|
||||||
|
startTime: timestampAt(appliedRange.startDate),
|
||||||
|
endTime: timestampAt(appliedRange.endDate, true),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!invalidRange) setAppliedRange({ startDate, endDate });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error) return <GQLError error={error} />;
|
||||||
|
|
||||||
|
const report = data?.inventoryReport;
|
||||||
|
const balanceChange = report ? Number(report.balanceAtEnd) - Number(report.balanceAtStart) : 0;
|
||||||
|
const inventoryChange = report ? Number(report.inventoryPurchases) - Number(report.productSales) : 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Varerapport</h2>
|
||||||
|
<form className={styles.summary} onSubmit={onSubmit}>
|
||||||
|
<label>
|
||||||
|
Fra
|
||||||
|
<input type="date" required value={startDate} onChange={(event) => setStartDate(event.target.value)} />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Til
|
||||||
|
<input type="date" required value={endDate} onChange={(event) => setEndDate(event.target.value)} />
|
||||||
|
</label>
|
||||||
|
<button type="submit" disabled={invalidRange}>
|
||||||
|
Oppdater
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{invalidRange && <p className={styles.error}>Startdato må være før eller lik sluttdato.</p>}
|
||||||
|
{loading && <div>Loading...</div>}
|
||||||
|
{report && (
|
||||||
|
<>
|
||||||
|
<section className={styles.report}>
|
||||||
|
<h3>Beholdningsendring</h3>
|
||||||
|
<div className={styles.tableWrap}>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Vare</th>
|
||||||
|
<th scope="col">Innkjøp</th>
|
||||||
|
<th scope="col">Salg</th>
|
||||||
|
<th scope="col">Endring verdi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{report.products.map((product) => (
|
||||||
|
<tr key={product.productId}>
|
||||||
|
<td>{product.productName}</td>
|
||||||
|
<td>
|
||||||
|
{formatCurrency(Number(product.purchaseValue))} kr ({product.purchaseUnits} stk)
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{formatCurrency(Number(product.salesValue))} kr ({product.salesUnits} stk)
|
||||||
|
</td>
|
||||||
|
<td>{formatCurrency(Number(product.purchaseValue) - Number(product.salesValue))} kr</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
{!report.products.length && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4}>Ingen varetransaksjoner i perioden.</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Totalt</th>
|
||||||
|
<td>{formatCurrency(Number(report.inventoryPurchases))} kr</td>
|
||||||
|
<td>{formatCurrency(Number(report.productSales))} kr</td>
|
||||||
|
<td>{formatCurrency(inventoryChange)} kr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section className={styles.report}>
|
||||||
|
<h3>Innskudd og kjøp</h3>
|
||||||
|
<div className={styles.tableWrap}>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Post</th>
|
||||||
|
<th scope="col">Saldo</th>
|
||||||
|
<th scope="col">Innskudd</th>
|
||||||
|
<th scope="col">Kjøp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Saldo ved periodestart</th>
|
||||||
|
<td>{formatCurrency(Number(report.balanceAtStart))} kr</td>
|
||||||
|
<td />
|
||||||
|
<td />
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Endring i perioden</th>
|
||||||
|
<td>{formatCurrency(balanceChange)} kr</td>
|
||||||
|
<td>{formatCurrency(Number(report.deposits))} kr</td>
|
||||||
|
<td>{formatCurrency(Number(report.orderPurchases))} kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Saldo ved periodeslutt</th>
|
||||||
|
<td>{formatCurrency(Number(report.balanceAtEnd))} kr</td>
|
||||||
|
<td />
|
||||||
|
<td />
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InventoryReport;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
mutation createInventoryTransaction($data: InventoryTransactionInput!) {
|
||||||
|
createInventoryTransaction(data: $data) {
|
||||||
|
... on CreateInventoryTransactionSuccess {
|
||||||
|
inventoryTransaction {
|
||||||
|
id
|
||||||
|
product {
|
||||||
|
name
|
||||||
|
inventoryAmount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on FormErrors {
|
||||||
|
message
|
||||||
|
fields {
|
||||||
|
field
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
query inventoryPage($limit: Int = 20, $offset: Int = 0) {
|
||||||
|
allProducts {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
active
|
||||||
|
inventoryAmount
|
||||||
|
updated
|
||||||
|
wholesaleUnitPrice
|
||||||
|
wholesaleValue
|
||||||
|
}
|
||||||
|
inventoryTransactionList(ordering: [{ created: DESC }], pagination: { limit: $limit, offset: $offset }) {
|
||||||
|
id
|
||||||
|
created
|
||||||
|
amount
|
||||||
|
unitPrice
|
||||||
|
comment
|
||||||
|
product {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
query inventoryProducts {
|
||||||
|
allProducts(filters: { active: true }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
inventoryAmount
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
query inventoryReport($startTime: DateTime!, $endTime: DateTime!) {
|
||||||
|
inventoryReport(startTime: $startTime, endTime: $endTime) {
|
||||||
|
products {
|
||||||
|
productId
|
||||||
|
productName
|
||||||
|
purchaseUnits
|
||||||
|
purchaseValue
|
||||||
|
salesUnits
|
||||||
|
salesValue
|
||||||
|
}
|
||||||
|
inventoryPurchases
|
||||||
|
productSales
|
||||||
|
deposits
|
||||||
|
orderPurchases
|
||||||
|
balanceAtStart
|
||||||
|
balanceAtEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React, { MouseEventHandler } from "react";
|
import React, { MouseEventHandler } from "react";
|
||||||
|
|
||||||
import { SchemaProduct as Product } from "../../types";
|
import { AllProductsQuery } from "../../types";
|
||||||
import styles from "./ProductCard.module.css";
|
import styles from "./ProductCard.module.css";
|
||||||
|
|
||||||
type ProductCardProps = {
|
type ProductCardProps = {
|
||||||
product: Omit<Product, "userCounts">;
|
product: AllProductsQuery["allProducts"][number];
|
||||||
onProduct: MouseEventHandler;
|
onProduct: MouseEventHandler;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { OrderLineInput, SchemaProduct as Product } from "../../types";
|
import { AllProductsQuery, OrderLineInput } from "../../types";
|
||||||
import { UserCard } from "../users/UserCard";
|
import { UserCard } from "../users/UserCard";
|
||||||
import { ProductCard } from "./ProductCard";
|
import { ProductCard } from "./ProductCard";
|
||||||
import styles from "./Register.module.css";
|
import styles from "./Register.module.css";
|
||||||
@@ -55,7 +55,7 @@ const Register = (): JSX.Element => {
|
|||||||
<section className={styles.productListSection}>
|
<section className={styles.productListSection}>
|
||||||
<h2>Kjøper hva?</h2>
|
<h2>Kjøper hva?</h2>
|
||||||
<div className={styles.productList}>
|
<div className={styles.productList}>
|
||||||
{products.map((product: Omit<Product, "userCounts">) => (
|
{products.map((product: AllProductsQuery["allProducts"][number]) => (
|
||||||
<ProductCard
|
<ProductCard
|
||||||
key={product.id}
|
key={product.id}
|
||||||
product={product}
|
product={product}
|
||||||
|
|||||||
@@ -2,15 +2,23 @@ import { useMutation, useQuery } from "@apollo/client";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useToast } from "../../components/ToastProvider";
|
import { useToast } from "../../components/ToastProvider";
|
||||||
import { AllProductsDocument, AllUsersDocument, CreateOrderDocument, OrderLineInput, SchemaProduct } from "../../types";
|
import {
|
||||||
|
AllProductsDocument,
|
||||||
|
AllProductsQuery,
|
||||||
|
AllUsersDocument,
|
||||||
|
CreateOrderDocument,
|
||||||
|
OrderLineInput,
|
||||||
|
} from "../../types";
|
||||||
import { formatCurrency } from "../../utils/currency";
|
import { formatCurrency } from "../../utils/currency";
|
||||||
import { activeUserFilter } from "../../utils/users";
|
import { activeUserFilter } from "../../utils/users";
|
||||||
|
|
||||||
const USER_EXTERNAL = "external";
|
const USER_EXTERNAL = "external";
|
||||||
|
|
||||||
const sumTotal = (products: Omit<SchemaProduct, "userCounts">[], order: OrderLineInput[], isExternal: boolean) => {
|
type Product = AllProductsQuery["allProducts"][number];
|
||||||
|
|
||||||
|
const sumTotal = (products: Product[], order: OrderLineInput[], isExternal: boolean) => {
|
||||||
const prices = order.map((orderLine: OrderLineInput) => {
|
const prices = order.map((orderLine: OrderLineInput) => {
|
||||||
const product = products.find((product: Omit<SchemaProduct, "userCounts">) => product.id === orderLine.productId);
|
const product = products.find((product) => product.id === orderLine.productId);
|
||||||
if (!product) return 0;
|
if (!product) return 0;
|
||||||
return orderLine.amount * Number(isExternal ? product.salePriceExt : product.salePriceInt);
|
return orderLine.amount * Number(isExternal ? product.salePriceExt : product.salePriceInt);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ export type SchemaCreateDepositSuccess = {
|
|||||||
transaction: SchemaTransaction;
|
transaction: SchemaTransaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SchemaCreateInventoryTransactionResponse = SchemaCreateInventoryTransactionSuccess | SchemaFormErrors;
|
||||||
|
|
||||||
|
export type SchemaCreateInventoryTransactionSuccess = {
|
||||||
|
__typename?: 'CreateInventoryTransactionSuccess';
|
||||||
|
inventoryTransaction: SchemaInventoryTransaction;
|
||||||
|
};
|
||||||
|
|
||||||
export type SchemaCreateOrderResponse = SchemaCreateOrderSuccess | SchemaInsufficientFunds | SchemaFormErrors;
|
export type SchemaCreateOrderResponse = SchemaCreateOrderSuccess | SchemaInsufficientFunds | SchemaFormErrors;
|
||||||
|
|
||||||
export type SchemaCreateOrderSuccess = {
|
export type SchemaCreateOrderSuccess = {
|
||||||
@@ -68,14 +75,62 @@ export type SchemaInsufficientFunds = SchemaError & {
|
|||||||
amountLacking: Scalars['Float']['output'];
|
amountLacking: Scalars['Float']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SchemaInventoryReport = {
|
||||||
|
__typename?: 'InventoryReport';
|
||||||
|
products: Array<SchemaInventoryReportProduct>;
|
||||||
|
inventoryPurchases: Scalars['Decimal']['output'];
|
||||||
|
productSales: Scalars['Decimal']['output'];
|
||||||
|
deposits: Scalars['Decimal']['output'];
|
||||||
|
orderPurchases: Scalars['Decimal']['output'];
|
||||||
|
balanceAtStart: Scalars['Decimal']['output'];
|
||||||
|
balanceAtEnd: Scalars['Decimal']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaInventoryReportProduct = {
|
||||||
|
__typename?: 'InventoryReportProduct';
|
||||||
|
productId: Scalars['ID']['output'];
|
||||||
|
productName: Scalars['String']['output'];
|
||||||
|
purchaseUnits: Scalars['Int']['output'];
|
||||||
|
purchaseValue: Scalars['Decimal']['output'];
|
||||||
|
salesUnits: Scalars['Int']['output'];
|
||||||
|
salesValue: Scalars['Decimal']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaInventoryTransaction = {
|
||||||
|
__typename?: 'InventoryTransaction';
|
||||||
|
id: Scalars['ID']['output'];
|
||||||
|
user: SchemaUser;
|
||||||
|
product: SchemaProduct;
|
||||||
|
amount: Scalars['Int']['output'];
|
||||||
|
unitPrice: Scalars['Decimal']['output'];
|
||||||
|
comment: Scalars['String']['output'];
|
||||||
|
created: Scalars['DateTime']['output'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaInventoryTransactionInput = {
|
||||||
|
productId: Scalars['ID']['input'];
|
||||||
|
amount: Scalars['Int']['input'];
|
||||||
|
unitPrice: Scalars['Decimal']['input'];
|
||||||
|
comment?: Scalars['String']['input'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaInventoryTransactionOrdering =
|
||||||
|
{ created: SchemaOrdering; };
|
||||||
|
|
||||||
export type SchemaMutation = {
|
export type SchemaMutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
|
createInventoryTransaction: SchemaCreateInventoryTransactionResponse;
|
||||||
createOrder: SchemaCreateOrderResponse;
|
createOrder: SchemaCreateOrderResponse;
|
||||||
createDeposit: SchemaCreateDepositResponse;
|
createDeposit: SchemaCreateDepositResponse;
|
||||||
createUser: SchemaUser;
|
createUser: SchemaUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type SchemaMutationCreateInventoryTransactionArgs = {
|
||||||
|
data: SchemaInventoryTransactionInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type SchemaMutationCreateOrderArgs = {
|
export type SchemaMutationCreateOrderArgs = {
|
||||||
customerId: Scalars['ID']['input'];
|
customerId: Scalars['ID']['input'];
|
||||||
orderLines: Array<SchemaOrderLineInput>;
|
orderLines: Array<SchemaOrderLineInput>;
|
||||||
@@ -161,6 +216,11 @@ export type SchemaProduct = {
|
|||||||
imageUrl: Scalars['String']['output'];
|
imageUrl: Scalars['String']['output'];
|
||||||
salePriceInt: Scalars['Decimal']['output'];
|
salePriceInt: Scalars['Decimal']['output'];
|
||||||
salePriceExt: Scalars['Decimal']['output'];
|
salePriceExt: Scalars['Decimal']['output'];
|
||||||
|
active: Scalars['Boolean']['output'];
|
||||||
|
inventoryAmount: Scalars['Int']['output'];
|
||||||
|
updated: Scalars['DateTime']['output'];
|
||||||
|
wholesaleUnitPrice: Scalars['Decimal']['output'];
|
||||||
|
wholesaleValue: Scalars['Decimal']['output'];
|
||||||
userCounts: Scalars['JSONScalar']['output'];
|
userCounts: Scalars['JSONScalar']['output'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,6 +242,8 @@ export type SchemaProductOrderStat = {
|
|||||||
export type SchemaQuery = {
|
export type SchemaQuery = {
|
||||||
__typename?: 'Query';
|
__typename?: 'Query';
|
||||||
transactionList: Array<SchemaTransaction>;
|
transactionList: Array<SchemaTransaction>;
|
||||||
|
inventoryTransactionList: Array<SchemaInventoryTransaction>;
|
||||||
|
inventoryReport: SchemaInventoryReport;
|
||||||
allProducts: Array<SchemaProduct>;
|
allProducts: Array<SchemaProduct>;
|
||||||
allOrders: Array<SchemaOrder>;
|
allOrders: Array<SchemaOrder>;
|
||||||
orderList: Array<SchemaOrder>;
|
orderList: Array<SchemaOrder>;
|
||||||
@@ -198,6 +260,18 @@ export type SchemaQueryTransactionListArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type SchemaQueryInventoryTransactionListArgs = {
|
||||||
|
ordering?: Array<SchemaInventoryTransactionOrdering>;
|
||||||
|
pagination?: InputMaybe<SchemaOffsetPaginationInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type SchemaQueryInventoryReportArgs = {
|
||||||
|
startTime: Scalars['DateTime']['input'];
|
||||||
|
endTime: Scalars['DateTime']['input'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type SchemaQueryAllProductsArgs = {
|
export type SchemaQueryAllProductsArgs = {
|
||||||
filters?: InputMaybe<SchemaProductFilter>;
|
filters?: InputMaybe<SchemaProductFilter>;
|
||||||
};
|
};
|
||||||
@@ -256,6 +330,13 @@ export type SchemaUserProfile = {
|
|||||||
productOrderStats: Array<SchemaProductOrderStat>;
|
productOrderStats: Array<SchemaProductOrderStat>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InventoryTransactionInput = {
|
||||||
|
productId: string | number;
|
||||||
|
amount: number;
|
||||||
|
unitPrice: string;
|
||||||
|
comment?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type OrderLineInput = {
|
export type OrderLineInput = {
|
||||||
productId: string | number;
|
productId: string | number;
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -282,6 +363,37 @@ export type CreateDepositMutation = { __typename: 'Mutation', createDeposit:
|
|||||||
| { __typename: 'FormErrors', error: boolean, message: string, fields: Array<{ __typename: 'FieldError', field: string, message: string }> }
|
| { __typename: 'FormErrors', error: boolean, message: string, fields: Array<{ __typename: 'FieldError', field: string, message: string }> }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CreateInventoryTransactionMutationVariables = Exact<{
|
||||||
|
data: InventoryTransactionInput;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type CreateInventoryTransactionMutation = { __typename: 'Mutation', createInventoryTransaction:
|
||||||
|
| { __typename: 'CreateInventoryTransactionSuccess', inventoryTransaction: { __typename: 'InventoryTransaction', id: string, product: { __typename: 'Product', name: string, inventoryAmount: number } } }
|
||||||
|
| { __typename: 'FormErrors', message: string, fields: Array<{ __typename: 'FieldError', field: string, message: string }> }
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InventoryPageQueryVariables = Exact<{
|
||||||
|
limit?: number | null | undefined;
|
||||||
|
offset?: number | null | undefined;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type InventoryPageQuery = { __typename: 'Query', allProducts: Array<{ __typename: 'Product', id: string, name: string, active: boolean, inventoryAmount: number, updated: string, wholesaleUnitPrice: string, wholesaleValue: string }>, inventoryTransactionList: Array<{ __typename: 'InventoryTransaction', id: string, created: string, amount: number, unitPrice: string, comment: string, product: { __typename: 'Product', name: string }, user: { __typename: 'User', firstName: string, lastName: string } }> };
|
||||||
|
|
||||||
|
export type InventoryProductsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type InventoryProductsQuery = { __typename: 'Query', allProducts: Array<{ __typename: 'Product', id: string, name: string, inventoryAmount: number }> };
|
||||||
|
|
||||||
|
export type InventoryReportQueryVariables = Exact<{
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type InventoryReportQuery = { __typename: 'Query', inventoryReport: { __typename: 'InventoryReport', inventoryPurchases: string, productSales: string, deposits: string, orderPurchases: string, balanceAtStart: string, balanceAtEnd: string, products: Array<{ __typename: 'InventoryReportProduct', productId: string, productName: string, purchaseUnits: number, purchaseValue: string, salesUnits: number, salesValue: string }> } };
|
||||||
|
|
||||||
export type OrderListQueryVariables = Exact<{
|
export type OrderListQueryVariables = Exact<{
|
||||||
limit?: number | null | undefined;
|
limit?: number | null | undefined;
|
||||||
offset?: number | null | undefined;
|
offset?: number | null | undefined;
|
||||||
@@ -350,6 +462,10 @@ export type UserDetailQuery = { __typename: 'Query', user: { __typename: 'User',
|
|||||||
|
|
||||||
export const CreateUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"firstName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"lastName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CreateUserMutation, CreateUserMutationVariables>;
|
export const CreateUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"firstName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"lastName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CreateUserMutation, CreateUserMutationVariables>;
|
||||||
export const CreateDepositDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDeposit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"amount"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createDeposit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}},{"kind":"Argument","name":{"kind":"Name","value":"amount"},"value":{"kind":"Variable","name":{"kind":"Name","value":"amount"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CreateDepositSuccess"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transaction"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AboveMaxSaldo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"maxSaldo"}},{"kind":"Field","name":{"kind":"Name","value":"above"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FormErrors"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]}}]}}]}}]} as unknown as DocumentNode<CreateDepositMutation, CreateDepositMutationVariables>;
|
export const CreateDepositDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDeposit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"amount"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createDeposit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}},{"kind":"Argument","name":{"kind":"Name","value":"amount"},"value":{"kind":"Variable","name":{"kind":"Name","value":"amount"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CreateDepositSuccess"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transaction"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AboveMaxSaldo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"maxSaldo"}},{"kind":"Field","name":{"kind":"Name","value":"above"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FormErrors"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]}}]}}]}}]} as unknown as DocumentNode<CreateDepositMutation, CreateDepositMutationVariables>;
|
||||||
|
export const CreateInventoryTransactionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createInventoryTransaction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"InventoryTransactionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createInventoryTransaction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CreateInventoryTransactionSuccess"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inventoryTransaction"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"inventoryAmount"}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FormErrors"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]}}]}}]}}]} as unknown as DocumentNode<CreateInventoryTransactionMutation, CreateInventoryTransactionMutationVariables>;
|
||||||
|
export const InventoryPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"inventoryPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"20"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allProducts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"active"}},{"kind":"Field","name":{"kind":"Name","value":"inventoryAmount"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"wholesaleUnitPrice"}},{"kind":"Field","name":{"kind":"Name","value":"wholesaleValue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inventoryTransactionList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ordering"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"created"},"value":{"kind":"EnumValue","value":"DESC"}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"unitPrice"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}}]}}]}}]}}]} as unknown as DocumentNode<InventoryPageQuery, InventoryPageQueryVariables>;
|
||||||
|
export const InventoryProductsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"inventoryProducts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allProducts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"active"},"value":{"kind":"BooleanValue","value":true}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"inventoryAmount"}}]}}]}}]} as unknown as DocumentNode<InventoryProductsQuery, InventoryProductsQueryVariables>;
|
||||||
|
export const InventoryReportDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"inventoryReport"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"startTime"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTime"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"endTime"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTime"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inventoryReport"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"startTime"},"value":{"kind":"Variable","name":{"kind":"Name","value":"startTime"}}},{"kind":"Argument","name":{"kind":"Name","value":"endTime"},"value":{"kind":"Variable","name":{"kind":"Name","value":"endTime"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productId"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"purchaseUnits"}},{"kind":"Field","name":{"kind":"Name","value":"purchaseValue"}},{"kind":"Field","name":{"kind":"Name","value":"salesUnits"}},{"kind":"Field","name":{"kind":"Name","value":"salesValue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inventoryPurchases"}},{"kind":"Field","name":{"kind":"Name","value":"productSales"}},{"kind":"Field","name":{"kind":"Name","value":"deposits"}},{"kind":"Field","name":{"kind":"Name","value":"orderPurchases"}},{"kind":"Field","name":{"kind":"Name","value":"balanceAtStart"}},{"kind":"Field","name":{"kind":"Name","value":"balanceAtEnd"}}]}}]}}]} as unknown as DocumentNode<InventoryReportQuery, InventoryReportQueryVariables>;
|
||||||
export const OrderListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"orderList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"10"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orderList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ordering"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"created"},"value":{"kind":"EnumValue","value":"DESC"}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isExternal"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"orderSum"}},{"kind":"Field","name":{"kind":"Name","value":"customer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"orderlines"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"unitPrice"}},{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceExt"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceInt"}}]}}]}}]}}]}}]} as unknown as DocumentNode<OrderListQuery, OrderListQueryVariables>;
|
export const OrderListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"orderList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"10"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orderList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ordering"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"created"},"value":{"kind":"EnumValue","value":"DESC"}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isExternal"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"orderSum"}},{"kind":"Field","name":{"kind":"Name","value":"customer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"orderlines"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"unitPrice"}},{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceExt"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceInt"}}]}}]}}]}}]}}]} as unknown as DocumentNode<OrderListQuery, OrderListQueryVariables>;
|
||||||
export const TransactionListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"transactionList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"10"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transactionList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ordering"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"created"},"value":{"kind":"EnumValue","value":"DESC"}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}}]}}]}}]} as unknown as DocumentNode<TransactionListQuery, TransactionListQueryVariables>;
|
export const TransactionListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"transactionList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"10"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transactionList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ordering"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"created"},"value":{"kind":"EnumValue","value":"DESC"}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"balance"}}]}}]}}]}}]}}]} as unknown as DocumentNode<TransactionListQuery, TransactionListQueryVariables>;
|
||||||
export const AllProductsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"allProducts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"active"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allProducts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"active"},"value":{"kind":"Variable","name":{"kind":"Name","value":"active"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceExt"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceInt"}}]}}]}}]} as unknown as DocumentNode<AllProductsQuery, AllProductsQueryVariables>;
|
export const AllProductsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"allProducts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"active"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allProducts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"active"},"value":{"kind":"Variable","name":{"kind":"Name","value":"active"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceExt"}},{"kind":"Field","name":{"kind":"Name","value":"salePriceInt"}}]}}]}}]} as unknown as DocumentNode<AllProductsQuery, AllProductsQueryVariables>;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default defineConfig({
|
|||||||
server: {
|
server: {
|
||||||
host: "127.0.0.1",
|
host: "127.0.0.1",
|
||||||
proxy: Object.fromEntries(
|
proxy: Object.fromEntries(
|
||||||
["/admin", "/accounts", "/inventory", "/report", "/static", "/media", "/graphql"].map(
|
["/admin", "/accounts", "/static", "/media", "/graphql"].map(
|
||||||
(path) => [path, process.env.VITE_DEV_API_PROXY || "http://127.0.0.1:3000"],
|
(path) => [path, process.env.VITE_DEV_API_PROXY || "http://127.0.0.1:3000"],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ type CreateDepositSuccess {
|
|||||||
transaction: Transaction!
|
transaction: Transaction!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union CreateInventoryTransactionResponse = CreateInventoryTransactionSuccess | FormErrors
|
||||||
|
|
||||||
|
type CreateInventoryTransactionSuccess {
|
||||||
|
inventoryTransaction: InventoryTransaction!
|
||||||
|
}
|
||||||
|
|
||||||
union CreateOrderResponse = CreateOrderSuccess | InsufficientFunds | FormErrors
|
union CreateOrderResponse = CreateOrderSuccess | InsufficientFunds | FormErrors
|
||||||
|
|
||||||
type CreateOrderSuccess {
|
type CreateOrderSuccess {
|
||||||
@@ -48,12 +54,53 @@ type InsufficientFunds implements Error {
|
|||||||
amountLacking: Float!
|
amountLacking: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InventoryReport {
|
||||||
|
products: [InventoryReportProduct!]!
|
||||||
|
inventoryPurchases: Decimal!
|
||||||
|
productSales: Decimal!
|
||||||
|
deposits: Decimal!
|
||||||
|
orderPurchases: Decimal!
|
||||||
|
balanceAtStart: Decimal!
|
||||||
|
balanceAtEnd: Decimal!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InventoryReportProduct {
|
||||||
|
productId: ID!
|
||||||
|
productName: String!
|
||||||
|
purchaseUnits: Int!
|
||||||
|
purchaseValue: Decimal!
|
||||||
|
salesUnits: Int!
|
||||||
|
salesValue: Decimal!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InventoryTransaction {
|
||||||
|
id: ID!
|
||||||
|
user: User!
|
||||||
|
product: Product!
|
||||||
|
amount: Int!
|
||||||
|
unitPrice: Decimal!
|
||||||
|
comment: String!
|
||||||
|
created: DateTime!
|
||||||
|
}
|
||||||
|
|
||||||
|
input InventoryTransactionInput {
|
||||||
|
productId: ID!
|
||||||
|
amount: Int!
|
||||||
|
unitPrice: Decimal!
|
||||||
|
comment: String! = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
input InventoryTransactionOrdering @oneOf {
|
||||||
|
created: Ordering
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The GenericScalar scalar type represents a generic GraphQL scalar value that could be: List or Object.
|
The GenericScalar scalar type represents a generic GraphQL scalar value that could be: List or Object.
|
||||||
"""
|
"""
|
||||||
scalar JSONScalar
|
scalar JSONScalar
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
createInventoryTransaction(data: InventoryTransactionInput!): CreateInventoryTransactionResponse!
|
||||||
createOrder(customerId: ID!, orderLines: [OrderLineInput!]!, isExternal: Boolean! = false): CreateOrderResponse!
|
createOrder(customerId: ID!, orderLines: [OrderLineInput!]!, isExternal: Boolean! = false): CreateOrderResponse!
|
||||||
createDeposit(userId: ID!, amount: Int!): CreateDepositResponse!
|
createDeposit(userId: ID!, amount: Int!): CreateDepositResponse!
|
||||||
createUser(input: UserInput!): User!
|
createUser(input: UserInput!): User!
|
||||||
@@ -122,6 +169,11 @@ type Product {
|
|||||||
imageUrl: String!
|
imageUrl: String!
|
||||||
salePriceInt: Decimal!
|
salePriceInt: Decimal!
|
||||||
salePriceExt: Decimal!
|
salePriceExt: Decimal!
|
||||||
|
active: Boolean!
|
||||||
|
inventoryAmount: Int!
|
||||||
|
updated: DateTime!
|
||||||
|
wholesaleUnitPrice: Decimal!
|
||||||
|
wholesaleValue: Decimal!
|
||||||
userCounts: JSONScalar!
|
userCounts: JSONScalar!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +193,8 @@ type ProductOrderStat {
|
|||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
transactionList(ordering: [TransactionOrdering!]! = [], pagination: OffsetPaginationInput): [Transaction!]!
|
transactionList(ordering: [TransactionOrdering!]! = [], pagination: OffsetPaginationInput): [Transaction!]!
|
||||||
|
inventoryTransactionList(ordering: [InventoryTransactionOrdering!]! = [], pagination: OffsetPaginationInput): [InventoryTransaction!]!
|
||||||
|
inventoryReport(startTime: DateTime!, endTime: DateTime!): InventoryReport!
|
||||||
allProducts(filters: ProductFilter): [Product!]!
|
allProducts(filters: ProductFilter): [Product!]!
|
||||||
allOrders: [Order!]!
|
allOrders: [Order!]!
|
||||||
orderList(ordering: [OrderOrdering!]! = [], pagination: OffsetPaginationInput): [Order!]!
|
orderList(ordering: [OrderOrdering!]! = [], pagination: OffsetPaginationInput): [Order!]!
|
||||||
|
|||||||
Reference in new issue
Block a user