Skip to content

Commit 88ed86f

Browse files
committed
Merge branch 'develop'
2 parents 64037aa + 764255e commit 88ed86f

25 files changed

+179
-75
lines changed

ios/Runner.xcodeproj/project.pbxproj

+6-6
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@
364364
CLANG_ENABLE_MODULES = YES;
365365
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
366366
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
367-
CURRENT_PROJECT_VERSION = 109;
367+
CURRENT_PROJECT_VERSION = 110;
368368
DEVELOPMENT_TEAM = NPC44Y2C98;
369369
ENABLE_BITCODE = NO;
370370
INFOPLIST_FILE = Runner/Info.plist;
@@ -373,7 +373,7 @@
373373
"$(inherited)",
374374
"@executable_path/Frameworks",
375375
);
376-
MARKETING_VERSION = 5.0.109;
376+
MARKETING_VERSION = 5.0.110;
377377
PRODUCT_BUNDLE_IDENTIFIER = com.invoiceninja.app;
378378
PRODUCT_NAME = "$(TARGET_NAME)";
379379
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -497,7 +497,7 @@
497497
CLANG_ENABLE_MODULES = YES;
498498
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
499499
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
500-
CURRENT_PROJECT_VERSION = 109;
500+
CURRENT_PROJECT_VERSION = 110;
501501
DEVELOPMENT_TEAM = NPC44Y2C98;
502502
ENABLE_BITCODE = NO;
503503
INFOPLIST_FILE = Runner/Info.plist;
@@ -506,7 +506,7 @@
506506
"$(inherited)",
507507
"@executable_path/Frameworks",
508508
);
509-
MARKETING_VERSION = 5.0.109;
509+
MARKETING_VERSION = 5.0.110;
510510
PRODUCT_BUNDLE_IDENTIFIER = com.invoiceninja.app;
511511
PRODUCT_NAME = "$(TARGET_NAME)";
512512
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -524,7 +524,7 @@
524524
CLANG_ENABLE_MODULES = YES;
525525
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
526526
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
527-
CURRENT_PROJECT_VERSION = 109;
527+
CURRENT_PROJECT_VERSION = 110;
528528
DEVELOPMENT_TEAM = NPC44Y2C98;
529529
ENABLE_BITCODE = NO;
530530
INFOPLIST_FILE = Runner/Info.plist;
@@ -533,7 +533,7 @@
533533
"$(inherited)",
534534
"@executable_path/Frameworks",
535535
);
536-
MARKETING_VERSION = 5.0.109;
536+
MARKETING_VERSION = 5.0.110;
537537
PRODUCT_BUNDLE_IDENTIFIER = com.invoiceninja.app;
538538
PRODUCT_NAME = "$(TARGET_NAME)";
539539
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

lib/constants.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Constants {
44
}
55

66
// TODO remove version once #46609 is fixed
7-
const String kClientVersion = '5.0.109';
7+
const String kClientVersion = '5.0.110';
88
const String kMinServerVersion = '5.0.4';
99

1010
const String kAppName = 'Invoice Ninja';
@@ -925,3 +925,4 @@ const String kActivityRestorePurchaseOrder = '134';
925925
const String kActivityEmailPurchaseOrder = '135';
926926
const String kActivityViewPurchaseOrder = '136';
927927
const String kActivityAcceptPurchaseOrder = '137';
928+
const String kActivityEmailPayment = '138';

lib/data/models/invoice_model.dart

+2
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ abstract class InvoiceEntity extends Object
630630
if (isPurchaseOrder &&
631631
[
632632
kPurchaseOrderStatusAccepted,
633+
kPurchaseOrderStatusReceived,
633634
].contains(statusId)) {
634635
return true;
635636
}
@@ -929,6 +930,7 @@ abstract class InvoiceEntity extends Object
929930
if (status.id == statusId || status.id == calculatedStatusId) {
930931
return true;
931932
} else if (status.id == kInvoiceStatusUnpaid &&
933+
isInvoice &&
932934
isUnpaid &&
933935
isSent &&
934936
!isCancelledOrReversed) {

lib/data/models/task_model.dart

+20-2
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,27 @@ abstract class TaskEntity extends Object
421421
return false;
422422
}
423423

