✨ Add order stats

This commit is contained in:
Nikolai R Kristiansen committed 2022-02-06 21:05:40 +01:00
1 parent 6fa6bf1334
commit 771e0c2a3b
10 files changed
+323 -14

No files matched your search

+124
View File
@@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@apollo/client": "^3.5.8",
"@nivo/bar": "^0.79.1",
"@nivo/pie": "^0.79.1",
"bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.0",
@@ -2347,6 +2348,20 @@
"graphql": "^15.4.0 || ^16.0.0"
}
},
"node_modules/@nivo/annotations": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.79.1.tgz",
"integrity": "sha512-lYso9Luu0maSDtIufwvyVt2+Wue7R9Fh3CIjuRDmNR72UjAgAVEcCar27Fy865UXGsj2hRJZ7KY/1s6kT3gu/w==",
"dependencies": {
"@nivo/colors": "0.79.1",
"@react-spring/web": "9.3.1",
"lodash": "^4.17.21"
},
"peerDependencies": {
"@nivo/core": "0.79.0",
"react": ">= 16.14.0 < 18.0.0"
}
},
"node_modules/@nivo/arcs": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/arcs/-/arcs-0.79.1.tgz",
@@ -2361,6 +2376,43 @@
"react": ">= 16.14.0 < 18.0.0"
}
},
"node_modules/@nivo/axes": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.79.0.tgz",
"integrity": "sha512-EhSeCPxtWEuxqnifeyF/pIJEzL7pRM3rfygL+MpfT5ypu5NcXYRGQo/Bw0Vh+GF1ML+tNAE0rRvCu2jgLSdVNQ==",
"dependencies": {
"@nivo/scales": "0.79.0",
"@react-spring/web": "9.3.1",
"d3-format": "^1.4.4",
"d3-time-format": "^3.0.0"
},
"peerDependencies": {
"@nivo/core": "0.79.0",
"prop-types": ">= 15.5.10 < 16.0.0",
"react": ">= 16.14.0 < 18.0.0"
}
},
"node_modules/@nivo/bar": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/bar/-/bar-0.79.1.tgz",
"integrity": "sha512-swJ2FtFeRPWJK9O6aZiqTDi2J6GrU2Z6kIHBBCXBlFmq6+vfd5AqOHytdXPTaN80JsKDBBdtY7tqRjpRPlDZwQ==",
"dependencies": {
"@nivo/annotations": "0.79.1",
"@nivo/axes": "0.79.0",
"@nivo/colors": "0.79.1",
"@nivo/legends": "0.79.1",
"@nivo/scales": "0.79.0",
"@nivo/tooltip": "0.79.0",
"@react-spring/web": "9.3.1",
"d3-scale": "^3.2.3",
"d3-shape": "^1.2.2",
"lodash": "^4.17.21"
},
"peerDependencies": {
"@nivo/core": "0.79.0",
"react": ">= 16.14.0 < 18.0.0"
}
},
"node_modules/@nivo/colors": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.79.1.tgz",
@@ -2438,6 +2490,22 @@
"react": ">= 16.14.0 < 18.0.0"
}
},
"node_modules/@nivo/scales": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.79.0.tgz",
"integrity": "sha512-5fAt5Wejp8yzAk6qmA3KU+celCxNYrrBhfvOi2ECDG8KQi+orbDnrO6qjVF6+ebfOn9az8ZVukcSeGA5HceiMg==",
"dependencies": {
"d3-scale": "^3.2.3",
"d3-time": "^1.0.11",
"d3-time-format": "^3.0.0",
"lodash": "^4.17.21"
}
},
"node_modules/@nivo/scales/node_modules/d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
},
"node_modules/@nivo/tooltip": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.79.0.tgz",
@@ -14114,6 +14182,16 @@
"dev": true,
"requires": {}
},
"@nivo/annotations": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.79.1.tgz",
"integrity": "sha512-lYso9Luu0maSDtIufwvyVt2+Wue7R9Fh3CIjuRDmNR72UjAgAVEcCar27Fy865UXGsj2hRJZ7KY/1s6kT3gu/w==",
"requires": {
"@nivo/colors": "0.79.1",
"@react-spring/web": "9.3.1",
"lodash": "^4.17.21"
}
},
"@nivo/arcs": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/arcs/-/arcs-0.79.1.tgz",
@@ -14124,6 +14202,34 @@
"d3-shape": "^1.3.5"
}
},
"@nivo/axes": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.79.0.tgz",
"integrity": "sha512-EhSeCPxtWEuxqnifeyF/pIJEzL7pRM3rfygL+MpfT5ypu5NcXYRGQo/Bw0Vh+GF1ML+tNAE0rRvCu2jgLSdVNQ==",
"requires": {
"@nivo/scales": "0.79.0",
"@react-spring/web": "9.3.1",
"d3-format": "^1.4.4",
"d3-time-format": "^3.0.0"
}
},
"@nivo/bar": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/bar/-/bar-0.79.1.tgz",
"integrity": "sha512-swJ2FtFeRPWJK9O6aZiqTDi2J6GrU2Z6kIHBBCXBlFmq6+vfd5AqOHytdXPTaN80JsKDBBdtY7tqRjpRPlDZwQ==",
"requires": {
"@nivo/annotations": "0.79.1",
"@nivo/axes": "0.79.0",
"@nivo/colors": "0.79.1",
"@nivo/legends": "0.79.1",
"@nivo/scales": "0.79.0",
"@nivo/tooltip": "0.79.0",
"@react-spring/web": "9.3.1",
"d3-scale": "^3.2.3",
"d3-shape": "^1.2.2",
"lodash": "^4.17.21"
}
},
"@nivo/colors": {
"version": "0.79.1",
"resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.79.1.tgz",
@@ -14180,6 +14286,24 @@
"react-lifecycles-compat": "^3.0.4"
}
},
"@nivo/scales": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.79.0.tgz",
"integrity": "sha512-5fAt5Wejp8yzAk6qmA3KU+celCxNYrrBhfvOi2ECDG8KQi+orbDnrO6qjVF6+ebfOn9az8ZVukcSeGA5HceiMg==",
"requires": {
"d3-scale": "^3.2.3",
"d3-time": "^1.0.11",
"d3-time-format": "^3.0.0",
"lodash": "^4.17.21"
},
"dependencies": {
"d3-time": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
}
}
},
"@nivo/tooltip": {
"version": "0.79.0",
"resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.79.0.tgz",
+1
View File
@@ -16,6 +16,7 @@
},
"dependencies": {
"@apollo/client": "^3.5.8",
"@nivo/bar": "^0.79.1",
"@nivo/pie": "^0.79.1",
"bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.0",
@@ -1,5 +1,6 @@
.products {
display: grid;
max-width: 1200px;
gap: 1rem;
grid-template-columns: repeat(3, 1fr);
}
+88 -10
View File
@@ -1,8 +1,9 @@
import { useQuery } from "@apollo/client";
import { Bar } from "@nivo/bar";
import { Pie } from "@nivo/pie";
import React from "react";
import { ProductStatsDocument } from "../../types";
import { OrderStatsDocument, ProductStatsDocument, OrderStatsByTime } from "../../types";
import styles from "./Stats.module.css";
type UserCount = {
@@ -10,18 +11,38 @@ type UserCount = {
count: number;
};
const days = { 1: "Mandag", 2: "Tirsdag", 3: "Onsdag", 4: "Torsdag", 5: "Fredag", 6: "Lørdag", 7: "Søndag" };
const months = {
1: "Januar",
2: "Februar",
3: "Mars",
4: "April",
5: "Mai",
6: "Juni",
7: "Juli",
8: "August",
9: "September",
10: "Oktober",
11: "November",
12: "Desember",
};
export const Stats = () => {
const { data, loading } = useQuery(ProductStatsDocument);
const { data: productData, loading: productLoading } = useQuery(ProductStatsDocument);
const { data: orderData, loading: orderLoading } = useQuery(OrderStatsDocument);
const loading = orderLoading || productLoading;
if (loading) {
return <div>Loading...</div>;
}
return (
<div className={styles.stats}>
<h2>Stats</h2>
<h3>Produkter</h3>
<div className={styles.products}>
{(data?.allProducts || []).map((product) => {
return (
{(productData?.allProducts || []).map((product) => (
<div key={product.id}>
{product.name}
<Pie
@@ -35,13 +56,70 @@ export const Stats = () => {
height={300}
/>
</div>
);
})}
))}
</div>
<h3>Hourly</h3>
<h3>Daily</h3>
<h3>Monthly</h3>
<h3>Yearly</h3>
<h3>Ordre per time</h3>
<Bar
data={(orderData?.orderStats?.hourly || []).map((stat: OrderStatsByTime) => ({
id: `${stat.period.toString().padStart(2, "0")}:00`,
label: stat.period,
value: stat.count,
}))}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
<h3>Ordre per ukedag</h3>
<Bar
data={(orderData?.orderStats?.dayly || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in days range. */
id: days[stat.period],
label: stat.period,
value: stat.count,
}))}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
<h3>Ordre per måned</h3>
<Bar
data={(orderData?.orderStats?.monthly || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in months range. */
id: months[stat.period],
label: stat.period,
value: stat.count,
}))}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
<h3>Ordre per år</h3>
<Bar
data={(orderData?.orderStats?.yearly || []).map((stat: OrderStatsByTime) => ({
id: stat.period,
label: stat.period,
value: stat.count,
}))}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
</div>
);
};
@@ -0,0 +1,20 @@
query orderStats {
orderStats {
yearly {
period
count
}
monthly {
period
count
}
dayly {
period
count
}
hourly {
period
count
}
}
}
+21
View File
@@ -117,6 +117,20 @@ export type OrderOrdering = {
created?: InputMaybe<Ordering>;
};
export type OrderStats = {
__typename?: 'OrderStats';
dayly: Array<OrderStatsByTime>;
hourly: Array<OrderStatsByTime>;
monthly: Array<OrderStatsByTime>;
yearly: Array<OrderStatsByTime>;
};
export type OrderStatsByTime = {
__typename?: 'OrderStatsByTime';
count: Scalars['String'];
period: Scalars['Int'];
};
export enum Ordering {
Asc = 'ASC',
Desc = 'DESC'
@@ -143,6 +157,7 @@ export type Query = {
allProducts: Array<Product>;
allUsers: Array<User>;
orderList: Array<Order>;
orderStats: OrderStats;
transactionList: Array<Transaction>;
};
@@ -236,6 +251,11 @@ export type CreateOrderMutationVariables = Exact<{
export type CreateOrderMutation = { __typename?: 'Mutation', createOrder: { __typename?: 'CreateOrderSuccess', order: { __typename?: 'Order', id: string, isExternal: boolean, orderSum: number, customer?: { __typename?: 'User', id: string, firstName: string, lastName: string, profile?: { __typename?: 'UserProfile', id: string, balance: number } | null } | null, orderlines?: Array<{ __typename?: 'OrderLine', id: string, amount: number, unitPrice: number, product: { __typename?: 'Product', id: string, name: string, salePriceExt: number, salePriceInt: number } }> | null } } | { __typename?: 'FormErrors', error: boolean, message: string, fields: Array<{ __typename?: 'FieldError', field: string, message: string }> } | { __typename?: 'InsufficientFunds', error: boolean, message: string, amountLacking: number } };
export type OrderStatsQueryVariables = Exact<{ [key: string]: never; }>;
export type OrderStatsQuery = { __typename?: 'Query', orderStats: { __typename?: 'OrderStats', yearly: Array<{ __typename?: 'OrderStatsByTime', period: number, count: string }>, monthly: Array<{ __typename?: 'OrderStatsByTime', period: number, count: string }>, dayly: Array<{ __typename?: 'OrderStatsByTime', period: number, count: string }>, hourly: Array<{ __typename?: 'OrderStatsByTime', period: number, count: string }> } };
export type ProductStatsQueryVariables = Exact<{
active?: InputMaybe<Scalars['Boolean']>;
}>;
@@ -250,4 +270,5 @@ export const TransactionListDocument = {"kind":"Document","definitions":[{"kind"
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 AllUsersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"allUsers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allUsers"},"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":"image"}},{"kind":"Field","name":{"kind":"Name","value":"lastPurchaseDate"}}]}}]}}]}}]} as unknown as DocumentNode<AllUsersQuery, AllUsersQueryVariables>;
export const CreateOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"customerId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderLines"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"OrderLineInput"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isExternal"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"customerId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"customerId"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderLines"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderLines"}}},{"kind":"Argument","name":{"kind":"Name","value":"isExternal"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isExternal"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOrderSuccess"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isExternal"}},{"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"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"orderSum"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"InsufficientFunds"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"amountLacking"}}]}},{"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<CreateOrderMutation, CreateOrderMutationVariables>;
export const OrderStatsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"orderStats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orderStats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"yearly"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"monthly"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dayly"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"hourly"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]}}]} as unknown as DocumentNode<OrderStatsQuery, OrderStatsQueryVariables>;
export const ProductStatsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"productStats"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"active"}},"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":"userCounts"}}]}}]}}]} as unknown as DocumentNode<ProductStatsQuery, ProductStatsQueryVariables>;
+20 -1
View File
@@ -1,8 +1,18 @@
import strawberry
import strawberry_django
from main import models
from main.api import mutations
from main.api.types import Order, OrderOrdering, Product, Transaction, TransactionOrdering, User
from main.api.types import (
Order,
OrderOrdering,
OrderStats,
OrderStatsByTime,
Product,
Transaction,
TransactionOrdering,
User,
)
@strawberry.type
@@ -13,6 +23,15 @@ class Query:
order_list: list[Order] = strawberry_django.field(pagination=True, order=OrderOrdering)
transaction_list: list[Transaction] = strawberry_django.field(pagination=True, order=TransactionOrdering)
@strawberry.field
def order_stats(self) -> OrderStats:
return OrderStats(
yearly=[OrderStatsByTime(**stat) for stat in models.Order.objects.count_by_year().order_by("period")],
monthly=[OrderStatsByTime(**stat) for stat in models.Order.objects.count_by_month().order_by("period")],
dayly=[OrderStatsByTime(**stat) for stat in models.Order.objects.count_by_weekday().order_by("period")],
hourly=[OrderStatsByTime(**stat) for stat in models.Order.objects.count_by_hour().order_by("period")],
)
@strawberry.type
class Mutation:
+14
View File
@@ -79,6 +79,20 @@ class OrderLine:
unit_price: auto
@strawberry.type
class OrderStatsByTime:
period: int
count: str
@strawberry.type
class OrderStats:
yearly: list[OrderStatsByTime]
monthly: list[OrderStatsByTime]
dayly: list[OrderStatsByTime]
hourly: list[OrderStatsByTime]
@strawberry_django.ordering.order(models.Transaction)
class TransactionOrdering:
created: auto
+21 -3
View File
@@ -2,8 +2,8 @@ from datetime import datetime
from django.conf import settings
from django.db import models
from django.db.models import Sum
from django.templatetags.static import static
from django.db.models import Count, Sum
from django.db.models.functions import ExtractHour, ExtractMonth, ExtractWeekDay, ExtractYear
EXTERNAL_USER = "Ekstern"
@@ -79,6 +79,22 @@ class Product(models.Model):
ordering = ["name"]
class OrderManager(models.Manager):
def count_by_year(self):
return self.get_queryset().annotate(period=ExtractYear("created")).values("period").annotate(count=Count("id"))
def count_by_month(self):
return self.get_queryset().annotate(period=ExtractMonth("created")).values("period").annotate(count=Count("id"))
def count_by_weekday(self):
return (
self.get_queryset().annotate(period=ExtractWeekDay("created")).values("period").annotate(count=Count("id"))
)
def count_by_hour(self):
return self.get_queryset().annotate(period=ExtractHour("created")).values("period").annotate(count=Count("id"))
class Order(models.Model):
customer = models.ForeignKey(
settings.AUTH_USER_MODEL,
@@ -90,6 +106,8 @@ class Order(models.Model):
order_sum = models.FloatField(db_column="sum")
created = models.DateTimeField(auto_now_add=True)
objects = OrderManager()
def is_external(self):
return self.customer is None
@@ -97,7 +115,7 @@ class Order(models.Model):
return "{}".format(", ".join([str(ol) for ol in self.orderlines.all()]))
def __str__(self):
return "{}: {} kr".format(self.customer or "Ekstern", self.order_sum)
return "{}: {} kr".format(self.customer or EXTERNAL_USER, self.order_sum)
class OrderLine(models.Model):
+13
View File
@@ -84,6 +84,18 @@ input OrderOrdering {
created: Ordering
}
type OrderStats {
yearly: [OrderStatsByTime!]!
monthly: [OrderStatsByTime!]!
dayly: [OrderStatsByTime!]!
hourly: [OrderStatsByTime!]!
}
type OrderStatsByTime {
period: Int!
count: String!
}
enum Ordering {
ASC
DESC
@@ -109,6 +121,7 @@ type Query {
allOrders: [Order!]!
orderList(pagination: OffsetPaginationInput, order: OrderOrdering): [Order!]!
transactionList(pagination: OffsetPaginationInput, order: TransactionOrdering): [Transaction!]!
orderStats: OrderStats!
}
type Transaction {