refactor: 인벤토리 테이블 스펙과 도메인 계층 정비
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
import 'package:superport_v2/core/network/api_error.dart';
|
||||
import 'package:superport_v2/core/network/failure.dart';
|
||||
import 'package:superport_v2/features/inventory/rental/presentation/controllers/rental_controller.dart';
|
||||
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction.dart';
|
||||
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction_input.dart';
|
||||
import 'package:superport_v2/features/inventory/transactions/domain/repositories/stock_transaction_repository.dart';
|
||||
import 'package:superport_v2/features/inventory/lookups/domain/repositories/inventory_lookup_repository.dart';
|
||||
|
||||
class _MockStockTransactionRepository extends Mock
|
||||
implements StockTransactionRepository {}
|
||||
|
||||
class _MockInventoryLookupRepository extends Mock
|
||||
implements InventoryLookupRepository {}
|
||||
|
||||
class _MockTransactionLineRepository extends Mock
|
||||
implements TransactionLineRepository {}
|
||||
|
||||
class _MockTransactionCustomerRepository extends Mock
|
||||
implements TransactionCustomerRepository {}
|
||||
|
||||
class _FakeStockTransactionCreateInput extends Fake
|
||||
implements StockTransactionCreateInput {}
|
||||
|
||||
class _FakeStockTransactionUpdateInput extends Fake
|
||||
implements StockTransactionUpdateInput {}
|
||||
|
||||
class _FakeStockTransactionListFilter extends Fake
|
||||
implements StockTransactionListFilter {}
|
||||
|
||||
void main() {
|
||||
group('RentalController', () {
|
||||
late StockTransactionRepository transactionRepository;
|
||||
late InventoryLookupRepository lookupRepository;
|
||||
late TransactionLineRepository lineRepository;
|
||||
late TransactionCustomerRepository customerRepository;
|
||||
late RentalController controller;
|
||||
|
||||
setUpAll(() {
|
||||
registerFallbackValue(_FakeStockTransactionCreateInput());
|
||||
registerFallbackValue(_FakeStockTransactionUpdateInput());
|
||||
registerFallbackValue(_FakeStockTransactionListFilter());
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
transactionRepository = _MockStockTransactionRepository();
|
||||
lookupRepository = _MockInventoryLookupRepository();
|
||||
lineRepository = _MockTransactionLineRepository();
|
||||
customerRepository = _MockTransactionCustomerRepository();
|
||||
controller = RentalController(
|
||||
transactionRepository: transactionRepository,
|
||||
lineRepository: lineRepository,
|
||||
customerRepository: customerRepository,
|
||||
lookupRepository: lookupRepository,
|
||||
);
|
||||
});
|
||||
|
||||
test('createTransaction은 레코드를 추가한다', () async {
|
||||
final transaction = _buildRentalTransaction();
|
||||
when(
|
||||
() => transactionRepository.create(any()),
|
||||
).thenAnswer((_) async => transaction);
|
||||
|
||||
final record = await controller.createTransaction(
|
||||
StockTransactionCreateInput(
|
||||
transactionTypeId: 1,
|
||||
transactionStatusId: 2,
|
||||
warehouseId: 4,
|
||||
transactionDate: DateTime(2024, 5, 1),
|
||||
createdById: 5,
|
||||
),
|
||||
refreshAfter: false,
|
||||
);
|
||||
|
||||
expect(record.id, equals(transaction.id));
|
||||
expect(controller.records.first.id, equals(transaction.id));
|
||||
});
|
||||
|
||||
test('deleteTransaction은 레코드를 제거하고 처리 상태를 초기화한다', () async {
|
||||
final transaction = _buildRentalTransaction();
|
||||
when(
|
||||
() => transactionRepository.create(any()),
|
||||
).thenAnswer((_) async => transaction);
|
||||
when(
|
||||
() => transactionRepository.delete(any()),
|
||||
).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
await controller.createTransaction(
|
||||
StockTransactionCreateInput(
|
||||
transactionTypeId: 1,
|
||||
transactionStatusId: 2,
|
||||
warehouseId: 4,
|
||||
transactionDate: DateTime(2024, 5, 1),
|
||||
createdById: 5,
|
||||
),
|
||||
refreshAfter: false,
|
||||
);
|
||||
|
||||
final future = controller.deleteTransaction(
|
||||
transaction.id!,
|
||||
refreshAfter: false,
|
||||
);
|
||||
|
||||
expect(
|
||||
controller.processingTransactionIds.contains(transaction.id),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
await future;
|
||||
|
||||
expect(controller.records, isEmpty);
|
||||
expect(
|
||||
controller.processingTransactionIds.contains(transaction.id),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('completeTransaction은 마지막 필터 설정을 유지하며 새로고침한다', () async {
|
||||
final rental = _buildRentalTransaction();
|
||||
final other = _buildNonRentalTransaction();
|
||||
|
||||
when(
|
||||
() => transactionRepository.list(filter: any(named: 'filter')),
|
||||
).thenAnswer(
|
||||
(_) async => PaginatedResult<StockTransaction>(
|
||||
items: [rental, other],
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 2,
|
||||
),
|
||||
);
|
||||
|
||||
await controller.fetchTransactions(
|
||||
filter: StockTransactionListFilter(transactionTypeId: 1),
|
||||
filterByRentalTypes: false,
|
||||
);
|
||||
|
||||
final updated = rental.copyWith(
|
||||
status: StockTransactionStatus(id: 2, name: '완료'),
|
||||
);
|
||||
when(
|
||||
() => transactionRepository.complete(any()),
|
||||
).thenAnswer((_) async => updated);
|
||||
when(
|
||||
() => transactionRepository.list(filter: any(named: 'filter')),
|
||||
).thenAnswer(
|
||||
(_) async => PaginatedResult<StockTransaction>(
|
||||
items: [updated, other],
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 2,
|
||||
),
|
||||
);
|
||||
|
||||
final result = await controller.completeTransaction(rental.id!);
|
||||
|
||||
expect(result.status, equals('완료'));
|
||||
expect(controller.records.length, equals(2));
|
||||
});
|
||||
|
||||
test('fetchTransactions 실패 시 Failure 메시지를 저장한다', () async {
|
||||
final exception = ApiException(
|
||||
code: ApiErrorCode.conflict,
|
||||
message: '대여 목록을 가져오는 데 실패했습니다.',
|
||||
details: {
|
||||
'errors': {
|
||||
'status': ['상태 필터가 올바르지 않습니다.'],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
when(
|
||||
() => transactionRepository.list(filter: any(named: 'filter')),
|
||||
).thenThrow(exception);
|
||||
|
||||
await controller.fetchTransactions(
|
||||
filter: StockTransactionListFilter(transactionTypeId: 1),
|
||||
);
|
||||
|
||||
final failure = Failure.from(exception);
|
||||
expect(controller.errorMessage, equals(failure.describe()));
|
||||
expect(controller.records, isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
StockTransaction _buildRentalTransaction({
|
||||
int id = 300,
|
||||
String statusName = '대여중',
|
||||
}) {
|
||||
return StockTransaction(
|
||||
id: id,
|
||||
transactionNo: 'RENT-$id',
|
||||
transactionDate: DateTime(2024, 5, 1),
|
||||
type: StockTransactionType(id: 30, name: '대여'),
|
||||
status: StockTransactionStatus(id: 31, name: statusName),
|
||||
warehouse: StockTransactionWarehouse(id: 5, code: 'WH-5', name: '대여 창고'),
|
||||
createdBy: StockTransactionEmployee(
|
||||
id: 5,
|
||||
employeeNo: 'EMP-5',
|
||||
name: '대여 담당',
|
||||
),
|
||||
note: '렌탈',
|
||||
lines: [
|
||||
StockTransactionLine(
|
||||
id: 20,
|
||||
lineNo: 1,
|
||||
product: StockTransactionProduct(id: 20, code: 'P-20', name: '렌탈 품목'),
|
||||
quantity: 2,
|
||||
unitPrice: 15000.0,
|
||||
),
|
||||
],
|
||||
customers: [
|
||||
StockTransactionCustomer(
|
||||
id: 2,
|
||||
customer: StockTransactionCustomerSummary(
|
||||
id: 200,
|
||||
code: 'C-200',
|
||||
name: '렌탈 고객',
|
||||
),
|
||||
),
|
||||
],
|
||||
expectedReturnDate: DateTime(2024, 5, 20),
|
||||
);
|
||||
}
|
||||
|
||||
StockTransaction _buildNonRentalTransaction() {
|
||||
return StockTransaction(
|
||||
id: 301,
|
||||
transactionNo: 'SRV-301',
|
||||
transactionDate: DateTime(2024, 5, 2),
|
||||
type: StockTransactionType(id: 40, name: '수리'),
|
||||
status: StockTransactionStatus(id: 32, name: '진행중'),
|
||||
warehouse: StockTransactionWarehouse(id: 6, code: 'WH-6', name: '서비스 센터'),
|
||||
createdBy: StockTransactionEmployee(
|
||||
id: 6,
|
||||
employeeNo: 'EMP-6',
|
||||
name: '서비스 담당',
|
||||
),
|
||||
lines: [
|
||||
StockTransactionLine(
|
||||
id: 21,
|
||||
lineNo: 1,
|
||||
product: StockTransactionProduct(id: 21, code: 'P-21', name: '서비스 품목'),
|
||||
quantity: 1,
|
||||
unitPrice: 5000.0,
|
||||
),
|
||||
],
|
||||
customers: const [],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user