Null safety

This commit is contained in:
Hillel Coren 2023-10-02 16:30:35 +03:00
parent eecabc6e6a
commit ac3e430c35
31 changed files with 139 additions and 130 deletions

View File

@ -318,9 +318,8 @@ abstract class InvoiceEntity extends Object
..documents.clear() ..documents.clear()
..lineItems.replace(lineItems ..lineItems.replace(lineItems
.where((lineItem) => .where((lineItem) =>
lineItem!.typeId != InvoiceItemEntity.TYPE_UNPAID_FEE) lineItem.typeId != InvoiceItemEntity.TYPE_UNPAID_FEE)
.map((lineItem) => lineItem! .map((lineItem) => lineItem.rebuild((b) => b..typeId = InvoiceItemEntity.TYPE_STANDARD))
.rebuild((b) => b..typeId = InvoiceItemEntity.TYPE_STANDARD))
.toList()) .toList())
..invitations.replace( ..invitations.replace(
invitations invitations
@ -561,7 +560,7 @@ abstract class InvoiceEntity extends Object
@override @override
@BuiltValueField(wireName: 'line_items') @BuiltValueField(wireName: 'line_items')
BuiltList<InvoiceItemEntity?> get lineItems; BuiltList<InvoiceItemEntity> get lineItems;
BuiltList<InvitationEntity> get invitations; BuiltList<InvitationEntity> get invitations;
@ -645,11 +644,11 @@ abstract class InvoiceEntity extends Object
kMillisecondsToRefreshActivities; kMillisecondsToRefreshActivities;
} }
bool get hasTasks => lineItems.any((item) => item!.isTask); bool get hasTasks => lineItems.any((item) => item.isTask);
bool get hasProducts => lineItems.any((item) => !item!.isTask); bool get hasProducts => lineItems.any((item) => !item.isTask);
bool get hasExpenses => lineItems.any((item) => item!.isExpense); bool get hasExpenses => lineItems.any((item) => item.isExpense);
@override @override
bool get isEditable { bool get isEditable {
@ -915,7 +914,7 @@ abstract class InvoiceEntity extends Object
@override @override
bool matchesFilter(String? filter) { bool matchesFilter(String? filter) {
for (var i = 0; i < lineItems.length; i++) { for (var i = 0; i < lineItems.length; i++) {
final lineItem = lineItems[i]!; final lineItem = lineItems[i];
final isMatch = matchesStrings( final isMatch = matchesStrings(
haystacks: [ haystacks: [
lineItem.productKey, lineItem.productKey,
@ -1409,7 +1408,7 @@ abstract class InvoiceEntity extends Object
} }
for (final item in lineItems) { for (final item in lineItems) {
final itemTaxable = getItemTaxable(item!, amount, precision); final itemTaxable = getItemTaxable(item, amount, precision);
if (item.taxName1.isNotEmpty) { if (item.taxName1.isNotEmpty) {
final itemTaxAmount = calculateAmount(itemTaxable, item.taxRate1); final itemTaxAmount = calculateAmount(itemTaxable, item.taxRate1);

View File

@ -269,7 +269,7 @@ class _$InvoiceEntitySerializer implements StructuredSerializer<InvoiceEntity> {
'line_items', 'line_items',
serializers.serialize(object.lineItems, serializers.serialize(object.lineItems,
specifiedType: const FullType( specifiedType: const FullType(
BuiltList, const [const FullType.nullable(InvoiceItemEntity)])), BuiltList, const [const FullType(InvoiceItemEntity)])),
'invitations', 'invitations',
serializers.serialize(object.invitations, serializers.serialize(object.invitations,
specifiedType: const FullType( specifiedType: const FullType(
@ -689,9 +689,9 @@ class _$InvoiceEntitySerializer implements StructuredSerializer<InvoiceEntity> {
break; break;
case 'line_items': case 'line_items':
result.lineItems.replace(serializers.deserialize(value, result.lineItems.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltList, const [ specifiedType: const FullType(
const FullType.nullable(InvoiceItemEntity) BuiltList, const [const FullType(InvoiceItemEntity)]))!
]))! as BuiltList<Object?>); as BuiltList<Object?>);
break; break;
case 'invitations': case 'invitations':
result.invitations.replace(serializers.deserialize(value, result.invitations.replace(serializers.deserialize(value,
@ -1571,7 +1571,7 @@ class _$InvoiceEntity extends InvoiceEntity {
@override @override
final BuiltList<InvoiceScheduleEntity>? recurringDates; final BuiltList<InvoiceScheduleEntity>? recurringDates;
@override @override
final BuiltList<InvoiceItemEntity?> lineItems; final BuiltList<InvoiceItemEntity> lineItems;
@override @override
final BuiltList<InvitationEntity> invitations; final BuiltList<InvitationEntity> invitations;
@override @override
@ -2313,10 +2313,10 @@ class InvoiceEntityBuilder
set recurringDates(ListBuilder<InvoiceScheduleEntity>? recurringDates) => set recurringDates(ListBuilder<InvoiceScheduleEntity>? recurringDates) =>
_$this._recurringDates = recurringDates; _$this._recurringDates = recurringDates;
ListBuilder<InvoiceItemEntity?>? _lineItems; ListBuilder<InvoiceItemEntity>? _lineItems;
ListBuilder<InvoiceItemEntity?> get lineItems => ListBuilder<InvoiceItemEntity> get lineItems =>
_$this._lineItems ??= new ListBuilder<InvoiceItemEntity?>(); _$this._lineItems ??= new ListBuilder<InvoiceItemEntity>();
set lineItems(ListBuilder<InvoiceItemEntity?>? lineItems) => set lineItems(ListBuilder<InvoiceItemEntity>? lineItems) =>
_$this._lineItems = lineItems; _$this._lineItems = lineItems;
ListBuilder<InvitationEntity>? _invitations; ListBuilder<InvitationEntity>? _invitations;

View File

@ -511,9 +511,8 @@ Serializers _$serializers = (new Serializers().toBuilder()
BuiltList, const [const FullType(InvoiceScheduleEntity)]), BuiltList, const [const FullType(InvoiceScheduleEntity)]),
() => new ListBuilder<InvoiceScheduleEntity>()) () => new ListBuilder<InvoiceScheduleEntity>())
..addBuilderFactory( ..addBuilderFactory(
const FullType( const FullType(BuiltList, const [const FullType(InvoiceItemEntity)]),
BuiltList, const [const FullType.nullable(InvoiceItemEntity)]), () => new ListBuilder<InvoiceItemEntity>())
() => new ListBuilder<InvoiceItemEntity?>())
..addBuilderFactory( ..addBuilderFactory(
const FullType(BuiltList, const [const FullType(InvitationEntity)]), const FullType(BuiltList, const [const FullType(InvitationEntity)]),
() => new ListBuilder<InvitationEntity>()) () => new ListBuilder<InvitationEntity>())

View File

@ -189,10 +189,13 @@ class AddCreditItems implements PersistUI {
} }
class UpdateCreditItem implements PersistUI { class UpdateCreditItem implements PersistUI {
UpdateCreditItem({this.index, this.creditItem}); UpdateCreditItem({
required this.index,
required this.creditItem,
});
final int? index; final int index;
final InvoiceItemEntity? creditItem; final InvoiceItemEntity creditItem;
} }
class DeleteCreditItem implements PersistUI { class DeleteCreditItem implements PersistUI {

View File

@ -284,7 +284,7 @@ Middleware<AppState> _saveCredit(CreditRepository repository) {
// remove any empty line items // remove any empty line items
final updatedCredit = action.credit.rebuild((b) => b final updatedCredit = action.credit.rebuild((b) => b
..lineItems ..lineItems
.replace(action.credit.lineItems.where((item) => !item!.isEmpty))); .replace(action.credit.lineItems.where((item) => !item.isEmpty)));
repository repository
.saveData(store.state.credentials, updatedCredit, action.action) .saveData(store.state.credentials, updatedCredit, action.action)

View File

@ -178,10 +178,10 @@ InvoiceEntity? _removeCreditItem(
InvoiceEntity? _updateCreditItem( InvoiceEntity? _updateCreditItem(
InvoiceEntity? credit, UpdateCreditItem action) { InvoiceEntity? credit, UpdateCreditItem action) {
if (credit!.lineItems.length <= action.index!) { if (credit!.lineItems.length <= action.index) {
return credit; return credit;
} }
return credit.rebuild((b) => b..lineItems[action.index!] = action.creditItem); return credit.rebuild((b) => b..lineItems[action.index] = action.creditItem);
} }
final creditListReducer = combineReducers<ListUIState>([ final creditListReducer = combineReducers<ListUIState>([

View File

@ -193,10 +193,13 @@ class AddInvoiceItems implements PersistUI {
} }
class UpdateInvoiceItem implements PersistUI { class UpdateInvoiceItem implements PersistUI {
UpdateInvoiceItem({this.index, this.invoiceItem}); UpdateInvoiceItem({
required this.index,
required this.invoiceItem,
});
final int? index; final int index;
final InvoiceItemEntity? invoiceItem; final InvoiceItemEntity invoiceItem;
} }
class DeleteInvoiceItem implements PersistUI { class DeleteInvoiceItem implements PersistUI {
@ -700,7 +703,8 @@ void handleInvoiceAction(BuildContext? context, List<BaseEntity?> invoices,
title: Text( title: Text(
invoiceIds.length == 1 invoiceIds.length == 1
? localization.emailInvoice ? localization.emailInvoice
: localization.emailCountInvoices.replaceFirst(':count', '${invoiceIds.length}'), : localization.emailCountInvoices
.replaceFirst(':count', '${invoiceIds.length}'),
), ),
children: templates.keys children: templates.keys
.map((template) => SimpleDialogOption( .map((template) => SimpleDialogOption(

View File

@ -381,7 +381,7 @@ Middleware<AppState> _saveInvoice(InvoiceRepository repository) {
// remove any empty line items // remove any empty line items
final updatedInvoice = action.invoice.rebuild((b) => b final updatedInvoice = action.invoice.rebuild((b) => b
..lineItems ..lineItems
.replace(action.invoice.lineItems.where((item) => !item!.isEmpty))); .replace(action.invoice.lineItems.where((item) => !item.isEmpty)));
repository repository
.saveData( .saveData(

View File

@ -182,11 +182,11 @@ InvoiceEntity? _removeInvoiceItem(
InvoiceEntity? _updateInvoiceItem( InvoiceEntity? _updateInvoiceItem(
InvoiceEntity? invoice, UpdateInvoiceItem action) { InvoiceEntity? invoice, UpdateInvoiceItem action) {
if (invoice!.lineItems.length <= action.index!) { if (invoice!.lineItems.length <= action.index) {
return invoice; return invoice;
} }
return invoice return invoice
.rebuild((b) => b..lineItems[action.index!] = action.invoiceItem); .rebuild((b) => b..lineItems[action.index] = action.invoiceItem);
} }
final invoiceListReducer = combineReducers<ListUIState>([ final invoiceListReducer = combineReducers<ListUIState>([

View File

@ -488,10 +488,13 @@ class AddPurchaseOrderItems implements PersistUI {
} }
class UpdatePurchaseOrderItem implements PersistUI { class UpdatePurchaseOrderItem implements PersistUI {
UpdatePurchaseOrderItem({this.index, this.purchaseOrderItem}); UpdatePurchaseOrderItem({
required this.index,
required this.purchaseOrderItem,
});
final int? index; final int index;
final InvoiceItemEntity? purchaseOrderItem; final InvoiceItemEntity purchaseOrderItem;
} }
class DeletePurchaseOrderItem implements PersistUI { class DeletePurchaseOrderItem implements PersistUI {

View File

@ -391,7 +391,7 @@ Middleware<AppState> _savePurchaseOrder(PurchaseOrderRepository repository) {
// remove any empty line items // remove any empty line items
final updatedPurchaseOrder = action.purchaseOrder.rebuild((b) => b final updatedPurchaseOrder = action.purchaseOrder.rebuild((b) => b
..lineItems.replace( ..lineItems.replace(
action.purchaseOrder.lineItems.where((item) => !item!.isEmpty))); action.purchaseOrder.lineItems.where((item) => !item.isEmpty)));
repository repository
.saveData( .saveData(

View File

@ -206,11 +206,11 @@ InvoiceEntity? _removePurchaseOrderItem(
InvoiceEntity? _updatePurchaseOrderItem( InvoiceEntity? _updatePurchaseOrderItem(
InvoiceEntity? purchaseOrder, UpdatePurchaseOrderItem action) { InvoiceEntity? purchaseOrder, UpdatePurchaseOrderItem action) {
if (purchaseOrder!.lineItems.length <= action.index!) { if (purchaseOrder!.lineItems.length <= action.index) {
return purchaseOrder; return purchaseOrder;
} }
return purchaseOrder return purchaseOrder
.rebuild((b) => b..lineItems[action.index!] = action.purchaseOrderItem); .rebuild((b) => b..lineItems[action.index] = action.purchaseOrderItem);
} }
final purchaseOrderListReducer = combineReducers<ListUIState>([ final purchaseOrderListReducer = combineReducers<ListUIState>([

View File

@ -190,10 +190,13 @@ class AddQuoteItems implements PersistUI {
} }
class UpdateQuoteItem implements PersistUI { class UpdateQuoteItem implements PersistUI {
UpdateQuoteItem({this.index, this.quoteItem}); UpdateQuoteItem({
required this.index,
required this.quoteItem,
});
final int? index; final int index;
final InvoiceItemEntity? quoteItem; final InvoiceItemEntity quoteItem;
} }
class DeleteQuoteItem implements PersistUI { class DeleteQuoteItem implements PersistUI {
@ -553,7 +556,8 @@ Future handleQuoteAction(BuildContext context, List<BaseEntity?> quotes,
break; break;
case EntityAction.approve: case EntityAction.approve:
final message = quoteIds.length > 1 final message = quoteIds.length > 1
? localization!.approvedQuotes.replaceFirst(':value', ':count') ? localization!.approvedQuotes
.replaceFirst(':value', ':count')
.replaceFirst(':count', quoteIds.length.toString()) .replaceFirst(':count', quoteIds.length.toString())
: localization!.approveQuote; : localization!.approveQuote;
store.dispatch( store.dispatch(

View File

@ -329,7 +329,7 @@ Middleware<AppState> _saveQuote(QuoteRepository repository) {
// remove any empty line items // remove any empty line items
final updatedQuote = action.quote.rebuild((b) => b final updatedQuote = action.quote.rebuild((b) => b
..lineItems ..lineItems
.replace(action.quote.lineItems.where((item) => !item!.isEmpty))); .replace(action.quote.lineItems.where((item) => !item.isEmpty)));
repository repository
.saveData(store.state.credentials, updatedQuote, action.action) .saveData(store.state.credentials, updatedQuote, action.action)

View File

@ -177,10 +177,10 @@ InvoiceEntity? _removeQuoteItem(InvoiceEntity? quote, DeleteQuoteItem action) {
} }
InvoiceEntity? _updateQuoteItem(InvoiceEntity? quote, UpdateQuoteItem action) { InvoiceEntity? _updateQuoteItem(InvoiceEntity? quote, UpdateQuoteItem action) {
if (quote!.lineItems.length <= action.index!) { if (quote!.lineItems.length <= action.index) {
return quote; return quote;
} }
return quote.rebuild((b) => b..lineItems[action.index!] = action.quoteItem); return quote.rebuild((b) => b..lineItems[action.index] = action.quoteItem);
} }
final quoteListReducer = combineReducers<ListUIState>([ final quoteListReducer = combineReducers<ListUIState>([

View File

@ -223,10 +223,13 @@ class AddRecurringInvoiceItems implements PersistUI {
} }
class UpdateRecurringInvoiceItem implements PersistUI { class UpdateRecurringInvoiceItem implements PersistUI {
UpdateRecurringInvoiceItem({this.index, this.item}); UpdateRecurringInvoiceItem({
required this.index,
required this.item,
});
final int? index; final int index;
final InvoiceItemEntity? item; final InvoiceItemEntity item;
} }
class DeleteRecurringInvoiceItem implements PersistUI { class DeleteRecurringInvoiceItem implements PersistUI {

View File

@ -335,7 +335,7 @@ Middleware<AppState> _saveRecurringInvoice(
// remove any empty line items // remove any empty line items
final updatedInvoice = action.recurringInvoice!.rebuild((b) => b final updatedInvoice = action.recurringInvoice!.rebuild((b) => b
..lineItems.replace( ..lineItems.replace(
action.recurringInvoice!.lineItems.where((item) => !item!.isEmpty))); action.recurringInvoice!.lineItems.where((item) => !item.isEmpty)));
repository repository
.saveData(store.state.credentials, updatedInvoice, .saveData(store.state.credentials, updatedInvoice,

View File

@ -217,11 +217,11 @@ InvoiceEntity? _removeRecurringInvoiceItem(
InvoiceEntity? _updateRecurringInvoiceItem( InvoiceEntity? _updateRecurringInvoiceItem(
InvoiceEntity? recurringInvoice, UpdateRecurringInvoiceItem action) { InvoiceEntity? recurringInvoice, UpdateRecurringInvoiceItem action) {
if (recurringInvoice!.lineItems.length <= action.index!) { if (recurringInvoice!.lineItems.length <= action.index) {
return recurringInvoice; return recurringInvoice;
} }
return recurringInvoice return recurringInvoice
.rebuild((b) => b..lineItems[action.index!] = action.item); .rebuild((b) => b..lineItems[action.index] = action.item);
} }
final recurringInvoiceListReducer = combineReducers<ListUIState>([ final recurringInvoiceListReducer = combineReducers<ListUIState>([

View File

@ -158,8 +158,8 @@ class _CreditEditState extends State<CreditEdit>
invoice: invoice, invoice: invoice,
showTasksAndExpenses: false, showTasksAndExpenses: false,
excluded: invoice.lineItems excluded: invoice.lineItems
.where((item) => item!.isTask || item.isExpense) .where((item) => item.isTask || item.isExpense)
.map((item) => item!.isTask .map((item) => item.isTask
? viewModel.state!.taskState.map[item.taskId] ? viewModel.state!.taskState.map[item.taskId]
: viewModel.state!.expenseState.map[item.expenseId]) : viewModel.state!.expenseState.map[item.expenseId])
.toList(), .toList(),

View File

@ -173,8 +173,8 @@ class _InvoiceEditState extends State<InvoiceEdit>
invoice: invoice, invoice: invoice,
showTasksAndExpenses: true, showTasksAndExpenses: true,
excluded: invoice.lineItems excluded: invoice.lineItems
.where((item) => item!.isTask || item.isExpense) .where((item) => item.isTask || item.isExpense)
.map((item) => item!.isTask .map((item) => item.isTask
? viewModel.state!.taskState.map[item.taskId] ? viewModel.state!.taskState.map[item.taskId]
: viewModel.state!.expenseState.map[item.expenseId]) : viewModel.state!.expenseState.map[item.expenseId])
.toList(), .toList(),

View File

@ -243,11 +243,11 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
final countProducts = invoice.lineItems final countProducts = invoice.lineItems
.where((item) => .where((item) =>
!item!.isEmpty && item.typeId != InvoiceItemEntity.TYPE_TASK) !item.isEmpty && item.typeId != InvoiceItemEntity.TYPE_TASK)
.length; .length;
final countTasks = invoice.lineItems final countTasks = invoice.lineItems
.where((item) => .where((item) =>
!item!.isEmpty && item.typeId == InvoiceItemEntity.TYPE_TASK) !item.isEmpty && item.typeId == InvoiceItemEntity.TYPE_TASK)
.length; .length;
final showTasksTable = (invoice.hasTasks || company.showTasksTable) && final showTasksTable = (invoice.hasTasks || company.showTasksTable) &&

View File

@ -46,7 +46,7 @@ class _InvoiceEditItemsState extends State<InvoiceEditItems> {
viewModel: viewModel, viewModel: viewModel,
entityViewModel: widget.entityViewModel, entityViewModel: widget.entityViewModel,
key: ValueKey('__${lineItemIndex}__'), key: ValueKey('__${lineItemIndex}__'),
invoiceItem: invoice.lineItems[lineItemIndex!]!, invoiceItem: invoice.lineItems[lineItemIndex!],
index: lineItemIndex, index: lineItemIndex,
); );
}); });

View File

@ -82,18 +82,18 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
final company = state.company; final company = state.company;
final includedLineItems = lineItems.where((lineItem) { final includedLineItems = lineItems.where((lineItem) {
return (lineItem!.typeId == InvoiceItemEntity.TYPE_TASK && return (lineItem.typeId == InvoiceItemEntity.TYPE_TASK &&
widget.isTasks) || widget.isTasks) ||
(lineItem.typeId != InvoiceItemEntity.TYPE_TASK && !widget.isTasks) || (lineItem.typeId != InvoiceItemEntity.TYPE_TASK && !widget.isTasks) ||
lineItem.isEmpty; lineItem.isEmpty;
}).toList(); }).toList();
final hasTax1 = company.enableFirstItemTaxRate || final hasTax1 = company.enableFirstItemTaxRate ||
includedLineItems.any((item) => item!.taxName1.isNotEmpty); includedLineItems.any((item) => item.taxName1.isNotEmpty);
final hasTax2 = company.enableSecondItemTaxRate || final hasTax2 = company.enableSecondItemTaxRate ||
includedLineItems.any((item) => item!.taxName2.isNotEmpty); includedLineItems.any((item) => item.taxName2.isNotEmpty);
final hasTax3 = company.enableThirdItemTaxRate || final hasTax3 = company.enableThirdItemTaxRate ||
includedLineItems.any((item) => item!.taxName3.isNotEmpty); includedLineItems.any((item) => item.taxName3.isNotEmpty);
final hasAnyTax = hasTax1 || hasTax2 || hasTax3; final hasAnyTax = hasTax1 || hasTax2 || hasTax3;
final customField1 = final customField1 =
@ -292,7 +292,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
state.staticState.currencyMap[client.currencyId]?.precision ?? 2; state.staticState.currencyMap[client.currencyId]?.precision ?? 2;
final lineItems = invoice.lineItems.toList(); final lineItems = invoice.lineItems.toList();
final includedLineItems = lineItems.where((lineItem) { final includedLineItems = lineItems.where((lineItem) {
return (lineItem!.typeId == InvoiceItemEntity.TYPE_TASK && return (lineItem.typeId == InvoiceItemEntity.TYPE_TASK &&
widget.isTasks) || widget.isTasks) ||
(lineItem.typeId != InvoiceItemEntity.TYPE_TASK && !widget.isTasks) || (lineItem.typeId != InvoiceItemEntity.TYPE_TASK && !widget.isTasks) ||
lineItem.isEmpty; lineItem.isEmpty;
@ -429,7 +429,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
buildDefaultDragHandles: false, buildDefaultDragHandles: false,
itemCount: lineItems.length, itemCount: lineItems.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = lineItems[index]!; final item = lineItems[index];
if ((item.typeId == InvoiceItemEntity.TYPE_TASK && if ((item.typeId == InvoiceItemEntity.TYPE_TASK &&
!widget.isTasks) || !widget.isTasks) ||
@ -577,7 +577,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
); );
} }
if (lineItems.where((item) => item!.isEmpty).isEmpty) { if (lineItems.where((item) => item.isEmpty).isEmpty) {
lineItems.add(InvoiceItemEntity( lineItems.add(InvoiceItemEntity(
quantity: company.defaultQuantity || !company.enableProductQuantity quantity: company.defaultQuantity || !company.enableProductQuantity
? 1 ? 1
@ -594,7 +594,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
color: tableFontColor.isNotEmpty color: tableFontColor.isNotEmpty
? convertHexStringToColor(tableFontColor) ? convertHexStringToColor(tableFontColor)
: null, : null,
onPressed: includedLineItems.where((item) => !item!.isEmpty).length < 2 onPressed: includedLineItems.where((item) => !item.isEmpty).length < 2
? null ? null
: () { : () {
setState(() => _isReordering = !_isReordering); setState(() => _isReordering = !_isReordering);
@ -623,14 +623,14 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
: BoxDecoration(), : BoxDecoration(),
), ),
for (var index = 0; index < lineItems.length; index++) for (var index = 0; index < lineItems.length; index++)
if ((lineItems[index]!.typeId == InvoiceItemEntity.TYPE_TASK && if ((lineItems[index].typeId == InvoiceItemEntity.TYPE_TASK &&
widget.isTasks) || widget.isTasks) ||
(lineItems[index]!.typeId != InvoiceItemEntity.TYPE_TASK && (lineItems[index].typeId != InvoiceItemEntity.TYPE_TASK &&
!widget.isTasks) || !widget.isTasks) ||
lineItems[index]!.isEmpty) lineItems[index].isEmpty)
TableRow( TableRow(
key: ValueKey( key: ValueKey(
'__line_item_${index}_${lineItems[index]!.createdAt}__'), '__line_item_${index}_${lineItems[index].createdAt}__'),
children: [ children: [
..._columns.map((column) { ..._columns.map((column) {
if (column == COLUMN_ITEM) { if (column == COLUMN_ITEM) {
@ -647,7 +647,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
key: ValueKey('__line_item_${index}_name__'), key: ValueKey('__line_item_${index}_name__'),
textEditingController: _textEditingController, textEditingController: _textEditingController,
initialValue: TextEditingValue( initialValue: TextEditingValue(
text: lineItems[index]!.productKey), text: lineItems[index].productKey),
optionsBuilder: optionsBuilder:
(TextEditingValue textEditingValue) { (TextEditingValue textEditingValue) {
final options = productIds final options = productIds
@ -672,8 +672,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
if (options.length == 1 && if (options.length == 1 &&
options[0].productKey.toLowerCase() == options[0].productKey.toLowerCase() ==
lineItems[index]! lineItems[index].productKey
.productKey
.toLowerCase()) { .toLowerCase()) {
return <ProductEntity>[]; return <ProductEntity>[];
} }
@ -706,7 +705,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
} }
final updatedItem = company.fillProducts final updatedItem = company.fillProducts
? item!.rebuild((b) => b ? item.rebuild((b) => b
..productKey = product.productKey ..productKey = product.productKey
..notes = item.isTask ..notes = item.isTask
? item.notes ? item.notes
@ -756,7 +755,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
product.taxName3.isNotEmpty product.taxName3.isNotEmpty
? product.taxRate3 ? product.taxRate3
: item.taxRate3) : item.taxRate3)
: item!.rebuild((b) => : item.rebuild((b) =>
b..productKey = product.productKey); b..productKey = product.productKey);
_onChanged(updatedItem, index, debounce: false); _onChanged(updatedItem, index, debounce: false);
@ -777,7 +776,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
}, },
onChanged: (value) { onChanged: (value) {
_onChanged( _onChanged(
lineItems[index]!.rebuild( lineItems[index].rebuild(
(b) => b..productKey = value), (b) => b..productKey = value),
index); index);
}, },
@ -865,10 +864,9 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
key: ValueKey( key: ValueKey(
'__line_item_${index}_description__'), '__line_item_${index}_description__'),
autofocus: _autocompleteFocusIndex == index, autofocus: _autocompleteFocusIndex == index,
initialValue: lineItems[index]!.notes, initialValue: lineItems[index].notes,
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]! lineItems[index].rebuild((b) => b..notes = value),
.rebuild((b) => b..notes = value),
index), index),
), ),
), ),
@ -882,11 +880,10 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: CustomField( child: CustomField(
field: customField1, field: customField1,
value: lineItems[index]!.customValue1, value: lineItems[index].customValue1,
hideFieldLabel: true, hideFieldLabel: true,
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]! lineItems[index].rebuild((b) => b..customValue1 = value),
.rebuild((b) => b..customValue1 = value),
index), index),
onSavePressed: onSavePressed:
widget.entityViewModel.onSavePressed, widget.entityViewModel.onSavePressed,
@ -902,11 +899,10 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: CustomField( child: CustomField(
field: customField2, field: customField2,
value: lineItems[index]!.customValue2, value: lineItems[index].customValue2,
hideFieldLabel: true, hideFieldLabel: true,
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]! lineItems[index].rebuild((b) => b..customValue2 = value),
.rebuild((b) => b..customValue2 = value),
index), index),
onSavePressed: onSavePressed:
widget.entityViewModel.onSavePressed, widget.entityViewModel.onSavePressed,
@ -922,11 +918,10 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: CustomField( child: CustomField(
field: customField3, field: customField3,
value: lineItems[index]!.customValue3, value: lineItems[index].customValue3,
hideFieldLabel: true, hideFieldLabel: true,
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]! lineItems[index].rebuild((b) => b..customValue3 = value),
.rebuild((b) => b..customValue3 = value),
index), index),
onSavePressed: onSavePressed:
widget.entityViewModel.onSavePressed, widget.entityViewModel.onSavePressed,
@ -942,11 +937,10 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: CustomField( child: CustomField(
field: customField4, field: customField4,
value: lineItems[index]!.customValue4, value: lineItems[index].customValue4,
hideFieldLabel: true, hideFieldLabel: true,
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]! lineItems[index].rebuild((b) => b..customValue4 = value),
.rebuild((b) => b..customValue4 = value),
index), index),
onSavePressed: onSavePressed:
widget.entityViewModel.onSavePressed, widget.entityViewModel.onSavePressed,
@ -954,7 +948,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
), ),
); );
} else if (column == COLUMN_TAX_CATEGORY && } else if (column == COLUMN_TAX_CATEGORY &&
!lineItems[index]!.hasOverrideTax) { !lineItems[index].hasOverrideTax) {
return Focus( return Focus(
onFocusChange: (hasFocus) => _onFocusChange(), onFocusChange: (hasFocus) => _onFocusChange(),
skipTraversal: true, skipTraversal: true,
@ -963,9 +957,9 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: AppDropdownButton<String>( child: AppDropdownButton<String>(
labelText: '', labelText: '',
value: lineItems[index]!.taxCategoryId, value: lineItems[index].taxCategoryId,
onChanged: (dynamic value) => _onChanged( onChanged: (dynamic value) => _onChanged(
lineItems[index]!.rebuild( lineItems[index].rebuild(
(b) => b..taxCategoryId = value), (b) => b..taxCategoryId = value),
index), index),
items: kTaxCategories.keys items: kTaxCategories.keys
@ -980,7 +974,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
); );
} else if (column == COLUMN_TAX1 || } else if (column == COLUMN_TAX1 ||
(column == COLUMN_TAX_CATEGORY && (column == COLUMN_TAX_CATEGORY &&
lineItems[index]!.hasOverrideTax)) { lineItems[index].hasOverrideTax)) {
Widget child = Focus( Widget child = Focus(
onFocusChange: (hasFocus) => _onFocusChange(), onFocusChange: (hasFocus) => _onFocusChange(),
skipTraversal: true, skipTraversal: true,
@ -989,27 +983,27 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: TaxRateDropdown( child: TaxRateDropdown(
onSelected: (taxRate) => _onChanged( onSelected: (taxRate) => _onChanged(
lineItems[index]!.rebuild((b) => b lineItems[index].rebuild((b) => b
..taxName1 = taxRate.name ..taxName1 = taxRate.name
..taxRate1 = taxRate.rate), ..taxRate1 = taxRate.rate),
index, index,
debounce: false, debounce: false,
), ),
labelText: null, labelText: null,
initialTaxName: lineItems[index]!.taxName1, initialTaxName: lineItems[index].taxName1,
initialTaxRate: lineItems[index]!.taxRate1, initialTaxRate: lineItems[index].taxRate1,
), ),
), ),
); );
if (lineItems[index]!.hasOverrideTax) { if (lineItems[index].hasOverrideTax) {
child = Row( child = Row(
children: [ children: [
Expanded(child: child), Expanded(child: child),
IconButton( IconButton(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
onPressed: () => _onChanged( onPressed: () => _onChanged(
lineItems[index]!.rebuild((b) => b lineItems[index].rebuild((b) => b
..taxName1 = '' ..taxName1 = ''
..taxRate1 = 0 ..taxRate1 = 0
..taxCategoryId = kTaxCategoryPhysical), ..taxCategoryId = kTaxCategoryPhysical),
@ -1029,15 +1023,15 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: TaxRateDropdown( child: TaxRateDropdown(
onSelected: (taxRate) => _onChanged( onSelected: (taxRate) => _onChanged(
lineItems[index]!.rebuild((b) => b lineItems[index].rebuild((b) => b
..taxName2 = taxRate.name ..taxName2 = taxRate.name
..taxRate2 = taxRate.rate), ..taxRate2 = taxRate.rate),
index, index,
debounce: false, debounce: false,
), ),
labelText: null, labelText: null,
initialTaxName: lineItems[index]!.taxName2, initialTaxName: lineItems[index].taxName2,
initialTaxRate: lineItems[index]!.taxRate2, initialTaxRate: lineItems[index].taxRate2,
), ),
), ),
); );
@ -1050,15 +1044,15 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
const EdgeInsets.only(right: kTableColumnGap), const EdgeInsets.only(right: kTableColumnGap),
child: TaxRateDropdown( child: TaxRateDropdown(
onSelected: (taxRate) => _onChanged( onSelected: (taxRate) => _onChanged(
lineItems[index]!.rebuild((b) => b lineItems[index].rebuild((b) => b
..taxName3 = taxRate.name ..taxName3 = taxRate.name
..taxRate3 = taxRate.rate), ..taxRate3 = taxRate.rate),
index, index,
debounce: false, debounce: false,
), ),
labelText: null, labelText: null,
initialTaxName: lineItems[index]!.taxName3, initialTaxName: lineItems[index].taxName3,
initialTaxRate: lineItems[index]!.taxRate3, initialTaxRate: lineItems[index].taxRate3,
), ),
), ),
); );
@ -1073,7 +1067,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
key: ValueKey('__line_item_${index}_cost__'), key: ValueKey('__line_item_${index}_cost__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index]!.cost, lineItems[index].cost,
context, context,
formatNumberType: FormatNumberType.inputMoney, formatNumberType: FormatNumberType.inputMoney,
clientId: invoice.isPurchaseOrder clientId: invoice.isPurchaseOrder
@ -1084,7 +1078,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
: null, : null,
), ),
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]!.rebuild( lineItems[index].rebuild(
(b) => b..cost = parseDouble(value)), (b) => b..cost = parseDouble(value)),
index, index,
debounce: false, debounce: false,
@ -1107,7 +1101,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
key: ValueKey('__line_item_${index}_quantity__'), key: ValueKey('__line_item_${index}_quantity__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index]!.quantity, lineItems[index].quantity,
context, context,
formatNumberType: FormatNumberType.inputAmount, formatNumberType: FormatNumberType.inputAmount,
clientId: invoice.isPurchaseOrder clientId: invoice.isPurchaseOrder
@ -1118,7 +1112,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
: null, : null,
), ),
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]!.rebuild( lineItems[index].rebuild(
(b) => b..quantity = parseDouble(value)), (b) => b..quantity = parseDouble(value)),
index, index,
debounce: false, debounce: false,
@ -1141,7 +1135,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
key: ValueKey('__line_item_${index}_discount__'), key: ValueKey('__line_item_${index}_discount__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index]!.discount, lineItems[index].discount,
context, context,
formatNumberType: FormatNumberType.inputAmount, formatNumberType: FormatNumberType.inputAmount,
clientId: invoice.isPurchaseOrder clientId: invoice.isPurchaseOrder
@ -1152,7 +1146,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
: null, : null,
), ),
onChanged: (value) => _onChanged( onChanged: (value) => _onChanged(
lineItems[index]!.rebuild( lineItems[index].rebuild(
(b) => b..discount = parseDouble(value)), (b) => b..discount = parseDouble(value)),
index), index),
keyboardType: TextInputType.numberWithOptions( keyboardType: TextInputType.numberWithOptions(
@ -1170,11 +1164,11 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
padding: const EdgeInsets.only(right: kTableColumnGap), padding: const EdgeInsets.only(right: kTableColumnGap),
child: TextFormField( child: TextFormField(
key: ValueKey( key: ValueKey(
'__total_${index}_${lineItems[index]!.total(invoice, precision)}_${invoice.clientId}__'), '__total_${index}_${lineItems[index].total(invoice, precision)}_${invoice.clientId}__'),
readOnly: true, readOnly: true,
enabled: false, enabled: false,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index]!.total(invoice, precision), lineItems[index].total(invoice, precision),
context, context,
clientId: clientId:
invoice.isPurchaseOrder ? null : invoice.clientId, invoice.isPurchaseOrder ? null : invoice.clientId,
@ -1186,13 +1180,13 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
), ),
PopupMenuButton<String>( PopupMenuButton<String>(
icon: Icon(Icons.more_vert), icon: Icon(Icons.more_vert),
enabled: !lineItems[index]!.isEmpty, enabled: !lineItems[index].isEmpty,
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
final sectionIndex = final sectionIndex =
includedLineItems.indexOf(lineItems[index]); includedLineItems.indexOf(lineItems[index]);
final options = { final options = {
if (widget.isTasks && if (widget.isTasks &&
(lineItems[index]!.taskId ?? '').isNotEmpty) (lineItems[index].taskId ?? '').isNotEmpty)
localization.viewTask: MdiIcons.chevronDoubleRight, localization.viewTask: MdiIcons.chevronDoubleRight,
if (sectionIndex > 0) if (sectionIndex > 0)
localization.moveTop: MdiIcons.chevronDoubleUp, localization.moveTop: MdiIcons.chevronDoubleUp,
@ -1218,7 +1212,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
onSelected: (String action) { onSelected: (String action) {
if (action == localization.viewTask) { if (action == localization.viewTask) {
viewEntityById( viewEntityById(
entityId: lineItems[index]!.taskId, entityId: lineItems[index].taskId,
entityType: EntityType.task); entityType: EntityType.task);
} else if (action == localization.moveTop) { } else if (action == localization.moveTop) {
viewModel.onMovedInvoiceItem!(index, 0); viewModel.onMovedInvoiceItem!(index, 0);

View File

@ -124,7 +124,7 @@ class InvoiceEditVM extends AbstractInvoiceEditVM {
final state = store.state; final state = store.state;
final clientId = invoice.clientId; final clientId = invoice.clientId;
for (int i = 0; i < invoice.lineItems.length; i++) { for (int i = 0; i < invoice.lineItems.length; i++) {
final lineItem = invoice.lineItems[i]!; final lineItem = invoice.lineItems[i];
final task = state.taskState.get(lineItem.taskId ?? ''); final task = state.taskState.get(lineItem.taskId ?? '');
if (task.clientId.isNotEmpty && task.clientId != clientId) { if (task.clientId.isNotEmpty && task.clientId != clientId) {
showDialog<ErrorDialog>( showDialog<ErrorDialog>(

View File

@ -161,8 +161,8 @@ class _PurchaseOrderEditState extends State<PurchaseOrderEdit>
invoice: invoice, invoice: invoice,
showTasksAndExpenses: false, showTasksAndExpenses: false,
excluded: invoice.lineItems excluded: invoice.lineItems
.where((item) => item!.isTask || item.isExpense) .where((item) => item.isTask || item.isExpense)
.map((item) => item!.isTask .map((item) => item.isTask
? viewModel.state!.taskState.map[item.taskId] ? viewModel.state!.taskState.map[item.taskId]
: viewModel.state!.expenseState.map[item.expenseId]) : viewModel.state!.expenseState.map[item.expenseId])
.toList(), .toList(),

View File

@ -158,8 +158,8 @@ class _QuoteEditState extends State<QuoteEdit>
invoice: invoice, invoice: invoice,
showTasksAndExpenses: false, showTasksAndExpenses: false,
excluded: invoice.lineItems excluded: invoice.lineItems
.where((item) => item!.isTask || item.isExpense) .where((item) => item.isTask || item.isExpense)
.map((item) => item!.isTask .map((item) => item.isTask
? viewModel.state!.taskState.map[item.taskId] ? viewModel.state!.taskState.map[item.taskId]
: viewModel.state!.expenseState.map[item.expenseId]) : viewModel.state!.expenseState.map[item.expenseId])
.toList(), .toList(),

View File

@ -161,8 +161,8 @@ class _RecurringInvoiceEditState extends State<RecurringInvoiceEdit>
invoice: invoice, invoice: invoice,
showTasksAndExpenses: false, showTasksAndExpenses: false,
excluded: invoice.lineItems excluded: invoice.lineItems
.where((item) => item!.isTask || item.isExpense) .where((item) => item.isTask || item.isExpense)
.map((item) => item!.isTask .map((item) => item.isTask
? viewModel.state!.taskState.map[item.taskId] ? viewModel.state!.taskState.map[item.taskId]
: viewModel.state!.expenseState.map[item.expenseId]) : viewModel.state!.expenseState.map[item.expenseId])
.toList(), .toList(),

View File

@ -113,7 +113,7 @@ ReportResult lineItemReport(
for (var column in columns) { for (var column in columns) {
dynamic value = ''; dynamic value = '';
final productId = productKeyMap[lineItem!.productKey]; final productId = productKeyMap[lineItem.productKey];
switch (column) { switch (column) {
case CreditItemReportFields.price: case CreditItemReportFields.price:

View File

@ -113,7 +113,7 @@ ReportResult lineItemReport(
for (var column in columns) { for (var column in columns) {
dynamic value = ''; dynamic value = '';
final productId = productKeyMap[lineItem!.productKey]; final productId = productKeyMap[lineItem.productKey];
switch (column) { switch (column) {
case InvoiceItemReportFields.price: case InvoiceItemReportFields.price:

View File

@ -115,7 +115,7 @@ ReportResult lineItemReport(
for (var column in columns) { for (var column in columns) {
dynamic value = ''; dynamic value = '';
final productId = productKeyMap[lineItem!.productKey]; final productId = productKeyMap[lineItem.productKey];
switch (column) { switch (column) {
case PurchaseOrderItemReportFields.price: case PurchaseOrderItemReportFields.price:

View File

@ -113,7 +113,7 @@ ReportResult lineItemReport(
for (var column in columns) { for (var column in columns) {
dynamic value = ''; dynamic value = '';
final productId = productKeyMap[lineItem!.productKey]; final productId = productKeyMap[lineItem.productKey];
switch (column) { switch (column) {
case QuoteItemReportFields.price: case QuoteItemReportFields.price: