diff --git a/internal/repository/analytics_repository.go b/internal/repository/analytics_repository.go index 1a6852a..62a9a90 100644 --- a/internal/repository/analytics_repository.go +++ b/internal/repository/analytics_repository.go @@ -145,179 +145,68 @@ func (r *AnalyticsRepositoryImpl) GetPurchasingAnalytics(ctx context.Context, or } } - rawMaterialOutletFilter := "" - expenseOutletFilter := "" - rawMaterialSummaryArgs := []interface{}{ - organizationID, - entities.InventoryMovementTypePurchase, - "INGREDIENT", - entities.InventoryMovementReferenceTypePurchaseOrder, - dateFrom, - dateTo, - } - expenseSummaryArgs := []interface{}{ - organizationID, - entities.PurchaseCategoryTypeExpense, - "approved", - dateFrom, - dateTo, - } - if outletID != nil { - rawMaterialOutletFilter = "AND im.outlet_id = ?" - expenseOutletFilter = "AND e.outlet_id = ?" - rawMaterialSummaryArgs = append(rawMaterialSummaryArgs, *outletID) - expenseSummaryArgs = append(expenseSummaryArgs, *outletID) - } - summaryArgs := append(rawMaterialSummaryArgs, expenseSummaryArgs...) - - summaryQuery := ` - WITH raw_material AS ( - SELECT - COALESCE(SUM(im.total_cost), 0) as raw_material_purchases, - COUNT(DISTINCT im.reference_id) as raw_material_purchase_orders, - COALESCE(SUM(im.quantity), 0) as total_quantity, - COUNT(DISTINCT im.item_id) as total_ingredients, - COUNT(DISTINCT po.vendor_id) as total_vendors - FROM inventory_movements im - LEFT JOIN purchase_orders po ON im.reference_id = po.id - WHERE im.organization_id = ? - AND im.movement_type = ? - AND im.item_type = ? - AND im.reference_type = ? - AND im.created_at >= ? AND im.created_at <= ? - ` + rawMaterialOutletFilter + ` - ), - expense AS ( - SELECT - COALESCE(SUM(ei.amount), 0) as expense_purchases, - COUNT(DISTINCT e.id) as expense_count - FROM expense_items ei - JOIN expenses e ON ei.expense_id = e.id - JOIN purchase_categories pc ON ei.purchase_category_id = pc.id - WHERE e.organization_id = ? - AND pc.type = ? - AND e.status = ? - AND e.transaction_date >= ? AND e.transaction_date <= ? - ` + expenseOutletFilter + ` - ) - SELECT - rm.raw_material_purchases + ex.expense_purchases as total_purchases, - rm.raw_material_purchases, - ex.expense_purchases, - rm.raw_material_purchase_orders + ex.expense_count as total_purchase_orders, - rm.raw_material_purchase_orders, - ex.expense_count, - rm.total_quantity, + summaryQuery := r.db.WithContext(ctx). + Table("inventory_movements im"). + Select(` + COALESCE(SUM(im.total_cost), 0) as total_purchases, + COUNT(DISTINCT im.reference_id) as total_purchase_orders, + COALESCE(SUM(im.quantity), 0) as total_quantity, CASE - WHEN rm.raw_material_purchase_orders + ex.expense_count > 0 - THEN (rm.raw_material_purchases + ex.expense_purchases) / (rm.raw_material_purchase_orders + ex.expense_count) + WHEN COUNT(DISTINCT im.reference_id) > 0 + THEN COALESCE(SUM(im.total_cost), 0) / COUNT(DISTINCT im.reference_id) ELSE 0 END as average_purchase_order_value, - rm.total_ingredients, - rm.total_vendors - FROM raw_material rm - CROSS JOIN expense ex - ` + COUNT(DISTINCT im.item_id) as total_ingredients, + COUNT(DISTINCT po.vendor_id) as total_vendors + `). + Joins("LEFT JOIN purchase_orders po ON im.reference_id = po.id"). + Where("im.organization_id = ?", organizationID). + Where("im.movement_type = ?", entities.InventoryMovementTypePurchase). + Where("im.item_type = ?", "INGREDIENT"). + Where("im.reference_type = ?", entities.InventoryMovementReferenceTypePurchaseOrder). + Where("im.created_at >= ? AND im.created_at <= ?", dateFrom, dateTo) - if err := r.db.WithContext(ctx).Raw(summaryQuery, summaryArgs...).Scan(&summary).Error; err != nil { + summaryQuery = r.resolveOutletID(summaryQuery, outletID, "im.outlet_id") + + if err := summaryQuery.Scan(&summary).Error; err != nil { return nil, err } var dateFormat string switch groupBy { case "hour": - dateFormat = "DATE_TRUNC('hour', im.created_at)::timestamp" + dateFormat = "DATE_TRUNC('hour', im.created_at)" case "week": - dateFormat = "DATE_TRUNC('week', im.created_at)::timestamp" + dateFormat = "DATE_TRUNC('week', im.created_at)" case "month": - dateFormat = "DATE_TRUNC('month', im.created_at)::timestamp" + dateFormat = "DATE_TRUNC('month', im.created_at)" default: - dateFormat = "DATE_TRUNC('day', im.created_at)::timestamp" + dateFormat = "DATE_TRUNC('day', im.created_at)" } - expenseDateFormat := "DATE_TRUNC('day', e.transaction_date)::timestamp" - switch groupBy { - case "hour": - expenseDateFormat = "DATE_TRUNC('hour', e.transaction_date)::timestamp" - case "week": - expenseDateFormat = "DATE_TRUNC('week', e.transaction_date)::timestamp" - case "month": - expenseDateFormat = "DATE_TRUNC('month', e.transaction_date)::timestamp" - } - - rawMaterialDataArgs := []interface{}{ - organizationID, - entities.InventoryMovementTypePurchase, - "INGREDIENT", - entities.InventoryMovementReferenceTypePurchaseOrder, - dateFrom, - dateTo, - } - expenseDataArgs := []interface{}{ - organizationID, - entities.PurchaseCategoryTypeExpense, - "approved", - dateFrom, - dateTo, - } - if outletID != nil { - rawMaterialDataArgs = append(rawMaterialDataArgs, *outletID) - expenseDataArgs = append(expenseDataArgs, *outletID) - } - dataArgs := append(rawMaterialDataArgs, expenseDataArgs...) - var data []entities.PurchasingAnalyticsData - dataQuery := ` - WITH raw_material AS ( - SELECT - ` + dateFormat + ` as date, - COALESCE(SUM(im.total_cost), 0) as raw_material_purchases, - COUNT(DISTINCT im.reference_id) as raw_material_purchase_orders, - COALESCE(SUM(im.quantity), 0) as quantity, - COUNT(DISTINCT im.item_id) as ingredients, - COUNT(DISTINCT po.vendor_id) as vendors - FROM inventory_movements im - LEFT JOIN purchase_orders po ON im.reference_id = po.id - WHERE im.organization_id = ? - AND im.movement_type = ? - AND im.item_type = ? - AND im.reference_type = ? - AND im.created_at >= ? AND im.created_at <= ? - ` + rawMaterialOutletFilter + ` - GROUP BY 1 - ), - expense AS ( - SELECT - ` + expenseDateFormat + ` as date, - COALESCE(SUM(ei.amount), 0) as expense_purchases, - COUNT(DISTINCT e.id) as expense_count - FROM expense_items ei - JOIN expenses e ON ei.expense_id = e.id - JOIN purchase_categories pc ON ei.purchase_category_id = pc.id - WHERE e.organization_id = ? - AND pc.type = ? - AND e.status = ? - AND e.transaction_date >= ? AND e.transaction_date <= ? - ` + expenseOutletFilter + ` - GROUP BY 1 - ) - SELECT - COALESCE(rm.date, ex.date) as date, - COALESCE(rm.raw_material_purchases, 0) + COALESCE(ex.expense_purchases, 0) as purchases, - COALESCE(rm.raw_material_purchases, 0) as raw_material_purchases, - COALESCE(ex.expense_purchases, 0) as expense_purchases, - COALESCE(rm.raw_material_purchase_orders, 0) + COALESCE(ex.expense_count, 0) as purchase_orders, - COALESCE(rm.raw_material_purchase_orders, 0) as raw_material_purchase_orders, - COALESCE(ex.expense_count, 0) as expense_count, - COALESCE(rm.quantity, 0) as quantity, - COALESCE(rm.ingredients, 0) as ingredients, - COALESCE(rm.vendors, 0) as vendors - FROM raw_material rm - FULL OUTER JOIN expense ex ON rm.date = ex.date - ORDER BY date - ` + dataQuery := r.db.WithContext(ctx). + Table("inventory_movements im"). + Select(` + `+dateFormat+` as date, + COALESCE(SUM(im.total_cost), 0) as purchases, + COUNT(DISTINCT im.reference_id) as purchase_orders, + COALESCE(SUM(im.quantity), 0) as quantity, + COUNT(DISTINCT im.item_id) as ingredients, + COUNT(DISTINCT po.vendor_id) as vendors + `). + Joins("LEFT JOIN purchase_orders po ON im.reference_id = po.id"). + Where("im.organization_id = ?", organizationID). + Where("im.movement_type = ?", entities.InventoryMovementTypePurchase). + Where("im.item_type = ?", "INGREDIENT"). + Where("im.reference_type = ?", entities.InventoryMovementReferenceTypePurchaseOrder). + Where("im.created_at >= ? AND im.created_at <= ?", dateFrom, dateTo). + Group(dateFormat). + Order(dateFormat) - if err := r.db.WithContext(ctx).Raw(dataQuery, dataArgs...).Scan(&data).Error; err != nil { + dataQuery = r.resolveOutletID(dataQuery, outletID, "im.outlet_id") + + if err := dataQuery.Scan(&data).Error; err != nil { return nil, err } @@ -749,7 +638,7 @@ func (r *AnalyticsRepositoryImpl) getExpenseByCategory(ctx context.Context, orga query := r.db.WithContext(ctx). Table("expense_items ei"). - Select(`COALESCE(parent_coa.name, coa.name, 'Lain-lain') as category_name, COALESCE(SUM(ei.amount), 0) as amount`). + Select(`COALESCE(parent_coa.name, 'Lain-lain') as category_name, COALESCE(SUM(ei.amount), 0) as amount`). Joins("JOIN expenses e ON ei.expense_id = e.id"). Joins("JOIN chart_of_accounts coa ON ei.chart_of_account_id = coa.id"). Joins("LEFT JOIN chart_of_accounts parent_coa ON coa.parent_id = parent_coa.id"). @@ -762,8 +651,8 @@ func (r *AnalyticsRepositoryImpl) getExpenseByCategory(ctx context.Context, orga } err := query. - Group("COALESCE(parent_coa.name, coa.name, 'Lain-lain')"). - Order("COALESCE(parent_coa.name, coa.name, 'Lain-lain')"). + Group("parent_coa.name"). + Order("parent_coa.name"). Scan(&results).Error return results, err