2026-07-04 02:34:20 +00:00

172 lines
6.1 KiB
Go

package repository
import (
"context"
"database/sql"
"fmt"
"github.com/muyuqingfeng/iloom/washing-service/internal/model"
)
type PlanRepo struct {
db *sql.DB
}
func NewPlanRepo(db *sql.DB) *PlanRepo {
return &PlanRepo{db: db}
}
func (r *PlanRepo) List(ctx context.Context, companyID string) ([]model.WashingPlan, error) {
query := `SELECT wp.id, wp.plan_code, wp.company_id, wp.product_id,
wp.washing_factory_id, wp.planned_meters, wp.washing_price,
wp.estimated_shrinkage_rate, wp.estimated_washed_meters, wp.estimated_total_cost,
wp.actual_shrinkage_rate, wp.actual_washed_meters, wp.actual_total_cost,
wp.washing_date, wp.status, wp.notes, wp.created_by, wp.created_at, wp.updated_at,
COALESCE(p.product_name, '') AS product_name
FROM ilm_washing_plan wp
LEFT JOIN ilm_product p ON wp.product_id = p.id
WHERE wp.washing_factory_id = ?
ORDER BY wp.created_at DESC`
rows, err := r.db.QueryContext(ctx, query, companyID)
if err != nil {
return nil, fmt.Errorf("list washing plans: %w", err)
}
defer rows.Close()
return scanPlans(rows)
}
func (r *PlanRepo) GetByID(ctx context.Context, id string) (*model.WashingPlan, error) {
query := `SELECT wp.id, wp.plan_code, wp.company_id, wp.product_id,
wp.washing_factory_id, wp.planned_meters, wp.washing_price,
wp.estimated_shrinkage_rate, wp.estimated_washed_meters, wp.estimated_total_cost,
wp.actual_shrinkage_rate, wp.actual_washed_meters, wp.actual_total_cost,
wp.washing_date, wp.status, wp.notes, wp.created_by, wp.created_at, wp.updated_at,
COALESCE(p.product_name, '') AS product_name
FROM ilm_washing_plan wp
LEFT JOIN ilm_product p ON wp.product_id = p.id
WHERE wp.id = ?`
plan := &model.WashingPlan{}
err := r.db.QueryRowContext(ctx, query, id).Scan(
&plan.ID, &plan.PlanCode, &plan.CompanyID, &plan.ProductID,
&plan.WashingFactoryID, &plan.PlannedMeters, &plan.WashingPrice,
&plan.EstimatedShrinkageRate, &plan.EstimatedWashedMeters, &plan.EstimatedTotalCost,
&plan.ActualShrinkageRate, &plan.ActualWashedMeters, &plan.ActualTotalCost,
&plan.WashingDate, &plan.Status, &plan.Notes, &plan.CreatedBy,
&plan.CreatedAt, &plan.UpdatedAt,
&plan.ProductName,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, fmt.Errorf("get washing plan by id: %w", err)
}
return plan, nil
}
func (r *PlanRepo) UpdateStatus(ctx context.Context, id, status string) error {
query := `UPDATE ilm_washing_plan SET status = ?, updated_at = NOW() WHERE id = ?`
result, err := r.db.ExecContext(ctx, query, status, id)
if err != nil {
return fmt.Errorf("update plan status: %w", err)
}
affected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("rows affected: %w", err)
}
if affected == 0 {
return fmt.Errorf("washing plan not found")
}
return nil
}
func (r *PlanRepo) UpdateActuals(ctx context.Context, tx *sql.Tx, id string, shrinkage, meters, cost float64) error {
query := `UPDATE ilm_washing_plan
SET actual_shrinkage_rate = ?, actual_washed_meters = ?, actual_total_cost = ?,
status = 'completed', washing_date = NOW(), updated_at = NOW()
WHERE id = ?`
_, err := tx.ExecContext(ctx, query, shrinkage, meters, cost, id)
if err != nil {
return fmt.Errorf("update plan actuals: %w", err)
}
return nil
}
func (r *PlanRepo) Pending(ctx context.Context, companyID string) ([]model.WashingPlan, error) {
query := `SELECT wp.id, wp.plan_code, wp.company_id, wp.product_id,
wp.washing_factory_id, wp.planned_meters, wp.washing_price,
wp.estimated_shrinkage_rate, wp.estimated_washed_meters, wp.estimated_total_cost,
wp.actual_shrinkage_rate, wp.actual_washed_meters, wp.actual_total_cost,
wp.washing_date, wp.status, wp.notes, wp.created_by, wp.created_at, wp.updated_at,
COALESCE(p.product_name, '') AS product_name
FROM ilm_washing_plan wp
LEFT JOIN ilm_product p ON wp.product_id = p.id
WHERE wp.washing_factory_id = ? AND wp.status IN ('pending', 'washing')
ORDER BY wp.created_at DESC`
rows, err := r.db.QueryContext(ctx, query, companyID)
if err != nil {
return nil, fmt.Errorf("list pending plans: %w", err)
}
defer rows.Close()
return scanPlans(rows)
}
func (r *PlanRepo) Completed(ctx context.Context, companyID string) ([]model.WashingPlan, error) {
query := `SELECT wp.id, wp.plan_code, wp.company_id, wp.product_id,
wp.washing_factory_id, wp.planned_meters, wp.washing_price,
wp.estimated_shrinkage_rate, wp.estimated_washed_meters, wp.estimated_total_cost,
wp.actual_shrinkage_rate, wp.actual_washed_meters, wp.actual_total_cost,
wp.washing_date, wp.status, wp.notes, wp.created_by, wp.created_at, wp.updated_at,
COALESCE(p.product_name, '') AS product_name
FROM ilm_washing_plan wp
LEFT JOIN ilm_product p ON wp.product_id = p.id
WHERE wp.washing_factory_id = ? AND wp.status = 'completed'
ORDER BY wp.washing_date DESC`
rows, err := r.db.QueryContext(ctx, query, companyID)
if err != nil {
return nil, fmt.Errorf("list completed plans: %w", err)
}
defer rows.Close()
return scanPlans(rows)
}
func (r *PlanRepo) CountByStatus(ctx context.Context, companyID string) (total, pending, completed int, err error) {
query := `SELECT
COUNT(*),
COALESCE(SUM(CASE WHEN status IN ('pending', 'washing') THEN 1 ELSE 0 END), 0),
COALESCE(SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END), 0)
FROM ilm_washing_plan WHERE washing_factory_id = ?`
err = r.db.QueryRowContext(ctx, query, companyID).Scan(&total, &pending, &completed)
if err != nil {
return 0, 0, 0, fmt.Errorf("count by status: %w", err)
}
return
}
func scanPlans(rows *sql.Rows) ([]model.WashingPlan, error) {
var plans []model.WashingPlan
for rows.Next() {
var plan model.WashingPlan
if err := rows.Scan(
&plan.ID, &plan.PlanCode, &plan.CompanyID, &plan.ProductID,
&plan.WashingFactoryID, &plan.PlannedMeters, &plan.WashingPrice,
&plan.EstimatedShrinkageRate, &plan.EstimatedWashedMeters, &plan.EstimatedTotalCost,
&plan.ActualShrinkageRate, &plan.ActualWashedMeters, &plan.ActualTotalCost,
&plan.WashingDate, &plan.Status, &plan.Notes, &plan.CreatedBy,
&plan.CreatedAt, &plan.UpdatedAt,
&plan.ProductName,
); err != nil {
return nil, fmt.Errorf("scan washing plan: %w", err)
}
plans = append(plans, plan)
}
return plans, nil
}