Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
hillelcoren committed Oct 31, 2023
2 parents 87d981d + a5bdbd7 commit ed71990
Show file tree
Hide file tree
Showing 20 changed files with 444 additions and 61 deletions.
15 changes: 12 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,33 @@ jobs:
sentry_url: ${{secrets.sentry_url}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: subosito/flutter-action@v1
- name: Checkout code
uses: actions/checkout@v1

- name: Setup Flutter
uses: subosito/flutter-action@v1
with:
flutter-version: '3.13.6'
#channel: 'stable'

- name: Install Sentry
run: |
curl -sL https://sentry.io/get-cli/ | bash
- name: Setup Flutter
- name: Check Flutter
run: |
flutter doctor -v
flutter pub get
flutter config --enable-web
- name: Prepare App
run: |
cp lib/.env.dart.example lib/.env.dart
sed -i 's/secret/${{secrets.api_secret}}/g' lib/.env.dart
echo "const FLUTTER_VERSION = const <String, String>" > lib/flutter_version.dart
flutter --version --machine >> lib/flutter_version.dart
echo ";" >> lib/flutter_version.dart
- name: Build Hosted App
run: |
#export SENTRY_RELEASE=$(sentry-cli releases propose-version)
Expand Down Expand Up @@ -70,6 +77,7 @@ jobs:
#sentry-cli --auth-token ${{secrets.sentry_auth_token}} --url ${{secrets.sentry_url}} releases --org ${{secrets.sentry_org}} finalize $SENTRY_RELEASE
#sentry-cli --auth-token ${{secrets.sentry_auth_token}} --url ${{secrets.sentry_url}} releases --org ${{secrets.sentry_org}} deploys $SENTRY_RELEASE new -e production
- name: Build Profile App
run: |
flutter build web --profile
Expand All @@ -83,6 +91,7 @@ jobs:
git commit -m 'Admin Portal - Profile'
git push
cd ..
- name: Build Selfhosted App
run: |
cp lib/utils/oauth.dart.foss lib/utils/oauth.dart
Expand Down
2 changes: 2 additions & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ const String kReportPayment = 'payment';
const String kReportProduct = 'product';
const String kReportProfitAndLoss = 'profit_and_loss';
const String kReportTask = 'task';
const String kReportTaskItem = 'task_item';
const String kReportInvoiceTax = 'invoice_tax';
const String kReportPaymentTax = 'payment_tax';
const String kReportQuote = 'quote';
Expand Down Expand Up @@ -736,6 +737,7 @@ const String kTaxRegionAustralia = 'AU';
const String kReportGroupDay = 'day';
const String kReportGroupWeek = 'week';
const String kReportGroupMonth = 'month';
const String kReportGroupQuarter = 'quarter';
const String kReportGroupYear = 'year';

const int kModuleRecurringInvoices = 1;
Expand Down
1 change: 1 addition & 0 deletions lib/data/models/entities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class EntityType extends EnumClass {
EntityType.task,
EntityType.expense,
EntityType.invoice,
EntityType.quote,
];
case EntityType.group:
return [
Expand Down
29 changes: 16 additions & 13 deletions lib/data/models/task_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ abstract class TaskTime implements Built<TaskTime, TaskTimeBuilder> {
);
}

double calculateAmount(double taskRate) =>
taskRate * round(duration.inSeconds / 3600, 3);

static Serializer<TaskTime> get serializer => _$taskTimeSerializer;
}

Expand Down Expand Up @@ -350,7 +353,7 @@ abstract class TaskEntity extends Object

TaskEntity stop() {
final times = getTaskTimes();
final taskTime = times.last!.stop;
final taskTime = times.last.stop;

return updateTaskTime(taskTime, times.length - 1);
}
Expand All @@ -373,7 +376,7 @@ abstract class TaskEntity extends Object
bool isValid = true;

