Files
fm_be/internal/repository/mysql/fm_report_repo.go
2026-07-16 22:16:45 +07:00

284 lines
8.6 KiB
Go

package mysql
import (
"context"
"errors"
"strings"
mysqldriver "github.com/go-sql-driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
fmreport "wucher/internal/domain/fm_report"
)
type FMReportRepository struct {
db *gorm.DB
}
func NewFMReportRepository(db *gorm.DB) *FMReportRepository {
return &FMReportRepository{db: db}
}
func (r *FMReportRepository) MaxReportSeqByHelicopter(ctx context.Context, helicopterID []byte) (int, error) {
if len(helicopterID) != 16 {
return 0, nil
}
var maxSeq *int
err := r.db.WithContext(ctx).
Model(&fmreport.Report{}).
Where("helicopter_id = ? AND report_code IS NOT NULL AND report_code <> '' AND deleted_at IS NULL", helicopterID).
Select("MAX(CAST(SUBSTRING_INDEX(report_code, '-', -1) AS UNSIGNED))").
Scan(&maxSeq).Error
if err != nil {
return 0, err
}
if maxSeq == nil {
return 0, nil
}
return *maxSeq, nil
}
func (r *FMReportRepository) SetReportCode(ctx context.Context, id []byte, code string) error {
if len(id) != 16 {
return nil
}
err := r.db.WithContext(ctx).
Model(&fmreport.Report{}).
Where("id = ?", id).
Update("report_code", code).Error
if isDuplicateKeyError(err) {
return fmreport.ErrDuplicateReportCode
}
return err
}
func isDuplicateKeyError(err error) bool {
if err == nil {
return false
}
if errors.Is(err, gorm.ErrDuplicatedKey) {
return true
}
var mysqlErr *mysqldriver.MySQLError
return errors.As(err, &mysqlErr) && mysqlErr.Number == 1062
}
func (r *FMReportRepository) Upsert(ctx context.Context, row *fmreport.Report) error {
if row == nil {
return nil
}
return r.db.WithContext(ctx).
Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "flight_id"}},
DoUpdates: clause.AssignmentColumns([]string{
"takeover_id",
"flight_inspection_id",
"engine1_gpc_n1",
"engine1_ptc_n2",
"engine2_gpc_n1",
"engine2_ptc_n2",
"completed_at",
"completed_by",
"updated_at",
"updated_by",
}),
}).Create(row).Error
}
func (r *FMReportRepository) GetByFlightID(ctx context.Context, flightID []byte) (*fmreport.Report, error) {
var row fmreport.Report
err := r.db.WithContext(ctx).
Where("flight_id = ? AND deleted_at IS NULL", flightID).
First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return &row, err
}
func (r *FMReportRepository) List(ctx context.Context, filter fmreport.ListFilter, limit, offset int) ([]fmreport.Report, int64, error) {
rows := make([]fmreport.Report, 0)
var total int64
base := r.db.WithContext(ctx).
Model(&fmreport.Report{}).
Joins("JOIN flights f ON f.id = fm_reports.flight_id AND f.deleted_at IS NULL").
Where("fm_reports.deleted_at IS NULL")
if len(filter.FlightID) == 16 {
base = base.Where("fm_reports.flight_id = ?", filter.FlightID)
}
if len(filter.TakeoverID) == 16 {
base = base.Where("fm_reports.takeover_id = ?", filter.TakeoverID)
}
if len(filter.FlightInspectionID) == 16 {
base = base.Where("fm_reports.flight_inspection_id = ?", filter.FlightInspectionID)
}
if strings.TrimSpace(filter.FlightDate) != "" {
base = base.Where("f.date = ?", strings.TrimSpace(filter.FlightDate))
}
if strings.TrimSpace(filter.FromDate) != "" {
base = base.Where("f.date >= ?", strings.TrimSpace(filter.FromDate))
}
if strings.TrimSpace(filter.ToDate) != "" {
base = base.Where("f.date <= ?", strings.TrimSpace(filter.ToDate))
}
if strings.TrimSpace(filter.HelicopterIdentifier) != "" {
base = base.
Joins("LEFT JOIN takeover_acs ta ON ta.id = fm_reports.takeover_id AND ta.deleted_at IS NULL").
Joins("LEFT JOIN reserve_acs ra ON ra.id = ta.reserve_ac_id AND ra.deleted_at IS NULL").
Joins("LEFT JOIN helicopters heli ON heli.id = ra.helicopter_id AND heli.deleted_at IS NULL").
Where("heli.identifier LIKE ?", "%"+strings.TrimSpace(filter.HelicopterIdentifier)+"%")
}
if strings.TrimSpace(filter.PilotName) != "" {
like := "%" + strings.TrimSpace(filter.PilotName) + "%"
base = base.Where(
"EXISTS (SELECT 1 FROM takeover_roster_crews trc LEFT JOIN users trc_u ON trc_u.id = trc.user_id WHERE trc.takeover_id = fm_reports.takeover_id AND trc.role_code = 'PILOT' AND trc.deleted_at IS NULL AND (trc.name_label LIKE ? OR CONCAT(trc_u.first_name, ' ', trc_u.last_name) LIKE ?))",
like, like,
)
}
if strings.TrimSpace(filter.Search) != "" {
like := "%" + strings.TrimSpace(filter.Search) + "%"
base = base.Where("(f.mission_code LIKE ? OR COALESCE(fm_reports.engine1_gpc_n1, '') LIKE ? OR COALESCE(fm_reports.engine1_ptc_n2, '') LIKE ? OR COALESCE(fm_reports.engine2_gpc_n1, '') LIKE ? OR COALESCE(fm_reports.engine2_ptc_n2, '') LIKE ?)", like, like, like, like, like)
}
if filter.HasEngine1GpcN1 != nil {
if *filter.HasEngine1GpcN1 {
base = base.Where("fm_reports.engine1_gpc_n1 IS NOT NULL AND fm_reports.engine1_gpc_n1 <> ''")
} else {
base = base.Where("(fm_reports.engine1_gpc_n1 IS NULL OR fm_reports.engine1_gpc_n1 = '')")
}
}
if filter.HasEngine1PtcN2 != nil {
if *filter.HasEngine1PtcN2 {
base = base.Where("fm_reports.engine1_ptc_n2 IS NOT NULL AND fm_reports.engine1_ptc_n2 <> ''")
} else {
base = base.Where("(fm_reports.engine1_ptc_n2 IS NULL OR fm_reports.engine1_ptc_n2 = '')")
}
}
if filter.HasEngine2GpcN1 != nil {
if *filter.HasEngine2GpcN1 {
base = base.Where("fm_reports.engine2_gpc_n1 IS NOT NULL AND fm_reports.engine2_gpc_n1 <> ''")
} else {
base = base.Where("(fm_reports.engine2_gpc_n1 IS NULL OR fm_reports.engine2_gpc_n1 = '')")
}
}
if filter.HasEngine2PtcN2 != nil {
if *filter.HasEngine2PtcN2 {
base = base.Where("fm_reports.engine2_ptc_n2 IS NOT NULL AND fm_reports.engine2_ptc_n2 <> ''")
} else {
base = base.Where("(fm_reports.engine2_ptc_n2 IS NULL OR fm_reports.engine2_ptc_n2 = '')")
}
}
if err := base.Count(&total).Error; err != nil {
return nil, 0, err
}
query := base.Order(fmReportListSortClause(filter.Sort))
if limit > 0 {
query = query.Limit(limit).Offset(offset)
}
if err := query.Find(&rows).Error; err != nil {
return nil, 0, err
}
return rows, total, nil
}
func fmReportListSortClause(sort string) string {
switch strings.ToLower(strings.TrimSpace(sort)) {
case "flight_id":
return "fm_reports.flight_id ASC"
case "-flight_id":
return "fm_reports.flight_id DESC"
case "takeover_id":
return "fm_reports.takeover_id ASC"
case "-takeover_id":
return "fm_reports.takeover_id DESC"
case "flight_inspection_id":
return "fm_reports.flight_inspection_id ASC"
case "-flight_inspection_id":
return "fm_reports.flight_inspection_id DESC"
case "flight_date":
return "f.date ASC"
case "-flight_date":
return "f.date DESC"
case "created_at":
return "fm_reports.created_at ASC"
case "-created_at":
return "fm_reports.created_at DESC"
case "updated_at":
return "fm_reports.updated_at ASC"
case "-updated_at":
return "fm_reports.updated_at DESC"
case "engine1_gpc_n1":
return "fm_reports.engine1_gpc_n1 ASC"
case "-engine1_gpc_n1":
return "fm_reports.engine1_gpc_n1 DESC"
case "engine1_ptc_n2":
return "fm_reports.engine1_ptc_n2 ASC"
case "-engine1_ptc_n2":
return "fm_reports.engine1_ptc_n2 DESC"
case "engine2_gpc_n1":
return "fm_reports.engine2_gpc_n1 ASC"
case "-engine2_gpc_n1":
return "fm_reports.engine2_gpc_n1 DESC"
case "engine2_ptc_n2":
return "fm_reports.engine2_ptc_n2 ASC"
case "-engine2_ptc_n2":
return "fm_reports.engine2_ptc_n2 DESC"
default:
return "f.date DESC, fm_reports.created_at DESC"
}
}
func (r *FMReportRepository) GetByID(ctx context.Context, id []byte) (*fmreport.Report, error) {
if len(id) != 16 {
return nil, nil
}
var row fmreport.Report
err := r.db.WithContext(ctx).
Where("id = ? AND deleted_at IS NULL", id).
First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return &row, err
}
func (r *FMReportRepository) Delete(ctx context.Context, id, deletedBy []byte) error {
if len(id) != 16 {
return nil
}
return r.db.WithContext(ctx).
Model(&fmreport.Report{}).
Where("id = ? AND deleted_at IS NULL", id).
Updates(map[string]any{
"deleted_at": gorm.Expr("NOW(3)"),
"deleted_by": deletedBy,
"updated_by": deletedBy,
}).Error
}
func (r *FMReportRepository) CreateFleetHistory(ctx context.Context, row *fmreport.FleetHistory) error {
if row == nil {
return nil
}
return r.db.WithContext(ctx).
Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "fm_report_id"}},
DoNothing: true,
}).Create(row).Error
}
func (r *FMReportRepository) GetFleetHistoryByReportID(ctx context.Context, reportID []byte) (*fmreport.FleetHistory, error) {
var row fmreport.FleetHistory
err := r.db.WithContext(ctx).
Where("fm_report_id = ?", reportID).
First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return &row, err
}