Go workspace (go.work) with 5 microservices + shared library: - gateway (8080), auth-service (8081), purchaser-service (8082) - textile-service (8083), washing-service (8084) - shared: proto definitions, common packages Infrastructure: docker-compose for local dev, K8s manifests for K3s cluster deployment (mysql/redis/etcd + traefik ingress). Frontend (iloom-flatten) added as git submodule. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type PaymentWithDetails struct {
|
|
ID string `json:"id"`
|
|
WashingPlanID string `json:"washing_plan_id"`
|
|
CompanyID string `json:"company_id"`
|
|
Amount float64 `json:"amount"`
|
|
Status string `json:"status"`
|
|
Notes *string `json:"notes,omitempty"`
|
|
PaidAt *time.Time `json:"paid_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
PlanCode string `json:"plan_code"`
|
|
FromCompanyName string `json:"from_company_name"`
|
|
}
|
|
|
|
type PaymentRepo struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewPaymentRepo(db *sql.DB) *PaymentRepo {
|
|
return &PaymentRepo{db: db}
|
|
}
|
|
|
|
func (r *PaymentRepo) ListByCompany(ctx context.Context, companyID string) ([]PaymentWithDetails, error) {
|
|
query := `SELECT wpy.id, wpy.washing_plan_id, wpy.company_id, wpy.amount,
|
|
wpy.status, wpy.notes, wpy.paid_at, wpy.created_at, wpy.updated_at,
|
|
COALESCE(wp.plan_code, '') AS plan_code,
|
|
COALESCE(c.name, '') AS from_company_name
|
|
FROM ilm_washing_payment wpy
|
|
LEFT JOIN ilm_washing_plan wp ON wpy.washing_plan_id = wp.id
|
|
LEFT JOIN ilm_company c ON wp.company_id = c.id
|
|
WHERE wpy.company_id = ?
|
|
ORDER BY wpy.created_at DESC`
|
|
|
|
rows, err := r.db.QueryContext(ctx, query, companyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list payments: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var payments []PaymentWithDetails
|
|
for rows.Next() {
|
|
var p PaymentWithDetails
|
|
if err := rows.Scan(
|
|
&p.ID, &p.WashingPlanID, &p.CompanyID, &p.Amount,
|
|
&p.Status, &p.Notes, &p.PaidAt, &p.CreatedAt, &p.UpdatedAt,
|
|
&p.PlanCode, &p.FromCompanyName,
|
|
); err != nil {
|
|
return nil, fmt.Errorf("scan payment: %w", err)
|
|
}
|
|
payments = append(payments, p)
|
|
}
|
|
return payments, nil
|
|
}
|
|
|
|
func (r *PaymentRepo) Confirm(ctx context.Context, paymentID string) error {
|
|
query := `UPDATE ilm_washing_payment
|
|
SET status = 'confirmed', paid_at = NOW(), updated_at = NOW()
|
|
WHERE id = ?`
|
|
result, err := r.db.ExecContext(ctx, query, paymentID)
|
|
if err != nil {
|
|
return fmt.Errorf("confirm payment: %w", err)
|
|
}
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
return fmt.Errorf("rows affected: %w", err)
|
|
}
|
|
if affected == 0 {
|
|
return fmt.Errorf("payment not found")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *PaymentRepo) CountPending(ctx context.Context, companyID string) (int, error) {
|
|
var count int
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT COUNT(*) FROM ilm_washing_payment WHERE company_id = ? AND status = 'pending'`,
|
|
companyID,
|
|
).Scan(&count)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("count pending payments: %w", err)
|
|
}
|
|
return count, nil
|
|
}
|