2025-07-18 20:10:29 +07:00
|
|
|
package transformer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"apskel-pos-be/internal/contract"
|
|
|
|
|
"apskel-pos-be/internal/models"
|
|
|
|
|
"fmt"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const ddmmyyyy = "02-01-2006"
|
|
|
|
|
|
|
|
|
|
// PaymentMethodAnalyticsContractToModel converts contract request to model
|
|
|
|
|
func PaymentMethodAnalyticsContractToModel(req *contract.PaymentMethodAnalyticsRequest) *models.PaymentMethodAnalyticsRequest {
|
|
|
|
|
var dateFrom, dateTo time.Time
|
|
|
|
|
if req.DateFrom != "" {
|
|
|
|
|
df, err := time.Parse(ddmmyyyy, req.DateFrom)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateFrom = df
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if req.DateTo != "" {
|
|
|
|
|
dt, err := time.Parse(ddmmyyyy, req.DateTo)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateTo = dt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.DateFrom == req.DateTo {
|
2025-08-05 22:50:12 +07:00
|
|
|
dateTo = dateTo.AddDate(0, 0, 1)
|
2025-07-18 20:10:29 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 req.DateFrom != "" {
|
|
|
|
|
df, err := time.Parse(ddmmyyyy, req.DateFrom)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateFrom = df
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if req.DateTo != "" {
|
|
|
|
|
dt, err := time.Parse(ddmmyyyy, req.DateTo)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateTo = dt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.DateFrom == req.DateTo {
|
2025-08-05 22:50:12 +07:00
|
|
|
dateTo = dateTo.AddDate(0, 0, 1)
|
2025-07-18 20:10:29 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 req.DateFrom != "" {
|
|
|
|
|
df, err := time.Parse(ddmmyyyy, req.DateFrom)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateFrom = df
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if req.DateTo != "" {
|
|
|
|
|
dt, err := time.Parse(ddmmyyyy, req.DateTo)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateTo = dt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.DateFrom == req.DateTo {
|
2025-08-05 22:50:12 +07:00
|
|
|
dateTo = dateTo.AddDate(0, 0, 1)
|
2025-07-18 20:10:29 +07:00
|
|
|
}
|
2025-08-05 22:50:12 +07:00
|
|
|
|
2025-07-18 20:10:29 +07:00
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DashboardAnalyticsContractToModel converts contract request to model
|
|
|
|
|
func DashboardAnalyticsContractToModel(req *contract.DashboardAnalyticsRequest) *models.DashboardAnalyticsRequest {
|
|
|
|
|
var dateFrom, dateTo time.Time
|
|
|
|
|
if req.DateFrom != "" {
|
|
|
|
|
df, err := time.Parse(ddmmyyyy, req.DateFrom)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateFrom = df
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if req.DateTo != "" {
|
|
|
|
|
dt, err := time.Parse(ddmmyyyy, req.DateTo)
|
|
|
|
|
if err == nil {
|
|
|
|
|
dateTo = dt
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-05 22:50:12 +07:00
|
|
|
|
|
|
|
|
if req.DateFrom == req.DateTo {
|
|
|
|
|
dateTo = dateTo.AddDate(0, 0, 1)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-18 20:10:29 +07:00
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dateFrom, err := time.Parse("02-01-2006", req.DateFrom)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("invalid date_from format: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dateTo, err := time.Parse("02-01-2006", req.DateTo)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("invalid date_to format: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
}
|