Matching transactions

This commit is contained in:
Hillel Coren 2022-12-01 11:10:38 +02:00
parent 8083c8ef6d
commit d0e48817ba
5 changed files with 161 additions and 91 deletions

View File

@ -92,6 +92,7 @@ abstract class TransactionEntity extends Object
transactionId: 0,
categoryId: '',
transactionRuleId: '',
paymentId: '',
);
}
@ -131,6 +132,9 @@ abstract class TransactionEntity extends Object
@BuiltValueField(wireName: 'invoice_ids')
String get invoiceIds;
@BuiltValueField(wireName: 'payment_id')
String get paymentId;
@BuiltValueField(wireName: 'expense_id')
String get expenseId;
@ -359,6 +363,7 @@ abstract class TransactionEntity extends Object
..baseType = ''
..bankAccountId = ''
..transactionRuleId = ''
..paymentId = ''
..currencyId = '';
static Serializer<TransactionEntity> get serializer =>

View File

@ -151,6 +151,9 @@ class _$TransactionEntitySerializer
'invoice_ids',
serializers.serialize(object.invoiceIds,
specifiedType: const FullType(String)),
'payment_id',
serializers.serialize(object.paymentId,
specifiedType: const FullType(String)),
'expense_id',
serializers.serialize(object.expenseId,
specifiedType: const FullType(String)),
@ -259,6 +262,10 @@ class _$TransactionEntitySerializer
result.invoiceIds = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'payment_id':
result.paymentId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'expense_id':
result.expenseId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
@ -577,6 +584,8 @@ class _$TransactionEntity extends TransactionEntity {
@override
final String invoiceIds;
@override
final String paymentId;
@override
final String expenseId;
@override
final String vendorId;
@ -620,6 +629,7 @@ class _$TransactionEntity extends TransactionEntity {
this.statusId,
this.categoryId,
this.invoiceIds,
this.paymentId,
this.expenseId,
this.vendorId,
this.transactionId,
@ -654,6 +664,8 @@ class _$TransactionEntity extends TransactionEntity {
categoryId, 'TransactionEntity', 'categoryId');
BuiltValueNullFieldError.checkNotNull(
invoiceIds, 'TransactionEntity', 'invoiceIds');
BuiltValueNullFieldError.checkNotNull(
paymentId, 'TransactionEntity', 'paymentId');
BuiltValueNullFieldError.checkNotNull(
expenseId, 'TransactionEntity', 'expenseId');
BuiltValueNullFieldError.checkNotNull(
@ -693,6 +705,7 @@ class _$TransactionEntity extends TransactionEntity {
statusId == other.statusId &&
categoryId == other.categoryId &&
invoiceIds == other.invoiceIds &&
paymentId == other.paymentId &&
expenseId == other.expenseId &&
vendorId == other.vendorId &&
transactionId == other.transactionId &&
@ -730,12 +743,12 @@ class _$TransactionEntity extends TransactionEntity {
$jc(
$jc(
$jc(
$jc($jc($jc($jc($jc($jc(0, amount.hashCode), currencyId.hashCode), category.hashCode), baseType.hashCode), date.hashCode),
bankAccountId.hashCode),
description.hashCode),
statusId.hashCode),
categoryId.hashCode),
invoiceIds.hashCode),
$jc($jc($jc($jc($jc($jc($jc(0, amount.hashCode), currencyId.hashCode), category.hashCode), baseType.hashCode), date.hashCode), bankAccountId.hashCode),
description.hashCode),
statusId.hashCode),
categoryId.hashCode),
invoiceIds.hashCode),
paymentId.hashCode),
expenseId.hashCode),
vendorId.hashCode),
transactionId.hashCode),
@ -765,6 +778,7 @@ class _$TransactionEntity extends TransactionEntity {
..add('statusId', statusId)
..add('categoryId', categoryId)
..add('invoiceIds', invoiceIds)
..add('paymentId', paymentId)
..add('expenseId', expenseId)
..add('vendorId', vendorId)
..add('transactionId', transactionId)
@ -828,6 +842,10 @@ class TransactionEntityBuilder
String get invoiceIds => _$this._invoiceIds;
set invoiceIds(String invoiceIds) => _$this._invoiceIds = invoiceIds;
String _paymentId;
String get paymentId => _$this._paymentId;
set paymentId(String paymentId) => _$this._paymentId = paymentId;
String _expenseId;
String get expenseId => _$this._expenseId;
set expenseId(String expenseId) => _$this._expenseId = expenseId;
@ -906,6 +924,7 @@ class TransactionEntityBuilder
_statusId = $v.statusId;
_categoryId = $v.categoryId;
_invoiceIds = $v.invoiceIds;
_paymentId = $v.paymentId;
_expenseId = $v.expenseId;
_vendorId = $v.vendorId;
_transactionId = $v.transactionId;
@ -956,9 +975,10 @@ class TransactionEntityBuilder
description, 'TransactionEntity', 'description'),
statusId: BuiltValueNullFieldError.checkNotNull(
statusId, 'TransactionEntity', 'statusId'),
categoryId: BuiltValueNullFieldError.checkNotNull(
categoryId, 'TransactionEntity', 'categoryId'),
categoryId:
BuiltValueNullFieldError.checkNotNull(categoryId, 'TransactionEntity', 'categoryId'),
invoiceIds: BuiltValueNullFieldError.checkNotNull(invoiceIds, 'TransactionEntity', 'invoiceIds'),
paymentId: BuiltValueNullFieldError.checkNotNull(paymentId, 'TransactionEntity', 'paymentId'),
expenseId: BuiltValueNullFieldError.checkNotNull(expenseId, 'TransactionEntity', 'expenseId'),
vendorId: BuiltValueNullFieldError.checkNotNull(vendorId, 'TransactionEntity', 'vendorId'),
transactionId: BuiltValueNullFieldError.checkNotNull(transactionId, 'TransactionEntity', 'transactionId'),

