import 'package:dio/dio.dart'; import 'package:hesabix_ui/core/api_client.dart'; import 'package:hesabix_ui/models/document_model.dart'; /// سرویس مدیریت اسناد حسابداری class DocumentService { final ApiClient _apiClient; DocumentService(this._apiClient); /// دریافت لیست اسناد با فیلتر و صفحه‌بندی /// /// Parameters: /// - [businessId]: شناسه کسب‌وکار /// - [documentType]: نوع سند (expense, income, receipt, payment, transfer, manual) /// - [fiscalYearId]: شناسه سال مالی /// - [fromDate]: از تاریخ (ISO format) /// - [toDate]: تا تاریخ (ISO format) /// - [currencyId]: شناسه ارز /// - [isProforma]: پیش‌فاکتور یا قطعی /// - [search]: جستجو در کد سند و توضیحات /// - [sortBy]: فیلد مرتب‌سازی /// - [sortDesc]: ترتیب نزولی /// - [page]: شماره صفحه /// - [perPage]: تعداد رکورد در هر صفحه Future> listDocuments({ required int businessId, String? documentType, int? fiscalYearId, String? fromDate, String? toDate, int? currencyId, bool? isProforma, String? search, String sortBy = 'document_date', bool sortDesc = true, int page = 1, int perPage = 50, }) async { try { final skip = (page - 1) * perPage; final body = { 'take': perPage, 'skip': skip, 'sort_by': sortBy, 'sort_desc': sortDesc, if (documentType != null) 'document_type': documentType, if (fiscalYearId != null) 'fiscal_year_id': fiscalYearId, if (fromDate != null) 'from_date': fromDate, if (toDate != null) 'to_date': toDate, if (currencyId != null) 'currency_id': currencyId, if (isProforma != null) 'is_proforma': isProforma, if (search != null && search.isNotEmpty) 'search': search, }; final response = await _apiClient.post( '/businesses/$businessId/documents', data: body, ); if (response.data['success'] == true) { final data = response.data['data']; return { 'items': (data['items'] as List) .map((json) => DocumentModel.fromJson(json as Map)) .toList(), 'pagination': data['pagination'], }; } throw Exception(response.data['message'] ?? 'خطا در دریافت لیست اسناد'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در ارتباط با سرور'); } rethrow; } } /// دریافت جزئیات یک سند Future getDocument(int documentId) async { try { final response = await _apiClient.get('/documents/$documentId'); if (response.data['success'] == true) { return DocumentModel.fromJson(response.data['data'] as Map); } throw Exception(response.data['message'] ?? 'خطا در دریافت جزئیات سند'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در ارتباط با سرور'); } rethrow; } } /// حذف یک سند (فقط اسناد manual) Future deleteDocument(int documentId) async { try { final response = await _apiClient.delete('/documents/$documentId'); if (response.data['success'] == true) { return true; } throw Exception(response.data['message'] ?? 'خطا در حذف سند'); } catch (e) { if (e is DioException) { final errorMessage = e.response?.data['message'] ?? 'خطا در ارتباط با سرور'; throw Exception(errorMessage); } rethrow; } } /// حذف گروهی اسناد Future> bulkDeleteDocuments(List documentIds) async { try { final response = await _apiClient.post( '/documents/bulk-delete', data: {'document_ids': documentIds}, ); if (response.data['success'] == true) { return response.data['data'] as Map; } throw Exception(response.data['message'] ?? 'خطا در حذف گروهی اسناد'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در ارتباط با سرور'); } rethrow; } } /// دریافت خلاصه آماری انواع اسناد Future> getDocumentTypesSummary(int businessId) async { try { final response = await _apiClient.get( '/businesses/$businessId/documents/types-summary', ); if (response.data['success'] == true) { final summary = response.data['data']['summary'] as Map; return summary.map((key, value) => MapEntry(key, value as int)); } throw Exception(response.data['message'] ?? 'خطا در دریافت آمار'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در ارتباط با سرور'); } rethrow; } } /// خروجی Excel لیست اسناد Future exportToExcel({ required int businessId, String? documentType, int? fiscalYearId, String? fromDate, String? toDate, int? currencyId, bool? isProforma, }) async { try { final body = { if (documentType != null) 'document_type': documentType, if (fiscalYearId != null) 'fiscal_year_id': fiscalYearId, if (fromDate != null) 'from_date': fromDate, if (toDate != null) 'to_date': toDate, if (currencyId != null) 'currency_id': currencyId, if (isProforma != null) 'is_proforma': isProforma, }; final response = await _apiClient.post( '/businesses/$businessId/documents/export/excel', data: body, options: Options( responseType: ResponseType.bytes, ), ); // ذخیره فایل // TODO: پیاده‌سازی ذخیره فایل // می‌توان از file_picker یا path_provider استفاده کرد throw UnimplementedError('Export to Excel is not implemented yet'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در دریافت فایل Excel'); } rethrow; } } /// دریافت PDF یک سند Future downloadPdf(int documentId) async { try { final response = await _apiClient.get( '/documents/$documentId/pdf', options: Options( responseType: ResponseType.bytes, ), ); // ذخیره فایل // TODO: پیاده‌سازی ذخیره فایل throw UnimplementedError('PDF download is not implemented yet'); } catch (e) { if (e is DioException) { throw Exception(e.response?.data['message'] ?? 'خطا در دریافت فایل PDF'); } rethrow; } } /// ایجاد سند حسابداری دستی جدید Future createManualDocument({ required int businessId, required CreateManualDocumentRequest request, }) async { try { // اعتبارسنجی درخواست final validationError = request.validate(); if (validationError != null) { throw Exception(validationError); } final response = await _apiClient.post( '/businesses/$businessId/documents/manual', data: request.toJson(), ); if (response.data['success'] == true) { return DocumentModel.fromJson(response.data['data'] as Map); } throw Exception(response.data['message'] ?? 'خطا در ایجاد سند'); } catch (e) { if (e is DioException) { final errorMessage = e.response?.data['message'] ?? 'خطا در ارتباط با سرور'; throw Exception(errorMessage); } rethrow; } } /// ویرایش سند حسابداری دستی Future updateManualDocument({ required int documentId, required UpdateManualDocumentRequest request, }) async { try { // اعتبارسنجی درخواست final validationError = request.validate(); if (validationError != null) { throw Exception(validationError); } final response = await _apiClient.put( '/documents/$documentId', data: request.toJson(), ); if (response.data['success'] == true) { return DocumentModel.fromJson(response.data['data'] as Map); } throw Exception(response.data['message'] ?? 'خطا در ویرایش سند'); } catch (e) { if (e is DioException) { final errorMessage = e.response?.data['message'] ?? 'خطا در ارتباط با سرور'; throw Exception(errorMessage); } rethrow; } } }