This commit is contained in:
aditya.siregar
2025-07-18 20:10:29 +07:00
parent 1bceae010b
commit 4f5950543e
511 changed files with 24132 additions and 34137 deletions
@@ -0,0 +1,377 @@
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 {
dateTo.AddDate(0, 0, 1)
}
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 {
dateTo.AddDate(0, 0, 1)
}
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 {
dateTo.AddDate(0, 0, 1)
}
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
}
}
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,
}
}
@@ -0,0 +1,55 @@
package transformer
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
func CreateCategoryRequestToModel(apctx *appcontext.ContextInfo, req *contract.CreateCategoryRequest) *models.CreateCategoryRequest {
return &models.CreateCategoryRequest{
OrganizationID: apctx.OrganizationID,
Name: req.Name,
Description: req.Description,
ImageURL: nil,
SortOrder: 0,
}
}
func UpdateCategoryRequestToModel(req *contract.UpdateCategoryRequest) *models.UpdateCategoryRequest {
return &models.UpdateCategoryRequest{
Name: req.Name,
Description: req.Description,
ImageURL: nil,
SortOrder: nil,
IsActive: nil,
}
}
func CategoryModelResponseToResponse(cat *models.CategoryResponse) *contract.CategoryResponse {
if cat == nil {
return nil
}
return &contract.CategoryResponse{
ID: cat.ID,
OrganizationID: cat.OrganizationID,
Name: cat.Name,
Description: cat.Description,
BusinessType: "restaurant", // Default business type
Metadata: map[string]interface{}{},
CreatedAt: cat.CreatedAt,
UpdatedAt: cat.UpdatedAt,
}
}
func CategoriesToResponses(categories []models.CategoryResponse) []contract.CategoryResponse {
responses := make([]contract.CategoryResponse, len(categories))
for i, cat := range categories {
response := CategoryModelResponseToResponse(&cat)
if response != nil {
responses[i] = *response
}
}
return responses
}
+109
View File
@@ -0,0 +1,109 @@
package transformer
import (
"apskel-pos-be/internal/contract"
"math"
)
func PaginationToRequest(page, limit int) (int, int) {
if page < 1 {
page = 1
}
if limit < 1 {
limit = 10
}
if limit > 100 {
limit = 100
}
return page, limit
}
func CreatePaginationResponse(totalCount, page, limit int) contract.PaginationResponse {
totalPages := int(math.Ceil(float64(totalCount) / float64(limit)))
if totalPages < 1 {
totalPages = 1
}
return contract.PaginationResponse{
TotalCount: totalCount,
Page: page,
Limit: limit,
TotalPages: totalPages,
}
}
func CreateListUsersResponse(users []contract.UserResponse, totalCount, page, limit int) *contract.ListUsersResponse {
pagination := CreatePaginationResponse(totalCount, page, limit)
return &contract.ListUsersResponse{
Users: users,
Pagination: pagination,
}
}
func CreateListOrganizationsResponse(orgs []contract.OrganizationResponse, totalCount, page, limit int) *contract.ListOrganizationsResponse {
pagination := CreatePaginationResponse(totalCount, page, limit)
return &contract.ListOrganizationsResponse{
Organizations: orgs,
TotalCount: pagination.TotalCount,
Page: pagination.Page,
Limit: pagination.Limit,
TotalPages: pagination.TotalPages,
}
}
func CreateListOutletsResponse(outlets []contract.OutletResponse, totalCount, page, limit int) *contract.ListOutletsResponse {
pagination := CreatePaginationResponse(totalCount, page, limit)
return &contract.ListOutletsResponse{
Outlets: outlets,
TotalCount: pagination.TotalCount,
Page: pagination.Page,
Limit: pagination.Limit,
TotalPages: pagination.TotalPages,
}
}
func CreateListOrdersResponse(orders []contract.OrderResponse, totalCount, page, limit int) *contract.ListOrdersResponse {
pagination := CreatePaginationResponse(totalCount, page, limit)
return &contract.ListOrdersResponse{
Orders: orders,
TotalCount: pagination.TotalCount,
Page: pagination.Page,
Limit: pagination.Limit,
TotalPages: pagination.TotalPages,
}
}
func CreateListProductsResponse(products []contract.ProductResponse, totalCount, page, limit int) *contract.ListProductsResponse {
pagination := CreatePaginationResponse(totalCount, page, limit)
return &contract.ListProductsResponse{
Products: products,
TotalCount: pagination.TotalCount,
Page: pagination.Page,
Limit: pagination.Limit,
TotalPages: pagination.TotalPages,
}
}
func CreateErrorResponse(message string, code int) *contract.ErrorResponse {
return &contract.ErrorResponse{
Error: "error",
Message: message,
Code: code,
}
}
func CreateValidationErrorResponse(message string, details map[string]string) *contract.ValidationErrorResponse {
return &contract.ValidationErrorResponse{
Error: "validation_error",
Message: message,
Details: details,
Code: 400,
}
}
func CreateSuccessResponse(message string, data interface{}) *contract.SuccessResponse {
return &contract.SuccessResponse{
Message: message,
Data: data,
}
}
@@ -0,0 +1,82 @@
package transformer
import (
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
// Contract to Model conversions
func CreateCustomerRequestToModel(req *contract.CreateCustomerRequest) *models.CreateCustomerRequest {
return &models.CreateCustomerRequest{
Name: req.Name,
Email: req.Email,
Phone: req.Phone,
Address: req.Address,
}
}
func UpdateCustomerRequestToModel(req *contract.UpdateCustomerRequest) *models.UpdateCustomerRequest {
return &models.UpdateCustomerRequest{
Name: req.Name,
Email: req.Email,
Phone: req.Phone,
Address: req.Address,
IsActive: req.IsActive,
}
}
func ListCustomersRequestToModel(req *contract.ListCustomersRequest) *models.ListCustomersQuery {
return &models.ListCustomersQuery{
Page: req.Page,
Limit: req.Limit,
Search: req.Search,
IsActive: req.IsActive,
IsDefault: req.IsDefault,
SortBy: req.SortBy,
SortOrder: req.SortOrder,
}
}
func SetDefaultCustomerRequestToModel(req *contract.SetDefaultCustomerRequest) *models.SetDefaultCustomerRequest {
return &models.SetDefaultCustomerRequest{
CustomerID: req.CustomerID,
}
}
// Model to Contract conversions
func CustomerModelToResponse(customer *models.CustomerResponse) *contract.CustomerResponse {
return &contract.CustomerResponse{
ID: customer.ID,
OrganizationID: customer.OrganizationID,
Name: customer.Name,
Email: customer.Email,
Phone: customer.Phone,
Address: customer.Address,
IsDefault: customer.IsDefault,
IsActive: customer.IsActive,
Metadata: customer.Metadata,
CreatedAt: customer.CreatedAt,
UpdatedAt: customer.UpdatedAt,
}
}
func CustomerResponsesToResponses(customers []models.CustomerResponse) []contract.CustomerResponse {
responses := make([]contract.CustomerResponse, len(customers))
for i, customer := range customers {
response := CustomerModelToResponse(&customer)
if response != nil {
responses[i] = *response
}
}
return responses
}
func PaginatedCustomerResponseToContract(paginatedResponse *models.PaginatedResponse[models.CustomerResponse]) *contract.PaginatedCustomerResponse {
return &contract.PaginatedCustomerResponse{
Data: CustomerResponsesToResponses(paginatedResponse.Data),
TotalCount: int(paginatedResponse.Pagination.Total),
Page: paginatedResponse.Pagination.Page,
Limit: paginatedResponse.Pagination.Limit,
TotalPages: paginatedResponse.Pagination.TotalPages,
}
}
+142
View File
@@ -0,0 +1,142 @@
package transformer
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"strconv"
"time"
"github.com/google/uuid"
)
// Contract to Model transformers
func UploadFileContractToModel(req *contract.UploadFileRequest) *models.UploadFileRequest {
if req == nil {
return nil
}
modelReq := &models.UploadFileRequest{
FileType: constants.FileType(req.FileType),
IsPublic: req.IsPublic,
Metadata: req.Metadata,
}
return modelReq
}
func UpdateFileContractToModel(req *contract.UpdateFileRequest) *models.UpdateFileRequest {
if req == nil {
return nil
}
return &models.UpdateFileRequest{
IsPublic: req.IsPublic,
Metadata: req.Metadata,
}
}
func ListFilesQueryToModel(query *contract.ListFilesQuery) *models.ListFilesRequest {
if query == nil {
return nil
}
req := &models.ListFilesRequest{
Search: query.Search,
Page: query.Page,
Limit: query.Limit,
}
// Parse UUID fields
if query.OrganizationID != "" {
if organizationID, err := uuid.Parse(query.OrganizationID); err == nil {
req.OrganizationID = &organizationID
}
}
if query.UserID != "" {
if userID, err := uuid.Parse(query.UserID); err == nil {
req.UserID = &userID
}
}
// Parse string fields
if query.FileType != "" {
fileType := constants.FileType(query.FileType)
req.FileType = &fileType
}
if query.IsPublic != "" {
if isPublic, err := strconv.ParseBool(query.IsPublic); err == nil {
req.IsPublic = &isPublic
}
}
// Parse date fields
if query.DateFrom != "" {
if dateFrom, err := time.Parse("2006-01-02", query.DateFrom); err == nil {
req.DateFrom = &dateFrom
}
}
if query.DateTo != "" {
if dateTo, err := time.Parse("2006-01-02", query.DateTo); err == nil {
req.DateTo = &dateTo
}
}
return req
}
// Model to Contract transformers
func FileModelToContract(resp *models.FileResponse) *contract.FileResponse {
if resp == nil {
return nil
}
return &contract.FileResponse{
ID: resp.ID,
OrganizationID: resp.OrganizationID,
UserID: resp.UserID,
FileName: resp.FileName,
OriginalName: resp.OriginalName,
FileURL: resp.FileURL,
FileSize: resp.FileSize,
MimeType: resp.MimeType,
FileType: resp.FileType,
UploadPath: resp.UploadPath,
IsPublic: resp.IsPublic,
Metadata: resp.Metadata,
CreatedAt: resp.CreatedAt,
UpdatedAt: resp.UpdatedAt,
}
}
func ListFilesModelToContract(resp *models.ListFilesResponse) *contract.ListFilesResponse {
if resp == nil {
return nil
}
files := make([]*contract.FileResponse, len(resp.Files))
for i, file := range resp.Files {
files[i] = FileModelToContract(file)
}
return &contract.ListFilesResponse{
Files: files,
TotalCount: resp.TotalCount,
Page: resp.Page,
Limit: resp.Limit,
TotalPages: resp.TotalPages,
}
}
func UploadFileModelToContract(resp *models.UploadFileResponse) *contract.UploadFileResponse {
if resp == nil {
return nil
}
return &contract.UploadFileResponse{
File: *FileModelToContract(&resp.File),
}
}
@@ -0,0 +1,74 @@
package transformer
import (
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"time"
)
func CreateInventoryRequestToModel(req *contract.CreateInventoryRequest) *models.CreateInventoryRequest {
return &models.CreateInventoryRequest{
OutletID: req.OutletID,
ProductID: req.ProductID,
Quantity: req.Quantity,
ReorderLevel: req.ReorderLevel,
}
}
func UpdateInventoryRequestToModel(req *contract.UpdateInventoryRequest) *models.UpdateInventoryRequest {
return &models.UpdateInventoryRequest{
Quantity: req.Quantity,
ReorderLevel: req.ReorderLevel,
}
}
func AdjustInventoryRequestToModel(req *contract.AdjustInventoryRequest) *models.InventoryAdjustmentRequest {
return &models.InventoryAdjustmentRequest{
Delta: req.Delta,
Reason: req.Reason,
}
}
// Model to Contract conversions
func InventoryModelResponseToResponse(inv *models.InventoryResponse) *contract.InventoryResponse {
if inv == nil {
return nil
}
return &contract.InventoryResponse{
ID: inv.ID,
OutletID: inv.OutletID,
ProductID: inv.ProductID,
Quantity: inv.Quantity,
ReorderLevel: inv.ReorderLevel,
IsLowStock: inv.IsLowStock,
UpdatedAt: inv.UpdatedAt,
}
}
func InventoryAdjustmentToResponse(
inventoryID, productID, outletID string,
previousQty, newQty, delta int,
reason string,
) *contract.InventoryAdjustmentResponse {
// This would need proper UUID parsing in a real implementation
return &contract.InventoryAdjustmentResponse{
PreviousQty: previousQty,
NewQty: newQty,
Delta: delta,
Reason: reason,
AdjustedAt: time.Now(),
}
}
// Slice conversions
func InventoryToResponses(inventory []models.InventoryResponse) []contract.InventoryResponse {
responses := make([]contract.InventoryResponse, len(inventory))
for i, inv := range inventory {
response := InventoryModelResponseToResponse(&inv)
if response != nil {
responses[i] = *response
}
}
return responses
}
+353
View File
@@ -0,0 +1,353 @@
package transformer
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"strconv"
"time"
"github.com/google/uuid"
)
func CreateOrderContractToModel(req *contract.CreateOrderRequest) *models.CreateOrderRequest {
items := make([]models.CreateOrderItemRequest, len(req.OrderItems))
for i, item := range req.OrderItems {
items[i] = models.CreateOrderItemRequest{
ProductID: item.ProductID,
ProductVariantID: item.ProductVariantID,
Quantity: item.Quantity,
UnitPrice: item.UnitPrice, // Now optional
Modifiers: item.Modifiers,
Notes: item.Notes,
Metadata: item.Metadata,
}
}
return &models.CreateOrderRequest{
OutletID: req.OutletID,
UserID: req.UserID,
TableNumber: req.TableNumber,
OrderType: constants.OrderType(req.OrderType),
OrderItems: items,
Notes: req.Notes,
CustomerName: req.CustomerName,
}
}
func UpdateOrderContractToModel(req *contract.UpdateOrderRequest) *models.UpdateOrderRequest {
var status *constants.OrderStatus
if req.Status != nil {
stats := constants.OrderStatus(*req.Status)
status = &stats
}
return &models.UpdateOrderRequest{
TableNumber: req.TableNumber,
Status: status,
DiscountAmount: req.DiscountAmount,
Notes: req.Notes,
Metadata: req.Metadata,
}
}
func AddToOrderContractToModel(req *contract.AddToOrderRequest) *models.AddToOrderRequest {
items := make([]models.CreateOrderItemRequest, len(req.OrderItems))
for i, item := range req.OrderItems {
items[i] = models.CreateOrderItemRequest{
ProductID: item.ProductID,
ProductVariantID: item.ProductVariantID,
Quantity: item.Quantity,
UnitPrice: item.UnitPrice, // Now optional
Modifiers: item.Modifiers,
Notes: item.Notes,
Metadata: item.Metadata,
}
}
return &models.AddToOrderRequest{
OrderItems: items,
Notes: req.Notes,
Metadata: req.Metadata,
}
}
func VoidOrderContractToModel(req *contract.VoidOrderRequest) *models.VoidOrderRequest {
items := make([]models.VoidItemRequest, len(req.Items))
for i, item := range req.Items {
items[i] = models.VoidItemRequest{
OrderItemID: item.OrderItemID,
Quantity: item.Quantity,
}
}
return &models.VoidOrderRequest{
OrderID: req.OrderID,
Reason: req.Reason,
Type: req.Type,
Items: items,
}
}
func OrderModelToContract(resp *models.OrderResponse) *contract.OrderResponse {
if resp == nil {
return nil
}
items := make([]contract.OrderItemResponse, len(resp.OrderItems))
for i, item := range resp.OrderItems {
items[i] = contract.OrderItemResponse{
ID: item.ID,
OrderID: item.OrderID,
ProductID: item.ProductID,
ProductName: item.ProductName,
ProductVariantID: item.ProductVariantID,
ProductVariantName: item.ProductVariantName,
Quantity: item.Quantity,
UnitPrice: item.UnitPrice,
TotalPrice: item.TotalPrice,
Modifiers: item.Modifiers,
Notes: item.Notes,
Metadata: item.Metadata,
Status: string(item.Status),
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
}
}
return &contract.OrderResponse{
ID: resp.ID,
OrderNumber: resp.OrderNumber,
OutletID: resp.OutletID,
UserID: resp.UserID,
TableNumber: resp.TableNumber,
OrderType: string(resp.OrderType),
Status: string(resp.Status),
Subtotal: resp.Subtotal,
TaxAmount: resp.TaxAmount,
DiscountAmount: resp.DiscountAmount,
TotalAmount: resp.TotalAmount,
Notes: resp.Notes,
Metadata: resp.Metadata,
CreatedAt: resp.CreatedAt,
UpdatedAt: resp.UpdatedAt,
OrderItems: items,
}
}
func AddToOrderModelToContract(resp *models.AddToOrderResponse) *contract.AddToOrderResponse {
if resp == nil {
return nil
}
items := make([]contract.OrderItemResponse, len(resp.AddedItems))
for i, item := range resp.AddedItems {
items[i] = contract.OrderItemResponse{
ID: item.ID,
OrderID: item.OrderID,
ProductID: item.ProductID,
ProductName: item.ProductName,
ProductVariantID: item.ProductVariantID,
ProductVariantName: item.ProductVariantName,
Quantity: item.Quantity,
UnitPrice: item.UnitPrice,
TotalPrice: item.TotalPrice,
Modifiers: item.Modifiers,
Notes: item.Notes,
Metadata: item.Metadata,
Status: string(item.Status),
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
}
}
return &contract.AddToOrderResponse{
OrderID: resp.OrderID,
OrderNumber: resp.OrderNumber,
AddedItems: items,
UpdatedOrder: *OrderModelToContract(&resp.UpdatedOrder),
}
}
func SetOrderCustomerContractToModel(req *contract.SetOrderCustomerRequest) *models.SetOrderCustomerRequest {
return &models.SetOrderCustomerRequest{
CustomerID: req.CustomerID,
}
}
func SetOrderCustomerModelToContract(resp *models.SetOrderCustomerResponse) *contract.SetOrderCustomerResponse {
if resp == nil {
return nil
}
return &contract.SetOrderCustomerResponse{
OrderID: resp.OrderID,
CustomerID: resp.CustomerID,
Message: resp.Message,
}
}
func ListOrdersQueryToModel(query *contract.ListOrdersQuery) *models.ListOrdersRequest {
req := &models.ListOrdersRequest{
Search: query.Search,
Page: query.Page,
Limit: query.Limit,
}
// Parse UUID fields
if query.OrganizationID != "" {
if organizationID, err := uuid.Parse(query.OrganizationID); err == nil {
req.OrganizationID = &organizationID
}
}
if query.OutletID != "" {
if outletID, err := uuid.Parse(query.OutletID); err == nil {
req.OutletID = &outletID
}
}
if query.UserID != "" {
if userID, err := uuid.Parse(query.UserID); err == nil {
req.UserID = &userID
}
}
if query.CustomerID != "" {
if customerID, err := uuid.Parse(query.CustomerID); err == nil {
req.CustomerID = &customerID
}
}
// Parse enum fields
if query.OrderType != "" {
orderType := constants.OrderType(query.OrderType)
req.OrderType = &orderType
}
if query.Status != "" {
status := constants.OrderStatus(query.Status)
req.Status = &status
}
if query.PaymentStatus != "" {
paymentStatus := constants.PaymentStatus(query.PaymentStatus)
req.PaymentStatus = &paymentStatus
}
// Parse boolean fields
if query.IsVoid != "" {
if isVoid, err := strconv.ParseBool(query.IsVoid); err == nil {
req.IsVoid = &isVoid
}
}
if query.IsRefund != "" {
if isRefund, err := strconv.ParseBool(query.IsRefund); err == nil {
req.IsRefund = &isRefund
}
}
// Parse date fields
if query.DateFrom != "" {
if dateFrom, err := time.Parse("2006-01-02", query.DateFrom); err == nil {
req.DateFrom = &dateFrom
}
}
if query.DateTo != "" {
if dateTo, err := time.Parse("2006-01-02", query.DateTo); err == nil {
req.DateTo = &dateTo
}
}
return req
}
func ListOrdersModelToContract(resp *models.ListOrdersResponse) *contract.ListOrdersResponse {
if resp == nil {
return nil
}
orders := make([]contract.OrderResponse, len(resp.Orders))
for i, order := range resp.Orders {
orders[i] = *OrderModelToContract(&order)
}
return &contract.ListOrdersResponse{
Orders: orders,
TotalCount: resp.TotalCount,
Page: resp.Page,
Limit: resp.Limit,
TotalPages: resp.TotalPages,
}
}
// Payment-related transformers
func CreatePaymentContractToModel(req *contract.CreatePaymentRequest) *models.CreatePaymentRequest {
paymentOrderItems := make([]models.CreatePaymentOrderItemRequest, len(req.PaymentOrderItems))
for i, item := range req.PaymentOrderItems {
paymentOrderItems[i] = models.CreatePaymentOrderItemRequest{
OrderItemID: item.OrderItemID,
Amount: item.Amount,
}
}
return &models.CreatePaymentRequest{
OrderID: req.OrderID,
PaymentMethodID: req.PaymentMethodID,
Amount: req.Amount,
TransactionID: req.TransactionID,
SplitNumber: req.SplitNumber,
SplitTotal: req.SplitTotal,
SplitDescription: req.SplitDescription,
PaymentOrderItems: paymentOrderItems,
Metadata: req.Metadata,
}
}
func PaymentModelToContract(resp *models.PaymentResponse) *contract.PaymentResponse {
if resp == nil {
return nil
}
paymentOrderItems := make([]contract.PaymentOrderItemResponse, len(resp.PaymentOrderItems))
for i, item := range resp.PaymentOrderItems {
paymentOrderItems[i] = contract.PaymentOrderItemResponse{
ID: item.ID,
PaymentID: item.PaymentID,
OrderItemID: item.OrderItemID,
Amount: item.Amount,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
}
}
return &contract.PaymentResponse{
ID: resp.ID,
OrderID: resp.OrderID,
PaymentMethodID: resp.PaymentMethodID,
Amount: resp.Amount,
Status: string(resp.Status),
TransactionID: resp.TransactionID,
SplitNumber: resp.SplitNumber,
SplitTotal: resp.SplitTotal,
SplitDescription: resp.SplitDescription,
RefundAmount: resp.RefundAmount,
RefundReason: resp.RefundReason,
RefundedAt: resp.RefundedAt,
RefundedBy: resp.RefundedBy,
Metadata: resp.Metadata,
CreatedAt: resp.CreatedAt,
UpdatedAt: resp.UpdatedAt,
PaymentOrderItems: paymentOrderItems,
}
}
func RefundOrderContractToModel(req *contract.RefundOrderRequest) *models.RefundOrderRequest {
orderItems := make([]models.RefundOrderItemRequest, len(req.OrderItems))
for i, item := range req.OrderItems {
orderItems[i] = models.RefundOrderItemRequest{
OrderItemID: item.OrderItemID,
RefundQuantity: item.RefundQuantity,
RefundAmount: item.RefundAmount,
Reason: item.Reason,
}
}
return &models.RefundOrderRequest{
Reason: req.Reason,
RefundAmount: req.RefundAmount,
OrderItems: orderItems,
}
}
@@ -0,0 +1,91 @@
package transformer
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
// Contract to Model conversions
func CreateOrganizationRequestToModel(req *contract.CreateOrganizationRequest) *models.CreateOrganizationRequest {
return &models.CreateOrganizationRequest{
OrganizationName: req.OrganizationName,
OrganizationEmail: req.OrganizationEmail,
OrganizationPhoneNumber: req.OrganizationPhoneNumber,
PlanType: constants.PlanType(req.PlanType),
AdminName: req.AdminName,
AdminEmail: req.AdminEmail,
AdminPassword: req.AdminPassword,
OutletName: req.OutletName,
OutletAddress: req.OutletAddress,
OutletTimezone: req.OutletTimezone,
OutletCurrency: req.OutletCurrency,
}
}
func UpdateOrganizationRequestToModel(req *contract.UpdateOrganizationRequest) *models.UpdateOrganizationRequest {
modelReq := &models.UpdateOrganizationRequest{
Name: req.Name,
Email: req.Email,
PhoneNumber: req.PhoneNumber,
}
if req.PlanType != nil {
planType := constants.PlanType(*req.PlanType)
modelReq.PlanType = &planType
}
return modelReq
}
// Model to Contract conversions
func OrganizationModelResponseToResponse(org *models.OrganizationResponse) *contract.OrganizationResponse {
return &contract.OrganizationResponse{
ID: org.ID,
Name: org.Name,
Email: org.Email,
PhoneNumber: org.PhoneNumber,
PlanType: string(org.PlanType),
CreatedAt: org.CreatedAt,
UpdatedAt: org.UpdatedAt,
}
}
func CreateOrganizationResponseToContract(resp *models.CreateOrganizationResponse) *contract.CreateOrganizationResponse {
return &contract.CreateOrganizationResponse{
Organization: *OrganizationModelResponseToResponse(resp.Organization),
AdminUser: *UserModelResponseToResponse(resp.AdminUser),
DefaultOutlet: *OutletModelResponseToContract(resp.DefaultOutlet),
}
}
func OutletModelResponseToContract(outlet *models.OutletResponse) *contract.OutletResponse {
address := ""
if outlet.Address != nil {
address = *outlet.Address
}
return &contract.OutletResponse{
ID: outlet.ID,
OrganizationID: outlet.OrganizationID,
Name: outlet.Name,
Address: address,
Currency: outlet.Currency,
TaxRate: outlet.TaxRate,
IsActive: outlet.IsActive,
CreatedAt: outlet.CreatedAt,
UpdatedAt: outlet.UpdatedAt,
}
}
// Slice conversions
func OrganizationsToResponses(organizations []models.OrganizationResponse) []contract.OrganizationResponse {
responses := make([]contract.OrganizationResponse, len(organizations))
for i, org := range organizations {
response := OrganizationModelResponseToResponse(&org)
if response != nil {
responses[i] = *response
}
}
return responses
}
@@ -0,0 +1,45 @@
package transformer
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
func CreateOutletRequestToModel(req *contract.CreateOutletRequest) *models.CreateOutletRequest {
return &models.CreateOutletRequest{
OrganizationID: req.OrganizationID,
Name: req.Name,
Address: req.Address,
PhoneNumber: req.PhoneNumber,
BusinessType: constants.BusinessTypeRestaurant,
Currency: constants.Currency(req.Currency),
TaxRate: req.TaxRate,
}
}
func UpdateOutletRequestToModel(req *contract.UpdateOutletRequest) *models.UpdateOutletRequest {
return &models.UpdateOutletRequest{
Name: req.Name,
Address: req.Address,
PhoneNumber: req.PhoneNumber,
TaxRate: req.TaxRate,
IsActive: req.IsActive,
OrganizationID: req.OrganizationID,
}
}
func OutletModelResponseToResponse(model *models.OutletResponse) contract.OutletResponse {
return contract.OutletResponse{
ID: model.ID,
OrganizationID: model.OrganizationID,
Name: model.Name,
Address: *model.Address,
BusinessType: string(constants.BusinessTypeRestaurant), // Default business type
Currency: model.Currency,
TaxRate: model.TaxRate,
IsActive: model.IsActive,
CreatedAt: model.CreatedAt,
UpdatedAt: model.UpdatedAt,
}
}
+187
View File
@@ -0,0 +1,187 @@
package transformer
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
func CreateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.CreateProductRequest) *models.CreateProductRequest {
cost := float64(0)
if req.Cost != nil {
cost = *req.Cost
}
businessType := constants.BusinessTypeRestaurant
if req.BusinessType != nil {
businessType = constants.BusinessType(*req.BusinessType)
}
var variants []models.CreateProductVariantRequest
if req.Variants != nil {
variants = make([]models.CreateProductVariantRequest, len(req.Variants))
for i, variant := range req.Variants {
variants[i] = models.CreateProductVariantRequest{
ProductID: variant.ProductID,
Name: variant.Name,
PriceModifier: variant.PriceModifier,
Cost: variant.Cost,
Metadata: variant.Metadata,
}
}
}
metadata := req.Metadata
if metadata == nil {
metadata = make(map[string]interface{})
}
if req.Image != nil {
metadata["image"] = *req.Image
}
return &models.CreateProductRequest{
OrganizationID: apctx.OrganizationID,
CategoryID: req.CategoryID,
SKU: req.SKU,
Name: req.Name,
Description: req.Description,
Price: req.Price,
Cost: cost,
BusinessType: businessType,
Metadata: metadata,
Variants: variants,
}
}
func UpdateProductRequestToModel(req *contract.UpdateProductRequest) *models.UpdateProductRequest {
metadata := req.Metadata
if metadata == nil {
metadata = make(map[string]interface{})
}
if req.Image != nil {
metadata["image"] = *req.Image
}
return &models.UpdateProductRequest{
CategoryID: req.CategoryID,
SKU: req.SKU,
Name: req.Name,
Description: req.Description,
Price: req.Price,
Cost: req.Cost,
Metadata: metadata,
IsActive: req.IsActive,
}
}
// Model to Contract conversions
func ProductModelResponseToResponse(prod *models.ProductResponse) *contract.ProductResponse {
if prod == nil {
return nil
}
// Convert variants to contract responses
var variantResponses []contract.ProductVariantResponse
if prod.Variants != nil {
variantResponses = make([]contract.ProductVariantResponse, len(prod.Variants))
for i, variant := range prod.Variants {
variantResponses[i] = contract.ProductVariantResponse{
ID: variant.ID,
ProductID: variant.ProductID,
Name: variant.Name,
PriceModifier: variant.PriceModifier,
Cost: variant.Cost,
Metadata: variant.Metadata,
CreatedAt: variant.CreatedAt,
UpdatedAt: variant.UpdatedAt,
}
}
}
response := &contract.ProductResponse{
ID: prod.ID,
OrganizationID: prod.OrganizationID,
CategoryID: prod.CategoryID,
SKU: prod.SKU,
Name: prod.Name,
Description: prod.Description,
Price: prod.Price,
Cost: prod.Cost,
BusinessType: string(prod.BusinessType),
Metadata: prod.Metadata,
IsActive: prod.IsActive,
CreatedAt: prod.CreatedAt,
UpdatedAt: prod.UpdatedAt,
Variants: variantResponses,
}
return response
}
// Slice conversions
func ProductsToResponses(products []models.ProductResponse) []contract.ProductResponse {
responses := make([]contract.ProductResponse, len(products))
for i, prod := range products {
response := ProductModelResponseToResponse(&prod)
if response != nil {
responses[i] = *response
}
}
return responses
}
// Product Variant Transformers
func CreateProductVariantRequestToModel(req *contract.CreateProductVariantRequest) *models.CreateProductVariantRequest {
if req == nil {
return nil
}
return &models.CreateProductVariantRequest{
ProductID: req.ProductID,
Name: req.Name,
PriceModifier: req.PriceModifier,
Cost: req.Cost,
Metadata: req.Metadata,
}
}
func UpdateProductVariantRequestToModel(req *contract.UpdateProductVariantRequest) *models.UpdateProductVariantRequest {
if req == nil {
return nil
}
return &models.UpdateProductVariantRequest{
Name: req.Name,
PriceModifier: req.PriceModifier,
Cost: req.Cost,
Metadata: req.Metadata,
}
}
func ProductVariantModelResponseToResponse(variant *models.ProductVariantResponse) *contract.ProductVariantResponse {
if variant == nil {
return nil
}
return &contract.ProductVariantResponse{
ID: variant.ID,
ProductID: variant.ProductID,
Name: variant.Name,
PriceModifier: variant.PriceModifier,
Cost: variant.Cost,
Metadata: variant.Metadata,
CreatedAt: variant.CreatedAt,
UpdatedAt: variant.UpdatedAt,
}
}
func ProductVariantsToResponses(variants []models.ProductVariantResponse) []contract.ProductVariantResponse {
responses := make([]contract.ProductVariantResponse, len(variants))
for i, variant := range variants {
response := ProductVariantModelResponseToResponse(&variant)
if response != nil {
responses[i] = *response
}
}
return responses
}
+38
View File
@@ -0,0 +1,38 @@
package transformer
import (
"github.com/gin-gonic/gin"
)
type Transformer interface {
Success(c *gin.Context, statusCode int, message string, data interface{})
Error(c *gin.Context, statusCode int, message string, err error)
}
type ResponseTransformer struct{}
func NewTransformer() Transformer {
return &ResponseTransformer{}
}
func (t *ResponseTransformer) Success(c *gin.Context, statusCode int, message string, data interface{}) {
response := gin.H{
"success": true,
"message": message,
"data": data,
}
c.JSON(statusCode, response)
}
func (t *ResponseTransformer) Error(c *gin.Context, statusCode int, message string, err error) {
response := gin.H{
"success": false,
"message": message,
}
if err != nil {
response["error"] = err.Error()
}
c.JSON(statusCode, response)
}
+105
View File
@@ -0,0 +1,105 @@
package transformer
import (
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
)
func CreateUserRequestToModel(req *contract.CreateUserRequest) *models.CreateUserRequest {
return &models.CreateUserRequest{
OrganizationID: req.OrganizationID,
OutletID: req.OutletID,
Name: req.Name,
Email: req.Email,
Password: req.Password,
Role: constants.UserRole(req.Role),
Permissions: req.Permissions,
}
}
func UpdateUserRequestToModel(req *contract.UpdateUserRequest) *models.UpdateUserRequest {
modelReq := &models.UpdateUserRequest{
OutletID: req.OutletID,
IsActive: req.IsActive,
}
if req.Name != nil {
modelReq.Name = req.Name
}
if req.Email != nil {
modelReq.Email = req.Email
}
if req.Role != nil {
role := constants.UserRole(*req.Role)
modelReq.Role = &role
}
if req.Permissions != nil {
modelReq.Permissions = req.Permissions
}
return modelReq
}
func ChangePasswordRequestToModel(req *contract.ChangePasswordRequest) *models.ChangePasswordRequest {
return &models.ChangePasswordRequest{
CurrentPassword: req.CurrentPassword,
NewPassword: req.NewPassword,
}
}
// Model to Contract conversions
func UserModelToResponse(user *models.User) *contract.UserResponse {
return &contract.UserResponse{
ID: user.ID,
OrganizationID: user.OrganizationID,
OutletID: user.OutletID,
Name: user.Name,
Email: user.Email,
Role: string(user.Role),
Permissions: user.Permissions,
IsActive: user.IsActive,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
}
}
func UserModelResponseToResponse(userResponse *models.UserResponse) *contract.UserResponse {
return &contract.UserResponse{
ID: userResponse.ID,
OrganizationID: userResponse.OrganizationID,
OutletID: userResponse.OutletID,
Name: userResponse.Name,
Email: userResponse.Email,
Role: string(userResponse.Role),
Permissions: userResponse.Permissions,
IsActive: userResponse.IsActive,
CreatedAt: userResponse.CreatedAt,
UpdatedAt: userResponse.UpdatedAt,
}
}
func UsersToResponses(users []models.User) []contract.UserResponse {
responses := make([]contract.UserResponse, len(users))
for i, user := range users {
response := UserModelToResponse(&user)
if response != nil {
responses[i] = *response
}
}
return responses
}
func UserResponsesToResponses(userResponses []models.UserResponse) []contract.UserResponse {
responses := make([]contract.UserResponse, len(userResponses))
for i, userResponse := range userResponses {
response := UserModelResponseToResponse(&userResponse)
if response != nil {
responses[i] = *response
}
}
return responses
}