package repository import ( "context" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "shop/internal/models" ) const orderSelect = ` SELECT id, user_id, guest_name, guest_email, guest_phone, address, total, status, COALESCE(payment_method, 'cod'), COALESCE(heleket_uuid, ''), COALESCE(heleket_order_id, ''), COALESCE(heleket_payment_url, ''), COALESCE(heleket_payment_status, ''), created_at FROM orders ` type OrderRepository struct { pool *pgxpool.Pool } func NewOrderRepository(pool *pgxpool.Pool) *OrderRepository { return &OrderRepository{pool: pool} } func scanOrder(row pgx.Row) (models.Order, error) { var o models.Order err := row.Scan( &o.ID, &o.UserID, &o.GuestName, &o.GuestEmail, &o.GuestPhone, &o.Address, &o.Total, &o.Status, &o.PaymentMethod, &o.HeleketUUID, &o.HeleketOrderID, &o.HeleketPaymentURL, &o.HeleketPaymentStatus, &o.CreatedAt, ) return o, err } func (r *OrderRepository) Create(ctx context.Context, order *models.Order, items []models.CartItem) error { tx, err := r.pool.Begin(ctx) if err != nil { return err } defer tx.Rollback(ctx) status := order.Status if status == "" { status = "pending" } paymentMethod := order.PaymentMethod if paymentMethod == "" { paymentMethod = "cod" } err = tx.QueryRow(ctx, ` INSERT INTO orders (user_id, guest_name, guest_email, guest_phone, address, total, status, payment_method) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id, created_at `, order.UserID, order.GuestName, order.GuestEmail, order.GuestPhone, order.Address, order.Total, status, paymentMethod, ).Scan(&order.ID, &order.CreatedAt) if err != nil { return err } for _, item := range items { _, err = tx.Exec(ctx, ` INSERT INTO order_items (order_id, product_id, product_name, price, quantity) VALUES ($1, $2, $3, $4, $5) `, order.ID, item.ProductID, item.Product.Name, item.Product.EffectivePrice(), item.Quantity) if err != nil { return err } } return tx.Commit(ctx) } func (r *OrderRepository) UpdateHeleketPayment(ctx context.Context, orderID int, uuid, externalID, paymentURL, paymentStatus string) error { _, err := r.pool.Exec(ctx, ` UPDATE orders SET heleket_uuid = $1, heleket_order_id = $2, heleket_payment_url = $3, heleket_payment_status = $4 WHERE id = $5 `, uuid, externalID, paymentURL, paymentStatus, orderID) return err } func (r *OrderRepository) UpdateHeleketStatus(ctx context.Context, orderID int, paymentStatus, orderStatus string) error { _, err := r.pool.Exec(ctx, ` UPDATE orders SET heleket_payment_status = $1, status = $2 WHERE id = $3 `, paymentStatus, orderStatus, orderID) return err } func (r *OrderRepository) GetByHeleketOrderID(ctx context.Context, externalID string) (models.Order, error) { row := r.pool.QueryRow(ctx, orderSelect+` WHERE heleket_order_id = $1`, externalID) o, err := scanOrder(row) if err != nil { return models.Order{}, err } o.Items, err = r.items(ctx, o.ID) return o, err } func (r *OrderRepository) ByUser(ctx context.Context, userID int) ([]models.Order, error) { rows, err := r.pool.Query(ctx, orderSelect+` WHERE user_id = $1 ORDER BY created_at DESC`, userID) if err != nil { return nil, err } defer rows.Close() var orders []models.Order for rows.Next() { o, err := scanOrder(rows) if err != nil { return nil, err } o.Items, err = r.items(ctx, o.ID) if err != nil { return nil, err } orders = append(orders, o) } return orders, rows.Err() } func (r *OrderRepository) items(ctx context.Context, orderID int) ([]models.OrderItem, error) { rows, err := r.pool.Query(ctx, ` SELECT id, order_id, product_id, product_name, price, quantity FROM order_items WHERE order_id = $1 `, orderID) if err != nil { return nil, err } defer rows.Close() var items []models.OrderItem for rows.Next() { var i models.OrderItem if err := rows.Scan(&i.ID, &i.OrderID, &i.ProductID, &i.ProductName, &i.Price, &i.Quantity); err != nil { return nil, err } items = append(items, i) } return items, rows.Err() } func (r *OrderRepository) All(ctx context.Context, limit int) ([]models.Order, error) { rows, err := r.pool.Query(ctx, orderSelect+` ORDER BY created_at DESC LIMIT $1`, limit) if err != nil { return nil, err } defer rows.Close() return r.collectOrders(ctx, rows) } func (r *OrderRepository) GetByID(ctx context.Context, id int) (models.Order, error) { row := r.pool.QueryRow(ctx, orderSelect+` WHERE id = $1`, id) o, err := scanOrder(row) if err != nil { return models.Order{}, err } o.Items, err = r.items(ctx, o.ID) return o, err } func (r *OrderRepository) UpdateStatus(ctx context.Context, id int, status string) error { tag, err := r.pool.Exec(ctx, `UPDATE orders SET status = $1 WHERE id = $2`, status, id) if err != nil { return err } if tag.RowsAffected() == 0 { return pgx.ErrNoRows } return nil } func (r *OrderRepository) Count(ctx context.Context) (int, error) { var n int err := r.pool.QueryRow(ctx, `SELECT COUNT(*) FROM orders`).Scan(&n) return n, err } func (r *OrderRepository) collectOrders(ctx context.Context, rows pgx.Rows) ([]models.Order, error) { var orders []models.Order for rows.Next() { o, err := scanOrder(rows) if err != nil { return nil, err } o.Items, err = r.items(ctx, o.ID) if err != nil { return nil, err } orders = append(orders, o) } return orders, rows.Err() }