View File

@ -11,9 +11,9 @@ import 'package:invoiceninja_flutter/utils/platforms.dart';
class BoolDropdownButton extends StatelessWidget {
const BoolDropdownButton({
@required this.label,
@required this.value,
@required this.onChanged,
this.label,
this.showBlank,
this.enabledLabel,
this.helpLabel,
@ -57,87 +57,92 @@ class BoolDropdownButton extends StatelessWidget {
);
}
final widget = _showBlank
? DropdownButtonHideUnderline(
child: DropdownButton<bool>(
value: value,
isExpanded: true,
isDense: true,
onChanged: (value) => onChanged(value),
items: [
DropdownMenuItem(
child: Text(''),
value: null,
),
DropdownMenuItem(
child: Text(falseLabel),
value: false,
),
DropdownMenuItem(
child: Text(trueLabel),
value: true,
),
].toList(),
),
)
: Padding(
padding: const EdgeInsets.only(top: 4),
child: Flex(
direction: isDesktop(context) ? Axis.horizontal : Axis.vertical,
children: <Widget>[
InkWell(
onTap: () => onChanged(false),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth ?? 130, minHeight: 36),
child: Row(
children: [
IgnorePointer(
child: Radio<bool>(
value: false,
onChanged: (value) => null,
groupValue: value,
activeColor:
Theme.of(context).colorScheme.secondary,
),
),
Text(falseLabel),
SizedBox(width: 16),
],
),
),
),
InkWell(
onTap: () => onChanged(true),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth ?? 120, minHeight: 36),
child: Row(
children: [
IgnorePointer(
child: Radio<bool>(
value: true,
onChanged: (value) => null,
groupValue: value,
activeColor:
Theme.of(context).colorScheme.secondary,
),
),
Text(trueLabel),
SizedBox(width: 16),
],
),
),
),
],
),
);
if (label == null) {
return widget;
}
return InputDecorator(
decoration: InputDecoration(
border: _showBlank ? null : InputBorder.none,
labelText: label,
),
isEmpty: '${value ?? ''}'.isEmpty,
child: _showBlank
? DropdownButtonHideUnderline(
child: DropdownButton<bool>(
value: value,
isExpanded: true,
isDense: true,
onChanged: (value) => onChanged(value),
items: [
DropdownMenuItem(
child: Text(''),
value: null,
),
DropdownMenuItem(
child: Text(falseLabel),
value: false,
),
DropdownMenuItem(
child: Text(trueLabel),
value: true,
),
].toList(),
),
)
: Padding(
padding: const EdgeInsets.only(top: 4),
child: Flex(
direction:
isDesktop(context) ? Axis.horizontal : Axis.vertical,
children: <Widget>[
InkWell(
onTap: () => onChanged(false),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth ?? 130, minHeight: 36),
child: Row(
children: [
IgnorePointer(
child: Radio<bool>(
value: false,
onChanged: (value) => null,
groupValue: value,
activeColor:
Theme.of(context).colorScheme.secondary,
),
),
Text(falseLabel),
SizedBox(width: 16),
],
),
),
),
InkWell(
onTap: () => onChanged(true),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: minWidth ?? 120, minHeight: 36),
child: Row(
children: [
IgnorePointer(
child: Radio<bool>(
value: true,
onChanged: (value) => null,
groupValue: value,
activeColor:
Theme.of(context).colorScheme.secondary,
),
),
Text(trueLabel),
SizedBox(width: 16),
],
),
),
),
],
),
));
child: widget);
}
}

