Transactions

This commit is contained in:
Hillel Coren 2022-09-22 13:35:49 +03:00
parent a2b4f1e508
commit 55f86ce09c
5 changed files with 227 additions and 29 deletions

View File

@ -85,6 +85,7 @@ abstract class TransactionEntity extends Object
invoiceIds: '',
statusId: '',
baseType: TYPE_DEPOSIT,
transactionId: 0,
);
}
@ -105,7 +106,7 @@ abstract class TransactionEntity extends Object
@BuiltValueField(wireName: 'category_type')
String get category;
@BuiltValueField(wireName: 'baseType')
@BuiltValueField(wireName: 'base_type')
String get baseType;
String get date;
@ -118,12 +119,18 @@ abstract class TransactionEntity extends Object
@BuiltValueField(wireName: 'status_id')
String get statusId;
//@BuiltValueField(wireName: 'ninja_category_id')
//String get categoryId;
@BuiltValueField(wireName: 'invoice_ids')
String get invoiceIds;
@BuiltValueField(wireName: 'expense_id')
String get expenseId;
@BuiltValueField(wireName: 'transaction_id')
int get transactionId;
//@BuiltValueField(wireName: 'is_matched')
//bool get isMached;
@ -226,9 +233,7 @@ abstract class TransactionEntity extends Object
if (response == 0) {
// STARTER: sort default - do not remove comment
return transactionA.description
.toLowerCase()
.compareTo(transactionB.description.toLowerCase());
return transactionA.transactionId.compareTo(transactionB.transactionId);
} else {
return response;
}

View File

@ -131,7 +131,7 @@ class _$TransactionEntitySerializer
'category_type',
serializers.serialize(object.category,
specifiedType: const FullType(String)),
'baseType',
'base_type',
serializers.serialize(object.baseType,
specifiedType: const FullType(String)),
'date',
@ -151,6 +151,9 @@ class _$TransactionEntitySerializer
'expense_id',
serializers.serialize(object.expenseId,
specifiedType: const FullType(String)),
'transaction_id',
serializers.serialize(object.transactionId,
specifiedType: const FullType(int)),
'created_at',
serializers.serialize(object.createdAt,
specifiedType: const FullType(int)),
@ -219,7 +222,7 @@ class _$TransactionEntitySerializer
result.category = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'baseType':
case 'base_type':
result.baseType = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
@ -247,6 +250,10 @@ class _$TransactionEntitySerializer
result.expenseId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'transaction_id':
result.transactionId = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'isChanged':
result.isChanged = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
@ -549,6 +556,8 @@ class _$TransactionEntity extends TransactionEntity {
@override
final String expenseId;
@override
final int transactionId;
@override
final bool isChanged;
@override
final int createdAt;
@ -580,6 +589,7 @@ class _$TransactionEntity extends TransactionEntity {
this.statusId,
this.invoiceIds,
this.expenseId,
this.transactionId,
this.isChanged,
this.createdAt,
this.updatedAt,
@ -608,6 +618,8 @@ class _$TransactionEntity extends TransactionEntity {
invoiceIds, 'TransactionEntity', 'invoiceIds');
BuiltValueNullFieldError.checkNotNull(
expenseId, 'TransactionEntity', 'expenseId');
BuiltValueNullFieldError.checkNotNull(
transactionId, 'TransactionEntity', 'transactionId');
BuiltValueNullFieldError.checkNotNull(
createdAt, 'TransactionEntity', 'createdAt');
BuiltValueNullFieldError.checkNotNull(
@ -639,6 +651,7 @@ class _$TransactionEntity extends TransactionEntity {
statusId == other.statusId &&
invoiceIds == other.invoiceIds &&
expenseId == other.expenseId &&
transactionId == other.transactionId &&
isChanged == other.isChanged &&
createdAt == other.createdAt &&
updatedAt == other.updatedAt &&
@ -670,21 +683,24 @@ class _$TransactionEntity extends TransactionEntity {
$jc(
$jc(
$jc(
0,
amount
$jc(
0,
amount
.hashCode),
currencyId
.hashCode),
currencyId
category
.hashCode),
category
baseType
.hashCode),
baseType
.hashCode),
date.hashCode),
bankAccountId.hashCode),
description.hashCode),
statusId.hashCode),
invoiceIds.hashCode),
expenseId.hashCode),
date.hashCode),
bankAccountId
.hashCode),
description.hashCode),
statusId.hashCode),
invoiceIds.hashCode),
expenseId.hashCode),
transactionId.hashCode),
isChanged.hashCode),
createdAt.hashCode),
updatedAt.hashCode),
@ -708,6 +724,7 @@ class _$TransactionEntity extends TransactionEntity {
..add('statusId', statusId)
..add('invoiceIds', invoiceIds)
..add('expenseId', expenseId)
..add('transactionId', transactionId)
..add('isChanged', isChanged)
..add('createdAt', createdAt)
..add('updatedAt', updatedAt)
@ -765,6 +782,10 @@ class TransactionEntityBuilder
String get expenseId => _$this._expenseId;
set expenseId(String expenseId) => _$this._expenseId = expenseId;
int _transactionId;
int get transactionId => _$this._transactionId;
set transactionId(int transactionId) => _$this._transactionId = transactionId;
bool _isChanged;
bool get isChanged => _$this._isChanged;
set isChanged(bool isChanged) => _$this._isChanged = isChanged;
@ -816,6 +837,7 @@ class TransactionEntityBuilder
_statusId = $v.statusId;
_invoiceIds = $v.invoiceIds;
_expenseId = $v.expenseId;
_transactionId = $v.transactionId;
_isChanged = $v.isChanged;
_createdAt = $v.createdAt;
_updatedAt = $v.updatedAt;
@ -863,6 +885,7 @@ class TransactionEntityBuilder
invoiceIds: BuiltValueNullFieldError.checkNotNull(
invoiceIds, 'TransactionEntity', 'invoiceIds'),
expenseId: BuiltValueNullFieldError.checkNotNull(expenseId, 'TransactionEntity', 'expenseId'),
transactionId: BuiltValueNullFieldError.checkNotNull(transactionId, 'TransactionEntity', 'transactionId'),
isChanged: isChanged,
createdAt: BuiltValueNullFieldError.checkNotNull(createdAt, 'TransactionEntity', 'createdAt'),
updatedAt: BuiltValueNullFieldError.checkNotNull(updatedAt, 'TransactionEntity', 'updatedAt'),

View File

@ -10,6 +10,7 @@ import 'package:invoiceninja_flutter/ui/app/search_text.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_list_item.dart';
import 'package:invoiceninja_flutter/ui/transaction/view/transaction_view_vm.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
import 'package:invoiceninja_flutter/ui/vendor/vendor_list_item.dart';
import 'package:invoiceninja_flutter/utils/formatting.dart';
import 'package:invoiceninja_flutter/utils/icons.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
@ -162,6 +163,18 @@ class _MatchDepositsState extends State<_MatchDeposits> {
});
}
bool get isFiltered {
if (_minAmount.isNotEmpty || _maxAmount.isNotEmpty) {
return true;
}
if (_startDate.isNotEmpty || _endDate.isNotEmpty) {
return true;
}
return false;
}
@override
void dispose() {
_filterController.dispose();
@ -218,7 +231,7 @@ class _MatchDepositsState extends State<_MatchDeposits> {
onPressed: () {
setState(() => _showFilter = !_showFilter);
},
color: _showFilter ? state.accentColor : null,
color: _showFilter || isFiltered ? state.accentColor : null,
icon: Icon(Icons.filter_alt),
tooltip:
state.prefState.enableTooltips ? localization.filter : '',
@ -312,6 +325,7 @@ class _MatchDepositsState extends State<_MatchDeposits> {
final invoice = _invoices[index];
return InvoiceListItem(
invoice: invoice,
filter: _filterController.text,
showCheck: true,
isChecked: _selectedInvoices.contains(invoice),
onTap: () => setState(() {
@ -361,3 +375,161 @@ class _MatchDepositsState extends State<_MatchDeposits> {
);
}
}
class _MatchWithdrawals extends StatefulWidget {
const _MatchWithdrawals({
Key key,
@required this.viewModel,
}) : super(key: key);
final TransactionViewVM viewModel;
@override
State<_MatchWithdrawals> createState() => _MatchWithdrawalsState();
}
class _MatchWithdrawalsState extends State<_MatchWithdrawals> {
TextEditingController _filterController;
FocusNode _focusNode;
List<VendorEntity> _vendors;
List<ExpenseCategoryEntity> _categories;
VendorEntity _selectedVendor;
ExpenseCategoryEntity _selectedCategory;
@override
void initState() {
super.initState();
_filterController = TextEditingController();
_focusNode = FocusNode();
updateVendorList();
}
void updateVendorList() {
final state = widget.viewModel.state;
final vendorState = state.vendorState;
_vendors = vendorState.map.values.where((vendor) {
if (_selectedVendor != null) {
if (vendor.id != _selectedVendor.id) {
return false;
}
}
if (vendor.isDeleted) {
return false;
}
final filter = _filterController.text;
if (filter.isNotEmpty) {
if (!vendor.matchesFilter(filter)) {
return false;
}
}
return true;
}).toList();
_vendors.sort((vendorA, vendorB) {
/*
if (_selectedInvoices.contains(invoiceA)) {
return -1;
} else if (_selectedInvoices.contains(invoiceB)) {
return 1;
}
*/
return vendorB.name.toLowerCase().compareTo(vendorA.name.toLowerCase());
});
}
@override
void dispose() {
_filterController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final localization = AppLocalization.of(context);
final viewModel = widget.viewModel;
final transaction = viewModel.transaction;
final state = viewModel.state;
return Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 18, top: 12, right: 10, bottom: 12),
child: SearchText(
filterController: _filterController,
focusNode: _focusNode,
onChanged: (value) {
setState(() {
updateVendorList();
});
},
onCleared: () {
setState(() {
_filterController.text = '';
updateVendorList();
});
},
placeholder: localization.search,
),
),
),
],
),
ListDivider(),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) => ListDivider(),
itemCount: _vendors.length,
itemBuilder: (BuildContext context, int index) {
final vendor = _vendors[index];
return VendorListItem(
vendor: vendor,
filter: _filterController.text,
showCheck: true,
isChecked: _selectedVendor.id == vendor.id,
onTap: () => setState(() {
_selectedVendor = vendor;
updateVendorList();
}),
);
},
),
),
ListDivider(),
Padding(
padding: const EdgeInsets.only(
left: 20,
bottom: 18,
right: 20,
),
child: AppButton(
label: localization.convertToPayment,
onPressed: _selectedVendor == null
? null
: () {
final viewModel = widget.viewModel;
viewModel.onConvertToExpense(
context,
transaction.id,
_selectedVendor.id,
);
},
iconData: getEntityActionIcon(EntityAction.convertToExpense),
),
)
],
);
}
}

