결재 비활성 안내 개선 및 테이블 기능 보강
This commit is contained in:
@@ -837,6 +837,8 @@ class _InboundPageState extends State<InboundPage> {
|
||||
};
|
||||
|
||||
String? writerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
void Function(VoidCallback fn)? refreshForm;
|
||||
|
||||
@@ -847,10 +849,14 @@ class _InboundPageState extends State<InboundPage> {
|
||||
void handleSubmit() {
|
||||
final validationResult = _validateInboundForm(
|
||||
writerController: writerController,
|
||||
warehouseValue: warehouseController.text,
|
||||
statusValue: statusValue.value,
|
||||
drafts: drafts,
|
||||
lineErrors: lineErrors,
|
||||
);
|
||||
writerError = validationResult.writerError;
|
||||
warehouseError = validationResult.warehouseError;
|
||||
statusError = validationResult.statusError;
|
||||
headerNotice = validationResult.headerNotice;
|
||||
refreshForm?.call(() {});
|
||||
|
||||
@@ -871,6 +877,7 @@ class _InboundPageState extends State<InboundPage> {
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
items.sort((a, b) => a.product.compareTo(b.product));
|
||||
result = InboundRecord(
|
||||
number: initial?.number ?? _generateInboundNumber(processedAt.value),
|
||||
transactionNumber:
|
||||
@@ -936,6 +943,7 @@ class _InboundPageState extends State<InboundPage> {
|
||||
child: SuperportFormField(
|
||||
label: '창고',
|
||||
required: true,
|
||||
errorText: warehouseError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: warehouseController.text,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -943,7 +951,11 @@ class _InboundPageState extends State<InboundPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
warehouseController.text = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (warehouseError != null) {
|
||||
warehouseError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
options: _warehouseOptions
|
||||
@@ -962,6 +974,7 @@ class _InboundPageState extends State<InboundPage> {
|
||||
child: SuperportFormField(
|
||||
label: '상태',
|
||||
required: true,
|
||||
errorText: statusError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: statusValue.value,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -969,7 +982,11 @@ class _InboundPageState extends State<InboundPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
statusValue.value = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (statusError != null) {
|
||||
statusError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
enabled: initial?.status != '승인완료',
|
||||
@@ -1525,11 +1542,15 @@ class _LineItemFieldErrors {
|
||||
|
||||
_InboundFormValidation _validateInboundForm({
|
||||
required TextEditingController writerController,
|
||||
required String warehouseValue,
|
||||
required String statusValue,
|
||||
required List<_LineItemDraft> drafts,
|
||||
required Map<_LineItemDraft, _LineItemFieldErrors> lineErrors,
|
||||
}) {
|
||||
var isValid = true;
|
||||
String? writerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
|
||||
if (writerController.text.trim().isEmpty) {
|
||||
@@ -1537,12 +1558,24 @@ _InboundFormValidation _validateInboundForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (warehouseValue.trim().isEmpty) {
|
||||
warehouseError = '창고를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (statusValue.trim().isEmpty) {
|
||||
statusError = '상태를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
var hasLineError = false;
|
||||
final seenProductKeys = <String>{};
|
||||
for (final draft in drafts) {
|
||||
final errors = lineErrors.putIfAbsent(draft, _LineItemFieldErrors.empty);
|
||||
errors.clearAll();
|
||||
|
||||
if (draft.product.text.trim().isEmpty) {
|
||||
final productText = draft.product.text.trim();
|
||||
if (productText.isEmpty) {
|
||||
errors.product = '제품을 입력하세요.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
@@ -1552,8 +1585,15 @@ _InboundFormValidation _validateInboundForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final productKey = (draft.catalogMatch?.code ?? productText.toLowerCase());
|
||||
if (productKey.isNotEmpty && !seenProductKeys.add(productKey)) {
|
||||
errors.product = '동일 제품이 중복되었습니다.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final quantity = int.tryParse(
|
||||
draft.quantity.text.trim() == '' ? '0' : draft.quantity.text.trim(),
|
||||
draft.quantity.text.trim().isEmpty ? '0' : draft.quantity.text.trim(),
|
||||
);
|
||||
if (quantity == null || quantity < 1) {
|
||||
errors.quantity = '수량은 1 이상 정수여야 합니다.';
|
||||
@@ -1576,6 +1616,8 @@ _InboundFormValidation _validateInboundForm({
|
||||
return _InboundFormValidation(
|
||||
isValid: isValid,
|
||||
writerError: writerError,
|
||||
warehouseError: warehouseError,
|
||||
statusError: statusError,
|
||||
headerNotice: headerNotice,
|
||||
);
|
||||
}
|
||||
@@ -1589,11 +1631,15 @@ class _InboundFormValidation {
|
||||
const _InboundFormValidation({
|
||||
required this.isValid,
|
||||
this.writerError,
|
||||
this.warehouseError,
|
||||
this.statusError,
|
||||
this.headerNotice,
|
||||
});
|
||||
|
||||
final bool isValid;
|
||||
final String? writerError;
|
||||
final String? warehouseError;
|
||||
final String? statusError;
|
||||
final String? headerNotice;
|
||||
}
|
||||
|
||||
|
||||
@@ -844,6 +844,8 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
|
||||
String? writerError;
|
||||
String? customerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
String customerSearchQuery = '';
|
||||
StateSetter? refreshForm;
|
||||
@@ -855,6 +857,8 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
void handleSubmit() {
|
||||
final validation = _validateOutboundForm(
|
||||
writerController: writerController,
|
||||
warehouseValue: warehouseController.text,
|
||||
statusValue: statusValue.value,
|
||||
customerController: customerController,
|
||||
drafts: drafts,
|
||||
lineErrors: lineErrors,
|
||||
@@ -862,6 +866,8 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
|
||||
writerError = validation.writerError;
|
||||
customerError = validation.customerError;
|
||||
warehouseError = validation.warehouseError;
|
||||
statusError = validation.statusError;
|
||||
headerNotice = validation.headerNotice;
|
||||
refreshForm?.call(() {});
|
||||
|
||||
@@ -882,6 +888,7 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
items.sort((a, b) => a.product.compareTo(b.product));
|
||||
result = OutboundRecord(
|
||||
number: initial?.number ?? _generateOutboundNumber(processedAt.value),
|
||||
transactionNumber:
|
||||
@@ -948,6 +955,7 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
child: SuperportFormField(
|
||||
label: '창고',
|
||||
required: true,
|
||||
errorText: warehouseError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: warehouseController.text,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -955,7 +963,11 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
warehouseController.text = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (warehouseError != null) {
|
||||
warehouseError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
options: [
|
||||
@@ -970,6 +982,7 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
child: SuperportFormField(
|
||||
label: '상태',
|
||||
required: true,
|
||||
errorText: statusError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: statusValue.value,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -977,7 +990,11 @@ class _OutboundPageState extends State<OutboundPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
statusValue.value = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (statusError != null) {
|
||||
statusError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
options: [
|
||||
@@ -1609,6 +1626,8 @@ double _parseCurrency(String input) {
|
||||
|
||||
_OutboundFormValidation _validateOutboundForm({
|
||||
required TextEditingController writerController,
|
||||
required String warehouseValue,
|
||||
required String statusValue,
|
||||
required ShadSelectController<String> customerController,
|
||||
required List<_OutboundLineItemDraft> drafts,
|
||||
required Map<_OutboundLineItemDraft, _OutboundLineErrors> lineErrors,
|
||||
@@ -1616,6 +1635,8 @@ _OutboundFormValidation _validateOutboundForm({
|
||||
var isValid = true;
|
||||
String? writerError;
|
||||
String? customerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
|
||||
if (writerController.text.trim().isEmpty) {
|
||||
@@ -1623,17 +1644,29 @@ _OutboundFormValidation _validateOutboundForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (warehouseValue.trim().isEmpty) {
|
||||
warehouseError = '창고를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (statusValue.trim().isEmpty) {
|
||||
statusError = '상태를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (customerController.value.isEmpty) {
|
||||
customerError = '최소 1개의 고객사를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
var hasLineError = false;
|
||||
final seenProductKeys = <String>{};
|
||||
for (final draft in drafts) {
|
||||
final errors = lineErrors.putIfAbsent(draft, _OutboundLineErrors.empty);
|
||||
errors.clearAll();
|
||||
|
||||
if (draft.product.text.trim().isEmpty) {
|
||||
final productText = draft.product.text.trim();
|
||||
if (productText.isEmpty) {
|
||||
errors.product = '제품을 입력하세요.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
@@ -1643,6 +1676,13 @@ _OutboundFormValidation _validateOutboundForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final productKey = draft.catalogMatch?.code ?? productText.toLowerCase();
|
||||
if (productKey.isNotEmpty && !seenProductKeys.add(productKey)) {
|
||||
errors.product = '동일 제품이 중복되었습니다.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final quantity = int.tryParse(
|
||||
draft.quantity.text.trim().isEmpty ? '0' : draft.quantity.text.trim(),
|
||||
);
|
||||
@@ -1668,6 +1708,8 @@ _OutboundFormValidation _validateOutboundForm({
|
||||
isValid: isValid,
|
||||
writerError: writerError,
|
||||
customerError: customerError,
|
||||
warehouseError: warehouseError,
|
||||
statusError: statusError,
|
||||
headerNotice: headerNotice,
|
||||
);
|
||||
}
|
||||
@@ -1677,12 +1719,16 @@ class _OutboundFormValidation {
|
||||
required this.isValid,
|
||||
this.writerError,
|
||||
this.customerError,
|
||||
this.warehouseError,
|
||||
this.statusError,
|
||||
this.headerNotice,
|
||||
});
|
||||
|
||||
final bool isValid;
|
||||
final String? writerError;
|
||||
final String? customerError;
|
||||
final String? warehouseError;
|
||||
final String? statusError;
|
||||
final String? headerNotice;
|
||||
}
|
||||
|
||||
|
||||
@@ -928,6 +928,8 @@ class _RentalPageState extends State<RentalPage> {
|
||||
String customerSearchQuery = '';
|
||||
String? writerError;
|
||||
String? customerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
void Function(VoidCallback fn)? refreshForm;
|
||||
|
||||
@@ -940,6 +942,8 @@ class _RentalPageState extends State<RentalPage> {
|
||||
void handleSubmit() {
|
||||
final validation = _validateRentalForm(
|
||||
writerController: writerController,
|
||||
warehouseValue: warehouseController.text,
|
||||
statusValue: statusValue.value,
|
||||
customerController: customerController,
|
||||
drafts: drafts,
|
||||
lineErrors: lineErrors,
|
||||
@@ -947,6 +951,8 @@ class _RentalPageState extends State<RentalPage> {
|
||||
|
||||
writerError = validation.writerError;
|
||||
customerError = validation.customerError;
|
||||
warehouseError = validation.warehouseError;
|
||||
statusError = validation.statusError;
|
||||
headerNotice = validation.headerNotice;
|
||||
refreshForm?.call(() {});
|
||||
|
||||
@@ -972,6 +978,7 @@ class _RentalPageState extends State<RentalPage> {
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
items.sort((a, b) => a.product.compareTo(b.product));
|
||||
result = RentalRecord(
|
||||
number: initial?.number ?? _generateRentalNumber(processedAt.value),
|
||||
transactionNumber:
|
||||
@@ -1062,8 +1069,10 @@ class _RentalPageState extends State<RentalPage> {
|
||||
),
|
||||
SizedBox(
|
||||
width: 220,
|
||||
child: _FormFieldLabel(
|
||||
child: SuperportFormField(
|
||||
label: '창고',
|
||||
required: true,
|
||||
errorText: warehouseError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: warehouseController.text,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -1071,7 +1080,11 @@ class _RentalPageState extends State<RentalPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
warehouseController.text = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (warehouseError != null) {
|
||||
warehouseError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
options: _warehouseOptions
|
||||
@@ -1087,8 +1100,10 @@ class _RentalPageState extends State<RentalPage> {
|
||||
),
|
||||
SizedBox(
|
||||
width: 240,
|
||||
child: _FormFieldLabel(
|
||||
child: SuperportFormField(
|
||||
label: '상태',
|
||||
required: true,
|
||||
errorText: statusError,
|
||||
child: ShadSelect<String>(
|
||||
initialValue: statusValue.value,
|
||||
selectedOptionBuilder: (context, value) =>
|
||||
@@ -1096,7 +1111,11 @@ class _RentalPageState extends State<RentalPage> {
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
statusValue.value = value;
|
||||
setState(() {});
|
||||
setState(() {
|
||||
if (statusError != null) {
|
||||
statusError = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
enabled: initial?.status != '완료',
|
||||
@@ -1833,6 +1852,8 @@ class RentalRecord {
|
||||
|
||||
_RentalFormValidation _validateRentalForm({
|
||||
required TextEditingController writerController,
|
||||
required String warehouseValue,
|
||||
required String statusValue,
|
||||
required ShadSelectController<String> customerController,
|
||||
required List<_RentalLineItemDraft> drafts,
|
||||
required Map<_RentalLineItemDraft, _RentalLineItemErrors> lineErrors,
|
||||
@@ -1840,6 +1861,8 @@ _RentalFormValidation _validateRentalForm({
|
||||
var isValid = true;
|
||||
String? writerError;
|
||||
String? customerError;
|
||||
String? warehouseError;
|
||||
String? statusError;
|
||||
String? headerNotice;
|
||||
|
||||
if (writerController.text.trim().isEmpty) {
|
||||
@@ -1847,17 +1870,29 @@ _RentalFormValidation _validateRentalForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (warehouseValue.trim().isEmpty) {
|
||||
warehouseError = '창고를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (statusValue.trim().isEmpty) {
|
||||
statusError = '상태를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (customerController.value.isEmpty) {
|
||||
customerError = '최소 1개의 고객사를 선택하세요.';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
var hasLineError = false;
|
||||
final seenProductKeys = <String>{};
|
||||
for (final draft in drafts) {
|
||||
final errors = lineErrors.putIfAbsent(draft, _RentalLineItemErrors.empty);
|
||||
errors.clearAll();
|
||||
|
||||
if (draft.product.text.trim().isEmpty) {
|
||||
final productText = draft.product.text.trim();
|
||||
if (productText.isEmpty) {
|
||||
errors.product = '제품을 입력하세요.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
@@ -1867,6 +1902,13 @@ _RentalFormValidation _validateRentalForm({
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final productKey = draft.catalogMatch?.code ?? productText.toLowerCase();
|
||||
if (productKey.isNotEmpty && !seenProductKeys.add(productKey)) {
|
||||
errors.product = '동일 제품이 중복되었습니다.';
|
||||
hasLineError = true;
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
final quantity = int.tryParse(
|
||||
draft.quantity.text.trim().isEmpty ? '0' : draft.quantity.text.trim(),
|
||||
);
|
||||
@@ -1892,6 +1934,8 @@ _RentalFormValidation _validateRentalForm({
|
||||
isValid: isValid,
|
||||
writerError: writerError,
|
||||
customerError: customerError,
|
||||
warehouseError: warehouseError,
|
||||
statusError: statusError,
|
||||
headerNotice: headerNotice,
|
||||
);
|
||||
}
|
||||
@@ -1901,12 +1945,16 @@ class _RentalFormValidation {
|
||||
required this.isValid,
|
||||
this.writerError,
|
||||
this.customerError,
|
||||
this.warehouseError,
|
||||
this.statusError,
|
||||
this.headerNotice,
|
||||
});
|
||||
|
||||
final bool isValid;
|
||||
final String? writerError;
|
||||
final String? customerError;
|
||||
final String? warehouseError;
|
||||
final String? statusError;
|
||||
final String? headerNotice;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user