diff --git a/internal/modules/gold/handlers.go b/internal/modules/gold/handlers.go index eb91b02..3a39ca3 100644 --- a/internal/modules/gold/handlers.go +++ b/internal/modules/gold/handlers.go @@ -184,11 +184,12 @@ func (s *state) handleStats(ctx context.Context, b *bot.Bot, update *models.Upda // Fetch under a reply-reserved sub-context; reply on the original ctx. fetchCtx, cancel := chathelper.FetchContext(ctx) defer cancel() - if buyPrice, _, err := s.prices.FetchLuongPrices(fetchCtx); err == nil { + if buyPrice, sellPrice, err := s.prices.FetchLuongPrices(fetchCtx); err == nil { goldValue := p.Luong * buyPrice totalValue += goldValue - lines = append(lines, "Price: "+FormatVND(buyPrice)+"/luong") - lines = append(lines, "Gold value: "+FormatVND(goldValue)) + lines = append(lines, "SJC buy (you sell): "+FormatVND(buyPrice)+"/luong") + lines = append(lines, "SJC sell (you buy): "+FormatVND(sellPrice)+"/luong") + lines = append(lines, "Gold value (at SJC buy): "+FormatVND(goldValue)) lines = append(lines, "Total value: "+FormatVND(totalValue)) lines = append(lines, "Invested: "+FormatVND(p.Meta.Invested)) lines = append(lines, "P&L: "+FormatPnL(totalValue, p.Meta.Invested)) diff --git a/internal/modules/gold/handlers_test.go b/internal/modules/gold/handlers_test.go index 3609862..4ee59f1 100644 --- a/internal/modules/gold/handlers_test.go +++ b/internal/modules/gold/handlers_test.go @@ -159,7 +159,14 @@ func TestStatsWithAndWithoutPrice(t *testing.T) { t.Fatalf("stats: %v", err) } text := rb.LastSent().Text() - for _, want := range []string{"Gold Account Summary", "Gold: 1 luong", "Price: 2.000.000 VND/luong", "P&L:"} { + for _, want := range []string{ + "Gold Account Summary", + "Gold: 1 luong", + "SJC buy (you sell): 2.000.000 VND/luong", + "SJC sell (you buy): 2.000.000 VND/luong", + "Gold value (at SJC buy): 2.000.000 VND", + "P&L:", + } { if !strings.Contains(text, want) { t.Fatalf("stats missing %q in %q", want, text) } @@ -172,6 +179,33 @@ func TestStatsWithAndWithoutPrice(t *testing.T) { rb.AssertSentText(t, "Price: no price") } +func TestHandleStatsShowsBuyAndSellPrices(t *testing.T) { + ctx := context.Background() + s := &state{ + store: newGoldStore(), + prices: spreadPriceFetcher{buy: 90_000_000, sell: 91_000_000}, + nowFn: func() time.Time { return time.UnixMilli(123) }, + } + rb := testutil.NewRecordingBot(t) + _ = s.handleTopup(ctx, rb.Bot, testutil.NewPrivateMessage(7, "/gold_topup 500000000")) + _ = s.handleBuy(ctx, rb.Bot, testutil.NewPrivateMessage(7, "/gold_buy 1")) + rb.Reset() + if err := s.handleStats(ctx, rb.Bot, testutil.NewPrivateMessage(7, "/gold_portfolio")); err != nil { + t.Fatalf("stats: %v", err) + } + text := rb.LastSent().Text() + for _, want := range []string{ + "SJC buy (you sell): 90.000.000 VND/luong", + "SJC sell (you buy): 91.000.000 VND/luong", + "Gold value (at SJC buy): 90.000.000 VND", + "Total value: 499.000.000 VND", + } { + if !strings.Contains(text, want) { + t.Fatalf("stats missing %q in %q", want, text) + } + } +} + // spreadPriceFetcher returns different buy/sell prices so handler tests can // verify that buys use the sell price and sells use the buy price. type spreadPriceFetcher struct {