424-
final date = convertDateTimeToSqlDate(taskTimes.first.startDate.toLocal());
424+
final taskStartDate =
425+
convertDateTimeToSqlDate(taskTimes.first.startDate.toLocal());
426+
if (startDate.compareTo(taskStartDate) <= 0 &&
427+
endDate.compareTo(taskStartDate) >= 0) {
428+
return true;
429+
}
430+
431+
final completedTimes = taskTimes.where((element) => !element.isRunning);
425432

426-
return startDate.compareTo(date) <= 0 && endDate.compareTo(date) >= 0;
433+
if (completedTimes.isNotEmpty) {
434+
final lastTaskTime = completedTimes.last;
435+
final taskEndDate =
436+
convertDateTimeToSqlDate(lastTaskTime.endDate.toLocal());
437+
438+
if (startDate.compareTo(taskEndDate) <= 0 &&
439+
endDate.compareTo(taskEndDate) >= 0) {
440+
return true;
441+
}
442+
}
443+
444+
return false;
427445
}
428446

429447
int get startTimestamp {

lib/data/repositories/task_repository.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ class TaskRepository {
3535
return taskResponse.data;
3636
}
3737

38-
Future<BuiltList<TaskEntity>> loadList(
39-
Credentials credentials, int createdAt, bool filterDeleted) async {
40-
final url = credentials.url + '/tasks?created_at=$createdAt';
38+
Future<BuiltList<TaskEntity>> loadList(Credentials credentials, int page,
39+
int createdAt, bool filterDeleted) async {
40+
final url = credentials.url +
41+
'/tasks?per_page=$kMaxRecordsPerPage&page=$page&created_at=$createdAt';
4142

4243
/* Server is incorrect if client isn't set
4344
if (filterDeleted) {

lib/redux/app/app_actions.dart

+9
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@ void createEntity({
10161016
bool force = false,
10171017
Completer completer,
10181018
Completer cancelCompleter,
1019+
BaseEntity filterEntity,
10191020
}) {
10201021
final store = StoreProvider.of<AppState>(context);
10211022
final state = store.state;
@@ -1038,6 +1039,14 @@ void createEntity({
10381039
store.dispatch(ToggleEditorLayout(entity.entityType));
10391040
}
10401041

1042+
if (filterEntity != null) {
1043+
if (uiState.filterEntityType != filterEntity.entityType ||
1044+
uiState.filterEntityId != filterEntity.id) {
1045+
store.dispatch(ClearEntitySelection(entityType: entity.entityType));
1046+
store.dispatch(FilterByEntity(entity: filterEntity));
1047+
}
1048+
}
1049+
10411050
switch (entity.entityType) {
10421051
case EntityType.client:
10431052
store.dispatch(EditClient(

lib/redux/credit/credit_actions.dart

+8-8
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ Future handleCreditAction(
462462
final localization = AppLocalization.of(context);
463463
final credit = credits.first as InvoiceEntity;
464464
final creditIds = credits.map((credit) => credit.id).toList();
465+
final client = state.clientState.get(credit.clientId);
465466

466467
switch (action) {
467468
case EntityAction.edit:
@@ -497,7 +498,7 @@ Future handleCreditAction(
497498
TextButton(
498499
onPressed: () {
499500
Navigator.of(context).pop();
500-
editEntity(entity: state.clientState.get(credit.clientId));
501+
editEntity(entity: client);
501502
},
502503
child: Text(localization.editClient.toUpperCase()))
503504
]);
@@ -587,13 +588,12 @@ Future handleCreditAction(
587588
case EntityAction.applyCredit:
588589
createEntity(
589590
context: context,
590-
entity: PaymentEntity(
591-
state: state, client: state.clientState.get(credit.clientId))
592-
.rebuild((b) => b
593-
..typeId = kPaymentTypeCredit
594-
..credits.addAll(credits
595-
.map((credit) => PaymentableEntity.fromCredit(credit))
596-
.toList())),
591+
entity: PaymentEntity(state: state, client: client).rebuild((b) => b
592+
..typeId = kPaymentTypeCredit
593+
..credits.addAll(credits
594+
.map((credit) => PaymentableEntity.fromCredit(credit))
595+
.toList())),
596+
filterEntity: client,
597597
);
598598
break;
599599
case EntityAction.download:

lib/redux/invoice/invoice_actions.dart

+8-8
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
528528
final localization = AppLocalization.of(context);
529529
final invoice = invoices.first as InvoiceEntity;
530530
final invoiceIds = invoices.map((invoice) => invoice.id).toList();
531+
final client = state.clientState.get(invoice.clientId);
531532

532533
switch (action) {
533534
case EntityAction.edit:
@@ -616,7 +617,7 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
616617
TextButton(
617618
onPressed: () {
618619
Navigator.of(context).pop();
619-
editEntity(entity: state.clientState.get(invoice.clientId));
620+
editEntity(entity: client);
620621
},
621622
child: Text(localization.editClient.toUpperCase()))
622623
]);
@@ -694,13 +695,12 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
694695
case EntityAction.newPayment:
695696
createEntity(
696697
context: context,
697-
entity: PaymentEntity(
698-
state: state, client: state.clientState.get(invoice.clientId))
699-
.rebuild((b) => b
700-
..invoices.addAll(invoices
701-
.where((invoice) => !(invoice as InvoiceEntity).isPaid)
702-
.map((invoice) => PaymentableEntity.fromInvoice(invoice))
703-
.toList())),
698+
entity: PaymentEntity(state: state, client: client).rebuild((b) => b
699+
..invoices.addAll(invoices
700+
.where((invoice) => !(invoice as InvoiceEntity).isPaid)
701+
.map((invoice) => PaymentableEntity.fromInvoice(invoice))
702+
.toList())),
703+
filterEntity: client,
704704
);
705705
break;
706706
case EntityAction.download:

lib/redux/task/task_actions.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ class LoadTaskActivity {
7373
}
7474

7575
class LoadTasks {
76-
LoadTasks({this.completer});
76+
LoadTasks({this.completer, this.page = 1});
7777

7878
final Completer completer;
79+
final int page;
7980
}
8081

8182
class LoadTaskRequest implements StartLoading {}

lib/redux/task/task_middleware.dart

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Flutter imports:
22
import 'package:flutter/material.dart';
33
import 'package:flutter/widgets.dart';
4+
import 'package:invoiceninja_flutter/constants.dart';
45

56
// Package imports:
67
import 'package:redux/redux.dart';
@@ -284,16 +285,24 @@ Middleware<AppState> _loadTasks(TaskRepository repository) {
284285
repository
285286
.loadList(
286287
state.credentials,
288+
action.page,
287289
state.createdAtLimit,
288290
state.filterDeletedClients,
289291
)
290292
.then((data) {
291293
store.dispatch(LoadTasksSuccess(data));
292294

293-
if (action.completer != null) {
294-
action.completer.complete(null);
295+
if (data.length == kMaxRecordsPerPage) {
296+
store.dispatch(LoadTasks(
297+
completer: action.completer,
298+
page: action.page + 1,
299+
));
300+
} else {
301+
if (action.completer != null) {
302+
action.completer.complete(null);
303+
}
304+
store.dispatch(LoadVendors());
295305
}
296-
store.dispatch(LoadVendors());
297306
}).catchError((Object error) {
298307
print(error);
299308
store.dispatch(LoadTasksFailure(error));

lib/ui/app/entity_dropdown.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ class _EntityDropdownState extends State<EntityDropdown> {
179179
builder: (BuildContext context) {
180180
return EntityDropdownDialog(
181181
entityMap: _entityMap,
182-
entityList: widget.entityList ?? _entityMap.keys.toList(),
182+
entityList: (widget.entityList ?? _entityMap.keys)
183+
.where((elementId) => !widget.excludeIds.contains(elementId))
184+
.toList(),
183185
onSelected: (entity, [update = true]) {
184186
if (entity?.id == widget.entityId) {
185187
return;

lib/ui/app/history_drawer.dart

+10-5
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,15 @@ class _HistoryListTileState extends State<HistoryListTile> {
122122
].contains(history.entityType)) {
123123
title = Text(localization.lookup(history.entityType.toString()));
124124
if (history.entityType == EntityType.reports) {
125-
subtitle =
126-
Text(localization.lookup(state.uiState.reportsUIState.report));
125+
subtitle = Text(
126+
localization.lookup(state.uiState.reportsUIState.report),
127+
style: Theme.of(context).textTheme.bodySmall,
128+
);
127129
} else if (history.entityType == EntityType.settings) {
128-
subtitle =
129-
Text(localization.lookup(history.id ?? kSettingsCompanyDetails));
130+
subtitle = Text(
131+
localization.lookup(history.id ?? kSettingsCompanyDetails),
132+
style: Theme.of(context).textTheme.bodySmall,
133+
);
130134
}
131135
} else {
132136
entity = state.getEntityMap(history.entityType)[history.id] as BaseEntity;
@@ -158,7 +162,7 @@ class _HistoryListTileState extends State<HistoryListTile> {
158162
key: ValueKey('__${history.id}_${history.entityType}__'),
159163
leading: Icon(getEntityIcon(history.entityType)),
160164
title: Row(
161-
crossAxisAlignment: CrossAxisAlignment.center,
165+
crossAxisAlignment: CrossAxisAlignment.start,
162166
children: [
163167
Expanded(
164168
child: Column(
@@ -168,6 +172,7 @@ class _HistoryListTileState extends State<HistoryListTile> {
168172
subtitle,
169173
],
170174
)),
175+
SizedBox(width: 8),
171176
Flexible(
172177
child: LiveText(
173178
() => timeago.format(history.dateTime,

lib/ui/purchase_order/purchase_order_list_item.dart

+7-4
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,11 @@ class PurchaseOrderListItem extends StatelessWidget {
155155
),
156156
SizedBox(width: 10),
157157
Text(
158-
formatNumber(purchaseOrder.amount, context),
158+
formatNumber(
159+
purchaseOrder.amount,
160+
context,
161+
vendorId: vendor.id,
162+
),
159163
style: textStyle,
160164
textAlign: TextAlign.end,
161165
),
@@ -198,10 +202,9 @@ class PurchaseOrderListItem extends StatelessWidget {
198202
SizedBox(width: 4),
199203
Text(
200204
formatNumber(
201-
purchaseOrder.balance > 0
202-
? purchaseOrder.balance
203-
: purchaseOrder.amount,
205+
purchaseOrder.amount,
204206
context,
207+
vendorId: vendor.id,
205208
),
206209
style: Theme.of(context).textTheme.subtitle1),
207210
],

lib/ui/reports/reports_screen.dart

+11-8
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,11 @@ class ReportsScreen extends StatelessWidget {
282282
]
283283
];
284284

285-
final entities = reportResult.entities ?? [];
286-
final firstEntity = entities.isNotEmpty ? entities.first : null;
287-
if (entities.length > kMaxEntitiesPerBulkAction) {
288-
entities.removeRange(kMaxEntitiesPerBulkAction, entities.length);
285+
final cappedEntities = [...reportResult.entities ?? []];
286+
final firstEntity = cappedEntities.isNotEmpty ? cappedEntities.first : null;
287+
if (cappedEntities.length > kMaxEntitiesPerBulkAction) {
288+
cappedEntities.removeRange(
289+
kMaxEntitiesPerBulkAction, cappedEntities.length);
289290
}
290291

291292
final chartChildren = [
@@ -382,16 +383,18 @@ class ReportsScreen extends StatelessWidget {
382383
multiselect: true),
383384
entity: firstEntity,
384385
onSelected: (context, action) {
386+
final entities = action.applyMaxLimit
387+
? cappedEntities
388+
: reportResult.entities;
385389
confirmCallback(
386390
context: context,
387391
message: localization.lookup(action.toString()) +
388392
' • ' +
389-
(reportResult.entities.length == 1
393+
(entities.length == 1
390394
? '1 ${localization.lookup(firstEntity.entityType.toString())}'
391-
: '${reportResult.entities.length} ${localization.lookup(firstEntity.entityType.plural)}'),
395+
: '${entities.length} ${localization.lookup(firstEntity.entityType.plural)}'),
392396
callback: (_) {
393-
handleEntitiesActions(
394-
reportResult.entities, action);
397+
handleEntitiesActions(entities, action);
395398
});
396399
}),
397400
),

0 commit comments

Comments
 (0)