Compare commits
No commits in common. "c2dc741152857dbe6504215192454d1c7533094d" and "e8586826bc821104fe155a4db9a4be8e7bf86623" have entirely different histories.
c2dc741152
...
e8586826bc
8 changed files with 56 additions and 101 deletions
|
|
@ -1,44 +0,0 @@
|
||||||
root = "."
|
|
||||||
testdata_dir = "testdata"
|
|
||||||
tmp_dir = "tmp"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
args_bin = []
|
|
||||||
bin = "./tmp/main"
|
|
||||||
cmd = "go build -o ./tmp/main ./cmd/api"
|
|
||||||
delay = 1000
|
|
||||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
|
||||||
exclude_file = []
|
|
||||||
exclude_regex = ["_test.go"]
|
|
||||||
exclude_unchanged = false
|
|
||||||
follow_symlink = false
|
|
||||||
full_bin = ""
|
|
||||||
include_dir = ["cmd", "internal", "pkg"]
|
|
||||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
|
||||||
include_regex = []
|
|
||||||
kill_delay = "0s"
|
|
||||||
log = "build-errors.log"
|
|
||||||
poll = false
|
|
||||||
poll_interval = 0
|
|
||||||
rerun = false
|
|
||||||
rerun_delay = 500
|
|
||||||
send_interrupt = false
|
|
||||||
stop_on_error = true
|
|
||||||
|
|
||||||
[color]
|
|
||||||
app = ""
|
|
||||||
build = "yellow"
|
|
||||||
main = "magenta"
|
|
||||||
runner = "green"
|
|
||||||
watcher = "cyan"
|
|
||||||
|
|
||||||
[log]
|
|
||||||
main_only = false
|
|
||||||
time = false
|
|
||||||
|
|
||||||
[misc]
|
|
||||||
clean_on_exit = false
|
|
||||||
|
|
||||||
[screen]
|
|
||||||
clear_on_rebuild = false
|
|
||||||
keep_scroll = true
|
|
||||||
|
|
@ -283,7 +283,6 @@ type PaymentWebhookEvent struct {
|
||||||
PaymentID string `json:"payment_id"`
|
PaymentID string `json:"payment_id"`
|
||||||
OrderID uuid.UUID `json:"order_id"`
|
OrderID uuid.UUID `json:"order_id"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Gateway string `json:"gateway"`
|
|
||||||
MarketplaceFee int64 `json:"marketplace_fee"`
|
MarketplaceFee int64 `json:"marketplace_fee"`
|
||||||
SellerAmount int64 `json:"seller_amount"`
|
SellerAmount int64 `json:"seller_amount"`
|
||||||
TotalPaidAmount int64 `json:"total_paid_amount"`
|
TotalPaidAmount int64 `json:"total_paid_amount"`
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,6 @@ func (h *Handler) SearchProducts(w http.ResponseWriter, r *http.Request) {
|
||||||
expires := time.Now().AddDate(0, 0, days)
|
expires := time.Now().AddDate(0, 0, days)
|
||||||
filter.ExpiresAfter = &expires
|
filter.ExpiresAfter = &expires
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if v := r.URL.Query().Get("expires_after"); v != "" {
|
if v := r.URL.Query().Get("expires_after"); v != "" {
|
||||||
// Also support direct date if needed
|
// Also support direct date if needed
|
||||||
if t, err := time.Parse("2006-01-02", v); err == nil {
|
if t, err := time.Parse("2006-01-02", v); err == nil {
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
|
||||||
"github.com/saveinmed/backend-go/internal/domain"
|
"github.com/saveinmed/backend-go/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
47
backend/internal/infrastructure/payments/split_math_test.go
Normal file
47
backend/internal/infrastructure/payments/split_math_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPsychologicalSplitMath(t *testing.T) {
|
||||||
|
// Base Price (what the seller wants to sell for)
|
||||||
|
basePrice := 100.0
|
||||||
|
|
||||||
|
// 1. Backend inflates by 6% for search/display
|
||||||
|
buyerFeeRate := 0.06
|
||||||
|
inflatedPrice := basePrice * (1 + buyerFeeRate) // 106.0
|
||||||
|
|
||||||
|
// 2. Buyer sees 12% fee in checkout, but math must stay at 106.0
|
||||||
|
// Visual Subtotal = 106.0 / 1.12 = 94.6428...
|
||||||
|
visualSubtotal := inflatedPrice / 1.12
|
||||||
|
visualFee := inflatedPrice - visualSubtotal
|
||||||
|
|
||||||
|
// 3. Marketplace takes 12% of the TOTAL (inflated) price
|
||||||
|
marketplaceCommission := 0.12
|
||||||
|
totalMarketplaceFee := inflatedPrice * marketplaceCommission // 12.72
|
||||||
|
|
||||||
|
// 4. Seller Receivable = Inflated Price - Marketplace Fee
|
||||||
|
sellerReceivable := inflatedPrice - totalMarketplaceFee // 106.0 - 12.72 = 93.28
|
||||||
|
|
||||||
|
// 5. Seller perceives it as 6% commission on THEIR base price
|
||||||
|
perceivedCommission := basePrice * 0.06 // 6.0
|
||||||
|
expectedSellerReceivable := basePrice - perceivedCommission // 94.0
|
||||||
|
|
||||||
|
// ASSERTION: Does 93.28 == 94.0?
|
||||||
|
// Result: NO.
|
||||||
|
// To make the seller receive 94.0 (Base - 6%),
|
||||||
|
// and Marketplace receive 12.72 (which is 12% of inflated 106.0),
|
||||||
|
// The math needs adjustment.
|
||||||
|
|
||||||
|
t.Logf("Base: %.2f", basePrice)
|
||||||
|
t.Logf("Inflated (Buyer sees total): %.2f", inflatedPrice)
|
||||||
|
t.Logf("Marketplace Fee (12%% of inflated): %.2f", totalMarketplaceFee)
|
||||||
|
t.Logf("Seller Net: %.2f", sellerReceivable)
|
||||||
|
t.Logf("Target Seller Net (Base - 6%%): %.2f", expectedSellerReceivable)
|
||||||
|
|
||||||
|
if math.Abs(sellerReceivable-expectedSellerReceivable) > 0.01 {
|
||||||
|
t.Errorf("Math mismatch! Seller receives %.2f but expected %.2f", sellerReceivable, expectedSellerReceivable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -115,6 +115,12 @@ func (s *Service) SearchProducts(ctx context.Context, filter domain.ProductSearc
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust displayed stock by subtracting reservations
|
||||||
|
// In production, the Repo query itself would handle this for better performance
|
||||||
|
// for i := range products {
|
||||||
|
// // This is a simplified adjustment.
|
||||||
|
// }
|
||||||
|
|
||||||
return &domain.ProductSearchPage{Products: products, Total: total, Page: page, PageSize: pageSize}, nil
|
return &domain.ProductSearchPage{Products: products, Total: total, Page: page, PageSize: pageSize}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,8 @@ type Repository interface {
|
||||||
GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error)
|
GetAddress(ctx context.Context, id uuid.UUID) (*domain.Address, error)
|
||||||
UpdateAddress(ctx context.Context, address *domain.Address) error
|
UpdateAddress(ctx context.Context, address *domain.Address) error
|
||||||
DeleteAddress(ctx context.Context, id uuid.UUID) error
|
DeleteAddress(ctx context.Context, id uuid.UUID) error
|
||||||
|
GeocodeAllAddresses(ctx context.Context) (int, error)
|
||||||
|
StartStockCleanupWorker(ctx context.Context)
|
||||||
|
|
||||||
ListManufacturers(ctx context.Context) ([]string, error)
|
ListManufacturers(ctx context.Context) ([]string, error)
|
||||||
ListCategories(ctx context.Context) ([]string, error)
|
ListCategories(ctx context.Context) ([]string, error)
|
||||||
|
|
@ -154,3 +156,4 @@ func NewService(
|
||||||
func (s *Service) GetNotificationService() notifications.NotificationService {
|
func (s *Service) GetNotificationService() notifications.NotificationService {
|
||||||
return s.notify
|
return s.notify
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
container_name: sim-db-dev
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: '123'
|
|
||||||
POSTGRES_DB: saveinmed
|
|
||||||
ports:
|
|
||||||
- '55432:5432'
|
|
||||||
volumes:
|
|
||||||
- sim-db-dev-data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres -d saveinmed"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
backend:
|
|
||||||
image: cosmtrek/air
|
|
||||||
container_name: sim-backend-dev
|
|
||||||
working_dir: /app
|
|
||||||
ports:
|
|
||||||
- "8522:8522"
|
|
||||||
environment:
|
|
||||||
- DB_URL=postgres://postgres:123@db:5432/saveinmed?sslmode=disable
|
|
||||||
- PORT=8522
|
|
||||||
volumes:
|
|
||||||
- ./backend:/app
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
image: node:22-alpine
|
|
||||||
container_name: sim-frontend-dev
|
|
||||||
working_dir: /app
|
|
||||||
ports:
|
|
||||||
- "3001:3001"
|
|
||||||
environment:
|
|
||||||
- NEXT_PUBLIC_API_URL=https://sim.rede5.com.br/api
|
|
||||||
- NODE_ENV=development
|
|
||||||
- PORT=3001
|
|
||||||
volumes:
|
|
||||||
- ./frontend:/app
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
command: sh -c 'npm install --silent && npm run dev'
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
sim-db-dev-data:
|
|
||||||
Loading…
Reference in a new issue