fixed add remove doscument
This commit is contained in:
parent
a88d085001
commit
502bb1e2d9
@ -42,6 +42,7 @@ class AddPaymentRequestController extends GetxController {
|
||||
final dueDateController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
final descriptionController = TextEditingController();
|
||||
final removedAttachments = <Map<String, dynamic>>[].obs;
|
||||
|
||||
// Attachments
|
||||
final attachments = <File>[].obs;
|
||||
@ -187,20 +188,47 @@ class AddPaymentRequestController extends GetxController {
|
||||
void selectCurrency(Currency currency) => selectedCurrency.value = currency;
|
||||
|
||||
void addAttachment(File file) => attachments.add(file);
|
||||
void removeAttachment(File file) => attachments.remove(file);
|
||||
void removeAttachment(File file) {
|
||||
if (attachments.contains(file)) {
|
||||
attachments.remove(file);
|
||||
}
|
||||
}
|
||||
|
||||
void removeExistingAttachment(Map<String, dynamic> existingAttachment) {
|
||||
final index = existingAttachments.indexWhere(
|
||||
(e) => e['id'] == existingAttachment['id']); // match by normalized id
|
||||
|
||||
if (index != -1) {
|
||||
// Mark as inactive
|
||||
existingAttachments[index]['isActive'] = false;
|
||||
existingAttachments.refresh();
|
||||
|
||||
// Add to removedAttachments to inform API
|
||||
removedAttachments.add({
|
||||
"documentId": existingAttachment['id'], // ensure API receives id
|
||||
"isActive": false,
|
||||
});
|
||||
|
||||
// Show snackbar feedback
|
||||
showAppSnackbar(
|
||||
title: 'Removed',
|
||||
message: 'Attachment has been removed.',
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Build attachment payload
|
||||
Future<List<Map<String, dynamic>>> buildAttachmentPayload() async {
|
||||
final existingPayload = existingAttachments
|
||||
.map((e) => {
|
||||
"documentId": e['documentId'],
|
||||
"documentId": e['id'], // use the normalized id
|
||||
"fileName": e['fileName'],
|
||||
"contentType": e['contentType'] ?? 'application/octet-stream',
|
||||
"fileSize": e['fileSize'] ?? 0,
|
||||
"description": "",
|
||||
"url": e['url'],
|
||||
"isActive": e['isActive'] ?? true,
|
||||
"base64Data": "",
|
||||
})
|
||||
.toList();
|
||||
|
||||
@ -215,7 +243,78 @@ class AddPaymentRequestController extends GetxController {
|
||||
};
|
||||
}));
|
||||
|
||||
return [...existingPayload, ...newPayload];
|
||||
// Combine active + removed attachments
|
||||
return [...existingPayload, ...newPayload, ...removedAttachments];
|
||||
}
|
||||
|
||||
/// Submit edited payment request
|
||||
Future<bool> submitEditedPaymentRequest({required String requestId}) async {
|
||||
if (isSubmitting.value) return false;
|
||||
|
||||
try {
|
||||
isSubmitting.value = true;
|
||||
|
||||
// Validate form
|
||||
if (!_validateForm()) return false;
|
||||
|
||||
// Build attachment payload
|
||||
final billAttachments = await buildAttachmentPayload();
|
||||
|
||||
final payload = {
|
||||
"id": requestId,
|
||||
"title": titleController.text.trim(),
|
||||
"projectId": selectedProject.value?['id'] ?? '',
|
||||
"expenseCategoryId": selectedCategory.value?.id ?? '',
|
||||
"amount": double.tryParse(amountController.text.trim()) ?? 0,
|
||||
"currencyId": selectedCurrency.value?.id ?? '',
|
||||
"description": descriptionController.text.trim(),
|
||||
"payee": selectedPayee.value,
|
||||
"dueDate": selectedDueDate.value?.toIso8601String(),
|
||||
"isAdvancePayment": isAdvancePayment.value,
|
||||
"billAttachments": billAttachments.map((a) {
|
||||
return {
|
||||
"documentId": a['documentId'],
|
||||
"fileName": a['fileName'],
|
||||
"base64Data": a['base64Data'] ?? "",
|
||||
"contentType": a['contentType'],
|
||||
"fileSize": a['fileSize'],
|
||||
"description": a['description'] ?? "",
|
||||
"isActive": a['isActive'] ?? true,
|
||||
};
|
||||
}).toList(),
|
||||
};
|
||||
|
||||
logSafe("💡 Submitting Edited Payment Request: ${jsonEncode(payload)}");
|
||||
|
||||
final success = await ApiService.editExpensePaymentRequestApi(
|
||||
id: payload['id'],
|
||||
title: payload['title'],
|
||||
projectId: payload['projectId'],
|
||||
expenseCategoryId: payload['expenseCategoryId'],
|
||||
amount: payload['amount'],
|
||||
currencyId: payload['currencyId'],
|
||||
description: payload['description'],
|
||||
payee: payload['payee'],
|
||||
dueDate: payload['dueDate'] ?? '',
|
||||
isAdvancePayment: payload['isAdvancePayment'],
|
||||
billAttachments: payload['billAttachments'],
|
||||
);
|
||||
|
||||
logSafe("💡 Edit Payment Request API Response: $success");
|
||||
|
||||
if (success == true) {
|
||||
logSafe("✅ Payment request edited successfully.");
|
||||
return true;
|
||||
} else {
|
||||
return _errorSnackbar("Failed to edit payment request.");
|
||||
}
|
||||
} catch (e, st) {
|
||||
logSafe("💥 Submit Edited Payment Request Error: $e\n$st",
|
||||
level: LogLevel.error);
|
||||
return _errorSnackbar("Something went wrong. Please try again later.");
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Submit payment request (Project API style)
|
||||
@ -314,5 +413,6 @@ class AddPaymentRequestController extends GetxController {
|
||||
isAdvancePayment.value = false;
|
||||
attachments.clear();
|
||||
existingAttachments.clear();
|
||||
removedAttachments.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,9 @@ class ApiEndpoints {
|
||||
"/Expense/payment-request/filter";
|
||||
static const String updateExpensePaymentRequestStatus =
|
||||
"/Expense/payment-request/action";
|
||||
static const String createExpenseforPR =
|
||||
"/expense/payment-request/action";
|
||||
|
||||
static const String createExpenseforPR = "/expense/payment-request/action";
|
||||
static const String getExpensePaymentRequestEdit =
|
||||
"/expense/payment-request/edit";
|
||||
|
||||
static const String getDashboardProjectProgress = "/dashboard/progression";
|
||||
static const String getDashboardTasks = "/dashboard/tasks";
|
||||
|
||||
@ -302,6 +302,69 @@ class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Edit Expense Payment Request
|
||||
static Future<bool> editExpensePaymentRequestApi({
|
||||
required String id,
|
||||
required String title,
|
||||
required String description,
|
||||
required String payee,
|
||||
required String currencyId,
|
||||
required double amount,
|
||||
required String dueDate,
|
||||
required String projectId,
|
||||
required String expenseCategoryId,
|
||||
required bool isAdvancePayment,
|
||||
List<Map<String, dynamic>> billAttachments = const [],
|
||||
}) async {
|
||||
final endpoint = "${ApiEndpoints.getExpensePaymentRequestEdit}/$id";
|
||||
|
||||
final body = {
|
||||
"id": id,
|
||||
"title": title,
|
||||
"description": description,
|
||||
"payee": payee,
|
||||
"currencyId": currencyId,
|
||||
"amount": amount,
|
||||
"dueDate": dueDate,
|
||||
"projectId": projectId,
|
||||
"expenseCategoryId": expenseCategoryId,
|
||||
"isAdvancePayment": isAdvancePayment,
|
||||
"billAttachments": billAttachments,
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await _putRequest(endpoint, body);
|
||||
|
||||
if (response == null) {
|
||||
logSafe("Edit Expense Payment Request failed: null response",
|
||||
level: LogLevel.error);
|
||||
return false;
|
||||
}
|
||||
|
||||
logSafe(
|
||||
"Edit Expense Payment Request response status: ${response.statusCode}");
|
||||
logSafe("Edit Expense Payment Request response body: ${response.body}");
|
||||
|
||||
final json = jsonDecode(response.body);
|
||||
if (json['success'] == true) {
|
||||
logSafe(
|
||||
"Expense Payment Request edited successfully: ${json['data'] ?? 'No data'}");
|
||||
return true;
|
||||
} else {
|
||||
logSafe(
|
||||
"Failed to edit Expense Payment Request: ${json['message'] ?? 'Unknown error'}",
|
||||
level: LogLevel.warning,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} catch (e, stack) {
|
||||
logSafe("Exception during editExpensePaymentRequestApi: $e",
|
||||
level: LogLevel.error);
|
||||
logSafe("StackTrace: $stack", level: LogLevel.debug);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create Expense for Payment Request
|
||||
static Future<bool> createExpenseForPRApi({
|
||||
required String paymentModeId,
|
||||
|
||||
@ -73,17 +73,14 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
||||
controller.isAdvancePayment.value = data["isAdvancePayment"] ?? false;
|
||||
|
||||
// 🕒 Wait until categories & currencies are loaded before setting them
|
||||
everAll([
|
||||
controller.categories,
|
||||
controller.currencies,
|
||||
], (_) {
|
||||
everAll([controller.categories, controller.currencies], (_) {
|
||||
controller.selectedCategory.value = controller.categories
|
||||
.firstWhereOrNull((c) => c.id == data["expenseCategoryId"]);
|
||||
controller.selectedCurrency.value = controller.currencies
|
||||
.firstWhereOrNull((c) => c.id == data["currencyId"]);
|
||||
});
|
||||
|
||||
// 🖇 Attachments - Safe parsing (avoids null or wrong type)
|
||||
// 🖇 Attachments
|
||||
final attachmentsData = data["attachments"];
|
||||
if (attachmentsData != null &&
|
||||
attachmentsData is List &&
|
||||
@ -91,12 +88,13 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
||||
final attachments = attachmentsData
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map((a) => {
|
||||
"id": a["id"],
|
||||
"id": a["documentId"] ?? a["id"], // map documentId to id
|
||||
"fileName": a["fileName"],
|
||||
"url": a["url"],
|
||||
"thumbUrl": a["thumbUrl"],
|
||||
"fileSize": a["fileSize"] ?? 0,
|
||||
"contentType": a["contentType"] ?? "",
|
||||
"isActive": true, // ensure active by default
|
||||
})
|
||||
.toList();
|
||||
controller.existingAttachments.assignAll(attachments);
|
||||
@ -106,7 +104,6 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() => Form(
|
||||
@ -120,7 +117,21 @@ class _PaymentRequestBottomSheetState extends State<_PaymentRequestBottomSheet>
|
||||
submitText: "Save as Draft",
|
||||
onSubmit: () async {
|
||||
if (_formKey.currentState!.validate() && _validateSelections()) {
|
||||
final success = await controller.submitPaymentRequest();
|
||||
bool success = false;
|
||||
if (widget.isEdit && widget.existingData != null) {
|
||||
final requestId =
|
||||
widget.existingData!['id']?.toString() ?? '';
|
||||
if (requestId.isNotEmpty) {
|
||||
success = await controller.submitEditedPaymentRequest(
|
||||
requestId: requestId);
|
||||
} else {
|
||||
_showError("Invalid Payment Request ID");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
success = await controller.submitPaymentRequest();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Get.back();
|
||||
if (widget.onUpdated != null) widget.onUpdated!();
|
||||
|
||||
@ -72,6 +72,7 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
|
||||
showPaymentRequestBottomSheet(
|
||||
isEdit: true,
|
||||
existingData: {
|
||||
"id": request.id,
|
||||
"paymentRequestId": request.paymentRequestUID,
|
||||
"title": request.title,
|
||||
"projectId": request.project.id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user