View File

@ -11,6 +11,7 @@ import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
import 'package:invoiceninja_flutter/ui/app/entities/entity_list_tile.dart';
import 'package:invoiceninja_flutter/ui/app/entity_header.dart';
import 'package:invoiceninja_flutter/ui/app/forms/bool_dropdown_button.dart';
import 'package:invoiceninja_flutter/ui/app/forms/date_picker.dart';
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
import 'package:invoiceninja_flutter/ui/app/lists/list_divider.dart';
@ -151,6 +152,7 @@ class _MatchDepositsState extends State<_MatchDeposits> {
List<InvoiceEntity> _invoices;
List<InvoiceEntity> _selectedInvoices;
bool _matchExisting = false;
bool _showFilter = false;
String _minAmount = '';
String _maxAmount = '';
@ -284,12 +286,24 @@ class _MatchDepositsState extends State<_MatchDeposits> {
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: BoolDropdownButton(
value: _matchExisting,
onChanged: (value) {
setState(() => _matchExisting = value);
},
enabledLabel: localization.matchPayment,
disabledLabel: localization.createPayment,
),
),
ListDivider(),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 18, top: 12, right: 10, bottom: 12),
left: 20, top: 12, right: 10, bottom: 12),
child: SearchText(
filterController: _filterController,
focusNode: _focusNode,
@ -304,8 +318,10 @@ class _MatchDepositsState extends State<_MatchDeposits> {
updateInvoiceList();
});
},
placeholder:
localization.searchInvoices.replaceFirst(':count ', ''),
placeholder: (_matchExisting
? localization.searchPayments
: localization.searchInvoices)
.replaceFirst(':count ', ''),
),
),
),
@ -477,6 +493,7 @@ class _MatchWithdrawalsState extends State<_MatchWithdrawals> {
final _vendorScrollController = ScrollController();
final _categoryScrollController = ScrollController();
bool _matchExisting = false;
TextEditingController _vendorFilterController;
TextEditingController _categoryFilterController;
FocusNode _vendorFocusNode;
@ -605,6 +622,18 @@ class _MatchWithdrawalsState extends State<_MatchWithdrawals> {
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
child: BoolDropdownButton(
value: _matchExisting,
onChanged: (value) {
setState(() => _matchExisting = value);
},
enabledLabel: localization.matchExpense,
disabledLabel: localization.createExpense,
),
),
ListDivider(),
Expanded(
child: Column(
children: [
@ -613,7 +642,7 @@ class _MatchWithdrawalsState extends State<_MatchWithdrawals> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 18, top: 12, right: 10, bottom: 12),
left: 20, top: 12, right: 10, bottom: 12),
child: SearchText(
filterController: _vendorFilterController,
focusNode: _vendorFocusNode,
@ -700,7 +729,7 @@ class _MatchWithdrawalsState extends State<_MatchWithdrawals> {
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 18, top: 12, right: 10, bottom: 12),
left: 20, top: 12, right: 10, bottom: 12),
child: SearchText(
filterController: _categoryFilterController,
focusNode: _categoryFocusNode,

View File

@ -16,8 +16,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'match_payment': 'Match Payment',
'match_expense': 'Match Expense',
'lock_invoiced_tasks': 'Lock Invoiced Tasks',
'lock_invoiced_tasks_help': 'Prevent tasks from being edited once invoiced',
'lock_invoiced_tasks_help':
'Prevent tasks from being edited once invoiced',
'registration_required': 'Registration Required',
'registration_required_help': 'Require clients to register',
'use_inventory_management': 'Use Inventory Management',
@ -90617,6 +90620,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['lock_invoiced_tasks_help'] ??
_localizedValues['en']['lock_invoiced_tasks_help'];
String get matchPayment =>
_localizedValues[localeCode]['match_payment'] ??
_localizedValues['en']['match_payment'];
String get matchExpense =>
_localizedValues[localeCode]['match_expense'] ??
_localizedValues['en']['match_expense'];
// STARTER: lang field - do not remove comment
String lookup(String key) {