package repository import ( "database/sql" "time" "github.com/wmms/wmms/internal/model" "github.com/wmms/wmms/pkg/database" ) type OutboundRepo struct{} func NewOutboundRepo() *OutboundRepo { return &OutboundRepo{} } func (r *OutboundRepo) Create(order *model.OutboundOrder) error { return r.CreateTx(nil, order) } func (r *OutboundRepo) CreateTx(tx *sql.Tx, order *model.OutboundOrder) error { shouldCommit := false if tx == nil { var err error tx, err = database.DB.Begin() if err != nil { return err } shouldCommit = true } if shouldCommit { defer tx.Rollback() } query := `INSERT INTO outbound_orders (outbound_date, operator, handler, receiver, remark) VALUES (?, ?, ?, ?, ?)` result, err := tx.Exec(query, order.OutboundDate, order.Operator, order.Handler, order.Receiver, order.Remark) if err != nil { return err } orderID, err := result.LastInsertId() if err != nil { return err } order.ID = orderID order.OutboundNo = model.OrderNo("OUT", orderID) if _, err = tx.Exec(`UPDATE outbound_orders SET outbound_no = ? WHERE id = ?`, order.OutboundNo, orderID); err != nil { return err } for i := range order.Items { item := &order.Items[i] item.OutboundOrderID = orderID query := `INSERT INTO outbound_items (outbound_order_id, material_id, quantity) VALUES (?, ?, ?)` result, err := tx.Exec(query, orderID, item.MaterialID, item.Quantity) if err != nil { return err } itemID, err := result.LastInsertId() if err != nil { return err } item.ID = itemID } if shouldCommit { return tx.Commit() } return nil } func (r *OutboundRepo) GetByID(id int64) (*model.OutboundOrder, error) { order := &model.OutboundOrder{} query := `SELECT id, COALESCE(outbound_no, CONCAT('OUT-', LPAD(id, 8, '0'))), COALESCE(operator, ''), outbound_date, handler, receiver, COALESCE(remark, ''), created_at, updated_at FROM outbound_orders WHERE id = ?` err := database.DB.QueryRow(query, id).Scan(&order.ID, &order.OutboundNo, &order.Operator, &order.OutboundDate, &order.Handler, &order.Receiver, &order.Remark, &order.CreatedAt, &order.UpdatedAt) if err != nil { return nil, err } itemsQuery := `SELECT oi.id, oi.outbound_order_id, oi.material_id, oi.quantity, m.material_code, m.name FROM outbound_items oi JOIN materials m ON oi.material_id = m.id WHERE oi.outbound_order_id = ?` rows, err := database.DB.Query(itemsQuery, id) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var item model.OutboundItem err := rows.Scan(&item.ID, &item.OutboundOrderID, &item.MaterialID, &item.Quantity, &item.MaterialCode, &item.MaterialName) if err != nil { return nil, err } order.Items = append(order.Items, item) } order.Status = "completed" return order, nil } func (r *OutboundRepo) List(search string, limit, offset int) ([]model.OutboundOrder, int64, error) { countQuery := `SELECT COUNT(*) FROM outbound_orders WHERE 1=1` var countArgs []interface{} if search != "" { countQuery += ` AND (handler LIKE ? OR receiver LIKE ?)` searchPattern := "%" + search + "%" countArgs = append(countArgs, searchPattern, searchPattern) } var total int64 err := database.DB.QueryRow(countQuery, countArgs...).Scan(&total) if err != nil { return nil, 0, err } query := `SELECT id, COALESCE(outbound_no, CONCAT('OUT-', LPAD(id, 8, '0'))), COALESCE(operator, ''), outbound_date, handler, receiver, COALESCE(remark, ''), created_at, updated_at FROM outbound_orders WHERE 1=1` var args []interface{} if search != "" { query += ` AND (handler LIKE ? OR receiver LIKE ?)` searchPattern := "%" + search + "%" args = append(args, searchPattern, searchPattern) } query += ` ORDER BY id DESC LIMIT ? OFFSET ?` args = append(args, limit, offset) rows, err := database.DB.Query(query, args...) if err != nil { return nil, 0, err } defer rows.Close() var orders []model.OutboundOrder for rows.Next() { var order model.OutboundOrder err := rows.Scan(&order.ID, &order.OutboundNo, &order.Operator, &order.OutboundDate, &order.Handler, &order.Receiver, &order.Remark, &order.CreatedAt, &order.UpdatedAt) if err != nil { return nil, 0, err } order.Status = "completed" orders = append(orders, order) } return orders, total, nil } func (r *OutboundRepo) GetByMaterialID(materialID int64) ([]model.OutboundRecord, error) { query := `SELECT oi.id, oi.outbound_order_id, oo.handler, oo.receiver, oi.quantity, oi.created_at FROM outbound_items oi JOIN outbound_orders oo ON oi.outbound_order_id = oo.id WHERE oi.material_id = ? ORDER BY oi.id DESC` rows, err := database.DB.Query(query, materialID) if err != nil { return nil, err } defer rows.Close() var records []model.OutboundRecord for rows.Next() { var rec model.OutboundRecord err := rows.Scan(&rec.ID, &rec.OutboundID, &rec.Handler, &rec.Receiver, &rec.Quantity, &rec.CreatedAt) if err != nil { return nil, err } records = append(records, rec) } return records, nil } func (r *OutboundRepo) GetOutboundDate(id int64) (time.Time, error) { var outboundDate time.Time query := `SELECT outbound_date FROM outbound_orders WHERE id = ?` err := database.DB.QueryRow(query, id).Scan(&outboundDate) return outboundDate, err } func (r *OutboundRepo) Delete(id int64) error { return r.DeleteTx(nil, id) } func (r *OutboundRepo) DeleteTx(tx *sql.Tx, id int64) error { if tx == nil { var err error tx, err = database.DB.Begin() if err != nil { return err } defer tx.Rollback() _, err = tx.Exec(`DELETE FROM outbound_orders WHERE id = ?`, id) if err != nil { return err } return tx.Commit() } _, err := tx.Exec(`DELETE FROM outbound_orders WHERE id = ?`, id) return err } func (r *OutboundRepo) Update(id int64, req *model.UpdateOutboundRequest) error { return r.UpdateTx(nil, id, req) } func (r *OutboundRepo) UpdateTx(tx *sql.Tx, id int64, req *model.UpdateOutboundRequest) error { shouldCommit := false if tx == nil { var err error tx, err = database.DB.Begin() if err != nil { return err } shouldCommit = true } if shouldCommit { defer tx.Rollback() } // Update order basic fields query := `UPDATE outbound_orders SET operator = ?, handler = ?, receiver = ?, remark = ? WHERE id = ?` _, err := tx.Exec(query, req.Operator, req.Handler, req.Receiver, req.Remark, id) if err != nil { return err } // Delete old items _, err = tx.Exec(`DELETE FROM outbound_items WHERE outbound_order_id = ?`, id) if err != nil { return err } // Insert new items for i := range req.Items { item := &req.Items[i] query := `INSERT INTO outbound_items (outbound_order_id, material_id, quantity) VALUES (?, ?, ?)` _, err = tx.Exec(query, id, item.MaterialID, item.Quantity) if err != nil { return err } } if shouldCommit { return tx.Commit() } return nil }