From 1d400357625eb66b78134f3fc7933a8e3bb2f629 Mon Sep 17 00:00:00 2001 From: Nick Kosarev Date: Thu, 31 Jul 2025 11:37:08 +0200 Subject: [PATCH] feat: network metrics --- .../api/kitchen/revenue/iiko-daily.post.ts | 16 ++++++++ .../server/tasks/kitchen/average-update.ts | 25 ++++++++--- packages/database/src/repository/index.ts | 2 + packages/database/src/repository/kitchen.ts | 7 +--- packages/database/src/repository/network.ts | 41 +++++++++++++++++++ packages/database/src/tables.ts | 9 ++++ packages/database/src/types.ts | 3 ++ 7 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 packages/database/src/repository/network.ts diff --git a/apps/web-app/server/api/kitchen/revenue/iiko-daily.post.ts b/apps/web-app/server/api/kitchen/revenue/iiko-daily.post.ts index 0e43e867..18f71759 100644 --- a/apps/web-app/server/api/kitchen/revenue/iiko-daily.post.ts +++ b/apps/web-app/server/api/kitchen/revenue/iiko-daily.post.ts @@ -153,6 +153,22 @@ async function parseFileAndUpdateData(file: MultiPartData) { kitchen.commonTotal = commonTotal } + // Create or update metrics + const metrics = await repository.network.listMetrics() + const existingMetrics = metrics.find((metric) => metric.date === dateOnly) + if (!existingMetrics) { + await repository.network.createMetrics({ + date: dateOnly, + averageCheck: commonAverageCheck, + total: commonTotal, + }) + } else { + await repository.network.updateMetrics(existingMetrics.id, { + averageCheck: commonAverageCheck, + total: commonTotal, + }) + } + // Every kitchen: find in DB and add amount for this day const kitchens = await repository.kitchen.list() let rowsUpdated = 0 diff --git a/apps/web-app/server/tasks/kitchen/average-update.ts b/apps/web-app/server/tasks/kitchen/average-update.ts index eed12661..370540b1 100644 --- a/apps/web-app/server/tasks/kitchen/average-update.ts +++ b/apps/web-app/server/tasks/kitchen/average-update.ts @@ -7,14 +7,27 @@ export default defineTask({ }, async run() { try { - const revenuesToUpdate = await repository.kitchen.listRevenuesToUpdate() - for (const revenue of revenuesToUpdate) { - // common + const revenues = await repository.kitchen.listRevenuesToUpdate() + let metrics = await repository.network.listMetrics() + + for (const revenue of revenues) { + // If have metric for this date + if (metrics.find((metric) => metric.date === revenue.date)) { + continue + } + const allRevenuesThisPeriod = await repository.kitchen.listRevenuesForDate(revenue.date) - const commonAverageCheck = Math.round(allRevenuesThisPeriod.reduce((acc, curr) => acc + curr.averageCheck, 0) / allRevenuesThisPeriod.length) - await repository.kitchen.updateRevenue(revenue.id, { - commonAverageCheck, + const averageCheck = Math.round(allRevenuesThisPeriod.reduce((acc, curr) => acc + curr.averageCheck, 0) / allRevenuesThisPeriod.length) + const total = Math.round(allRevenuesThisPeriod.reduce((acc, curr) => acc + curr.total, 0) / allRevenuesThisPeriod.length) + + await repository.network.createMetrics({ + date: revenue.date, + averageCheck, + total, }) + + // Update + metrics = await repository.network.listMetrics() } } catch (error) { errorResolver(error) diff --git a/packages/database/src/repository/index.ts b/packages/database/src/repository/index.ts index b23e5e7a..526bdb9a 100644 --- a/packages/database/src/repository/index.ts +++ b/packages/database/src/repository/index.ts @@ -9,6 +9,7 @@ import { File } from './file' import { Kitchen } from './kitchen' import { Media } from './media' import { Menu } from './menu' +import { Network } from './network' import { Notification } from './notification' import { Partner } from './partner' import { Payment } from './payment' @@ -30,6 +31,7 @@ class Repository { readonly kitchen = Kitchen readonly media = Media readonly menu = Menu + readonly network = Network readonly notification = Notification readonly partner = Partner readonly payment = Payment diff --git a/packages/database/src/repository/kitchen.ts b/packages/database/src/repository/kitchen.ts index c795f31b..1d74d129 100644 --- a/packages/database/src/repository/kitchen.ts +++ b/packages/database/src/repository/kitchen.ts @@ -64,12 +64,7 @@ export class Kitchen { } static async listRevenuesToUpdate() { - return useDatabase().query.kitchenRevenues.findMany({ - where: (revenues, { eq, or }) => or( - eq(revenues.commonAverageCheck, 0), - ), - limit: 50, - }) + return useDatabase().query.kitchenRevenues.findMany() } static async create(data: KitchenDraft) { diff --git a/packages/database/src/repository/network.ts b/packages/database/src/repository/network.ts new file mode 100644 index 00000000..d5679177 --- /dev/null +++ b/packages/database/src/repository/network.ts @@ -0,0 +1,41 @@ +import type { NetworkMetricsDraft } from '../types' +import { eq, sql } from 'drizzle-orm' +import { useDatabase } from '../database' +import { networkMetrics } from '../tables' + +export class Network { + static async findMetrics(id: string) { + return useDatabase().query.networkMetrics.findFirst({ + where: (metrics, { eq }) => eq(metrics.id, id), + }) + } + + static async listMetrics() { + return useDatabase().query.networkMetrics.findMany({ + orderBy: (metrics, { desc }) => desc(metrics.date), + }) + } + + static async listMetricsForDate(date: string) { + return useDatabase().query.networkMetrics.findMany({ + where: (metrics, { and }) => and( + sql`date(${metrics.date}) >= date(${date})`, + sql`date(${metrics.date}) <= date(${date})`, + ), + }) + } + + static async createMetrics(data: NetworkMetricsDraft) { + const [metrics] = await useDatabase().insert(networkMetrics).values(data).returning() + return metrics + } + + static async updateMetrics(id: string, data: Partial) { + const [metrics] = await useDatabase() + .update(networkMetrics) + .set(data) + .where(eq(networkMetrics.id, id)) + .returning() + return metrics + } +} diff --git a/packages/database/src/tables.ts b/packages/database/src/tables.ts index 4100a3e5..792e48cf 100644 --- a/packages/database/src/tables.ts +++ b/packages/database/src/tables.ts @@ -577,6 +577,15 @@ export const clientReviews = pgTable('client_reviews', { feedbackPointId: cuid2('feedback_point_id').references(() => feedbackPoints.id), }) +export const networkMetrics = pgTable('network_metrics', { + id: cuid2('id').defaultRandom().primaryKey(), + createdAt: timestamp('created_at', { precision: 3, withTimezone: true, mode: 'string' }).notNull().defaultNow(), + updatedAt: timestamp('updated_at', { precision: 3, withTimezone: true, mode: 'string' }).notNull().defaultNow(), + date: date('date', { mode: 'string' }).notNull(), + total: numeric('total', { mode: 'number' }).notNull().default(0), + averageCheck: numeric('average_check', { mode: 'number' }).notNull().default(0), +}) + export const userRelations = relations(users, ({ many, one }) => ({ chatMessages: many(chatMessages), chatMembers: many(chatMembers), diff --git a/packages/database/src/types.ts b/packages/database/src/types.ts index d164a51b..19e6af94 100644 --- a/packages/database/src/types.ts +++ b/packages/database/src/types.ts @@ -125,3 +125,6 @@ export type FeedbackPointDraft = InferInsertModel export type ClientReview = InferSelectModel export type ClientReviewDraft = InferInsertModel + +export type NetworkMetrics = InferSelectModel +export type NetworkMetricsDraft = InferInsertModel