package services import ( "encoding/json" "time" "restaurant-pos/internal/models" "gorm.io/gorm" ) // SyncEnqueuer provides simple helper methods to enqueue sync events from handlers. // Handlers call these after successful operations. // EnqueueOrderSync enqueues an order event with a lightweight summary payload. func (s *SyncService) EnqueueOrderSync(order *models.Order, action string) { if s == nil || s.Config.IsCloud() || s.Config.CloudURL == "" { return } // Build lightweight payload (no full items — just summary) items := []map[string]interface{}{} for _, item := range order.Items { items = append(items, map[string]interface{}{ "name": item.ProductName, "qty": item.Quantity, "total": item.TotalPrice, }) } itemsJSON, _ := json.Marshal(items) // Get table name if linked tableName := "" if order.TableID != nil && *order.TableID != "" { var table models.RestaurantTable s.DB.Select("name").Where("id = ?", *order.TableID).First(&table) tableName = table.Name } // Get staff name (captain) staffName := "" if order.CaptainID != nil && *order.CaptainID != "" { var user models.User s.DB.Select("full_name").Where("id = ?", *order.CaptainID).First(&user) staffName = user.FullName } // Get payment method from first payment if available paymentMethod := "" if len(order.Payments) > 0 { paymentMethod = string(order.Payments[0].Method) } payload := map[string]interface{}{ "order_number": order.OrderNumber, "source": order.Source, "status": order.Status, "payment_status": order.PaymentStatus, "sub_total": order.SubTotal, "tax_amount": order.TaxAmount, "discount_amount": order.DiscountAmount, "grand_total": order.GrandTotal, "payment_method": paymentMethod, "item_count": len(order.Items), "customer_name": order.CustomerName, "customer_phone": order.CustomerPhone, "table_name": tableName, "staff_name": staffName, "items_summary": string(itemsJSON), "order_date": order.CreatedAt.Format(time.RFC3339), } s.EnqueueEvent("order", order.ID, action, payload) } // EnqueuePaymentSync enqueues a payment event. func (s *SyncService) EnqueuePaymentSync(payment *models.Payment, action string) { if s == nil || s.Config.IsCloud() || s.Config.CloudURL == "" { return } payload := map[string]interface{}{ "order_id": payment.OrderID, "method": payment.Method, "amount": payment.Amount, "reference": payment.Reference, } s.EnqueueEvent("payment", payment.ID, action, payload) } // EnqueueDailySummary generates and enqueues end-of-day summary. func (s *SyncService) EnqueueDailySummary(db *gorm.DB, date string) { if s == nil || s.Config.IsCloud() || s.Config.CloudURL == "" { return } dateStart := date + " 00:00:00" dateEnd := date + " 23:59:59" var totalOrders int64 var totalRevenue, totalTax, totalDiscount float64 var cashRev, cardRev, upiRev float64 var cancelledOrders int64 var cancelledValue float64 db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid'", dateStart, dateEnd). Count(&totalOrders) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid'", dateStart, dateEnd). Select("COALESCE(SUM(grand_total), 0)").Row().Scan(&totalRevenue) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid'", dateStart, dateEnd). Select("COALESCE(SUM(tax_amount), 0)").Row().Scan(&totalTax) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid'", dateStart, dateEnd). Select("COALESCE(SUM(discount_amount), 0)").Row().Scan(&totalDiscount) // Payment method breakdown db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid' AND payment_method = 'cash'", dateStart, dateEnd). Select("COALESCE(SUM(grand_total), 0)").Row().Scan(&cashRev) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid' AND payment_method = 'card'", dateStart, dateEnd). Select("COALESCE(SUM(grand_total), 0)").Row().Scan(&cardRev) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND payment_status = 'paid' AND payment_method = 'upi'", dateStart, dateEnd). Select("COALESCE(SUM(grand_total), 0)").Row().Scan(&upiRev) // Cancelled db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND status = 'cancelled'", dateStart, dateEnd). Count(&cancelledOrders) db.Model(&models.Order{}). Where("created_at BETWEEN ? AND ? AND status = 'cancelled'", dateStart, dateEnd). Select("COALESCE(SUM(grand_total), 0)").Row().Scan(&cancelledValue) // Expenses var expenseTotal float64 db.Model(&models.Expense{}). Where("date = ?", date). Select("COALESCE(SUM(amount), 0)").Row().Scan(&expenseTotal) avgOrder := float64(0) if totalOrders > 0 { avgOrder = totalRevenue / float64(totalOrders) } summary := map[string]interface{}{ "date": date, "total_orders": totalOrders, "total_revenue": totalRevenue, "total_tax": totalTax, "total_discount": totalDiscount, "cash_revenue": cashRev, "card_revenue": cardRev, "upi_revenue": upiRev, "other_revenue": totalRevenue - cashRev - cardRev - upiRev, "avg_order_value": avgOrder, "cancelled_orders": cancelledOrders, "cancelled_value": cancelledValue, "expense_total": expenseTotal, } s.EnqueueEvent("daily_summary", date, "update", summary) }