View File

@ -16,22 +16,22 @@ import 'package:invoiceninja_flutter/utils/platforms.dart';
class VendorListItem extends StatelessWidget {
const VendorListItem({
@required this.user,
@required this.vendor,
@required this.filter,
this.onTap,
this.onLongPress,
this.showCheck = false,
this.onCheckboxChanged,
this.isChecked = false,
});
final UserEntity user;
final GestureTapCallback onTap;
final GestureTapCallback onLongPress;
final VendorEntity vendor;
final String filter;
final Function(bool) onCheckboxChanged;
final bool isChecked;
final bool showCheck;
@override
Widget build(BuildContext context) {
@ -43,18 +43,18 @@ class VendorListItem extends StatelessWidget {
? vendor.matchesFilterValue(filter)
: null;
final listUIState = vendorUIState.listUIState;
final isInMultiselect = listUIState.isInMultiselect();
final showCheckbox = onCheckboxChanged != null || isInMultiselect;
final textStyle = TextStyle(fontSize: 16);
final textColor = Theme.of(context).textTheme.bodyText1.color;
final documents = vendor.documents ?? <DocumentEntity>[];
return DismissibleEntity(
isSelected: isDesktop(context) &&
!showCheck &&
vendor.id ==
(uiState.isEditing
? vendorUIState.editing.id
: vendorUIState.selectedId),
showCheckbox: showCheck,
userCompany: store.state.userCompany,
entity: vendor,
child: LayoutBuilder(
@ -77,11 +77,10 @@ class VendorListItem extends StatelessWidget {
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16),
child: showCheckbox
child: showCheck
? Padding(
padding: const EdgeInsets.only(right: 20),
child: IgnorePointer(
ignoring: listUIState.isInMultiselect(),
child: Checkbox(
value: isChecked,
materialTapTargetSize:
@ -160,7 +159,7 @@ class VendorListItem extends StatelessWidget {
onLongPress: () => onLongPress != null
? onLongPress()
: selectEntity(entity: vendor, longPress: true),
leading: showCheckbox
leading: showCheck
? IgnorePointer(
ignoring: listUIState.isInMultiselect(),
child: Checkbox(

View File

@ -45,13 +45,12 @@ class VendorListBuilder extends StatelessWidget {
final vendor = viewModel.vendorMap[vendorId];
final state = viewModel.state;
final listUIState = state.getListState(EntityType.vendor);
final isInMultiselect = listUIState.isInMultiselect();
return VendorListItem(
user: viewModel.state.user,
filter: viewModel.filter,
vendor: vendor,
isChecked: isInMultiselect && listUIState.isSelected(vendor.id),
isChecked: listUIState.isSelected(vendor.id),
showCheck: listUIState.isInMultiselect(),
);
},
);