142 | | |
143 | | |
144 | | === Stored procedure |
145 | | |
146 | | {{{ |
147 | | CREATE OR REPLACE FUNCTION get_analytics_stats( |
148 | | p_start_date DATE, |
149 | | p_end_date DATE |
150 | | ) |
151 | | RETURNS JSON AS $$ |
152 | | DECLARE |
153 | | result JSON; |
154 | | BEGIN |
155 | | SELECT json_build_object( |
156 | | 'dailyRevenue', ( |
157 | | SELECT json_agg(r) |
158 | | FROM ( |
159 | | SELECT DATE(timestamp) AS payment_date, SUM(amount) AS total_revenue |
160 | | FROM payments |
161 | | WHERE DATE(timestamp) BETWEEN p_start_date AND p_end_date |
162 | | GROUP BY DATE(timestamp) |
163 | | ORDER BY payment_date |
164 | | ) r |
165 | | ), |
166 | | 'dailyOrders', ( |
167 | | SELECT json_agg(r) |
168 | | FROM ( |
169 | | SELECT DATE(o.datetime) AS order_date, COUNT(o.id) AS total_orders, AVG(p.amount) AS avg_order_value |
170 | | FROM orders o |
171 | | JOIN payments p ON o.id = p.order_id |
172 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
173 | | GROUP BY DATE(o.datetime) |
174 | | ORDER BY order_date |
175 | | ) r |
176 | | ), |
177 | | 'orderDistribution', ( |
178 | | SELECT json_agg(r) |
179 | | FROM ( |
180 | | SELECT c.name AS category, COUNT(oi.id) AS total_items_ordered |
181 | | FROM order_items oi |
182 | | JOIN products p ON oi.product_id = p.id |
183 | | JOIN categories c ON p.category_id = c.id |
184 | | JOIN orders o ON o.id = oi.order_id -- filter by order date |
185 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
186 | | GROUP BY c.name |
187 | | ORDER BY total_items_ordered DESC |
188 | | ) r |
189 | | ), |
190 | | 'topProducts', ( |
191 | | SELECT json_agg(r) |
192 | | FROM ( |
193 | | SELECT p.name AS product, SUM(oi.quantity) AS total_quantity_sold |
194 | | FROM order_items oi |
195 | | JOIN products p ON oi.product_id = p.id |
196 | | JOIN orders o ON o.id = oi.order_id -- apply date filter |
197 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
198 | | GROUP BY p.name |
199 | | ORDER BY total_quantity_sold DESC |
200 | | LIMIT 10 |
201 | | ) r |
202 | | ), |
203 | | 'onlineVsTabOrders', ( |
204 | | SELECT json_agg(r) |
205 | | FROM ( |
206 | | SELECT 'Online Orders' AS order_type, COUNT(*) AS total_orders |
207 | | FROM online_orders oo |
208 | | JOIN orders o ON oo.order_id = o.id |
209 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
210 | | UNION ALL |
211 | | SELECT 'Tab Orders' AS order_type, COUNT(*) AS total_orders |
212 | | FROM tab_orders tord |
213 | | JOIN orders o ON tord.order_id = o.id |
214 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
215 | | ) r |
216 | | ), |
217 | | 'revenueSplit', ( |
218 | | SELECT json_agg(r) |
219 | | FROM ( |
220 | | SELECT 'Online Orders' AS order_type, SUM(p.amount) AS total_revenue |
221 | | FROM orders o |
222 | | JOIN payments p ON o.id = p.order_id |
223 | | JOIN online_orders oo ON o.id = oo.order_id |
224 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
225 | | UNION ALL |
226 | | SELECT 'Tab Orders' AS order_type, SUM(p.amount) AS total_revenue |
227 | | FROM orders o |
228 | | JOIN payments p ON o.id = p.order_id |
229 | | JOIN tab_orders tord ON o.id = tord.order_id |
230 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
231 | | ) r |
232 | | ), |
233 | | 'avgShiftDuration', ( |
234 | | SELECT json_agg(r) |
235 | | FROM ( |
236 | | SELECT manager_id, |
237 | | AVG(EXTRACT(EPOCH FROM (end_time - start_time)) / 3600) AS avg_shift_duration_hours |
238 | | FROM shifts |
239 | | WHERE DATE(start_time) BETWEEN p_start_date AND p_end_date |
240 | | GROUP BY manager_id |
241 | | ) r |
242 | | ), |
243 | | 'ordersByFrontStaff', ( |
244 | | SELECT json_agg(r) |
245 | | FROM ( |
246 | | SELECT fs.employee_id, COUNT(tord.order_id) AS total_orders_managed |
247 | | FROM tab_orders tord |
248 | | JOIN front_staff fs ON tord.front_staff_id = fs.employee_id |
249 | | JOIN orders o ON tord.order_id = o.id |
250 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
251 | | GROUP BY fs.employee_id |
252 | | ORDER BY total_orders_managed DESC |
253 | | ) r |
254 | | ), |
255 | | 'avgTipPercentage', ( |
256 | | SELECT json_agg(r) |
257 | | FROM ( |
258 | | SELECT sr.name AS staff_role, AVG(fs.tip_percent) AS avg_tip_percent |
259 | | FROM front_staff fs |
260 | | JOIN staff_roles sr ON fs.staff_role_id = sr.id |
261 | | GROUP BY sr.name |
262 | | ) r |
263 | | ), |
264 | | 'inventoryTurnover', ( |
265 | | SELECT json_agg(r) |
266 | | FROM ( |
267 | | SELECT p.name AS product, inv.quantity AS current_inventory, |
268 | | SUM(oi.quantity) AS total_quantity_ordered, |
269 | | CASE WHEN inv.quantity = 0 THEN NULL ELSE SUM(oi.quantity)::decimal / inv.quantity END AS turnover_ratio |
270 | | FROM products p |
271 | | JOIN inventories inv ON p.id = inv.product_id |
272 | | JOIN order_items oi ON p.id = oi.product_id |
273 | | JOIN orders o ON o.id = oi.order_id |
274 | | WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date |
275 | | GROUP BY p.name, inv.quantity |
276 | | ORDER BY turnover_ratio DESC |
277 | | ) r |
278 | | ), |
279 | | 'mostPopularTable', ( |
280 | | SELECT json_build_object( |
281 | | 'table_number', table_number, |
282 | | 'reservation_count', reservation_count |
283 | | ) |
284 | | FROM ( |
285 | | SELECT table_number, COUNT(*) AS reservation_count |
286 | | FROM frontstaff_managed_reservations |
287 | | WHERE DATE(datetime) BETWEEN p_start_date AND p_end_date |
288 | | GROUP BY table_number |
289 | | ORDER BY reservation_count DESC |
290 | | LIMIT 1 |
291 | | ) sub |
292 | | ), |
293 | | 'reservationsByDayOfWeek', ( |
294 | | SELECT json_agg(r) |
295 | | FROM ( |
296 | | SELECT EXTRACT(DOW FROM datetime) AS day_of_week, COUNT(*) AS total_reservations |
297 | | FROM reservations |
298 | | WHERE DATE(datetime) BETWEEN p_start_date AND p_end_date |
299 | | GROUP BY day_of_week |
300 | | ORDER BY total_reservations DESC |
301 | | ) r |
302 | | ) |
303 | | ) INTO result; |
304 | | |
305 | | RETURN result; |
306 | | END; |
307 | | $$ LANGUAGE plpgsql; |
308 | | }}} |
309 | | {{{ |
310 | | SELECT get_analytics_stats('2025-01-01', '2025-01-31'); |
311 | | }}} |