diff --git a/frontend/mgramseva/lib/model/reports/expense_bill_report_data.dart b/frontend/mgramseva/lib/model/reports/expense_bill_report_data.dart new file mode 100644 index 000000000..109d24491 --- /dev/null +++ b/frontend/mgramseva/lib/model/reports/expense_bill_report_data.dart @@ -0,0 +1,64 @@ +class ExpenseBillReportData { + String? typeOfExpense; + String? vendorName; + int? amount; + int? billDate; + int? taxPeriodFrom; + int? taxPeriodTo; + String? applicationStatus; + int? paidDate; + String? filestoreid; + int? lastModifiedTime; + dynamic? lastModifiedByUuid; + dynamic? lastModifiedBy; + String? tenantId; + + ExpenseBillReportData( + {this.typeOfExpense, + this.vendorName, + this.amount, + this.billDate, + this.taxPeriodFrom, + this.taxPeriodTo, + this.applicationStatus, + this.paidDate, + this.filestoreid, + this.lastModifiedTime, + this.lastModifiedByUuid, + this.lastModifiedBy, + this.tenantId}); + + ExpenseBillReportData.fromJson(Map json) { + typeOfExpense = json['typeOfExpense']; + vendorName = json['vendorName']; + amount = json['amount']; + billDate = json['billDate']; + taxPeriodFrom = json['taxPeriodFrom']; + taxPeriodTo = json['taxPeriodTo']; + applicationStatus = json['applicationStatus']; + paidDate = json['paidDate']; + filestoreid = json['filestoreid']; + lastModifiedTime = json['lastModifiedTime']; + lastModifiedByUuid = json['lastModifiedByUuid']; + lastModifiedBy = json['lastModifiedBy']; + tenantId = json['tenantId']; + } + + Map toJson() { + final Map data = new Map(); + data['typeOfExpense'] = this.typeOfExpense; + data['vendorName'] = this.vendorName; + data['amount'] = this.amount; + data['billDate'] = this.billDate; + data['taxPeriodFrom'] = this.taxPeriodFrom; + data['taxPeriodTo'] = this.taxPeriodTo; + data['applicationStatus'] = this.applicationStatus; + data['paidDate'] = this.paidDate; + data['filestoreid'] = this.filestoreid; + data['lastModifiedTime'] = this.lastModifiedTime; + data['lastModifiedByUuid'] = this.lastModifiedByUuid; + data['lastModifiedBy'] = this.lastModifiedBy; + data['tenantId'] = this.tenantId; + return data; + } +} \ No newline at end of file diff --git a/frontend/mgramseva/lib/providers/reports_provider.dart b/frontend/mgramseva/lib/providers/reports_provider.dart index dfa75bfd3..3dade3de0 100644 --- a/frontend/mgramseva/lib/providers/reports_provider.dart +++ b/frontend/mgramseva/lib/providers/reports_provider.dart @@ -10,6 +10,7 @@ import '../model/localization/language.dart'; import '../model/mdms/tax_period.dart'; import '../model/reports/bill_report_data.dart'; import '../model/reports/collection_report_data.dart'; +import '../model/reports/expense_bill_report_data.dart'; import '../repository/core_repo.dart'; import '../repository/reports_repo.dart'; import '../utils/common_methods.dart'; @@ -36,6 +37,7 @@ class ReportsProvider with ChangeNotifier { List? demandreports; List? collectionreports; List? inactiveconsumers; + List? expenseBillReportData; BillsTableData genericTableData = BillsTableData([], []); int limit = 10; int offset = 1; @@ -88,7 +90,20 @@ class ReportsProvider with ChangeNotifier { TableHeader(i18.common.INACTIVATED_DATE), TableHeader(i18.common.INACTIVATED_BY_NAME), ]; + List get expenseBillReportHeaderList => [ + TableHeader(i18.expense.EXPENSE_TYPE), + TableHeader(i18.expense.VENDOR_NAME), + TableHeader(i18.expense.AMOUNT), + TableHeader(i18.expense.BILL_DATE), + TableHeader(i18.expense.EXPENSE_START_DATE), + TableHeader(i18.expense.EXPENSE_END_DATE), + TableHeader(i18.expense.APPLICATION_STATUS), + TableHeader(i18.expense.PAID_DATE), + TableHeader(i18.expense.FILE_LINK), + TableHeader(i18.expense.LAST_MODIFIED_TIME), + TableHeader(i18.expense.LAST_MODIFIED_BY), + ]; void onChangeOfPageLimit( PaginationResponse response, String type, BuildContext context) { if (type == i18.dashboard.BILL_REPORT) { @@ -172,6 +187,36 @@ class ReportsProvider with ChangeNotifier { TableData('${inactivatedBy ?? '-'}'), ]); } + List getExpenseBillReportData(List list, + {bool isExcel = false}) { + return list.map((e) => getExpenseBillReportDataRow(e, isExcel: isExcel)).toList(); + } + TableDataRow getExpenseBillReportDataRow(ExpenseBillReportData data, + {bool isExcel = false}) { + String? vendorName = CommonMethods.truncateWithEllipsis(20, data.vendorName!); + String? typeOfExpense = CommonMethods.truncateWithEllipsis(20, data.typeOfExpense!); + String? applicationStatus = CommonMethods.truncateWithEllipsis(20, data.applicationStatus!); + String? lastModifiedBy = CommonMethods.truncateWithEllipsis(20, data.lastModifiedBy!); + String? fileLink = CommonMethods.truncateWithEllipsis(20, data.filestoreid!); + var billDate = DateFormats.timeStampToDate(data.billDate?.toInt(),format: "dd/MM/yyyy"); + var taxPeriodFrom = DateFormats.timeStampToDate(data.taxPeriodFrom?.toInt(),format: "dd/MM/yyyy"); + var taxPeriodTo = DateFormats.timeStampToDate(data.taxPeriodTo?.toInt(),format: "dd/MM/yyyy"); + var paidDate = DateFormats.timeStampToDate(data.paidDate?.toInt(),format: "dd/MM/yyyy"); + var lastModifiedTime = DateFormats.timeStampToDate(data.lastModifiedTime?.toInt(),format: "dd/MM/yyyy"); + return TableDataRow([ + TableData('${typeOfExpense ?? '-'}'), + TableData('${vendorName ?? '-'}'), + TableData('${data.amount ?? '-'}'), + TableData('${billDate ?? '-'}'), + TableData('${taxPeriodFrom ?? '-'}'), + TableData('${taxPeriodTo ?? '-'}'), + TableData('${applicationStatus ?? '-'}'), + TableData('${paidDate ?? '-'}'), + TableData('${fileLink ?? '-'}'), + TableData('${lastModifiedTime ?? '-'}'), + TableData('${lastModifiedBy ?? '-'}'), + ]); + } void callNotifier() { notifyListeners(); } @@ -524,7 +569,70 @@ class ReportsProvider with ChangeNotifier { callNotifier(); } } - + Future getExpenseBillReport( + {bool download = false, + int offset = 1, + int limit = 10, + String sortOrder = "ASC"}) async { + try { + var commonProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + if (selectedBillPeriod == null) { + throw Exception('Select Billing Cycle'); + } + Map params = { + 'tenantId': commonProvider.userDetails!.selectedtenant!.code, + 'monthstartDate': selectedBillPeriod?.split('-')[0], + 'monthendDate': selectedBillPeriod?.split('-')[1], + 'offset': '${offset - 1}', + 'limit': '${download ? -1 : limit}', + 'sortOrder': '$sortOrder' + }; + var response = await ReportsRepo().fetchExpenseBillReport(params); + if (response != null) { + expenseBillReportData = response; + if (download) { + generateExcel( + expenseBillReportHeaderList + .map((e) => + '${ApplicationLocalizations.of(navigatorKey.currentContext!).translate(e.label)}') + .toList(), + getExpenseBillReportData(expenseBillReportData!, isExcel: true) + .map>( + (e) => e.tableRow.map((e) => e.label).toList()) + .toList() ?? + [], + title: + 'ExpenseBillReport_${commonProvider.userDetails?.selectedtenant?.code?.substring(3)}_${selectedBillPeriod.toString().replaceAll('/', '_')}', + optionalData: [ + 'Expense Bill Report', + '$selectedBillPeriod', + '${ApplicationLocalizations.of(navigatorKey.currentContext!).translate(commonProvider.userDetails!.selectedtenant!.code!)}', + '${commonProvider.userDetails?.selectedtenant?.code?.substring(3)}', + 'Downloaded On ${DateFormats.timeStampToDate(DateTime.now().millisecondsSinceEpoch, format: 'dd/MMM/yyyy')}' + ]); + } else { + if (expenseBillReportData != null && expenseBillReportData!.isNotEmpty) { + this.limit = limit; + this.offset = offset; + this.genericTableData = BillsTableData( + expenseBillReportHeaderList, getExpenseBillReportData(expenseBillReportData!)); + } + } + streamController.add(response); + callNotifier(); + } else { + streamController.add('error'); + throw Exception('API Error'); + } + } + catch (e, s) { + ErrorHandler().allExceptionsHandler(navigatorKey.currentContext!, e, s); + streamController.addError('error'); + callNotifier(); + } + } void clearBuildTableData() { genericTableData = BillsTableData([], []); callNotifier(); diff --git a/frontend/mgramseva/lib/repository/reports_repo.dart b/frontend/mgramseva/lib/repository/reports_repo.dart index 575853ebc..0f88a4cb7 100644 --- a/frontend/mgramseva/lib/repository/reports_repo.dart +++ b/frontend/mgramseva/lib/repository/reports_repo.dart @@ -1,3 +1,4 @@ +import 'package:mgramseva/model/reports/expense_bill_report_data.dart'; import 'package:mgramseva/services/urls.dart'; import 'package:mgramseva/services/base_service.dart'; import 'package:provider/provider.dart'; @@ -121,4 +122,40 @@ class ReportsRepo extends BaseService{ } return inactiveConsumers; } + Future?> fetchExpenseBillReport(Map params, + [String? token]) async { + var commonProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + List? expenseBillReports; + final requestInfo = RequestInfo( + APIConstants.API_MODULE_NAME, + APIConstants.API_VERSION, + APIConstants.API_TS, + '_get', + APIConstants.API_DID, + APIConstants.API_KEY, + APIConstants.API_MESSAGE_ID, + commonProvider.userDetails?.accessToken, + commonProvider.userDetails?.userRequest?.toJson()); + + var res = await makeRequest( + url: Url.EXPENSE_BILL_REPORT, + queryParameters: params, + requestInfo: requestInfo, + body: {}, + method: RequestType.POST); + if (res != null && res['ExpenseBillReportData'] != null) { + try { + expenseBillReports = []; + res['ExpenseBillReportData'].forEach((val){ + expenseBillReports?.add(ExpenseBillReportData.fromJson(val)); + }); + } catch (e) { + print(e); + expenseBillReports = null; + } + } + return expenseBillReports; + } } \ No newline at end of file diff --git a/frontend/mgramseva/lib/screeens/reports/expense_bill_report.dart b/frontend/mgramseva/lib/screeens/reports/expense_bill_report.dart new file mode 100644 index 000000000..01deb2519 --- /dev/null +++ b/frontend/mgramseva/lib/screeens/reports/expense_bill_report.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../providers/reports_provider.dart'; +import '../../utils/localization/application_localizations.dart'; +import 'package:mgramseva/utils/constants/i18_key_constants.dart'; +import '../../utils/notifiers.dart'; +import '../../utils/testing_keys/testing_keys.dart'; +import '../../widgets/button.dart'; + +class ExpenseBillReport extends StatefulWidget { + final Function onViewClick; + + ExpenseBillReport({Key? key, required this.onViewClick}) : super(key: key); + + @override + State createState() => _ExpenseBillReportState(); +} + +class _ExpenseBillReportState extends State + with SingleTickerProviderStateMixin { + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + final isWideScreen = constraints.maxWidth > 700; + final containerMargin = isWideScreen + ? const EdgeInsets.only(top: 5.0, bottom: 5, right: 20, left: 10) + : const EdgeInsets.symmetric(vertical: 5.0, horizontal: 8); + return Consumer(builder: (_, reportProvider, child) { + return Container( + margin: containerMargin, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 30, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: constraints.maxWidth > 344?constraints.maxWidth / 2.5:constraints.maxWidth / 3, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "4. ", + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w700), + ), + Expanded( + child: Text( + ApplicationLocalizations.of(context) + .translate(i18.dashboard.EXPENSE_BILL_REPORT), + maxLines: 3, + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w700), + ), + ), + ], + ), + ), + Row( + children: [ + Container( + width: 50, + child: Button( + ApplicationLocalizations.of(context) + .translate(i18.common.VIEW), + () { + if (reportProvider.selectedBillPeriod == null) { + Notifiers.getToastMessage( + context, 'Select Billing Cycle', 'ERROR'); + } else { + reportProvider.clearTableData(); + reportProvider.getExpenseBillReport(); + widget.onViewClick( + true, i18.dashboard.EXPENSE_BILL_REPORT); + } + }, + key: Keys.billReport.EXPENSE_BILL_REPORT_VIEW_BUTTON, + ), + ), + SizedBox( + width: 10, + ), + TextButton.icon( + onPressed: () { + if (reportProvider.selectedBillPeriod == null) { + Notifiers.getToastMessage( + context, 'Select Billing Cycle', 'ERROR'); + } else { + reportProvider.getExpenseBillReport(download: true); + } + }, + icon: Icon(Icons.download_sharp), + label: Text(ApplicationLocalizations.of(context) + .translate(i18.common.CORE_DOWNLOAD))), + ], + ), + ], + ), + ], + ), + ); + }); + }); + } +} diff --git a/frontend/mgramseva/lib/screeens/reports/reports.dart b/frontend/mgramseva/lib/screeens/reports/reports.dart index 95fe976a2..72ae25668 100644 --- a/frontend/mgramseva/lib/screeens/reports/reports.dart +++ b/frontend/mgramseva/lib/screeens/reports/reports.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:mgramseva/screeens/reports/expense_bill_report.dart'; import 'package:mgramseva/screeens/reports/inactive_consumer_report.dart'; import 'package:mgramseva/screeens/reports/view_table.dart'; import 'package:provider/provider.dart'; @@ -214,7 +215,8 @@ class _Reports extends State with SingleTickerProviderStateMixin { children: [ BillReport(onViewClick: showTable), CollectionReport(onViewClick: showTable), - InactiveConsumerReport(onViewClick: showTable,) + InactiveConsumerReport(onViewClick: showTable,), + ExpenseBillReport(onViewClick: showTable,) ], ), ), diff --git a/frontend/mgramseva/lib/services/urls.dart b/frontend/mgramseva/lib/services/urls.dart index 9972db9f3..634f402e8 100644 --- a/frontend/mgramseva/lib/services/urls.dart +++ b/frontend/mgramseva/lib/services/urls.dart @@ -93,6 +93,8 @@ class Url { 'ws-services/wc/_collectionReport'; static const String INACTIVE_CONSUMER_REPORT= 'ws-services/wc/_inactiveConsumerReport'; + static const String EXPENSE_BILL_REPORT= + 'echallan-services/eChallan/v1/_expenseBillReport'; } diff --git a/frontend/mgramseva/lib/utils/constants/i18_key_constants.dart b/frontend/mgramseva/lib/utils/constants/i18_key_constants.dart index ec4a240b3..4aff616a7 100644 --- a/frontend/mgramseva/lib/utils/constants/i18_key_constants.dart +++ b/frontend/mgramseva/lib/utils/constants/i18_key_constants.dart @@ -357,6 +357,11 @@ class Expense { String get HAS_THIS_BILL_PAID => 'HAS_THIS_BILL_PAID'; String get CANCELLED => 'CANCELLED'; String get ADD_NEW_EXPENSE => 'ADD_NEW_EXPENSE'; + String get APPLICATION_STATUS => 'APPLICATION_STATUS'; + String get PAID_DATE => 'PAID_DATE'; + String get FILE_LINK => 'FILE_LINK'; + String get LAST_MODIFIED_TIME => 'LAST_MODIFIED_TIME'; + String get LAST_MODIFIED_BY => 'LAST_MODIFIED_BY'; } class CreateConsumer { @@ -656,6 +661,7 @@ class _DashBoard { String get PENDING_EXPENDITURE => 'PENDING_EXPENDITURE'; String get ACTUAL_PAYMENT => 'ACTUAL_PAYMENT'; String get SUMMARY_REPORT => 'SUMMARY_REPORT'; + String get EXPENSE_BILL_REPORT => 'EXPENSE_BILL_REPORT'; String get USER_GAVE_FEEDBACK => 'USER_GAVE_FEEDBACK'; String get ANNUAL_SHARE_MSG_WEB => 'ANNUAL_SHARE_MSG_WEB'; diff --git a/frontend/mgramseva/lib/utils/testing_keys/testing_keys.dart b/frontend/mgramseva/lib/utils/testing_keys/testing_keys.dart index abae97452..b87a79b37 100644 --- a/frontend/mgramseva/lib/utils/testing_keys/testing_keys.dart +++ b/frontend/mgramseva/lib/utils/testing_keys/testing_keys.dart @@ -138,4 +138,5 @@ class BillReportKeys { Key get COLLECTION_REPORT_DOWNLOAD_BUTTON => Key("collection_report_download_button"); Key get BILL_REPORT_BILLING_YEAR => Key("bill_report_billing_year"); Key get BILL_REPORT_BILLING_CYCLE => Key("bill_report_billing_cycle"); + Key get EXPENSE_BILL_REPORT_VIEW_BUTTON => Key("expense_bill_report_view_button"); } \ No newline at end of file