apskel-pos-backend/internal/transformer/analytics_transformer.go
2025-10-07 00:02:15 +07:00

405 lines
12 KiB
Go

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,
CategoryOrder: item.CategoryOrder,
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,
}
}