feature/exclusive-summary #16
@ -216,3 +216,12 @@ type ExclusiveSummaryDailyTransaction struct {
|
|||||||
Amount float64
|
Amount float64
|
||||||
Source string
|
Source string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExclusiveSummaryBankBalance struct {
|
||||||
|
Bank string
|
||||||
|
OpeningBalance *float64
|
||||||
|
IncomingMutation *float64
|
||||||
|
OutgoingMutation *float64
|
||||||
|
ClosingBalance *float64
|
||||||
|
Notes *string
|
||||||
|
}
|
||||||
|
|||||||
@ -700,6 +700,23 @@ func (p *AnalyticsProcessorImpl) GetExclusiveSummaryMonthly(ctx context.Context,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bankBalances, err := p.analyticsRepo.GetExclusiveSummaryBankBalances(ctx, req.OrganizationID, req.OutletID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get exclusive summary bank balances: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bankBalance := make([]models.ExclusiveSummaryBankBalance, len(bankBalances))
|
||||||
|
for i, item := range bankBalances {
|
||||||
|
bankBalance[i] = models.ExclusiveSummaryBankBalance{
|
||||||
|
Bank: item.Bank,
|
||||||
|
OpeningBalance: item.OpeningBalance,
|
||||||
|
IncomingMutation: item.IncomingMutation,
|
||||||
|
OutgoingMutation: item.OutgoingMutation,
|
||||||
|
ClosingBalance: item.ClosingBalance,
|
||||||
|
Notes: item.Notes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &models.ExclusiveSummaryMonthlyResponse{
|
return &models.ExclusiveSummaryMonthlyResponse{
|
||||||
OrganizationID: req.OrganizationID,
|
OrganizationID: req.OrganizationID,
|
||||||
OutletID: req.OutletID,
|
OutletID: req.OutletID,
|
||||||
@ -714,10 +731,7 @@ func (p *AnalyticsProcessorImpl) GetExclusiveSummaryMonthly(ctx context.Context,
|
|||||||
NetProfitMargin: percentage(fullPeriod.Summary.NetProfit, fullPeriod.Summary.Sales),
|
NetProfitMargin: percentage(fullPeriod.Summary.NetProfit, fullPeriod.Summary.Sales),
|
||||||
},
|
},
|
||||||
Periods: periods,
|
Periods: periods,
|
||||||
BankBalance: []models.ExclusiveSummaryBankBalance{
|
BankBalance: bankBalance,
|
||||||
{Bank: "BCA"},
|
|
||||||
{Bank: "BRI"},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ type analyticsRepositoryStub struct {
|
|||||||
purchasingResult *entities.PurchasingAnalytics
|
purchasingResult *entities.PurchasingAnalytics
|
||||||
profitLossResult *entities.ProfitLossAnalytics
|
profitLossResult *entities.ProfitLossAnalytics
|
||||||
exclusiveSummaryResults []*entities.ExclusiveSummaryAnalytics
|
exclusiveSummaryResults []*entities.ExclusiveSummaryAnalytics
|
||||||
|
bankBalances []entities.ExclusiveSummaryBankBalance
|
||||||
profitLossGroup string
|
profitLossGroup string
|
||||||
exclusiveSummaryCalls int
|
exclusiveSummaryCalls int
|
||||||
}
|
}
|
||||||
@ -59,6 +60,10 @@ func (s *analyticsRepositoryStub) GetExclusiveSummaryAnalytics(context.Context,
|
|||||||
return &entities.ExclusiveSummaryAnalytics{}, nil
|
return &entities.ExclusiveSummaryAnalytics{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *analyticsRepositoryStub) GetExclusiveSummaryBankBalances(context.Context, uuid.UUID, *uuid.UUID) ([]entities.ExclusiveSummaryBankBalance, error) {
|
||||||
|
return s.bankBalances, nil
|
||||||
|
}
|
||||||
|
|
||||||
type expenseRepositoryStub struct{}
|
type expenseRepositoryStub struct{}
|
||||||
|
|
||||||
func (expenseRepositoryStub) Create(context.Context, *entities.Expense) error { return nil }
|
func (expenseRepositoryStub) Create(context.Context, *entities.Expense) error { return nil }
|
||||||
@ -343,6 +348,9 @@ func TestAnalyticsProcessorGetExclusiveSummaryMonthlyBuildsSummaryAndBuckets(t *
|
|||||||
location, err := time.LoadLocation("Asia/Jakarta")
|
location, err := time.LoadLocation("Asia/Jakarta")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
month := time.Date(2026, 5, 1, 0, 0, 0, 0, location)
|
month := time.Date(2026, 5, 1, 0, 0, 0, 0, location)
|
||||||
|
openingBalance := 5000000.0
|
||||||
|
closingBalance := 5000000.0
|
||||||
|
notes := "Main cash account for daily transactions"
|
||||||
stub := &analyticsRepositoryStub{
|
stub := &analyticsRepositoryStub{
|
||||||
exclusiveSummaryResults: []*entities.ExclusiveSummaryAnalytics{
|
exclusiveSummaryResults: []*entities.ExclusiveSummaryAnalytics{
|
||||||
{SalesTotal: 1000, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 400}}, OperationalExpenseBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 100}}},
|
{SalesTotal: 1000, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 400}}, OperationalExpenseBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 100}}},
|
||||||
@ -352,6 +360,9 @@ func TestAnalyticsProcessorGetExclusiveSummaryMonthlyBuildsSummaryAndBuckets(t *
|
|||||||
{SalesTotal: 400, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 160}}},
|
{SalesTotal: 400, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 160}}},
|
||||||
{SalesTotal: 500, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 200}}},
|
{SalesTotal: 500, HPPBreakdown: []entities.ExclusiveSummaryCategoryTotal{{Amount: 200}}},
|
||||||
},
|
},
|
||||||
|
bankBalances: []entities.ExclusiveSummaryBankBalance{
|
||||||
|
{Bank: "Cash and Bank", OpeningBalance: &openingBalance, ClosingBalance: &closingBalance, Notes: ¬es},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
processor := NewAnalyticsProcessorImpl(stub, expenseRepositoryStub{})
|
processor := NewAnalyticsProcessorImpl(stub, expenseRepositoryStub{})
|
||||||
|
|
||||||
@ -370,7 +381,15 @@ func TestAnalyticsProcessorGetExclusiveSummaryMonthlyBuildsSummaryAndBuckets(t *
|
|||||||
require.Len(t, result.Periods, 5)
|
require.Len(t, result.Periods, 5)
|
||||||
require.Equal(t, "1 - 3 Mei", result.Periods[0].Label)
|
require.Equal(t, "1 - 3 Mei", result.Periods[0].Label)
|
||||||
require.Equal(t, "25 - 31 Mei", result.Periods[4].Label)
|
require.Equal(t, "25 - 31 Mei", result.Periods[4].Label)
|
||||||
require.Len(t, result.BankBalance, 2)
|
require.Len(t, result.BankBalance, 1)
|
||||||
require.Equal(t, "BCA", result.BankBalance[0].Bank)
|
require.Equal(t, "Cash and Bank", result.BankBalance[0].Bank)
|
||||||
|
require.NotNil(t, result.BankBalance[0].OpeningBalance)
|
||||||
|
require.Equal(t, openingBalance, *result.BankBalance[0].OpeningBalance)
|
||||||
|
require.NotNil(t, result.BankBalance[0].ClosingBalance)
|
||||||
|
require.Equal(t, closingBalance, *result.BankBalance[0].ClosingBalance)
|
||||||
|
require.Nil(t, result.BankBalance[0].IncomingMutation)
|
||||||
|
require.Nil(t, result.BankBalance[0].OutgoingMutation)
|
||||||
|
require.NotNil(t, result.BankBalance[0].Notes)
|
||||||
|
require.Equal(t, notes, *result.BankBalance[0].Notes)
|
||||||
require.Equal(t, 6, stub.exclusiveSummaryCalls)
|
require.Equal(t, 6, stub.exclusiveSummaryCalls)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ type AnalyticsRepository interface {
|
|||||||
GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error)
|
GetDashboardOverview(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.DashboardOverview, error)
|
||||||
GetProfitLossAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) (*entities.ProfitLossAnalytics, error)
|
GetProfitLossAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time, groupBy string) (*entities.ProfitLossAnalytics, error)
|
||||||
GetExclusiveSummaryAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.ExclusiveSummaryAnalytics, error)
|
GetExclusiveSummaryAnalytics(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID, dateFrom, dateTo time.Time) (*entities.ExclusiveSummaryAnalytics, error)
|
||||||
|
GetExclusiveSummaryBankBalances(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]entities.ExclusiveSummaryBankBalance, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnalyticsRepositoryImpl struct {
|
type AnalyticsRepositoryImpl struct {
|
||||||
@ -854,3 +855,47 @@ func (r *AnalyticsRepositoryImpl) exclusiveSummaryPurchaseOrderItemQuery(organiz
|
|||||||
|
|
||||||
return query, args
|
return query, args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *AnalyticsRepositoryImpl) GetExclusiveSummaryBankBalances(ctx context.Context, organizationID uuid.UUID, outletID *uuid.UUID) ([]entities.ExclusiveSummaryBankBalance, error) {
|
||||||
|
type accountBalance struct {
|
||||||
|
Name string
|
||||||
|
OpeningBalance float64
|
||||||
|
CurrentBalance float64
|
||||||
|
Description *string
|
||||||
|
}
|
||||||
|
|
||||||
|
var accounts []accountBalance
|
||||||
|
query := r.db.WithContext(ctx).
|
||||||
|
Table("accounts").
|
||||||
|
Select("name, opening_balance, current_balance, description").
|
||||||
|
Where("organization_id = ?", organizationID).
|
||||||
|
Where("account_type IN ?", []entities.AccountType{entities.AccountTypeCash, entities.AccountTypeWallet, entities.AccountTypeBank}).
|
||||||
|
Where("is_active = ?", true)
|
||||||
|
|
||||||
|
if outletID != nil {
|
||||||
|
query = query.Where("outlet_id = ? OR outlet_id IS NULL", *outletID)
|
||||||
|
} else {
|
||||||
|
query = query.Where("outlet_id IS NULL")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := query.
|
||||||
|
Order("number ASC, name ASC").
|
||||||
|
Scan(&accounts).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
balances := make([]entities.ExclusiveSummaryBankBalance, len(accounts))
|
||||||
|
for i, account := range accounts {
|
||||||
|
openingBalance := account.OpeningBalance
|
||||||
|
closingBalance := account.CurrentBalance
|
||||||
|
balances[i] = entities.ExclusiveSummaryBankBalance{
|
||||||
|
Bank: account.Name,
|
||||||
|
OpeningBalance: &openingBalance,
|
||||||
|
ClosingBalance: &closingBalance,
|
||||||
|
Notes: account.Description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return balances, nil
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user