package transformer import ( "encoding/json" "testing" "time" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/models" "github.com/google/uuid" "github.com/stretchr/testify/require" ) func TestPurchasingAnalyticsContractToModelParsesDateRangeAndOutlet(t *testing.T) { orgID := uuid.New() outletID := uuid.New().String() req := &contract.PurchasingAnalyticsRequest{ OrganizationID: orgID, OutletID: &outletID, DateFrom: "01-05-2026", DateTo: "02-05-2026", GroupBy: "week", } result := PurchasingAnalyticsContractToModel(req) require.Equal(t, orgID, result.OrganizationID) require.NotNil(t, result.OutletID) require.Equal(t, outletID, result.OutletID.String()) require.Equal(t, "week", result.GroupBy) location, err := time.LoadLocation("Asia/Jakarta") require.NoError(t, err) require.Equal(t, time.Date(2026, 5, 1, 0, 0, 0, 0, location), result.DateFrom) require.Equal(t, time.Date(2026, 5, 2, 23, 59, 59, int(time.Second-time.Nanosecond), location), result.DateTo) } func TestPurchasingAnalyticsContractToModelIgnoresInvalidOutlet(t *testing.T) { outletID := "not-a-uuid" result := PurchasingAnalyticsContractToModel(&contract.PurchasingAnalyticsRequest{ OutletID: &outletID, DateFrom: "01-05-2026", DateTo: "02-05-2026", }) require.Nil(t, result.OutletID) } func TestPurchasingAnalyticsModelToContractCopiesOutletName(t *testing.T) { outletID := uuid.New() outletName := "Main Outlet" now := time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC) result := PurchasingAnalyticsModelToContract(&models.PurchasingAnalyticsResponse{ OrganizationID: uuid.New(), OutletID: &outletID, OutletName: &outletName, Summary: models.PurchasingSummary{ TotalPurchases: 300, RawMaterialPurchases: 125, ExpensePurchases: 175, TotalPurchaseOrders: 3, RawMaterialPurchaseOrders: 1, ExpenseCount: 2, }, Data: []models.PurchasingAnalyticsData{ { Date: now, Purchases: 300, RawMaterialPurchases: 125, ExpensePurchases: 175, PurchaseOrders: 3, RawMaterialPurchaseOrders: 1, ExpenseCount: 2, }, }, }) require.NotNil(t, result) require.Equal(t, &outletID, result.OutletID) require.NotNil(t, result.OutletName) require.Equal(t, outletName, *result.OutletName) require.Equal(t, float64(300), result.Summary.TotalPurchases) require.Equal(t, float64(125), result.Summary.RawMaterialPurchases) require.Equal(t, float64(175), result.Summary.ExpensePurchases) require.Equal(t, int64(3), result.Summary.TotalPurchaseOrders) require.Equal(t, int64(1), result.Summary.RawMaterialPurchaseOrders) require.Equal(t, int64(2), result.Summary.ExpenseCount) require.Len(t, result.Data, 1) require.Equal(t, float64(300), result.Data[0].Purchases) require.Equal(t, float64(125), result.Data[0].RawMaterialPurchases) require.Equal(t, float64(175), result.Data[0].ExpensePurchases) } func TestPurchasingAnalyticsModelToContractCopiesTeamData(t *testing.T) { categoryID := uuid.New() result := PurchasingAnalyticsModelToContract(&models.PurchasingAnalyticsResponse{ OrganizationID: uuid.New(), Team: categoryID.String(), Summary: models.PurchasingSummary{TotalPurchases: 300, TotalTeams: 2}, TeamData: []models.PurchasingTeamData{ { Scope: constants.PurchaseTeamScopeCategory, CategoryID: &categoryID, Name: "Kitchen", TotalPurchases: 200, RawMaterialPurchases: 150, ExpensePurchases: 50, PurchaseOrderCount: 2, Quantity: 12, Percentage: 66.67, }, { Scope: constants.PurchaseTeamNone, Name: constants.PurchaseTeamNoneName, TotalPurchases: 100, PurchaseOrderCount: 1, Percentage: 33.33, }, }, }) require.NotNil(t, result) require.Equal(t, categoryID.String(), result.Team) require.Equal(t, int64(2), result.Summary.TotalTeams) require.Len(t, result.TeamData, 2) require.Equal(t, constants.PurchaseTeamScopeCategory, result.TeamData[0].Scope) require.Equal(t, &categoryID, result.TeamData[0].CategoryID) require.Equal(t, "Kitchen", result.TeamData[0].Name) require.Equal(t, float64(200), result.TeamData[0].TotalPurchases) require.Equal(t, 66.67, result.TeamData[0].Percentage) require.Equal(t, constants.PurchaseTeamNone, result.TeamData[1].Scope) require.Nil(t, result.TeamData[1].CategoryID) require.Equal(t, constants.PurchaseTeamNoneName, result.TeamData[1].Name) } func TestPurchasingAnalyticsModelToContractOmitsNilOutletName(t *testing.T) { result := PurchasingAnalyticsModelToContract(&models.PurchasingAnalyticsResponse{ OrganizationID: uuid.New(), }) payload, err := json.Marshal(result) require.NoError(t, err) require.NotContains(t, string(payload), "outlet_name") } func TestProfitLossAnalyticsContractToModelParsesDateRange(t *testing.T) { orgID := uuid.New() outletID := uuid.New().String() result, err := ProfitLossAnalyticsContractToModel(&contract.ProfitLossAnalyticsRequest{ OrganizationID: orgID, OutletID: &outletID, DateFrom: "01-05-2026", DateTo: "29-05-2026", GroupBy: "week", }) require.NoError(t, err) require.Equal(t, orgID, result.OrganizationID) require.NotNil(t, result.OutletID) require.Equal(t, outletID, result.OutletID.String()) require.Equal(t, "week", result.GroupBy) location, err := time.LoadLocation("Asia/Jakarta") require.NoError(t, err) require.Equal(t, time.Date(2026, 5, 1, 0, 0, 0, 0, location), result.DateFrom) require.Equal(t, time.Date(2026, 5, 29, 23, 59, 59, int(time.Second-time.Nanosecond), location), result.DateTo) } func TestProfitLossAnalyticsModelToContractCopiesDateRange(t *testing.T) { dateFrom := time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC) dateTo := time.Date(2026, 5, 29, 23, 59, 59, int(time.Second-time.Nanosecond), time.UTC) productID := uuid.New() categoryID := uuid.New() result := ProfitLossAnalyticsModelToContract(&models.ProfitLossAnalyticsResponse{ OrganizationID: uuid.New(), DateFrom: dateFrom, DateTo: dateTo, GroupBy: "month", Summary: models.ProfitLossSummary{ TotalRevenue: 1000, NetProfit: 500, }, Data: []models.ProfitLossData{ { Date: dateFrom, Revenue: 1000, NetProfit: 500, }, }, ProductData: []models.ProductProfitData{ { ProductID: productID, ProductName: "Nasi", CategoryID: categoryID, CategoryName: "Food", Revenue: 1000, GrossProfit: 500, }, }, MainSummary: []models.ProfitLossSummaryRow{ { ID: "total_omset", Label: "TOTAL OMSET", TodayNominal: 1000, }, }, }) require.NotNil(t, result) require.Equal(t, dateFrom, result.DateFrom) require.Equal(t, dateTo, result.DateTo) require.Equal(t, "month", result.GroupBy) require.Equal(t, float64(1000), result.Summary.TotalRevenue) require.Len(t, result.Data, 1) require.Equal(t, float64(500), result.Data[0].NetProfit) require.Len(t, result.ProductData, 1) require.Equal(t, productID, result.ProductData[0].ProductID) require.Len(t, result.MainSummary, 1) require.Equal(t, "total_omset", result.MainSummary[0].ID) } func TestExclusiveSummaryPeriodContractToModelParsesFlexibleDates(t *testing.T) { orgID := uuid.New() outletID := uuid.New().String() result, err := ExclusiveSummaryPeriodContractToModel(&contract.ExclusiveSummaryPeriodRequest{ OrganizationID: orgID, OutletID: &outletID, DateFrom: "2026-05-26", DateTo: "2026-05-31", ExcludeGajiStaffFromReimburse: true, }) require.NoError(t, err) require.Equal(t, orgID, result.OrganizationID) require.NotNil(t, result.OutletID) require.Equal(t, outletID, result.OutletID.String()) require.True(t, result.ExcludeGajiStaffFromReimburse) location, err := time.LoadLocation("Asia/Jakarta") require.NoError(t, err) require.Equal(t, time.Date(2026, 5, 26, 0, 0, 0, 0, location), result.DateFrom) require.Equal(t, time.Date(2026, 5, 31, 23, 59, 59, int(time.Second-time.Nanosecond), location), result.DateTo) } func TestExclusiveSummaryMonthlyContractToModelParsesMonth(t *testing.T) { orgID := uuid.New() result, err := ExclusiveSummaryMonthlyContractToModel(&contract.ExclusiveSummaryMonthlyRequest{ OrganizationID: orgID, Month: "2026-05", }) require.NoError(t, err) require.Equal(t, orgID, result.OrganizationID) location, err := time.LoadLocation("Asia/Jakarta") require.NoError(t, err) require.Equal(t, time.Date(2026, 5, 1, 0, 0, 0, 0, location), result.Month) }