Update
This commit is contained in:
parent
7adba2c8f5
commit
3a0c262c77
@ -113,6 +113,33 @@ type ProductAnalyticsData struct {
|
|||||||
OrderCount int64 `json:"order_count"`
|
OrderCount int64 `json:"order_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryRequest represents the request for product analytics per category
|
||||||
|
type ProductAnalyticsPerCategoryRequest struct {
|
||||||
|
OrganizationID uuid.UUID
|
||||||
|
OutletID *uuid.UUID `form:"outlet_id,omitempty"`
|
||||||
|
DateFrom string `form:"date_from" validate:"required"`
|
||||||
|
DateTo string `form:"date_to" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryResponse represents the response for product analytics per category
|
||||||
|
type ProductAnalyticsPerCategoryResponse struct {
|
||||||
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
|
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||||
|
DateFrom time.Time `json:"date_from"`
|
||||||
|
DateTo time.Time `json:"date_to"`
|
||||||
|
Data []ProductAnalyticsPerCategoryData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryData represents individual category analytics data
|
||||||
|
type ProductAnalyticsPerCategoryData struct {
|
||||||
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
|
CategoryName string `json:"category_name"`
|
||||||
|
TotalRevenue float64 `json:"total_revenue"`
|
||||||
|
TotalQuantity int64 `json:"total_quantity"`
|
||||||
|
ProductCount int64 `json:"product_count"`
|
||||||
|
OrderCount int64 `json:"order_count"`
|
||||||
|
}
|
||||||
|
|
||||||
// DashboardAnalyticsRequest represents the request for dashboard analytics
|
// DashboardAnalyticsRequest represents the request for dashboard analytics
|
||||||
type DashboardAnalyticsRequest struct {
|
type DashboardAnalyticsRequest struct {
|
||||||
OrganizationID uuid.UUID
|
OrganizationID uuid.UUID
|
||||||
|
|||||||
@ -39,6 +39,16 @@ type ProductAnalytics struct {
|
|||||||
OrderCount int64 `json:"order_count"`
|
OrderCount int64 `json:"order_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategory represents product analytics data grouped by category
|
||||||
|
type ProductAnalyticsPerCategory struct {
|
||||||
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
|
CategoryName string `json:"category_name"`
|
||||||
|
TotalRevenue float64 `json:"total_revenue"`
|
||||||
|
TotalQuantity int64 `json:"total_quantity"`
|
||||||
|
ProductCount int64 `json:"product_count"`
|
||||||
|
OrderCount int64 `json:"order_count"`
|
||||||
|
}
|
||||||
|
|
||||||
// DashboardOverview represents dashboard overview data
|
// DashboardOverview represents dashboard overview data
|
||||||
type DashboardOverview struct {
|
type DashboardOverview struct {
|
||||||
TotalSales float64 `json:"total_sales"`
|
TotalSales float64 `json:"total_sales"`
|
||||||
|
|||||||
@ -97,6 +97,30 @@ func (h *AnalyticsHandler) GetProductAnalytics(c *gin.Context) {
|
|||||||
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalytics")
|
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalytics")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *AnalyticsHandler) GetProductAnalyticsPerCategory(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
contextInfo := appcontext.FromGinContext(ctx)
|
||||||
|
|
||||||
|
var req contract.ProductAnalyticsPerCategoryRequest
|
||||||
|
if err := c.ShouldBindQuery(&req); err != nil {
|
||||||
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.OrganizationID = contextInfo.OrganizationID
|
||||||
|
req.OutletID = &contextInfo.OutletID
|
||||||
|
modelReq := transformer.ProductAnalyticsPerCategoryContractToModel(&req)
|
||||||
|
|
||||||
|
response, err := h.analyticsService.GetProductAnalyticsPerCategory(ctx, modelReq)
|
||||||
|
if err != nil {
|
||||||
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contractResp := transformer.ProductAnalyticsPerCategoryModelToContract(response)
|
||||||
|
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalyticsPerCategory")
|
||||||
|
}
|
||||||
|
|
||||||
func (h *AnalyticsHandler) GetDashboardAnalytics(c *gin.Context) {
|
func (h *AnalyticsHandler) GetDashboardAnalytics(c *gin.Context) {
|
||||||
ctx := c.Request.Context()
|
ctx := c.Request.Context()
|
||||||
contextInfo := appcontext.FromGinContext(ctx)
|
contextInfo := appcontext.FromGinContext(ctx)
|
||||||
|
|||||||
@ -117,6 +117,33 @@ type ProductAnalyticsData struct {
|
|||||||
OrderCount int64 `json:"order_count"`
|
OrderCount int64 `json:"order_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryRequest represents the request for product analytics per category
|
||||||
|
type ProductAnalyticsPerCategoryRequest struct {
|
||||||
|
OrganizationID uuid.UUID `validate:"required"`
|
||||||
|
OutletID *uuid.UUID `validate:"omitempty"`
|
||||||
|
DateFrom time.Time `validate:"required"`
|
||||||
|
DateTo time.Time `validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryResponse represents the response for product analytics per category
|
||||||
|
type ProductAnalyticsPerCategoryResponse struct {
|
||||||
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
|
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||||
|
DateFrom time.Time `json:"date_from"`
|
||||||
|
DateTo time.Time `json:"date_to"`
|
||||||
|
Data []ProductAnalyticsPerCategoryData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryData represents individual category analytics data
|
||||||
|
type ProductAnalyticsPerCategoryData struct {
|
||||||
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
|
CategoryName string `json:"category_name"`
|
||||||
|
TotalRevenue float64 `json:"total_revenue"`
|
||||||
|
TotalQuantity int64 `json:"total_quantity"`
|
||||||
|
ProductCount int64 `json:"product_count"`
|
||||||
|
OrderCount int64 `json:"order_count"`
|
||||||
|
}
|
||||||
|
|
||||||
// DashboardAnalyticsRequest represents the request for dashboard analytics
|
// DashboardAnalyticsRequest represents the request for dashboard analytics
|
||||||
type DashboardAnalyticsRequest struct {
|
type DashboardAnalyticsRequest struct {
|
||||||
OrganizationID uuid.UUID `validate:"required"`
|
OrganizationID uuid.UUID `validate:"required"`
|
||||||
|
|||||||
@ -13,6 +13,7 @@ type AnalyticsProcessor interface {
|
|||||||
GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error)
|
GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error)
|
||||||
GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error)
|
GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error)
|
||||||
GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error)
|
GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error)
|
||||||
|
GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error)
|
||||||
GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error)
|
GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error)
|
||||||
GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error)
|
GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error)
|
||||||
}
|
}
|
||||||
@ -204,6 +205,40 @@ func (p *AnalyticsProcessorImpl) GetProductAnalytics(ctx context.Context, req *m
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *AnalyticsProcessorImpl) GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error) {
|
||||||
|
// Validate date range
|
||||||
|
if req.DateFrom.After(req.DateTo) {
|
||||||
|
return nil, fmt.Errorf("date_from cannot be after date_to")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get analytics data from repository
|
||||||
|
analyticsData, err := p.analyticsRepo.GetProductAnalyticsPerCategory(ctx, req.OrganizationID, req.OutletID, req.DateFrom, req.DateTo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get product analytics per category: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform data
|
||||||
|
var resultData []models.ProductAnalyticsPerCategoryData
|
||||||
|
for _, data := range analyticsData {
|
||||||
|
resultData = append(resultData, models.ProductAnalyticsPerCategoryData{
|
||||||
|
CategoryID: data.CategoryID,
|
||||||
|
CategoryName: data.CategoryName,
|
||||||
|
TotalRevenue: data.TotalRevenue,
|
||||||
|
TotalQuantity: data.TotalQuantity,
|
||||||
|
ProductCount: data.ProductCount,
|
||||||
|
OrderCount: data.OrderCount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &models.ProductAnalyticsPerCategoryResponse{
|
||||||
|
OrganizationID: req.OrganizationID,
|
||||||
|
OutletID: req.OutletID,
|
||||||
|
DateFrom: req.DateFrom,
|
||||||
|
DateTo: req.DateTo,
|
||||||
|
Data: resultData,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *AnalyticsProcessorImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) {
|
func (p *AnalyticsProcessorImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) {
|
||||||
// Validate date range
|
// Validate date range
|
||||||
if req.DateFrom.After(req.DateTo) {
|
if req.DateFrom.After(req.DateTo) {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type AnalyticsRepository interface {
|
|||||||
GetPaymentMethodAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.PaymentMethodAnalytics, error)
|
GetPaymentMethodAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.PaymentMethodAnalytics, error)
|
||||||
GetSalesAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) ([]*entities.SalesAnalytics, error)
|
GetSalesAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) ([]*entities.SalesAnalytics, error)
|
||||||
GetProductAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, limit int) ([]*entities.ProductAnalytics, error)
|
GetProductAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, limit int) ([]*entities.ProductAnalytics, error)
|
||||||
|
GetProductAnalyticsPerCategory(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.ProductAnalyticsPerCategory, error)
|
||||||
GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error)
|
GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error)
|
||||||
GetProfitLossAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) (*entities.ProfitLossAnalytics, error)
|
GetProfitLossAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) (*entities.ProfitLossAnalytics, error)
|
||||||
}
|
}
|
||||||
@ -140,6 +141,38 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalytics(ctx context.Context, organ
|
|||||||
return results, err
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AnalyticsRepositoryImpl) GetProductAnalyticsPerCategory(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) ([]*entities.ProductAnalyticsPerCategory, error) {
|
||||||
|
var results []*entities.ProductAnalyticsPerCategory
|
||||||
|
|
||||||
|
query := r.db.WithContext(ctx).
|
||||||
|
Table("order_items oi").
|
||||||
|
Select(`
|
||||||
|
c.id as category_id,
|
||||||
|
c.name as category_name,
|
||||||
|
COALESCE(SUM(oi.total_price), 0) as total_revenue,
|
||||||
|
COALESCE(SUM(oi.quantity), 0) as total_quantity,
|
||||||
|
COUNT(DISTINCT p.id) as product_count,
|
||||||
|
COUNT(DISTINCT oi.order_id) as order_count
|
||||||
|
`).
|
||||||
|
Joins("JOIN products p ON oi.product_id = p.id").
|
||||||
|
Joins("JOIN categories c ON p.category_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.created_at >= ? AND o.created_at <= ?", dateFrom, dateTo)
|
||||||
|
|
||||||
|
if outletID != nil {
|
||||||
|
query = query.Where("o.outlet_id = ?", *outletID)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := query.
|
||||||
|
Group("c.id, c.name").
|
||||||
|
Order("total_revenue DESC").
|
||||||
|
Scan(&results).Error
|
||||||
|
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *AnalyticsRepositoryImpl) GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error) {
|
func (r *AnalyticsRepositoryImpl) GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error) {
|
||||||
var result entities.DashboardOverview
|
var result entities.DashboardOverview
|
||||||
|
|
||||||
|
|||||||
@ -269,6 +269,7 @@ func (r *Router) addAppRoutes(rg *gin.Engine) {
|
|||||||
analytics.GET("/payment-methods", r.analyticsHandler.GetPaymentMethodAnalytics)
|
analytics.GET("/payment-methods", r.analyticsHandler.GetPaymentMethodAnalytics)
|
||||||
analytics.GET("/sales", r.analyticsHandler.GetSalesAnalytics)
|
analytics.GET("/sales", r.analyticsHandler.GetSalesAnalytics)
|
||||||
analytics.GET("/products", r.analyticsHandler.GetProductAnalytics)
|
analytics.GET("/products", r.analyticsHandler.GetProductAnalytics)
|
||||||
|
analytics.GET("/categories", r.analyticsHandler.GetProductAnalyticsPerCategory)
|
||||||
analytics.GET("/dashboard", r.analyticsHandler.GetDashboardAnalytics)
|
analytics.GET("/dashboard", r.analyticsHandler.GetDashboardAnalytics)
|
||||||
analytics.GET("/profit-loss", r.analyticsHandler.GetProfitLossAnalytics)
|
analytics.GET("/profit-loss", r.analyticsHandler.GetProfitLossAnalytics)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type AnalyticsService interface {
|
|||||||
GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error)
|
GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error)
|
||||||
GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error)
|
GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error)
|
||||||
GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error)
|
GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error)
|
||||||
|
GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error)
|
||||||
GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error)
|
GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error)
|
||||||
GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error)
|
GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error)
|
||||||
}
|
}
|
||||||
@ -71,6 +72,21 @@ func (s *AnalyticsServiceImpl) GetProductAnalytics(ctx context.Context, req *mod
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AnalyticsServiceImpl) GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error) {
|
||||||
|
// Validate request
|
||||||
|
if err := s.validateProductAnalyticsPerCategoryRequest(req); err != nil {
|
||||||
|
return nil, fmt.Errorf("validation error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process analytics request
|
||||||
|
response, err := s.analyticsProcessor.GetProductAnalyticsPerCategory(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get product analytics per category: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AnalyticsServiceImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) {
|
func (s *AnalyticsServiceImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) {
|
||||||
// Validate request
|
// Validate request
|
||||||
if err := s.validateDashboardAnalyticsRequest(req); err != nil {
|
if err := s.validateDashboardAnalyticsRequest(req); err != nil {
|
||||||
@ -176,6 +192,26 @@ func (s *AnalyticsServiceImpl) validateProductAnalyticsRequest(req *models.Produ
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AnalyticsServiceImpl) validateProductAnalyticsPerCategoryRequest(req *models.ProductAnalyticsPerCategoryRequest) error {
|
||||||
|
if req.OrganizationID == uuid.Nil {
|
||||||
|
return fmt.Errorf("organization ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.DateFrom.IsZero() {
|
||||||
|
return fmt.Errorf("date_from is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.DateTo.IsZero() {
|
||||||
|
return fmt.Errorf("date_to is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.DateFrom.After(req.DateTo) {
|
||||||
|
return fmt.Errorf("date_from cannot be after date_to")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AnalyticsServiceImpl) validateDashboardAnalyticsRequest(req *models.DashboardAnalyticsRequest) error {
|
func (s *AnalyticsServiceImpl) validateDashboardAnalyticsRequest(req *models.DashboardAnalyticsRequest) error {
|
||||||
if req.OrganizationID == uuid.Nil {
|
if req.OrganizationID == uuid.Nil {
|
||||||
return fmt.Errorf("organization ID is required")
|
return fmt.Errorf("organization ID is required")
|
||||||
|
|||||||
@ -175,6 +175,55 @@ func ProductAnalyticsModelToContract(resp *models.ProductAnalyticsResponse) *con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryContractToModel converts contract request to model
|
||||||
|
func ProductAnalyticsPerCategoryContractToModel(req *contract.ProductAnalyticsPerCategoryRequest) *models.ProductAnalyticsPerCategoryRequest {
|
||||||
|
var dateFrom, dateTo time.Time
|
||||||
|
|
||||||
|
// Parse date range using utility function
|
||||||
|
if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
|
||||||
|
if fromTime != nil {
|
||||||
|
dateFrom = *fromTime
|
||||||
|
}
|
||||||
|
if toTime != nil {
|
||||||
|
dateTo = *toTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &models.ProductAnalyticsPerCategoryRequest{
|
||||||
|
OrganizationID: req.OrganizationID,
|
||||||
|
OutletID: req.OutletID,
|
||||||
|
DateFrom: dateFrom,
|
||||||
|
DateTo: dateTo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductAnalyticsPerCategoryModelToContract converts model response to contract
|
||||||
|
func ProductAnalyticsPerCategoryModelToContract(resp *models.ProductAnalyticsPerCategoryResponse) *contract.ProductAnalyticsPerCategoryResponse {
|
||||||
|
if resp == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []contract.ProductAnalyticsPerCategoryData
|
||||||
|
for _, item := range resp.Data {
|
||||||
|
data = append(data, contract.ProductAnalyticsPerCategoryData{
|
||||||
|
CategoryID: item.CategoryID,
|
||||||
|
CategoryName: item.CategoryName,
|
||||||
|
TotalRevenue: item.TotalRevenue,
|
||||||
|
TotalQuantity: item.TotalQuantity,
|
||||||
|
ProductCount: item.ProductCount,
|
||||||
|
OrderCount: item.OrderCount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &contract.ProductAnalyticsPerCategoryResponse{
|
||||||
|
OrganizationID: resp.OrganizationID,
|
||||||
|
OutletID: resp.OutletID,
|
||||||
|
DateFrom: resp.DateFrom,
|
||||||
|
DateTo: resp.DateTo,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DashboardAnalyticsContractToModel converts contract request to model
|
// DashboardAnalyticsContractToModel converts contract request to model
|
||||||
func DashboardAnalyticsContractToModel(req *contract.DashboardAnalyticsRequest) *models.DashboardAnalyticsRequest {
|
func DashboardAnalyticsContractToModel(req *contract.DashboardAnalyticsRequest) *models.DashboardAnalyticsRequest {
|
||||||
var dateFrom, dateTo time.Time
|
var dateFrom, dateTo time.Time
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user