feat: update profit sharing

This commit is contained in:
efrilm
2026-10-04 21:54:13 +07:00
parent b59b7b4ddd
commit 117e3529aa
23 changed files with 521 additions and 95 deletions
+12 -2
View File
@@ -614,6 +614,8 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerParentCategory(ctx conte
Joins("JOIN categories c ON p.category_id = c.id").
// Categories without a parent roll up to themselves, so top-level categories still appear
Joins("JOIN categories pc ON pc.id = COALESCE(c.parent_id, c.id)").
// Profit sharing only covers the parent categories that are teams
Where("pc.is_team = ?", true).
Joins("JOIN orders o ON oi.order_id = o.id").
Joins("LEFT JOIN (SELECT pr.product_id, SUM(pr.quantity * (1 + COALESCE(pr.waste_percentage, 0)/100.0) * i.cost) as hpp_per_unit FROM product_recipes pr JOIN ingredients i ON pr.ingredient_id = i.id GROUP BY pr.product_id) shpp ON shpp.product_id = p.id").
Joins("LEFT JOIN (?) mahpp ON mahpp.product_id = p.id",
@@ -665,6 +667,7 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerParentCategory(ctx conte
Joins("JOIN categories c ON p.category_id = c.id").
Joins("JOIN categories pc ON pc.id = COALESCE(c.parent_id, c.id)").
Joins("JOIN orders o ON oi.order_id = o.id").
Where("pc.is_team = ?", true).
Where("o.organization_id = ?", organizationID).
Where("o.is_void = ?", false).
Where("o.is_refund = ?", false).
@@ -739,11 +742,12 @@ func (r *AnalyticsRepositoryImpl) GetParentCategoryAnalyticsDetail(ctx context.C
var parent struct {
ID uuid.UUID
Name string
IsTeam bool
OwnerFeePercent float64
}
if err := r.db.WithContext(ctx).
Table("categories").
Select("id, name, COALESCE(owner_fee_percent, ?) as owner_fee_percent", constants.BudgetLimitOwnerPercent).
Select("id, name, is_team, COALESCE(owner_fee_percent, ?) as owner_fee_percent", constants.BudgetLimitOwnerPercent).
Where("id = ? AND organization_id = ?", parentCategoryID, organizationID).
Scan(&parent).Error; err != nil {
return nil, err
@@ -751,6 +755,9 @@ func (r *AnalyticsRepositoryImpl) GetParentCategoryAnalyticsDetail(ctx context.C
if parent.ID == uuid.Nil {
return nil, fmt.Errorf("category not found")
}
if !parent.IsTeam {
return nil, fmt.Errorf("category %s is not a team", parent.Name)
}
detail := &entities.ParentCategoryAnalyticsDetail{
ParentCategoryID: parent.ID,
@@ -849,7 +856,8 @@ func (r *AnalyticsRepositoryImpl) GetParentCategoryAnalyticsDetail(ctx context.C
// GetBudgetCutOffWeekly buckets revenue and cost of goods sold into Monday-to-Sunday
// weeks. DATE_TRUNC('week') is ISO, so the buckets start on Monday, and the connection
// runs with TimeZone=Asia/Jakarta so the boundaries land on local midnight.
// A nil parentCategoryID covers every category in scope.
// A nil parentCategoryID covers every team in scope; parent categories that are not a
// team stay out of the split.
func (r *AnalyticsRepositoryImpl) GetBudgetCutOffWeekly(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, parentCategoryID *uuid.UUID, cutOffFrom, cutOffTo time.Time) ([]*entities.BudgetCutOffWeek, error) {
var results []*entities.BudgetCutOffWeek
@@ -868,6 +876,8 @@ func (r *AnalyticsRepositoryImpl) GetBudgetCutOffWeekly(ctx context.Context, org
// The owner fee lives on the parent category; a category without a parent is its own group
Joins("JOIN categories pc ON pc.id = COALESCE(c.parent_id, c.id)").
Joins("JOIN orders o ON oi.order_id = o.id").
// Only teams take part in the revenue split
Where("pc.is_team = ?", true).
Where("o.organization_id = ?", organizationID).
Where("o.is_void = ?", false).
Where("o.is_refund = ?", false).