Include Due Date, Taxable, and Tax Rate columns in Invoice Item Report #273
This commit is contained in:
parent
92204b13e2
commit
2b2f6b701a
|
|
@ -1210,30 +1210,42 @@ abstract class InvoiceItemEntity
|
||||||
@nullable
|
@nullable
|
||||||
int get createdAt;
|
int get createdAt;
|
||||||
|
|
||||||
/*
|
double taxAmount(InvoiceEntity invoice, int precision) {
|
||||||
double taxAmount(bool useInclusiveTaxes, int precision) {
|
|
||||||
double calculateTaxAmount(double rate) {
|
double calculateTaxAmount(double rate) {
|
||||||
double taxAmount;
|
double taxAmount;
|
||||||
if (rate == 0) {
|
if (rate == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (useInclusiveTaxes) {
|
final lineTotal = total(invoice);
|
||||||
taxAmount = total - (total / (1 + (rate / 100)));
|
if (invoice.usesInclusiveTaxes) {
|
||||||
|
taxAmount = lineTotal - (lineTotal / (1 + (rate / 100)));
|
||||||
} else {
|
} else {
|
||||||
taxAmount = total * rate / 100;
|
taxAmount = lineTotal * rate / 100;
|
||||||
}
|
}
|
||||||
return round(taxAmount, precision);
|
return round(taxAmount, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateTaxAmount(taxRate1) + calculateTaxAmount(taxRate2) +
|
return calculateTaxAmount(taxRate1) +
|
||||||
|
calculateTaxAmount(taxRate2) +
|
||||||
calculateTaxAmount(taxRate3);
|
calculateTaxAmount(taxRate3);
|
||||||
}
|
}
|
||||||
|
|
||||||
double netTotal(bool useInclusiveTaxes, int precision) =>
|
double netTotal(InvoiceEntity invoice, int precision) =>
|
||||||
total - taxAmount(useInclusiveTaxes, precision);
|
total(invoice) - taxAmount(invoice, precision);
|
||||||
*/
|
|
||||||
|
|
||||||
double get total => round(quantity * cost, 2);
|
double total(InvoiceEntity invoice) {
|
||||||
|
var total = quantity * cost;
|
||||||
|
|
||||||
|
if (discount != 0) {
|
||||||
|
if (invoice.isAmountDiscount) {
|
||||||
|
total = total - discount;
|
||||||
|
} else {
|
||||||
|
total = total - (discount / 100 * total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return round(total, 2);
|
||||||
|
}
|
||||||
|
|
||||||
bool get isTask => typeId == TYPE_TASK;
|
bool get isTask => typeId == TYPE_TASK;
|
||||||
|
|
||||||
|
|
@ -1245,9 +1257,31 @@ abstract class InvoiceItemEntity
|
||||||
cost == 0 &&
|
cost == 0 &&
|
||||||
quantity == 0 &&
|
quantity == 0 &&
|
||||||
customValue1.isEmpty &&
|
customValue1.isEmpty &&
|
||||||
customValue2.isEmpty;
|
customValue2.isEmpty &&
|
||||||
|
customValue3.isEmpty &&
|
||||||
|
customValue4.isEmpty;
|
||||||
|
|
||||||
// TODO add custom 3 and 4
|
bool get hasTaxes =>
|
||||||
|
taxRate1 != 0 ||
|
||||||
|
taxRate2 != 0 ||
|
||||||
|
taxRate3 != 0 ||
|
||||||
|
taxName1.isNotEmpty ||
|
||||||
|
taxName2.isNotEmpty ||
|
||||||
|
taxName3.isNotEmpty;
|
||||||
|
|
||||||
|
String get taxRates {
|
||||||
|
final parts = <String>[];
|
||||||
|
if (taxName1.isNotEmpty) {
|
||||||
|
parts.add(taxName1);
|
||||||
|
}
|
||||||
|
if (taxName2.isNotEmpty) {
|
||||||
|
parts.add(taxName2);
|
||||||
|
}
|
||||||
|
if (taxName3.isNotEmpty) {
|
||||||
|
parts.add(taxName3);
|
||||||
|
}
|
||||||
|
return parts.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
InvoiceItemEntity applyTax(TaxRateEntity taxRate,
|
InvoiceItemEntity applyTax(TaxRateEntity taxRate,
|
||||||
{bool isSecond = false, bool isThird = false}) {
|
{bool isSecond = false, bool isThird = false}) {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ class InvoiceItemListTile extends StatelessWidget {
|
||||||
title: Row(
|
title: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(child: Text(invoiceItem.productKey)),
|
Expanded(child: Text(invoiceItem.productKey)),
|
||||||
Text(formatNumber(invoiceItem.total, context,
|
Text(formatNumber(invoiceItem.total(invoice), context,
|
||||||
clientId: invoice.clientId)),
|
clientId: invoice.clientId)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ class EntityPresenter {
|
||||||
'calculated_rate',
|
'calculated_rate',
|
||||||
'duration',
|
'duration',
|
||||||
'net_amount',
|
'net_amount',
|
||||||
|
'net_total',
|
||||||
].contains(field);
|
].contains(field);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
|
||||||
|
|
@ -576,7 +576,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
initialValue: formatNumber(
|
initialValue: formatNumber(
|
||||||
lineItems[index].total, context,
|
lineItems[index].total(invoice), context,
|
||||||
clientId: invoice.clientId),
|
clientId: invoice.clientId),
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ enum InvoiceItemReportFields {
|
||||||
cost,
|
cost,
|
||||||
quantity,
|
quantity,
|
||||||
profit,
|
profit,
|
||||||
lineTotal,
|
total,
|
||||||
discount,
|
discount,
|
||||||
custom1,
|
custom1,
|
||||||
custom2,
|
custom2,
|
||||||
|
|
@ -26,6 +26,11 @@ enum InvoiceItemReportFields {
|
||||||
invoiceNumber,
|
invoiceNumber,
|
||||||
invoiceDate,
|
invoiceDate,
|
||||||
client,
|
client,
|
||||||
|
dueDate,
|
||||||
|
hasTaxes,
|
||||||
|
taxRates,
|
||||||
|
taxAmount,
|
||||||
|
netTotal,
|
||||||
}
|
}
|
||||||
|
|
||||||
var memoizedInvoiceItemReport = memo6((
|
var memoizedInvoiceItemReport = memo6((
|
||||||
|
|
@ -81,6 +86,7 @@ ReportResult lineItemReport(
|
||||||
for (var entry in invoiceMap.entries) {
|
for (var entry in invoiceMap.entries) {
|
||||||
final invoice = entry.value;
|
final invoice = entry.value;
|
||||||
final client = clientMap[invoice.clientId];
|
final client = clientMap[invoice.clientId];
|
||||||
|
final precision = staticState.currencyMap[client.currencyId].precision;
|
||||||
|
|
||||||
if (invoice.isDeleted || client.isDeleted) {
|
if (invoice.isDeleted || client.isDeleted) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -105,9 +111,8 @@ ReportResult lineItemReport(
|
||||||
value = productId == null ? 0.0 : productMap[productId].cost;
|
value = productId == null ? 0.0 : productMap[productId].cost;
|
||||||
break;
|
break;
|
||||||
case InvoiceItemReportFields.profit:
|
case InvoiceItemReportFields.profit:
|
||||||
value = productId == null
|
value = lineItem.netTotal(invoice, precision) -
|
||||||
? 0.0
|
(productId == null ? 0.0 : productMap[productId].cost);
|
||||||
: lineItem.total - productMap[productId].cost;
|
|
||||||
break;
|
break;
|
||||||
case InvoiceItemReportFields.custom1:
|
case InvoiceItemReportFields.custom1:
|
||||||
value = lineItem.customValue1;
|
value = lineItem.customValue1;
|
||||||
|
|
@ -124,7 +129,7 @@ ReportResult lineItemReport(
|
||||||
case InvoiceItemReportFields.notes:
|
case InvoiceItemReportFields.notes:
|
||||||
value = lineItem.notes;
|
value = lineItem.notes;
|
||||||
break;
|
break;
|
||||||
case InvoiceItemReportFields.lineTotal:
|
case InvoiceItemReportFields.total:
|
||||||
value = lineItem.total;
|
value = lineItem.total;
|
||||||
break;
|
break;
|
||||||
case InvoiceItemReportFields.productKey:
|
case InvoiceItemReportFields.productKey:
|
||||||
|
|
@ -142,6 +147,21 @@ ReportResult lineItemReport(
|
||||||
case InvoiceItemReportFields.client:
|
case InvoiceItemReportFields.client:
|
||||||
value = client.displayName;
|
value = client.displayName;
|
||||||
break;
|
break;
|
||||||
|
case InvoiceItemReportFields.dueDate:
|
||||||
|
value = invoice.dueDate;
|
||||||
|
break;
|
||||||
|
case InvoiceItemReportFields.hasTaxes:
|
||||||
|
value = lineItem.hasTaxes;
|
||||||
|
break;
|
||||||
|
case InvoiceItemReportFields.taxRates:
|
||||||
|
value = lineItem.taxRates;
|
||||||
|
break;
|
||||||
|
case InvoiceItemReportFields.taxAmount:
|
||||||
|
value = lineItem.taxAmount(invoice, precision);
|
||||||
|
break;
|
||||||
|
case InvoiceItemReportFields.netTotal:
|
||||||
|
value = lineItem.netTotal(invoice, precision);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReportResult.matchField(
|
if (!ReportResult.matchField(
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ enum QuoteItemReportFields {
|
||||||
cost,
|
cost,
|
||||||
quantity,
|
quantity,
|
||||||
profit,
|
profit,
|
||||||
lineTotal,
|
total,
|
||||||
discount,
|
discount,
|
||||||
custom1,
|
custom1,
|
||||||
custom2,
|
custom2,
|
||||||
|
|
@ -26,6 +26,11 @@ enum QuoteItemReportFields {
|
||||||
quoteNumber,
|
quoteNumber,
|
||||||
quoteDate,
|
quoteDate,
|
||||||
client,
|
client,
|
||||||
|
validUntil,
|
||||||
|
hasTaxes,
|
||||||
|
taxRates,
|
||||||
|
taxAmount,
|
||||||
|
netTotal,
|
||||||
}
|
}
|
||||||
|
|
||||||
var memoizedQuoteItemReport = memo6((
|
var memoizedQuoteItemReport = memo6((
|
||||||
|
|
@ -81,6 +86,7 @@ ReportResult lineItemReport(
|
||||||
for (var entry in invoiceMap.entries) {
|
for (var entry in invoiceMap.entries) {
|
||||||
final invoice = entry.value;
|
final invoice = entry.value;
|
||||||
final client = clientMap[invoice.clientId];
|
final client = clientMap[invoice.clientId];
|
||||||
|
final precision = staticState.currencyMap[client.currencyId].precision;
|
||||||
|
|
||||||
if (invoice.isDeleted || client.isDeleted) {
|
if (invoice.isDeleted || client.isDeleted) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -105,9 +111,8 @@ ReportResult lineItemReport(
|
||||||
value = productId == null ? 0.0 : productMap[productId].cost;
|
value = productId == null ? 0.0 : productMap[productId].cost;
|
||||||
break;
|
break;
|
||||||
case QuoteItemReportFields.profit:
|
case QuoteItemReportFields.profit:
|
||||||
value = productId == null
|
value = lineItem.netTotal(invoice, precision) -
|
||||||
? 0.0
|
(productId == null ? 0.0 : productMap[productId].cost);
|
||||||
: lineItem.total - productMap[productId].cost;
|
|
||||||
break;
|
break;
|
||||||
case QuoteItemReportFields.custom1:
|
case QuoteItemReportFields.custom1:
|
||||||
value = lineItem.customValue1;
|
value = lineItem.customValue1;
|
||||||
|
|
@ -124,7 +129,7 @@ ReportResult lineItemReport(
|
||||||
case QuoteItemReportFields.notes:
|
case QuoteItemReportFields.notes:
|
||||||
value = lineItem.notes;
|
value = lineItem.notes;
|
||||||
break;
|
break;
|
||||||
case QuoteItemReportFields.lineTotal:
|
case QuoteItemReportFields.total:
|
||||||
value = lineItem.total;
|
value = lineItem.total;
|
||||||
break;
|
break;
|
||||||
case QuoteItemReportFields.productKey:
|
case QuoteItemReportFields.productKey:
|
||||||
|
|
@ -142,6 +147,21 @@ ReportResult lineItemReport(
|
||||||
case QuoteItemReportFields.client:
|
case QuoteItemReportFields.client:
|
||||||
value = client.displayName;
|
value = client.displayName;
|
||||||
break;
|
break;
|
||||||
|
case QuoteItemReportFields.validUntil:
|
||||||
|
value = invoice.dueDate;
|
||||||
|
break;
|
||||||
|
case QuoteItemReportFields.hasTaxes:
|
||||||
|
value = lineItem.hasTaxes;
|
||||||
|
break;
|
||||||
|
case QuoteItemReportFields.taxRates:
|
||||||
|
value = lineItem.taxRates;
|
||||||
|
break;
|
||||||
|
case QuoteItemReportFields.taxAmount:
|
||||||
|
value = lineItem.taxAmount(invoice, precision);
|
||||||
|
break;
|
||||||
|
case QuoteItemReportFields.netTotal:
|
||||||
|
value = lineItem.netTotal(invoice, precision);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReportResult.matchField(
|
if (!ReportResult.matchField(
|
||||||
|
|
|
||||||
|
|
@ -534,6 +534,8 @@ enum ReportColumnType {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportColumnType getReportColumnType(String column, BuildContext context) {
|
ReportColumnType getReportColumnType(String column, BuildContext context) {
|
||||||
|
column = toSnakeCase(column);
|
||||||
|
|
||||||
ReportColumnType convertCustomFieldType(String type) {
|
ReportColumnType convertCustomFieldType(String type) {
|
||||||
if (type == kFieldTypeDate) {
|
if (type == kFieldTypeDate) {
|
||||||
return ReportColumnType.date;
|
return ReportColumnType.date;
|
||||||
|
|
@ -1125,6 +1127,9 @@ class ReportResult {
|
||||||
final sortedColumns = columns.toList()
|
final sortedColumns = columns.toList()
|
||||||
..sort((String str1, String str2) => str1.compareTo(str2));
|
..sort((String str1, String str2) => str1.compareTo(str2));
|
||||||
|
|
||||||
|
for (String column in sortedColumns)
|
||||||
|
print('## $column => ${getReportColumnType(column, context)}');
|
||||||
|
|
||||||
final totalColumns = [
|
final totalColumns = [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(localization.currency),
|
label: Text(localization.currency),
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
static final Map<String, Map<String, String>> _localizedValues = {
|
static final Map<String, Map<String, String>> _localizedValues = {
|
||||||
'en': {
|
'en': {
|
||||||
// STARTER: lang key - do not remove comment
|
// STARTER: lang key - do not remove comment
|
||||||
|
'net_total': 'Net Total',
|
||||||
|
'has_taxes': 'Has Taxes',
|
||||||
'import_customers': 'Import Customers',
|
'import_customers': 'Import Customers',
|
||||||
'imported_customers': 'Successfully started importing customers',
|
'imported_customers': 'Successfully started importing customers',
|
||||||
'login_success': 'Successful Login',
|
'login_success': 'Successful Login',
|
||||||
|
|
@ -60405,6 +60407,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
||||||
_localizedValues[localeCode]['imported_customers'] ??
|
_localizedValues[localeCode]['imported_customers'] ??
|
||||||
_localizedValues['en']['imported_customers'];
|
_localizedValues['en']['imported_customers'];
|
||||||
|
|
||||||
|
String get hasTaxes =>
|
||||||
|
_localizedValues[localeCode]['has_taxes'] ??
|
||||||
|
_localizedValues['en']['has_taxes'];
|
||||||
|
|
||||||
|
String get netTotal =>
|
||||||
|
_localizedValues[localeCode]['net_total'] ??
|
||||||
|
_localizedValues['en']['net_total'];
|
||||||
|
|
||||||
String lookup(String key) {
|
String lookup(String key) {
|
||||||
final lookupKey = toSnakeCase(key);
|
final lookupKey = toSnakeCase(key);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue