material_manage_system/internal/repository/material.go

249 lines
7.5 KiB
Go

package repository
import (
"database/sql"
"fmt"
"strings"
"github.com/wmms/wmms/internal/model"
"github.com/wmms/wmms/pkg/database"
)
// BeginTx starts a new database transaction
func BeginTx() (*sql.Tx, error) {
return database.DB.Begin()
}
type MaterialRepo struct{}
func NewMaterialRepo() *MaterialRepo {
return &MaterialRepo{}
}
func (r *MaterialRepo) IsActiveSubcategory(categoryID, organizationID int64) (bool, error) {
query := `SELECT EXISTS(
SELECT 1 FROM material_categories
WHERE id = ? AND organization_id = ? AND parent_id IS NOT NULL AND status = 'active'
)`
var exists bool
err := database.DB.QueryRow(query, categoryID, organizationID).Scan(&exists)
return exists, err
}
func (r *MaterialRepo) Create(m *model.Material) error {
query := `INSERT INTO materials (organization_id, material_code, name, material_image, spec, manufacturer_model,
category_id, base_unit_id, unit, status, version)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
result, err := database.DB.Exec(query, m.OrganizationID, m.MaterialCode, m.Name, m.MaterialImage, m.Spec,
m.ManufacturerModel, m.CategoryID, m.BaseUnitID, m.Unit, m.Status, m.Version)
if err != nil {
if strings.Contains(err.Error(), "Duplicate entry") {
return fmt.Errorf("material code already exists")
}
return err
}
id, err := result.LastInsertId()
if err != nil {
return err
}
m.ID = id
return r.GetByID(m.ID, m)
}
func (r *MaterialRepo) GetByID(id int64, m *model.Material) error {
query := `SELECT id, organization_id, material_code, name, material_image, spec, manufacturer_model,
category_id, base_unit_id, unit, status, version, created_at, updated_at
FROM materials WHERE id = ?`
var materialImage sql.NullString
var manufacturerModel sql.NullString
err := database.DB.QueryRow(query, id).Scan(&m.ID, &m.OrganizationID, &m.MaterialCode, &m.Name, &materialImage,
&m.Spec, &manufacturerModel, &m.CategoryID, &m.BaseUnitID,
&m.Unit, &m.Status, &m.Version, &m.CreatedAt, &m.UpdatedAt)
if err != nil {
return err
}
if materialImage.Valid {
m.MaterialImage = &materialImage.String
}
if manufacturerModel.Valid {
m.ManufacturerModel = &manufacturerModel.String
}
return nil
}
func (r *MaterialRepo) GetByMaterialCode(code string) (*model.Material, error) {
m := &model.Material{}
query := `SELECT id, organization_id, material_code, name, material_image, spec, manufacturer_model,
category_id, base_unit_id, unit, status, version, created_at, updated_at
FROM materials WHERE material_code = ?`
var materialImage sql.NullString
var manufacturerModel sql.NullString
err := database.DB.QueryRow(query, code).Scan(&m.ID, &m.OrganizationID, &m.MaterialCode, &m.Name, &materialImage,
&m.Spec, &manufacturerModel, &m.CategoryID, &m.BaseUnitID,
&m.Unit, &m.Status, &m.Version, &m.CreatedAt, &m.UpdatedAt)
if err != nil {
return nil, err
}
if materialImage.Valid {
m.MaterialImage = &materialImage.String
}
if manufacturerModel.Valid {
m.ManufacturerModel = &manufacturerModel.String
}
return m, nil
}
func (r *MaterialRepo) List(search, category string, limit, offset int) ([]model.Material, int64, error) {
countQuery := `SELECT COUNT(*) FROM materials WHERE 1=1`
var countArgs []interface{}
if search != "" {
countQuery += ` AND (material_code LIKE ? OR name 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, organization_id, material_code, name, material_image, spec, manufacturer_model,
category_id, base_unit_id, unit, status, version, created_at, updated_at
FROM materials WHERE 1=1`
var args []interface{}
if search != "" {
query += ` AND (material_code LIKE ? OR name 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 materials []model.Material
for rows.Next() {
var m model.Material
var materialImage sql.NullString
var manufacturerModel sql.NullString
err := rows.Scan(&m.ID, &m.OrganizationID, &m.MaterialCode, &m.Name, &materialImage, &m.Spec,
&manufacturerModel, &m.CategoryID, &m.BaseUnitID,
&m.Unit, &m.Status, &m.Version, &m.CreatedAt, &m.UpdatedAt)
if err != nil {
return nil, 0, err
}
if materialImage.Valid {
m.MaterialImage = &materialImage.String
}
if manufacturerModel.Valid {
m.ManufacturerModel = &manufacturerModel.String
}
materials = append(materials, m)
}
return materials, total, nil
}
func (r *MaterialRepo) Update(id int64, req *model.UpdateMaterialRequest) error {
var sets []string
var args []interface{}
if req.Name != "" {
sets = append(sets, "name = ?")
args = append(args, req.Name)
}
if req.MaterialImage != nil && *req.MaterialImage != "" {
sets = append(sets, "material_image = ?")
args = append(args, *req.MaterialImage)
}
if req.Spec != "" {
sets = append(sets, "spec = ?")
args = append(args, req.Spec)
}
if req.ManufacturerModel != nil && *req.ManufacturerModel != "" {
sets = append(sets, "manufacturer_model = ?")
args = append(args, *req.ManufacturerModel)
}
if req.CategoryID != nil {
sets = append(sets, "category_id = ?")
args = append(args, req.CategoryID)
}
if req.Unit != "" {
sets = append(sets, "unit = ?")
args = append(args, req.Unit)
}
if req.BaseUnitID != nil {
sets = append(sets, "base_unit_id = ?")
args = append(args, req.BaseUnitID)
}
if req.Status != "" {
sets = append(sets, "status = ?")
args = append(args, req.Status)
}
sets = append(sets, "version = version + 1")
if len(sets) == 0 {
return nil
}
query := fmt.Sprintf("UPDATE materials SET %s WHERE id = ?", strings.Join(sets, ", "))
args = append(args, id)
_, err := database.DB.Exec(query, args...)
return err
}
func (r *MaterialRepo) Delete(id int64) error {
// Check if material has related records
var count int
// Check inbound_items
database.DB.QueryRow(`SELECT COUNT(*) FROM inbound_items WHERE material_id = ?`, id).Scan(&count)
if count > 0 {
return fmt.Errorf("该物料有入库记录,无法删除")
}
// Check outbound_items
database.DB.QueryRow(`SELECT COUNT(*) FROM outbound_items WHERE material_id = ?`, id).Scan(&count)
if count > 0 {
return fmt.Errorf("该物料有出库记录,无法删除")
}
// Check stock_logs
database.DB.QueryRow(`SELECT COUNT(*) FROM stock_logs WHERE material_id = ?`, id).Scan(&count)
if count > 0 {
return fmt.Errorf("该物料有库存流水记录,无法删除")
}
_, err := database.DB.Exec(`DELETE FROM materials WHERE id = ?`, id)
return err
}
func (r *MaterialRepo) Obsolete(id int64) error {
var nonZero int
if err := database.DB.QueryRow(`SELECT COUNT(*) FROM inventory_balances WHERE material_id = ? AND (on_hand <> 0 OR reserved <> 0 OR locked <> 0 OR in_transit <> 0)`, id).Scan(&nonZero); err != nil {
return err
}
if nonZero > 0 {
return fmt.Errorf("该物料仍有库存,无法作废")
}
_, err := database.DB.Exec(`UPDATE materials SET status = 'obsolete', version = version + 1 WHERE id = ?`, id)
return err
}
func (r *MaterialRepo) Restore(id int64) error {
result, err := database.DB.Exec(`UPDATE materials SET status = 'active', version = version + 1 WHERE id = ?`, id)
if err != nil {
return err
}
affected, _ := result.RowsAffected()
if affected == 0 {
return fmt.Errorf("物料不存在")
}
return nil
}