package models import ( "context" "fmt" "time" "quyun/app/requests" "quyun/database/fields" "quyun/database/schemas/public/model" "quyun/database/schemas/public/table" . "github.com/go-jet/jet/v2/postgres" "github.com/pkg/errors" "github.com/samber/lo" "github.com/sirupsen/logrus" ) // @provider type ordersModel struct { log *logrus.Entry `inject:"false"` } func (m *ordersModel) Prepare() error { m.log = logrus.WithField("model", "ordersModel") return nil } // GetByID returns an order by ID func (m *ordersModel) GetByID(ctx context.Context, id int64) (*model.Orders, error) { tbl := table.Orders stmt := tbl. SELECT(tbl.AllColumns). WHERE( tbl.ID.EQ(Int64(id)), ) m.log.Infof("sql: %s", stmt.DebugSql()) var order model.Orders err := stmt.QueryContext(ctx, db, &order) if err != nil { m.log.Errorf("error querying order by ID: %v", err) return nil, err } return &order, nil } // BuildConditionWithKey builds the WHERE clause for order queries func (m *ordersModel) BuildConditionWithKey(orderNumber *string, userID *int64) BoolExpression { tbl := table.Orders cond := Bool(true) if orderNumber != nil && *orderNumber != "" { cond = cond.AND( tbl.OrderNo.LIKE(String("%" + *orderNumber + "%")), ) } if userID != nil { cond = cond.AND( tbl.UserID.EQ(Int(*userID)), ) } return cond } // countByCondition counts orders matching the given condition func (m *ordersModel) countByCondition(ctx context.Context, expr BoolExpression) (int64, error) { var cnt struct { Cnt int64 } tbl := table.Orders stmt := SELECT(COUNT(tbl.ID).AS("cnt")).FROM(tbl).WHERE(expr) m.log.Infof("sql: %s", stmt.DebugSql()) err := stmt.QueryContext(ctx, db, &cnt) if err != nil { m.log.Errorf("error counting orders: %v", err) return 0, err } return cnt.Cnt, nil } // List returns a paginated list of orders func (m *ordersModel) List(ctx context.Context, pagination *requests.Pagination, cond BoolExpression) (*requests.Pager, error) { pagination.Format() tbl := table.Orders stmt := tbl. SELECT(tbl.AllColumns). WHERE(cond). ORDER_BY(tbl.ID.DESC()). LIMIT(pagination.Limit). OFFSET(pagination.Offset) m.log.Infof("sql: %s", stmt.DebugSql()) var orders []model.Orders = make([]model.Orders, 0) if err := stmt.QueryContext(ctx, db, &orders); err != nil { m.log.Errorf("error querying orders: %v", err) return nil, err } postsMap, err := Posts.GetPostsMapByIDs(ctx, lo.Map(orders, func(order model.Orders, _ int) int64 { return order.PostID })) if err != nil { m.log.Errorf("error getting posts map: %v", err) return nil, err } userMap, err := Users.GetUsersMapByIDs(ctx, lo.Map(orders, func(order model.Orders, _ int) int64 { return order.UserID })) if err != nil { m.log.Errorf("error getting users map: %v", err) return nil, err } count, err := m.countByCondition(ctx, cond) if err != nil { m.log.Errorf("error getting order count: %v", err) return nil, err } type orderItem struct { model.Orders PostTitle string `json:"post_title"` Username string `json:"username"` } return &requests.Pager{ Items: lo.Map(orders, func(order model.Orders, _ int) *orderItem { item := &orderItem{ Orders: order, } if post, ok := postsMap[order.PostID]; ok { item.PostTitle = post.Title } if user, ok := userMap[order.UserID]; ok { item.Username = user.Username } return item }), Total: count, Pagination: *pagination, }, nil } // Create creates a new order func (m *ordersModel) Create(ctx context.Context, userId, postId int64) (*model.Orders, error) { post, err := Posts.GetByID(ctx, postId) if err != nil { return nil, errors.Wrap(err, "failed to get post") } model := &model.Orders{} model.CreatedAt = time.Now() model.UpdatedAt = time.Now() model.Status = fields.OrderStatusPending model.OrderNo = fmt.Sprintf("%s", time.Now().Format("20060102150405")) model.SubOrderNo = model.OrderNo model.UserID = userId model.PostID = postId model.Meta = fields.ToJson(fields.OrderMeta{}) model.Price = post.Price model.Discount = post.Discount tbl := table.Orders stmt := tbl.INSERT(tbl.MutableColumns).MODEL(model) m.log.Infof("sql: %s", stmt.DebugSql()) if _, err := stmt.ExecContext(ctx, db); err != nil { m.log.Errorf("error creating order: %v", err) return nil, err } return model, nil } // DeleteByID soft deletes an order by ID func (m *ordersModel) SetStatus(ctx context.Context, orderNo string, status fields.OrderStatus) error { tbl := table.Orders stmt := tbl. UPDATE(tbl.Status). SET(status). WHERE( tbl.OrderNo.EQ(String(orderNo)), ) m.log.Infof("sql: %s", stmt.DebugSql()) if _, err := stmt.ExecContext(ctx, db); err != nil { m.log.Errorf("error set order status: %v", err) return err } return nil } // Count func (m *ordersModel) Count(ctx context.Context, cond BoolExpression) (int64, error) { tbl := table.Orders stmt := SELECT(COUNT(tbl.ID).AS("cnt")).FROM(tbl).WHERE(cond) m.log.Infof("sql: %s", stmt.DebugSql()) var cnt struct { Cnt int64 } err := stmt.QueryContext(ctx, db, &cnt) if err != nil { m.log.Errorf("error counting orders: %v", err) return 0, err } return cnt.Cnt, nil } // SumAmount func (m *ordersModel) SumAmount(ctx context.Context) (int64, error) { tbl := table.Orders stmt := SELECT(SUM(tbl.Price).AS("cnt")).FROM(tbl).WHERE( tbl.Status.EQ(Int(int64(fields.OrderStatusCompleted))), ) m.log.Infof("sql: %s", stmt.DebugSql()) var cnt struct { Cnt int64 } err := stmt.QueryContext(ctx, db, &cnt) if err != nil { m.log.Errorf("error summing order amount: %v", err) return 0, err } return cnt.Cnt, nil } // GetByOrderNo func (m *ordersModel) GetByOrderNo(ctx context.Context, orderNo string) (*model.Orders, error) { tbl := table.Orders stmt := tbl. SELECT(tbl.AllColumns). WHERE( tbl.OrderNo.EQ(String(orderNo)), ) m.log.Infof("sql: %s", stmt.DebugSql()) var order model.Orders err := stmt.QueryContext(ctx, db, &order) if err != nil { m.log.Errorf("error querying order by orderNo: %v", err) return nil, err } return &order, nil } // SetTranscationID func (m *ordersModel) SetTranscationID(ctx context.Context, id int64, transactionID string) error { tbl := table.Orders stmt := tbl. UPDATE(tbl.TransactionID). SET(String(transactionID)). WHERE( tbl.ID.EQ(Int64(id)), ) m.log.Infof("sql: %s", stmt.DebugSql()) if _, err := stmt.ExecContext(ctx, db); err != nil { m.log.Errorf("error set order transaction ID: %v", err) return err } return nil } // Update func (m *ordersModel) Update(ctx context.Context, order *model.Orders) error { tbl := table.Orders stmt := tbl. UPDATE( tbl.MutableColumns.Except( tbl.OrderNo, tbl.Price, tbl.Discount, tbl.SubOrderNo, tbl.PostID, tbl.UserID, ), ). MODEL(order). WHERE( tbl.ID.EQ(Int64(order.ID)), ) m.log.Infof("sql: %s", stmt.DebugSql()) if _, err := stmt.ExecContext(ctx, db); err != nil { m.log.Errorf("error updating order: %v", err) return err } return nil }