172 lines
6.1 KiB
Go
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(*),
|
||
|
|
SUM(CASE WHEN status IN ('pending', 'washing') THEN 1 ELSE 0 END),
|
||
|
|
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END)
|
||
|
|
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
|
||
|
|
}
|