refactor: 인벤토리 테이블 스펙과 도메인 계층 정비

This commit is contained in:
JiWoong Sul
2025-10-14 18:09:26 +09:00
parent 8d3b2c1e20
commit 1325109fba
32 changed files with 5550 additions and 290 deletions

View File

@@ -0,0 +1,54 @@
import '../../../../../core/common/utils/json_utils.dart';
import '../../domain/entities/lookup_item.dart';
/// 룩업 API 응답을 표현하는 DTO.
class LookupItemDto {
LookupItemDto({
required this.id,
required this.name,
this.code,
this.isDefault = false,
this.isActive = true,
this.note,
});
final int id;
final String? code;
final String name;
final bool isDefault;
final bool isActive;
final String? note;
factory LookupItemDto.fromJson(Map<String, dynamic> json) {
return LookupItemDto(
id: json['id'] as int? ?? 0,
code: json['code'] as String? ?? json['status_code'] as String?,
name:
json['name'] as String? ??
json['type_name'] as String? ??
json['status_name'] as String? ??
json['action_name'] as String? ??
'',
isDefault: (json['is_default'] as bool?) ?? false,
isActive: (json['is_active'] as bool?) ?? true,
note: json['note'] as String?,
);
}
LookupItem toEntity() => LookupItem(
id: id,
code: code,
name: name,
isDefault: isDefault,
isActive: isActive,
note: note,
);
static List<LookupItem> parseList(Map<String, dynamic>? json) {
final rawItems = JsonUtils.extractList(json, keys: const ['items']);
return rawItems
.map(LookupItemDto.fromJson)
.map((dto) => dto.toEntity())
.toList(growable: false);
}
}

View File

@@ -0,0 +1,63 @@
import 'package:dio/dio.dart';
import '../../../../../core/network/api_client.dart';
import '../../../../../core/network/api_routes.dart';
import '../../domain/entities/lookup_item.dart';
import '../../domain/repositories/inventory_lookup_repository.dart';
import '../dtos/lookup_item_dto.dart';
/// 인벤토리 공통 룩업 API 호출 구현체.
class InventoryLookupRepositoryRemote implements InventoryLookupRepository {
InventoryLookupRepositoryRemote({required ApiClient apiClient})
: _api = apiClient;
final ApiClient _api;
static const _transactionTypesPath = '${ApiRoutes.apiV1}/transaction-types';
static const _transactionStatusesPath =
'${ApiRoutes.apiV1}/transaction-statuses';
static const _approvalStatusesPath = '${ApiRoutes.apiV1}/approval-statuses';
static const _approvalActionsPath = '${ApiRoutes.apiV1}/approval-actions';
@override
Future<List<LookupItem>> fetchTransactionTypes({bool activeOnly = true}) {
return _fetchList(_transactionTypesPath, activeOnly: activeOnly);
}
@override
Future<List<LookupItem>> fetchTransactionStatuses({bool activeOnly = true}) {
return _fetchList(_transactionStatusesPath, activeOnly: activeOnly);
}
@override
Future<List<LookupItem>> fetchApprovalStatuses({bool activeOnly = true}) {
return _fetchList(_approvalStatusesPath, activeOnly: activeOnly);
}
@override
Future<List<LookupItem>> fetchApprovalActions({bool activeOnly = true}) {
return _fetchList(
_approvalActionsPath,
activeOnly: activeOnly,
// Approval actions는 is_active 필터가 없을 수 있어 조건적으로 전달.
includeIsActive: false,
);
}
Future<List<LookupItem>> _fetchList(
String path, {
required bool activeOnly,
bool includeIsActive = true,
}) async {
final response = await _api.get<Map<String, dynamic>>(
path,
query: {
'page': 1,
'page_size': 200,
if (includeIsActive && activeOnly) 'is_active': true,
},
options: Options(responseType: ResponseType.json),
);
return LookupItemDto.parseList(response.data ?? const {});
}
}

View File

@@ -0,0 +1,18 @@
/// 공통 조회용 룩업 항목 엔티티.
class LookupItem {
LookupItem({
required this.id,
required this.name,
this.code,
this.isDefault = false,
this.isActive = true,
this.note,
});
final int id;
final String? code;
final String name;
final bool isDefault;
final bool isActive;
final String? note;
}

View File

@@ -0,0 +1,16 @@
import '../entities/lookup_item.dart';
/// 인벤토리 공통 룩업(타입/상태/승인 액션) 저장소 인터페이스.
abstract class InventoryLookupRepository {
/// 입출고 트랜잭션 타입 목록을 조회한다.
Future<List<LookupItem>> fetchTransactionTypes({bool activeOnly = true});
/// 입출고 트랜잭션 상태 목록을 조회한다.
Future<List<LookupItem>> fetchTransactionStatuses({bool activeOnly = true});
/// 결재 상태 목록을 조회한다.
Future<List<LookupItem>> fetchApprovalStatuses({bool activeOnly = true});
/// 결재 액션 목록을 조회한다.
Future<List<LookupItem>> fetchApprovalActions({bool activeOnly = true});
}