| package controllers |
|
|
| import ( |
| "fmt" |
| "net/http" |
| "strconv" |
| "strings" |
| "time" |
|
|
| "service-warungpos-go/config" |
| "service-warungpos-go/models" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| type TopProductRow struct { |
| ProductName string `json:"product_name"` |
| TotalQuantity int `json:"total_quantity"` |
| TotalRevenue int `json:"total_revenue"` |
| } |
|
|
| type SummaryTopProduct struct { |
| Name string `json:"name"` |
| TotalSold int `json:"total_sold"` |
| TotalRevenue int `json:"total_revenue"` |
| } |
|
|
| type ReportOrderRow struct { |
| OrderNumber string `json:"order_number"` |
| TotalAmount int `json:"total_amount"` |
| PaymentMethod string `json:"payment_method"` |
| CreatedAt time.Time `json:"created_at"` |
| Items string `json:"items"` |
| } |
|
|
| func getDayRange(targetDate time.Time) (time.Time, time.Time) { |
| |
| loc, _ := time.LoadLocation("Asia/Jakarta") |
| if loc == nil { |
| loc = time.Local |
| } |
| start := time.Date(targetDate.Year(), targetDate.Month(), targetDate.Day(), 0, 0, 0, 0, loc) |
| end := start.Add(24 * time.Hour) |
| return start, end |
| } |
|
|
| func fmtRupiah(amount int) string { |
| |
| str := fmt.Sprintf("%d", amount) |
| var result []string |
| length := len(str) |
| for i := length; i > 0; i -= 3 { |
| start := i - 3 |
| if start < 0 { |
| start = 0 |
| } |
| result = append([]string{str[start:i]}, result...) |
| } |
| return "Rp " + strings.Join(result, ".") |
| } |
|
|
| |
|
|
| func DailyReport(c *gin.Context) { |
| userVal, _ := c.Get("user") |
| user := userVal.(*models.User) |
|
|
| dateQuery := c.Query("date") |
| branchQuery := c.Query("branch_id") |
|
|
| var targetDate time.Time |
| var err error |
| if dateQuery != "" { |
| targetDate, err = time.Parse("2006-01-02", dateQuery) |
| if err != nil { |
| c.JSON(http.StatusBadRequest, gin.H{"detail": "Format tanggal salah, gunakan YYYY-MM-DD"}) |
| return |
| } |
| } else { |
| |
| targetDate = time.Now() |
| } |
|
|
| startDt, endDt := getDayRange(targetDate) |
|
|
| query := config.DB.Preload("Items.Product"). |
| Where("company_id = ? AND created_at >= ? AND created_at < ? AND payment_status = ?", *user.CompanyID, startDt, endDt, "paid") |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| query = query.Where("branch_id = ?", bID) |
| } |
| } |
|
|
| var orders []models.Order |
| if err := query.Find(&orders).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data laporan harian"}) |
| return |
| } |
|
|
| totalRevenue := 0 |
| totalCash := 0 |
| totalMidtrans := 0 |
| totalPlatformFee := 0 |
|
|
| var orderRows []ReportOrderRow |
| for _, o := range orders { |
| totalRevenue += o.TotalAmount |
| if o.PaymentMethod == "cash" { |
| totalCash += o.TotalAmount |
| } else if o.PaymentMethod == "midtrans" || o.PaymentMethod == "tripay" { |
| totalMidtrans += o.TotalAmount |
| } |
| totalPlatformFee += o.PlatformFee |
|
|
| itemNames := []string{} |
| for _, item := range o.Items { |
| name := "Item" |
| if item.Product != nil { |
| name = item.Product.Name |
| } |
| itemNames = append(itemNames, fmt.Sprintf("%s (x%d)", name, item.Quantity)) |
| } |
| |
| itemsStr := strings.Join(itemNames, ", ") |
|
|
| orderRows = append(orderRows, ReportOrderRow{ |
| OrderNumber: o.OrderNumber, |
| TotalAmount: o.TotalAmount, |
| PaymentMethod: o.PaymentMethod, |
| CreatedAt: o.CreatedAt, |
| Items: itemsStr, |
| }) |
| } |
|
|
| |
| var topProducts []TopProductRow |
| topQuery := config.DB.Table("products"). |
| Select("products.name as product_name, sum(order_items.quantity) as total_quantity, sum(order_items.subtotal) as total_revenue"). |
| Joins("join order_items on products.id = order_items.product_id"). |
| Joins("join orders on order_items.order_id = orders.id"). |
| Where("orders.company_id = ? AND orders.payment_status = ? AND orders.created_at >= ? AND orders.created_at < ?", *user.CompanyID, "paid", startDt, endDt) |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| topQuery = topQuery.Where("orders.branch_id = ?", bID) |
| } |
| } |
|
|
| topQuery.Group("products.name"). |
| Order("total_quantity desc"). |
| Limit(5). |
| Scan(&topProducts) |
|
|
| c.JSON(http.StatusOK, gin.H{ |
| "date": targetDate.Format("2006-01-02"), |
| "total_transactions": len(orders), |
| "total_revenue": totalRevenue, |
| "total_cash": totalCash, |
| "total_midtrans": totalMidtrans, |
| "total_platform_fee": totalPlatformFee, |
| "top_products": topProducts, |
| "orders": orderRows, |
| }) |
| } |
|
|
| func SummaryReport(c *gin.Context) { |
| userVal, _ := c.Get("user") |
| user := userVal.(*models.User) |
|
|
| branchQuery := c.Query("branch_id") |
|
|
| |
| totalOrders := int64(0) |
| totalRevenue := int64(0) |
|
|
| totalQuery := config.DB.Model(&models.Order{}). |
| Where("company_id = ? AND payment_status = ?", *user.CompanyID, "paid") |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| totalQuery = totalQuery.Where("branch_id = ?", bID) |
| } |
| } |
|
|
| totalQuery.Count(&totalOrders) |
| totalQuery.Select("coalesce(sum(total_amount), 0)").Row().Scan(&totalRevenue) |
|
|
| |
| var totalProducts int64 |
| prodQuery := config.DB.Model(&models.Product{}). |
| Where("company_id = ? AND is_active = ?", *user.CompanyID, true) |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| |
| subQuery := config.DB.Model(&models.BranchProduct{}). |
| Select("product_id"). |
| Where("branch_id = ? AND is_available = ?", bID, false) |
| prodQuery = prodQuery.Where("id NOT IN (?)", subQuery) |
| } |
| } |
| prodQuery.Count(&totalProducts) |
|
|
| |
| var topProducts []SummaryTopProduct |
| topQuery := config.DB.Table("products"). |
| Select("products.name as name, sum(order_items.quantity) as total_sold, sum(order_items.subtotal) as total_revenue"). |
| Joins("join order_items on products.id = order_items.product_id"). |
| Joins("join orders on order_items.order_id = orders.id"). |
| Where("orders.company_id = ? AND orders.payment_status = ?", *user.CompanyID, "paid") |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| topQuery = topQuery.Where("orders.branch_id = ?", bID) |
| } |
| } |
|
|
| topQuery.Group("products.name"). |
| Order("total_sold desc"). |
| Limit(5). |
| Scan(&topProducts) |
|
|
| |
| todayOrders := int64(0) |
| todayRevenue := int64(0) |
|
|
| startToday, endToday := getDayRange(time.Now()) |
|
|
| todayQuery := config.DB.Model(&models.Order{}). |
| Where("company_id = ? AND payment_status = ? AND created_at >= ? AND created_at < ?", *user.CompanyID, "paid", startToday, endToday) |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| todayQuery = todayQuery.Where("branch_id = ?", bID) |
| } |
| } |
|
|
| todayQuery.Count(&todayOrders) |
| todayQuery.Select("coalesce(sum(total_amount), 0)").Row().Scan(&todayRevenue) |
|
|
| |
| var qrisRevenue int64 |
| var qrisFee int64 |
|
|
| qrisQuery := config.DB.Model(&models.Order{}). |
| Where("company_id = ? AND payment_status = ? AND payment_method != 'cash'", *user.CompanyID, "paid") |
|
|
| if branchQuery != "" { |
| if bID, err := strconv.Atoi(branchQuery); err == nil { |
| qrisQuery = qrisQuery.Where("branch_id = ?", bID) |
| } |
| } |
|
|
| qrisQuery.Select("coalesce(sum(total_amount), 0), coalesce(sum(platform_fee), 0)").Row().Scan(&qrisRevenue, &qrisFee) |
|
|
| c.JSON(http.StatusOK, gin.H{ |
| "all_time": gin.H{ |
| "total_orders": totalOrders, |
| "total_revenue": totalRevenue, |
| }, |
| "today": gin.H{ |
| "total_orders": todayOrders, |
| "total_revenue": todayRevenue, |
| }, |
| "qris_report": gin.H{ |
| "total_transactions": qrisRevenue, |
| "system_fee": qrisFee, |
| "net_amount": qrisRevenue - qrisFee, |
| }, |
| "total_products": totalProducts, |
| "top_products": topProducts, |
| }) |
| } |
|
|