290 lines
8.3 KiB
Go
290 lines
8.3 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
airrescuechecklist "wucher/internal/domain/air_rescue_checklist"
|
|
)
|
|
|
|
type AirRescuerChecklistService struct {
|
|
repo airrescuechecklist.Repository
|
|
}
|
|
|
|
func NewAirRescuerChecklistService(repo airrescuechecklist.Repository) *AirRescuerChecklistService {
|
|
return &AirRescuerChecklistService{repo: repo}
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) CreateBulk(ctx context.Context, rows []airrescuechecklist.ChecklistCreateInput) error {
|
|
if len(rows) == 0 {
|
|
return nil
|
|
}
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
for i := range rows {
|
|
header := &rows[i].Checklist
|
|
if header.Position <= 0 {
|
|
nextPos, err := txRepo.NextChecklistPosition(ctx, header.HEMSBaseID, header.ScopeCode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
header.Position = nextPos
|
|
}
|
|
if err := txRepo.CreateChecklist(ctx, header); err != nil {
|
|
return err
|
|
}
|
|
|
|
var nextItemPos int
|
|
itemNextInitialized := false
|
|
for j := range rows[i].Items {
|
|
item := &rows[i].Items[j]
|
|
item.ChecklistID = append([]byte(nil), header.ID...)
|
|
if item.Position <= 0 {
|
|
if !itemNextInitialized {
|
|
pos, err := txRepo.NextChecklistItemPosition(ctx, header.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nextItemPos = pos
|
|
itemNextInitialized = true
|
|
}
|
|
item.Position = nextItemPos
|
|
nextItemPos++
|
|
}
|
|
if err := txRepo.CreateChecklistItem(ctx, item); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) UpdateChecklist(ctx context.Context, row *airrescuechecklist.AirRescuerChecklist) error {
|
|
if row == nil {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
row.Position = normalizeChecklistPosition(row.Position)
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, row.ID); err != nil {
|
|
return err
|
|
}
|
|
return txRepo.UpdateChecklist(ctx, row)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) UpdateChecklistWithNewItems(
|
|
ctx context.Context,
|
|
row *airrescuechecklist.AirRescuerChecklist,
|
|
newItems []airrescuechecklist.AirRescuerChecklistItem,
|
|
) error {
|
|
if row == nil && len(newItems) == 0 {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
|
|
checklistID := []byte(nil)
|
|
if row != nil {
|
|
row.Position = normalizeChecklistPosition(row.Position)
|
|
checklistID = append([]byte(nil), row.ID...)
|
|
}
|
|
if len(checklistID) == 0 && len(newItems) > 0 {
|
|
checklistID = append([]byte(nil), newItems[0].ChecklistID...)
|
|
}
|
|
if len(checklistID) == 0 {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, checklistID); err != nil {
|
|
return err
|
|
}
|
|
|
|
if row != nil {
|
|
if err := txRepo.UpdateChecklist(ctx, row); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if len(newItems) == 0 {
|
|
return nil
|
|
}
|
|
nextItemPos := 0
|
|
itemNextInitialized := false
|
|
for i := range newItems {
|
|
newItems[i].ChecklistID = append([]byte(nil), checklistID...)
|
|
if newItems[i].Position <= 0 {
|
|
if !itemNextInitialized {
|
|
pos, err := txRepo.NextChecklistItemPosition(ctx, checklistID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nextItemPos = pos
|
|
itemNextInitialized = true
|
|
}
|
|
newItems[i].Position = nextItemPos
|
|
nextItemPos++
|
|
}
|
|
}
|
|
return txRepo.CreateChecklistItems(ctx, newItems)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) DeleteChecklist(ctx context.Context, id []byte, deletedBy []byte) error {
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
if err := txRepo.SoftDeleteChecklist(ctx, id, deletedBy); err != nil {
|
|
return err
|
|
}
|
|
return txRepo.SoftDeleteItemsByChecklistID(ctx, id, deletedBy)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) CreateChecklistItem(ctx context.Context, row *airrescuechecklist.AirRescuerChecklistItem) error {
|
|
if row == nil {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, row.ChecklistID); err != nil {
|
|
return err
|
|
}
|
|
if row.Position <= 0 {
|
|
nextPos, err := txRepo.NextChecklistItemPosition(ctx, row.ChecklistID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row.Position = nextPos
|
|
}
|
|
return txRepo.CreateChecklistItem(ctx, row)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) CreateChecklistItems(ctx context.Context, checklistID []byte, rows []airrescuechecklist.AirRescuerChecklistItem) error {
|
|
if len(rows) == 0 {
|
|
return nil
|
|
}
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, checklistID); err != nil {
|
|
return err
|
|
}
|
|
nextItemPos := 0
|
|
itemNextInitialized := false
|
|
for i := range rows {
|
|
rows[i].ChecklistID = append([]byte(nil), checklistID...)
|
|
if rows[i].Position <= 0 {
|
|
if !itemNextInitialized {
|
|
pos, err := txRepo.NextChecklistItemPosition(ctx, checklistID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nextItemPos = pos
|
|
itemNextInitialized = true
|
|
}
|
|
rows[i].Position = nextItemPos
|
|
nextItemPos++
|
|
}
|
|
}
|
|
return txRepo.CreateChecklistItems(ctx, rows)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) ReorderChecklistItems(
|
|
ctx context.Context,
|
|
checklistID []byte,
|
|
rows []airrescuechecklist.ChecklistItemReorderInput,
|
|
updatedBy []byte,
|
|
) error {
|
|
if len(rows) == 0 {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistByID(ctx, checklistID); err != nil {
|
|
return err
|
|
}
|
|
|
|
seenItemIDs := make(map[string]struct{}, len(rows))
|
|
for i := range rows {
|
|
itemID := rows[i].ID
|
|
if len(itemID) == 0 {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
itemKey := string(itemID)
|
|
if _, exists := seenItemIDs[itemKey]; exists {
|
|
return errors.New("duplicate item_uuid in reorder payload")
|
|
}
|
|
seenItemIDs[itemKey] = struct{}{}
|
|
|
|
current, err := txRepo.LockChecklistItemByID(ctx, itemID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !bytes.Equal(current.ChecklistID, checklistID) {
|
|
return gorm.ErrRecordNotFound
|
|
}
|
|
|
|
if err := txRepo.UpdateChecklistItem(ctx, &airrescuechecklist.AirRescuerChecklistItem{
|
|
ID: append([]byte(nil), itemID...),
|
|
Name: current.Name,
|
|
Position: normalizeChecklistPosition(rows[i].Position),
|
|
UpdatedBy: append([]byte(nil), updatedBy...),
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) UpdateChecklistItem(ctx context.Context, row *airrescuechecklist.AirRescuerChecklistItem) error {
|
|
if row == nil {
|
|
return gorm.ErrInvalidData
|
|
}
|
|
row.Position = normalizeChecklistPosition(row.Position)
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistItemByID(ctx, row.ID); err != nil {
|
|
return err
|
|
}
|
|
return txRepo.UpdateChecklistItem(ctx, row)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) DeleteChecklistItem(ctx context.Context, id []byte, deletedBy []byte) error {
|
|
return s.repo.InTx(ctx, func(txRepo airrescuechecklist.TxRepository) error {
|
|
if _, err := txRepo.LockChecklistItemByID(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
return txRepo.SoftDeleteChecklistItem(ctx, id, deletedBy)
|
|
})
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) GetChecklistByID(ctx context.Context, id []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
|
|
return s.repo.GetChecklistByID(ctx, id)
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) GetChecklistItemByID(ctx context.Context, id []byte) (*airrescuechecklist.ChecklistItemView, error) {
|
|
return s.repo.GetChecklistItemByID(ctx, id)
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) ListChecklistHeaders(ctx context.Context, filter airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
|
|
return s.repo.ListChecklistHeaders(ctx, filter)
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) ListChecklistItemsByChecklistIDs(ctx context.Context, checklistIDs [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
|
|
return s.repo.ListChecklistItemsByChecklistIDs(ctx, checklistIDs)
|
|
}
|
|
|
|
func (s *AirRescuerChecklistService) ListHEMSBases(ctx context.Context, filter airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
|
|
return s.repo.ListHEMSBases(ctx, filter)
|
|
}
|
|
|
|
func normalizeChecklistPosition(v int) int {
|
|
if v <= 0 {
|
|
return 1
|
|
}
|
|
return v
|
|
}
|