package model import ( "context" "fmt" "time" "quyun/app/requests" "quyun/database/fields" "quyun/database/table" . "github.com/go-jet/jet/v2/postgres" "github.com/pkg/errors" "github.com/samber/lo" ) var ordersUpdateExcludeColumns = []Column{ table.Orders.OrderNo, table.Orders.Price, table.Orders.Discount, table.Orders.SubOrderNo, table.Orders.PostID, table.Orders.UserID, } func (m *Orders) Update(ctx context.Context) error { m.UpdatedAt = time.Now() stmt := table.Orders.UPDATE(table.Orders.MutableColumns.Except(table.Orders.OrderNo, table.Orders.Price, table.Orders.Discount, table.Orders.SubOrderNo, table.Orders.PostID, table.Orders.UserID)).SET(m).WHERE(table.Orders.ID.EQ(Int(m.ID))).RETURNING(table.Orders.AllColumns) m.log().WithField("func", "Update").Info(stmt.DebugSql()) if err := stmt.QueryContext(ctx, db, m); err != nil { m.log().WithField("func", "Update").Errorf("error updating Orders item: %v", err) return err } m.log().WithField("func", "Update").Infof("Orders item updated successfully") return nil } // BuildConditionWithKey builds the WHERE clause for order queries func (m *Orders) 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 *Orders) 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 *Orders) 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 []Orders = make([]Orders, 0) if err := stmt.QueryContext(ctx, db, &orders); err != nil { m.log().Errorf("error querying orders: %v", err) return nil, err } postsMap, err := PostsModel().GetPostsMapByIDs(ctx, lo.Map(orders, func(order Orders, _ int) int64 { return order.PostID })) if err != nil { m.log().Errorf("error getting posts map: %v", err) return nil, err } userMap, err := UsersModel().GetUsersMapByIDs(ctx, lo.Map(orders, func(order 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 { Orders PostTitle string `json:"post_title"` Username string `json:"username"` } return &requests.Pager{ Items: lo.Map(orders, func(order 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 (o *Orders) CreateFromUserPostID(ctx context.Context, userId, postId int64) (*Orders, error) { post, err := PostsModel().GetByID(ctx, postId) if err != nil { return nil, errors.Wrap(err, "failed to get post") } m := &Orders{} m.CreatedAt = time.Now() m.UpdatedAt = time.Now() m.Status = fields.OrderStatusPending m.OrderNo = fmt.Sprintf("%s", time.Now().Format("20060102150405")) m.SubOrderNo = m.OrderNo m.UserID = userId m.PostID = postId m.Meta = fields.ToJson(fields.OrderMeta{}) m.Price = post.Price m.Discount = post.Discount tbl := table.Orders stmt := tbl.INSERT(tbl.MutableColumns).MODEL(m).RETURNING(tbl.AllColumns) o.log().Infof("sql: %s", stmt.DebugSql()) if err := stmt.QueryContext(ctx, db, o); err != nil { o.log().Errorf("error creating order: %v", err) return nil, err } return o, nil } func (m *Orders) SetMeta(ctx context.Context, metaFunc func(fields.OrderMeta) fields.OrderMeta) error { tbl := table.Orders stmt := tbl. UPDATE(tbl.Meta). SET(fields.ToJson(metaFunc(m.Meta.Data))). WHERE( tbl.ID.EQ(Int64(m.ID)), ). RETURNING(tbl.AllColumns) m.log().Infof("sql: %s", stmt.DebugSql()) if err := stmt.QueryContext(ctx, db, m); err != nil { m.log().Errorf("error set order meta: %v", err) return err } return nil } func (m *Orders) SetStatus(ctx context.Context, status fields.OrderStatus) error { tbl := table.Orders stmt := tbl. UPDATE(tbl.Status). SET(status). WHERE( tbl.ID.EQ(Int64(m.ID)), ). RETURNING(tbl.AllColumns) m.log().Infof("sql: %s", stmt.DebugSql()) if err := stmt.QueryContext(ctx, db, m); err != nil { m.log().Errorf("error set order status: %v", err) return err } return nil } // SumAmount func (m *Orders) 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 *Orders) GetByOrderNo(ctx context.Context, orderNo string) (*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 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 } // SetTransactionID func (m *Orders) SetTransactionID(ctx context.Context, transactionID string) error { tbl := table.Orders stmt := tbl. UPDATE(tbl.TransactionID). SET(String(transactionID)). WHERE( tbl.ID.EQ(Int64(m.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 }