250 lines
6.9 KiB
Go
250 lines
6.9 KiB
Go
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, m.status
|
||
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, &item.MaterialStatus)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
order.Items = append(order.Items, item)
|
||
}
|
||
|
||
// 状态不落库:outbound_orders 没有 status 列,统一在这里给出。引入状态机时改为真实读写。
|
||
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
|
||
}
|