feat: add limit owner
This commit is contained in:
@@ -600,6 +600,7 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerParentCategory(ctx conte
|
||||
Select(`
|
||||
pc.id as parent_category_id,
|
||||
pc.name as parent_category_name,
|
||||
COALESCE(pc.owner_fee_percent, ?) as owner_fee_percent,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) as total_revenue,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.quantity - COALESCE(oi.refund_quantity, 0) ELSE 0 END), 0) as total_quantity,
|
||||
COUNT(DISTINCT c.id) as category_count,
|
||||
@@ -608,7 +609,7 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerParentCategory(ctx conte
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN COALESCE(shpp.hpp_per_unit, p.cost, 0) * `+billableQtyNet+` ELSE 0 END), 0) as total_standard_hpp,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_cost * ((oi.quantity - COALESCE(oi.refund_quantity, 0))::float / NULLIF(oi.quantity, 0)) ELSE 0 END), 0) as total_fifo_hpp,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN COALESCE(mahpp.hpp_per_unit, p.cost, 0) * `+billableQtyNet+` ELSE 0 END), 0) as total_moving_average_hpp
|
||||
`).
|
||||
`, constants.BudgetLimitOwnerPercent).
|
||||
Joins("JOIN products p ON oi.product_id = p.id").
|
||||
Joins("JOIN categories c ON p.category_id = c.id").
|
||||
// Categories without a parent roll up to themselves, so top-level categories still appear
|
||||
@@ -640,11 +641,56 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerParentCategory(ctx conte
|
||||
query = r.resolveOutletID(query, outletID, "o.outlet_id")
|
||||
|
||||
err := query.
|
||||
Group("pc.id, pc.name").
|
||||
Group("pc.id, pc.name, pc.owner_fee_percent").
|
||||
Order("pc.name ASC").
|
||||
Scan(&results).Error
|
||||
if err != nil || len(results) == 0 {
|
||||
return results, err
|
||||
}
|
||||
|
||||
return results, err
|
||||
// Best-selling product of each parent category. DISTINCT ON keeps the first row per
|
||||
// parent category, which the ordering makes the one with the highest revenue.
|
||||
var topProducts []*entities.ParentCategoryTopProduct
|
||||
topQuery := r.db.WithContext(ctx).
|
||||
Table("order_items oi").
|
||||
Select(`
|
||||
DISTINCT ON (pc.id)
|
||||
pc.id as parent_category_id,
|
||||
p.id as product_id,
|
||||
p.name as product_name,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.quantity - COALESCE(oi.refund_quantity, 0) ELSE 0 END), 0) as quantity_sold,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) as revenue
|
||||
`).
|
||||
Joins("JOIN products p ON oi.product_id = p.id").
|
||||
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("o.organization_id = ?", organizationID).
|
||||
Where("o.is_void = ?", false).
|
||||
Where("o.is_refund = ?", false).
|
||||
Where("o.payment_status = ?", entities.PaymentStatusCompleted).
|
||||
Where("oi.status != ?", entities.OrderItemStatusCancelled).
|
||||
Where("o.created_at >= ? AND o.created_at <= ?", dateFrom, dateTo)
|
||||
|
||||
topQuery = r.resolveOutletID(topQuery, outletID, "o.outlet_id")
|
||||
|
||||
err = topQuery.
|
||||
Group("pc.id, p.id, p.name").
|
||||
Order("pc.id, COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) DESC, p.name ASC").
|
||||
Scan(&topProducts).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
topByParent := make(map[uuid.UUID]*entities.ParentCategoryTopProduct, len(topProducts))
|
||||
for _, product := range topProducts {
|
||||
topByParent[product.ParentCategoryID] = product
|
||||
}
|
||||
for _, result := range results {
|
||||
result.TopProduct = topByParent[result.ParentCategoryID]
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// movingAverageHppSubquery builds the per-product moving-average HPP lookup shared by
|
||||
@@ -691,12 +737,13 @@ func (r *AnalyticsRepositoryImpl) GetParentCategoryAnalyticsDetail(ctx context.C
|
||||
// Resolve the category first so the endpoint still identifies the category when it
|
||||
// has no sales in the requested range, and rejects ids from another organization.
|
||||
var parent struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
OwnerFeePercent float64
|
||||
}
|
||||
if err := r.db.WithContext(ctx).
|
||||
Table("categories").
|
||||
Select("id, name").
|
||||
Select("id, name, 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
|
||||
@@ -732,6 +779,7 @@ func (r *AnalyticsRepositoryImpl) GetParentCategoryAnalyticsDetail(ctx context.C
|
||||
}
|
||||
summary.ParentCategoryID = parent.ID
|
||||
summary.ParentCategoryName = parent.Name
|
||||
summary.OwnerFeePercent = parent.OwnerFeePercent
|
||||
detail.Summary = summary
|
||||
|
||||
// Sub-category rows.
|
||||
@@ -810,12 +858,15 @@ func (r *AnalyticsRepositoryImpl) GetBudgetCutOffWeekly(ctx context.Context, org
|
||||
Select(`
|
||||
DATE_TRUNC('week', o.created_at) as week_start,
|
||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) as revenue,
|
||||
COALESCE(SUM((CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END) * COALESCE(pc.owner_fee_percent, ?) / 100.0), 0) as sdl,
|
||||
COUNT(DISTINCT oi.order_id) as order_count
|
||||
`).
|
||||
`, constants.BudgetLimitOwnerPercent).
|
||||
// products and categories are joined to keep the scope identical to the report
|
||||
// the block is attached to, even when no parent category filter is applied
|
||||
Joins("JOIN products p ON oi.product_id = p.id").
|
||||
Joins("JOIN categories c ON p.category_id = c.id").
|
||||
// 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").
|
||||
Where("o.organization_id = ?", organizationID).
|
||||
Where("o.is_void = ?", false).
|
||||
|
||||
Reference in New Issue
Block a user