times.forEach((time) {
final startDate = time!.startDate;
final startDate = time.startDate;
final endDate = time.endDate;

if (time.isRunning) {
Expand Down Expand Up @@ -404,7 +407,7 @@ abstract class TaskEntity extends Object
int counter = 0;

times.forEach((time) {
final startDate = time!.startDate;
final startDate = time.startDate;
final endDate = time.endDate;

if (time.isRunning) {
Expand Down Expand Up @@ -434,7 +437,7 @@ abstract class TaskEntity extends Object
return false;
}

return taskTimes.any((taskTime) => taskTime!.isRunning);
return taskTimes.any((taskTime) => taskTime.isRunning);
}

bool isBetween(String? startDate, String? endDate) {
Expand All @@ -445,16 +448,16 @@ abstract class TaskEntity extends Object
}

final taskStartDate =
convertDateTimeToSqlDate(taskTimes.first!.startDate!.toLocal());
convertDateTimeToSqlDate(taskTimes.first.startDate!.toLocal());
if (startDate!.compareTo(taskStartDate) <= 0 &&
endDate!.compareTo(taskStartDate) >= 0) {
return true;
}

final completedTimes = taskTimes.where((element) => !element!.isRunning);
final completedTimes = taskTimes.where((element) => !element.isRunning);

if (completedTimes.isNotEmpty) {
final lastTaskTime = completedTimes.last!;
final lastTaskTime = completedTimes.last;
final taskEndDate =
convertDateTimeToSqlDate(lastTaskTime.endDate!.toLocal());

Expand Down Expand Up @@ -504,8 +507,8 @@ abstract class TaskEntity extends Object
return last[1].round();
}

List<TaskTime?> getTaskTimes({bool sort = true}) {
final List<TaskTime?> details = [];
List<TaskTime> getTaskTimes({bool sort = true}) {
final List<TaskTime> details = [];

if (timeLog.isEmpty) {
return details;
Expand Down Expand Up @@ -541,8 +544,8 @@ abstract class TaskEntity extends Object
});

if (sort) {
details.sort(
(timeA, timeB) => timeA!.startDate!.compareTo(timeB!.startDate!));
details
.sort((timeA, timeB) => timeA.startDate!.compareTo(timeB.startDate!));
}

return details;
Expand Down Expand Up @@ -588,8 +591,8 @@ abstract class TaskEntity extends Object
int seconds = 0;

getTaskTimes().forEach((taskTime) {
if (!onlyBillable || taskTime!.isBillable) {
seconds += taskTime!.duration.inSeconds;
if (!onlyBillable || taskTime.isBillable) {
seconds += taskTime.duration.inSeconds;
}
});

Expand Down
16 changes: 11 additions & 5 deletions lib/data/web_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,17 @@ void _checkResponse(String url, http.Response response) {
final minClientVersion = response.headers['x-minimum-client-version'];

if (response.statusCode >= 500) {
throw _parseError(response.statusCode, response.body);
throw _parseError(
response.statusCode, response.body, response.reasonPhrase);
} else if (serverVersion == null) {
throw 'Error: please check that Invoice Ninja v5 is installed on the server\n\nURL: $url\n\nResponse: ${response.body.length > 200 ? response.body.substring(0, 200) : response.body}\n\nHeaders: ${response.headers}}';
} else if (Version.parse(kClientVersion) < Version.parse(minClientVersion!)) {
throw 'Error: client not supported, please update to the latest version [Current v$kClientVersion < Minimum v$minClientVersion]';
} else if (Version.parse(serverVersion) < Version.parse(kMinServerVersion)) {
throw 'Error: server not supported, please update to the latest version [Current v$serverVersion < Minimum v$kMinServerVersion]';
} else if (response.statusCode >= 400) {
throw _parseError(response.statusCode, response.body);
throw _parseError(
response.statusCode, response.body, response.reasonPhrase);
}
}

Expand All @@ -277,8 +279,12 @@ void _preCheck() {
*/
}

String _parseError(int code, String response) {
dynamic message = response;
String _parseError(int code, String response, String? reason) {
String message = '';

if ((reason ?? '').isNotEmpty) {
message += reason! + ' • ';
}

if (response.contains('DOCTYPE html')) {
return '$code: An error occurred';
Expand All @@ -287,7 +293,7 @@ String _parseError(int code, String response) {
try {
final dynamic jsonResponse = json.decode(response);

message = jsonResponse['message'] ?? jsonResponse;
message += jsonResponse['message'] ?? jsonResponse;

if (jsonResponse['errors'] != null &&
(jsonResponse['errors'] as Map).isNotEmpty) {
Expand Down
2 changes: 1 addition & 1 deletion lib/redux/dashboard/dashboard_selectors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ List<ChartDataGroup> chartTasks(
// skip it
} else {
task.getTaskTimes().forEach((taskTime) {
taskTime!.getParts().forEach((date, duration) {
taskTime.getParts().forEach((date, duration) {
if (settings.groupBy == kReportGroupYear) {
date = date.substring(0, 4) + '-01-01';
} else if (settings.groupBy == kReportGroupMonth) {
Expand Down
4 changes: 2 additions & 2 deletions lib/redux/project/project_selectors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ List<InvoiceItemEntity> convertProjectToInvoiceItem({
final taskTimesA = taskA!.getTaskTimes();
final taskTimesB = taskB!.getTaskTimes();

final taskADate = taskTimesA.isEmpty ? null : taskTimesA.first!.startDate;
final taskBDate = taskTimesB.isEmpty ? null : taskTimesB.first!.startDate;
final taskADate = taskTimesA.isEmpty ? null : taskTimesA.first.startDate;
final taskBDate = taskTimesB.isEmpty ? null : taskTimesB.first.startDate;

if (taskADate == null) {
return 1;
Expand Down
4 changes: 2 additions & 2 deletions lib/redux/task/task_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,10 +420,10 @@ void handleTaskAction(
final taskBTimes = taskBEntity.getTaskTimes();
final taskADate = taskATimes.isEmpty
? convertTimestampToDate(taskA.createdAt)
: taskATimes.first!.startDate!;
: taskATimes.first.startDate!;
final taskBDate = taskBTimes.isEmpty
? convertTimestampToDate(taskB.createdAt)
: taskBTimes.first!.startDate!;
: taskBTimes.first.startDate!;
return taskADate.compareTo(taskBDate);
});

Expand Down
4 changes: 2 additions & 2 deletions lib/redux/task/task_selectors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ InvoiceItemEntity convertTaskToInvoiceItem({
task
.getTaskTimes()
.where((time) =>
time!.startDate != null && time.endDate != null && time.isBillable)
time.startDate != null && time.endDate != null && time.isBillable)
.forEach((time) {
final hours = round(time!.duration.inSeconds / 3600, 3);
final hours = round(time.duration.inSeconds / 3600, 3);
final hoursStr = hours == 1
? ' • 1 ${localization.hour}'
: ' • $hours ${localization.hours}';
Expand Down
2 changes: 0 additions & 2 deletions lib/ui/invoice/invoice_pdf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
import 'package:invoiceninja_flutter/ui/app/presenters/entity_presenter.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart';
import 'package:invoiceninja_flutter/utils/dialogs.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
Expand Down Expand Up @@ -362,7 +361,6 @@ Future<Response?> _loadPDF(
errorMessage += response.body;
}

showErrorDialog(message: errorMessage);
throw errorMessage;
}

Expand Down
12 changes: 11 additions & 1 deletion lib/ui/reports/reports_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ class ReportsScreen extends StatelessWidget {
],
kReportProduct,
kReportProfitAndLoss,
kReportTask,
if (state.company.isModuleEnabled(EntityType.task)) ...[
kReportTask,
kReportTaskItem,
],
if (state.company.isModuleEnabled(EntityType.vendor)) ...[
kReportVendor,
if (state.company.isModuleEnabled(EntityType.purchaseOrder))
Expand Down Expand Up @@ -187,6 +190,10 @@ class ReportsScreen extends StatelessWidget {
child: Text(localization.month),
value: kReportGroupMonth,
),
DropdownMenuItem(
child: Text(localization.quarter),
value: kReportGroupQuarter,
),
DropdownMenuItem(
child: Text(localization.year),
value: kReportGroupYear,
Expand Down Expand Up @@ -1390,6 +1397,9 @@ class ReportResult {
customStartDate = group;
if (reportState.subgroup == kReportGroupDay) {
customEndDate = convertDateTimeToSqlDate(date);
} else if (reportState.subgroup == kReportGroupQuarter) {
customEndDate =
convertDateTimeToSqlDate(addDays(addMonths(date!, 3), -1));
} else if (reportState.subgroup == kReportGroupMonth) {
customEndDate =
convertDateTimeToSqlDate(addDays(addMonths(date!, 1), -1));
Expand Down
28 changes: 28 additions & 0 deletions lib/ui/reports/reports_screen_vm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:invoiceninja_flutter/ui/reports/purchase_order_item_report.dart'
import 'package:invoiceninja_flutter/ui/reports/purchase_order_report.dart';
import 'package:invoiceninja_flutter/ui/reports/recurring_expense_report.dart';
import 'package:invoiceninja_flutter/ui/reports/recurring_invoice_report.dart';
import 'package:invoiceninja_flutter/ui/reports/task_item_report.dart';
import 'package:invoiceninja_flutter/ui/reports/transaction_report.dart';
import 'package:invoiceninja_flutter/ui/reports/vendor_report.dart';
import 'package:invoiceninja_flutter/utils/files.dart';
Expand Down Expand Up @@ -214,6 +215,20 @@ class ReportsScreenVM {
state.staticState,
);
break;
case kReportTaskItem:
reportResult = memoizedTaskItemReport(
state.userCompany,
state.uiState.reportsUIState,
state.taskState.map,
state.invoiceState.map,
state.groupState.map,
state.clientState.map,
state.taskStatusState.map,
state.userState.map,
state.projectState.map,
state.staticState,
);
break;
case kReportQuote:
reportResult = memoizedQuoteReport(
state.userCompany,
Expand Down Expand Up @@ -637,6 +652,19 @@ GroupTotals calculateReportTotals({
group = group.substring(0, 4) + '-01-01';
} else if (reportState.subgroup == kReportGroupMonth) {
group = group.substring(0, 7) + '-01';
} else if (reportState.subgroup == kReportGroupQuarter) {
final parts = group.split('-');
final month = parseInt(parts[1]) ?? 0;
group = parts[0] + '-';
if (month <= 3) {
group += '01-01';
} else if (month <= 6) {
group += '04-01';
} else if (month <= 9) {
group += '07-01';
} else {
group += '10-01';
}
} else if (reportState.subgroup == kReportGroupWeek) {
final date = DateTime.parse(group);
final dateWeek =
Expand Down
Loading

0 comments on commit ed71990

Please sign in to comment.