package transformer import ( "apskel-pos-be/internal/contract" "apskel-pos-be/internal/models" "apskel-pos-be/internal/util" "fmt" "time" ) // PaymentMethodAnalyticsContractToModel converts contract request to model func PaymentMethodAnalyticsContractToModel(req *contract.PaymentMethodAnalyticsRequest) *models.PaymentMethodAnalyticsRequest { var dateFrom, dateTo time.Time if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil { if fromTime != nil { dateFrom = *fromTime } if toTime != nil { dateTo = *toTime } } return &models.PaymentMethodAnalyticsRequest{ OrganizationID: req.OrganizationID, OutletID: req.OutletID, DateFrom: dateFrom, DateTo: dateTo, GroupBy: req.GroupBy, } } // PaymentMethodAnalyticsModelToContract converts model response to contract func PaymentMethodAnalyticsModelToContract(resp *models.PaymentMethodAnalyticsResponse) *contract.PaymentMethodAnalyticsResponse { if resp == nil { return nil } var data []contract.PaymentMethodAnalyticsData for _, item := range resp.Data { data = append(data, contract.PaymentMethodAnalyticsData{ PaymentMethodID: item.PaymentMethodID, PaymentMethodName: item.PaymentMethodName, PaymentMethodType: item.PaymentMethodType, TotalAmount: item.TotalAmount, OrderCount: item.OrderCount, PaymentCount: item.PaymentCount, Percentage: item.Percentage, }) } return &contract.PaymentMethodAnalyticsResponse{ OrganizationID: resp.OrganizationID, OutletID: resp.OutletID, DateFrom: resp.DateFrom, DateTo: resp.DateTo, GroupBy: resp.GroupBy, Summary: contract.PaymentMethodSummary{ TotalAmount: resp.Summary.TotalAmount, TotalOrders: resp.Summary.TotalOrders, TotalPayments: resp.Summary.TotalPayments, AverageOrderValue: resp.Summary.AverageOrderValue, }, Data: data, } } func SalesAnalyticsContractToModel(req *contract.SalesAnalyticsRequest) *models.SalesAnalyticsRequest { var dateFrom, dateTo time.Time if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil { if fromTime != nil { dateFrom = *fromTime } if toTime != nil { dateTo = *toTime } } return &models.SalesAnalyticsRequest{ OrganizationID: req.OrganizationID, OutletID: req.OutletID, DateFrom: dateFrom, DateTo: dateTo, GroupBy: req.GroupBy, } } // SalesAnalyticsModelToContract converts model response to contract func SalesAnalyticsModelToContract(resp *models.SalesAnalyticsResponse) *contract.SalesAnalyticsResponse { if resp == nil { return nil } var data []contract.SalesAnalyticsData for _, item := range resp.Data { data = append(data, contract.SalesAnalyticsData{ Date: item.Date, Sales: item.Sales, Orders: item.Orders, Items: item.Items, Tax: item.Tax, Discount: item.Discount, NetSales: item.NetSales, }) } return &contract.SalesAnalyticsResponse{ OrganizationID: resp.OrganizationID, OutletID: resp.OutletID, DateFrom: resp.DateFrom, DateTo: resp.DateTo, GroupBy: resp.GroupBy, Summary: contract.SalesSummary{ TotalSales: resp.Summary.TotalSales, TotalOrders: resp.Summary.TotalOrders, TotalItems: resp.Summary.TotalItems, AverageOrderValue: resp.Summary.AverageOrderValue, TotalTax: resp.Summary.TotalTax, TotalDiscount: resp.Summary.TotalDiscount, NetSales: resp.Summary.NetSales, }, Data: data, } } // ProductAnalyticsContractToModel converts contract request to model func ProductAnalyticsContractToModel(req *contract.ProductAnalyticsRequest) *models.ProductAnalyticsRequest { var dateFrom, dateTo time.Time if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil { if fromTime != nil { dateFrom = *fromTime } if toTime != nil { dateTo = *toTime } } return &models.ProductAnalyticsRequest{ OrganizationID: req.OrganizationID, OutletID: req.OutletID, DateFrom: dateFrom, DateTo: dateTo, Limit: req.Limit, } } // ProductAnalyticsModelToContract converts model response to contract func ProductAnalyticsModelToContract(resp *models.ProductAnalyticsResponse) *contract.ProductAnalyticsResponse { if resp == nil { return nil } var data []contract.ProductAnalyticsData for _, item := range resp.Data { data = append(data, contract.ProductAnalyticsData{ ProductID: item.ProductID, ProductName: item.ProductName, CategoryID: item.CategoryID, CategoryName: item.CategoryName, QuantitySold: item.QuantitySold, Revenue: item.Revenue, AveragePrice: item.AveragePrice, OrderCount: item.OrderCount, }) } return &contract.ProductAnalyticsResponse{ OrganizationID: resp.OrganizationID, OutletID: resp.OutletID, DateFrom: resp.DateFrom, DateTo: resp.DateTo, Data: data, } } // 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 func DashboardAnalyticsContractToModel(req *contract.DashboardAnalyticsRequest) *models.DashboardAnalyticsRequest { 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.DashboardAnalyticsRequest{ OrganizationID: req.OrganizationID, OutletID: req.OutletID, DateFrom: dateFrom, DateTo: dateTo, } } // DashboardAnalyticsModelToContract converts model response to contract func DashboardAnalyticsModelToContract(resp *models.DashboardAnalyticsResponse) *contract.DashboardAnalyticsResponse { if resp == nil { return nil } var topProducts []contract.ProductAnalyticsData for _, item := range resp.TopProducts { topProducts = append(topProducts, contract.ProductAnalyticsData{ ProductID: item.ProductID, ProductName: item.ProductName, CategoryID: item.CategoryID, CategoryName: item.CategoryName, QuantitySold: item.QuantitySold, Revenue: item.Revenue, AveragePrice: item.AveragePrice, OrderCount: item.OrderCount, }) } var paymentMethods []contract.PaymentMethodAnalyticsData for _, item := range resp.PaymentMethods { paymentMethods = append(paymentMethods, contract.PaymentMethodAnalyticsData{ PaymentMethodID: item.PaymentMethodID, PaymentMethodName: item.PaymentMethodName, PaymentMethodType: item.PaymentMethodType, TotalAmount: item.TotalAmount, OrderCount: item.OrderCount, PaymentCount: item.PaymentCount, Percentage: item.Percentage, }) } var recentSales []contract.SalesAnalyticsData for _, item := range resp.RecentSales { recentSales = append(recentSales, contract.SalesAnalyticsData{ Date: item.Date, Sales: item.Sales, Orders: item.Orders, Items: item.Items, Tax: item.Tax, Discount: item.Discount, NetSales: item.NetSales, }) } return &contract.DashboardAnalyticsResponse{ OrganizationID: resp.OrganizationID, OutletID: resp.OutletID, DateFrom: resp.DateFrom, DateTo: resp.DateTo, Overview: contract.DashboardOverview{ TotalSales: resp.Overview.TotalSales, TotalOrders: resp.Overview.TotalOrders, AverageOrderValue: resp.Overview.AverageOrderValue, TotalCustomers: resp.Overview.TotalCustomers, VoidedOrders: resp.Overview.VoidedOrders, RefundedOrders: resp.Overview.RefundedOrders, }, TopProducts: topProducts, PaymentMethods: paymentMethods, RecentSales: recentSales, } } // ProfitLossAnalyticsContractToModel transforms contract request to model func ProfitLossAnalyticsContractToModel(req *contract.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsRequest, error) { if req == nil { return nil, fmt.Errorf("request cannot be nil") } // Parse date range using utility function dateFrom, dateTo, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo) if err != nil { return nil, fmt.Errorf("invalid date format: %w", err) } if dateFrom == nil || dateTo == nil { return nil, fmt.Errorf("both date_from and date_to are required") } return &models.ProfitLossAnalyticsRequest{ OrganizationID: req.OrganizationID, OutletID: req.OutletID, DateFrom: *dateFrom, DateTo: *dateTo, GroupBy: req.GroupBy, }, nil } // ProfitLossAnalyticsModelToContract transforms model response to contract func ProfitLossAnalyticsModelToContract(resp *models.ProfitLossAnalyticsResponse) *contract.ProfitLossAnalyticsResponse { if resp == nil { return nil } // Transform profit/loss data data := make([]contract.ProfitLossData, len(resp.Data)) for i, item := range resp.Data { data[i] = contract.ProfitLossData{ Date: item.Date, Revenue: item.Revenue, Cost: item.Cost, GrossProfit: item.GrossProfit, GrossProfitMargin: item.GrossProfitMargin, Tax: item.Tax, Discount: item.Discount, NetProfit: item.NetProfit, NetProfitMargin: item.NetProfitMargin, Orders: item.Orders, } } // Transform product profit data productData := make([]contract.ProductProfitData, len(resp.ProductData)) for i, item := range resp.ProductData { productData[i] = contract.ProductProfitData{ ProductID: item.ProductID, ProductName: item.ProductName, CategoryID: item.CategoryID, CategoryName: item.CategoryName, QuantitySold: item.QuantitySold, Revenue: item.Revenue, Cost: item.Cost, GrossProfit: item.GrossProfit, GrossProfitMargin: item.GrossProfitMargin, AveragePrice: item.AveragePrice, AverageCost: item.AverageCost, ProfitPerUnit: item.ProfitPerUnit, } } return &contract.ProfitLossAnalyticsResponse{ OrganizationID: resp.OrganizationID, OutletID: resp.OutletID, DateFrom: resp.DateFrom, DateTo: resp.DateTo, GroupBy: resp.GroupBy, Summary: contract.ProfitLossSummary{ TotalRevenue: resp.Summary.TotalRevenue, TotalCost: resp.Summary.TotalCost, GrossProfit: resp.Summary.GrossProfit, GrossProfitMargin: resp.Summary.GrossProfitMargin, TotalTax: resp.Summary.TotalTax, TotalDiscount: resp.Summary.TotalDiscount, NetProfit: resp.Summary.NetProfit, NetProfitMargin: resp.Summary.NetProfitMargin, TotalOrders: resp.Summary.TotalOrders, AverageProfit: resp.Summary.AverageProfit, ProfitabilityRatio: resp.Summary.ProfitabilityRatio, }, Data: data, ProductData: productData, } }