265 lines
8.5 KiB
Go
265 lines
8.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/muyuqingfeng/iloom/purchaser-service/internal/model"
|
|
)
|
|
|
|
type ProductRepo struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewProductRepo(db *sql.DB) *ProductRepo {
|
|
return &ProductRepo{db: db}
|
|
}
|
|
|
|
func (r *ProductRepo) List(ctx context.Context, companyID string) ([]model.Product, error) {
|
|
query := `SELECT id, company_id, product_name, fabric_code, color, color_code,
|
|
weight, warp_weight, weft_weight, total_weight, yarn_usage_per_meter,
|
|
production_price, total_stock, raw_fabric_meters, raw_fabric_rolls,
|
|
image_url, product_type, yarn_types, yarn_ratios, created_at, updated_at
|
|
FROM products WHERE company_id = ? ORDER BY created_at DESC`
|
|
|
|
rows, err := r.db.QueryContext(ctx, query, companyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list products: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var products []model.Product
|
|
for rows.Next() {
|
|
var p model.Product
|
|
if err := rows.Scan(
|
|
&p.ID, &p.CompanyID, &p.ProductName, &p.FabricCode, &p.Color, &p.ColorCode,
|
|
&p.Weight, &p.WarpWeight, &p.WeftWeight, &p.TotalWeight,
|
|
&p.YarnUsagePerMeter, &p.ProductionPrice,
|
|
&p.TotalStock, &p.RawFabricMeters, &p.RawFabricRolls,
|
|
&p.ImageURL, &p.ProductType, &p.YarnTypes, &p.YarnRatios,
|
|
&p.CreatedAt, &p.UpdatedAt,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("scan product: %w", err)
|
|
}
|
|
products = append(products, p)
|
|
}
|
|
return products, nil
|
|
}
|
|
|
|
func (r *ProductRepo) Create(ctx context.Context, p *model.Product) error {
|
|
query := `INSERT INTO products
|
|
(id, company_id, product_name, fabric_code, color, color_code,
|
|
weight, warp_weight, weft_weight, total_weight, yarn_usage_per_meter,
|
|
production_price, total_stock, raw_fabric_meters, raw_fabric_rolls,
|
|
image_url, product_type, yarn_types, yarn_ratios, created_at, updated_at)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
|
|
_, err := r.db.ExecContext(ctx, query,
|
|
p.ID, p.CompanyID, p.ProductName, p.FabricCode, p.Color, p.ColorCode,
|
|
p.Weight, p.WarpWeight, p.WeftWeight, p.TotalWeight,
|
|
p.YarnUsagePerMeter, p.ProductionPrice,
|
|
p.TotalStock, p.RawFabricMeters, p.RawFabricRolls,
|
|
p.ImageURL, p.ProductType, p.YarnTypes, p.YarnRatios,
|
|
p.CreatedAt, p.UpdatedAt,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("insert product: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) Update(ctx context.Context, p *model.Product) error {
|
|
query := `UPDATE products SET
|
|
product_name = ?, fabric_code = ?, color = ?, color_code = ?,
|
|
weight = ?, warp_weight = ?, weft_weight = ?, total_weight = ?,
|
|
yarn_usage_per_meter = ?, production_price = ?,
|
|
image_url = ?, product_type = ?, yarn_types = ?, yarn_ratios = ?, updated_at = ?
|
|
WHERE id = ?`
|
|
_, err := r.db.ExecContext(ctx, query,
|
|
p.ProductName, p.FabricCode, p.Color, p.ColorCode,
|
|
p.Weight, p.WarpWeight, p.WeftWeight, p.TotalWeight,
|
|
p.YarnUsagePerMeter, p.ProductionPrice,
|
|
p.ImageURL, p.ProductType, p.YarnTypes, p.YarnRatios, time.Now(),
|
|
p.ID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update product: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) Delete(ctx context.Context, id, companyID string) error {
|
|
_, err := r.db.ExecContext(ctx,
|
|
`DELETE FROM products WHERE id = ? AND company_id = ?`,
|
|
id, companyID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("delete product: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) Inbound(ctx context.Context, tx *sql.Tx, rec *model.ProductInventoryRecord) error {
|
|
query := `INSERT INTO ilm_product_inventory
|
|
(id, product_id, batch_no, rolls, meters, notes, operator_id, company_id, warehouse_id, created_at)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?)`
|
|
_, err := tx.ExecContext(ctx, query,
|
|
rec.ID, rec.ProductID, rec.BatchNo, rec.Rolls, rec.Meters,
|
|
rec.Notes, rec.OperatorID, rec.CompanyID, rec.WarehouseID, rec.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("insert inbound record: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) UpdateStock(ctx context.Context, tx *sql.Tx, productID string, deltaMeters float64, deltaRolls int) error {
|
|
query := `UPDATE products SET
|
|
total_stock = total_stock + ?,
|
|
raw_fabric_meters = raw_fabric_meters + ?,
|
|
raw_fabric_rolls = raw_fabric_rolls + ?,
|
|
updated_at = ?
|
|
WHERE id = ?`
|
|
_, err := tx.ExecContext(ctx, query, deltaMeters, deltaMeters, deltaRolls, time.Now(), productID)
|
|
if err != nil {
|
|
return fmt.Errorf("update stock: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) Outbound(ctx context.Context, tx *sql.Tx, rec *model.ProductOutboundRecord) error {
|
|
query := `INSERT INTO ilm_product_outbound
|
|
(id, product_id, batch_no, rolls, meters, outbound_type, notes,
|
|
operator_id, company_id, recipient_company_id, recipient_company_name,
|
|
source_batch_id, washing_plan_id, created_at)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
|
|
_, err := tx.ExecContext(ctx, query,
|
|
rec.ID, rec.ProductID, rec.BatchNo, rec.Rolls, rec.Meters,
|
|
rec.OutboundType, rec.Notes,
|
|
rec.OperatorID, rec.CompanyID,
|
|
rec.RecipientCompanyID, rec.RecipientCompanyName,
|
|
rec.SourceBatchID, rec.WashingPlanID, rec.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("insert outbound record: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) Records(ctx context.Context, productID string) ([]model.ProductInventoryRecord, error) {
|
|
query := `SELECT id, product_id, batch_no, rolls, meters, notes,
|
|
operator_id, company_id, warehouse_id, created_at
|
|
FROM ilm_product_inventory
|
|
WHERE product_id = ? ORDER BY created_at DESC`
|
|
rows, err := r.db.QueryContext(ctx, query, productID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list records: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var records []model.ProductInventoryRecord
|
|
for rows.Next() {
|
|
var rec model.ProductInventoryRecord
|
|
if err := rows.Scan(
|
|
&rec.ID, &rec.ProductID, &rec.BatchNo, &rec.Rolls, &rec.Meters,
|
|
&rec.Notes, &rec.OperatorID, &rec.CompanyID, &rec.WarehouseID, &rec.CreatedAt,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("scan record: %w", err)
|
|
}
|
|
records = append(records, rec)
|
|
}
|
|
return records, nil
|
|
}
|
|
|
|
func (r *ProductRepo) UpdatePrice(ctx context.Context, tx *sql.Tx, productID string, newPrice float64) error {
|
|
_, err := tx.ExecContext(ctx,
|
|
`UPDATE products SET production_price = ?, updated_at = ? WHERE id = ?`,
|
|
newPrice, time.Now(), productID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update price: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) GetPrice(ctx context.Context, productID string) (*float64, error) {
|
|
var price *float64
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT production_price FROM products WHERE id = ?`, productID,
|
|
).Scan(&price)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get price: %w", err)
|
|
}
|
|
return price, nil
|
|
}
|
|
|
|
func (r *ProductRepo) InsertPriceHistory(ctx context.Context, tx *sql.Tx, productID string, oldPrice *float64, newPrice float64, reason, changedBy string) error {
|
|
id := uuid.New().String()
|
|
var reasonPtr *string
|
|
if reason != "" {
|
|
reasonPtr = &reason
|
|
}
|
|
var changedByPtr *string
|
|
if changedBy != "" {
|
|
changedByPtr = &changedBy
|
|
}
|
|
_, err := tx.ExecContext(ctx,
|
|
`INSERT INTO ilm_product_price_history
|
|
(id, product_id, old_price, new_price, reason, changed_by, created_at)
|
|
VALUES (?,?,?,?,?,?,?)`,
|
|
id, productID, oldPrice, newPrice, reasonPtr, changedByPtr, time.Now(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("insert price history: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ProductRepo) PriceHistory(ctx context.Context, productID string) ([]model.ProductPriceHistory, error) {
|
|
query := `SELECT id, product_id, old_price, new_price, reason, changed_by, created_at
|
|
FROM ilm_product_price_history
|
|
WHERE product_id = ? ORDER BY created_at DESC`
|
|
rows, err := r.db.QueryContext(ctx, query, productID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list price history: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var history []model.ProductPriceHistory
|
|
for rows.Next() {
|
|
var h model.ProductPriceHistory
|
|
if err := rows.Scan(
|
|
&h.ID, &h.ProductID, &h.OldPrice, &h.NewPrice,
|
|
&h.Reason, &h.ChangedBy, &h.CreatedAt,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("scan price history: %w", err)
|
|
}
|
|
history = append(history, h)
|
|
}
|
|
return history, nil
|
|
}
|
|
|
|
func (r *ProductRepo) Count(ctx context.Context, companyID string) (int, error) {
|
|
var count int
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT COUNT(*) FROM products WHERE company_id = ?`, companyID,
|
|
).Scan(&count)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("count products: %w", err)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func (r *ProductRepo) TotalStock(ctx context.Context, companyID string) (float64, error) {
|
|
var total float64
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT COALESCE(SUM(total_stock), 0) FROM products WHERE company_id = ?`, companyID,
|
|
).Scan(&total)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("total stock: %w", err)
|
|
}
|
|
return total, nil
|
|
}
|