Files
superport_v2/lib/features/approvals/domain/entities/approval.dart

303 lines
7.4 KiB
Dart

/// 결재(Approval) 엔티티
///
/// - 결재 기본 정보와 현재 단계, 라인(단계/이력) 데이터를 포함한다.
/// - presentation/data 레이어 구현에 의존하지 않는다.
class Approval {
Approval({
this.id,
required this.approvalNo,
required this.transactionNo,
required this.status,
this.currentStep,
required this.requester,
required this.requestedAt,
this.decidedAt,
this.note,
this.isActive = true,
this.isDeleted = false,
this.steps = const [],
this.histories = const [],
this.createdAt,
this.updatedAt,
});
final int? id;
final String approvalNo;
final String transactionNo;
final ApprovalStatus status;
final ApprovalStep? currentStep;
final ApprovalRequester requester;
final DateTime requestedAt;
final DateTime? decidedAt;
final String? note;
final bool isActive;
final bool isDeleted;
final List<ApprovalStep> steps;
final List<ApprovalHistory> histories;
final DateTime? createdAt;
final DateTime? updatedAt;
Approval copyWith({
int? id,
String? approvalNo,
String? transactionNo,
ApprovalStatus? status,
ApprovalStep? currentStep,
ApprovalRequester? requester,
DateTime? requestedAt,
DateTime? decidedAt,
String? note,
bool? isActive,
bool? isDeleted,
List<ApprovalStep>? steps,
List<ApprovalHistory>? histories,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return Approval(
id: id ?? this.id,
approvalNo: approvalNo ?? this.approvalNo,
transactionNo: transactionNo ?? this.transactionNo,
status: status ?? this.status,
currentStep: currentStep ?? this.currentStep,
requester: requester ?? this.requester,
requestedAt: requestedAt ?? this.requestedAt,
decidedAt: decidedAt ?? this.decidedAt,
note: note ?? this.note,
isActive: isActive ?? this.isActive,
isDeleted: isDeleted ?? this.isDeleted,
steps: steps ?? this.steps,
histories: histories ?? this.histories,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
}
class ApprovalStatus {
ApprovalStatus({required this.id, required this.name, this.color});
final int id;
final String name;
final String? color;
}
class ApprovalRequester {
ApprovalRequester({
required this.id,
required this.employeeNo,
required this.name,
});
final int id;
final String employeeNo;
final String name;
}
class ApprovalStep {
ApprovalStep({
this.id,
required this.stepOrder,
required this.approver,
required this.status,
required this.assignedAt,
this.decidedAt,
this.note,
this.isDeleted = false,
});
final int? id;
final int stepOrder;
final ApprovalApprover approver;
final ApprovalStatus status;
final DateTime assignedAt;
final DateTime? decidedAt;
final String? note;
final bool isDeleted;
ApprovalStep copyWith({
int? id,
int? stepOrder,
ApprovalApprover? approver,
ApprovalStatus? status,
DateTime? assignedAt,
DateTime? decidedAt,
String? note,
bool? isDeleted,
}) {
return ApprovalStep(
id: id ?? this.id,
stepOrder: stepOrder ?? this.stepOrder,
approver: approver ?? this.approver,
status: status ?? this.status,
assignedAt: assignedAt ?? this.assignedAt,
decidedAt: decidedAt ?? this.decidedAt,
note: note ?? this.note,
isDeleted: isDeleted ?? this.isDeleted,
);
}
}
class ApprovalApprover {
ApprovalApprover({
required this.id,
required this.employeeNo,
required this.name,
});
final int id;
final String employeeNo;
final String name;
}
class ApprovalHistory {
ApprovalHistory({
this.id,
required this.action,
this.fromStatus,
required this.toStatus,
required this.approver,
required this.actionAt,
this.note,
});
final int? id;
final ApprovalAction action;
final ApprovalStatus? fromStatus;
final ApprovalStatus toStatus;
final ApprovalApprover approver;
final DateTime actionAt;
final String? note;
}
class ApprovalAction {
ApprovalAction({required this.id, required this.name});
final int id;
final String name;
}
/// 결재 단계에서 수행 가능한 행위 타입
///
/// - API `approval_actions` 테이블의 대표 코드와 매핑된다.
/// - UI에서는 이 타입을 기반으로 표시 라벨과 권한을 제어한다.
enum ApprovalStepActionType { approve, reject, comment }
extension ApprovalStepActionTypeX on ApprovalStepActionType {
/// API 호출 시 사용되는 행위 코드
String get code {
switch (this) {
case ApprovalStepActionType.approve:
return 'approve';
case ApprovalStepActionType.reject:
return 'reject';
case ApprovalStepActionType.comment:
return 'comment';
}
}
}
/// 결재 생성 입력 모델
/// 결재 신규 생성 입력 모델
///
/// - 트랜잭션, 결재번호, 상태, 상신자 정보를 백엔드 계약에 맞춰 전달한다.
class ApprovalCreateInput {
ApprovalCreateInput({
required this.transactionId,
required this.approvalStatusId,
required this.requestedById,
this.note,
});
final int transactionId;
final int approvalStatusId;
final int requestedById;
final String? note;
Map<String, dynamic> toPayload() {
final trimmedNote = note?.trim();
return {
'transaction_id': transactionId,
'approval_status_id': approvalStatusId,
'requested_by_id': requestedById,
if (trimmedNote != null && trimmedNote.isNotEmpty) 'note': trimmedNote,
};
}
}
/// 결재 기본 정보 수정 입력 모델
///
/// - 상태/비고 변경 시 결재 식별자를 포함해 패치를 수행한다.
class ApprovalUpdateInput {
ApprovalUpdateInput({required this.id, this.approvalStatusId, this.note});
final int id;
final int? approvalStatusId;
final String? note;
Map<String, dynamic> toPayload() {
final trimmedNote = note?.trim();
return {
'id': id,
if (approvalStatusId != null) 'approval_status_id': approvalStatusId,
if (trimmedNote != null && trimmedNote.isNotEmpty) 'note': trimmedNote,
};
}
}
/// 결재 단계 행위 입력 모델
///
/// - `POST /approval-steps/{id}/actions` 요청 바디를 구성한다.
/// - `note`는 비고가 있을 때만 포함한다.
class ApprovalStepActionInput {
ApprovalStepActionInput({
required this.stepId,
required this.actionId,
this.note,
});
final int stepId;
final int actionId;
final String? note;
Map<String, dynamic> toPayload() {
return {
'id': stepId,
'approval_action_id': actionId,
if (note != null && note!.trim().isNotEmpty) 'note': note,
};
}
}
/// 결재 단계를 일괄 등록/재배치하기 위한 입력 모델
class ApprovalStepAssignmentInput {
ApprovalStepAssignmentInput({required this.approvalId, required this.steps});
final int approvalId;
final List<ApprovalStepAssignmentItem> steps;
Map<String, dynamic> toPayload() {
return {'id': approvalId, 'steps': steps.map((e) => e.toJson()).toList()};
}
}
class ApprovalStepAssignmentItem {
ApprovalStepAssignmentItem({
required this.stepOrder,
required this.approverId,
this.note,
});
final int stepOrder;
final int approverId;
final String? note;
Map<String, dynamic> toJson() {
return {
'step_order': stepOrder,
'approver_id': approverId,
if (note != null && note!.trim().isNotEmpty) 'note': note,
};
}
}