mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-12 23:45:10 +00:00
Improve bill overview.
This commit is contained in:
@@ -312,11 +312,23 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
|
|||||||
Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString()));
|
Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString()));
|
||||||
|
|
||||||
return $bill->transactionJournals()
|
return $bill->transactionJournals()
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->leftJoin('transaction_currencies AS currency', 'currency.id', '=', 'transactions.transaction_currency_id')
|
||||||
|
->leftJoin('transaction_currencies AS foreign_currency', 'foreign_currency.id', '=', 'transactions.foreign_currency_id')
|
||||||
|
->where('transactions.amount', '>', 0)
|
||||||
->before($end)->after($start)->get(
|
->before($end)->after($start)->get(
|
||||||
[
|
[
|
||||||
'transaction_journals.id',
|
'transaction_journals.id',
|
||||||
'transaction_journals.date',
|
'transaction_journals.date',
|
||||||
'transaction_journals.transaction_group_id',
|
'transaction_journals.transaction_group_id',
|
||||||
|
'transactions.transaction_currency_id',
|
||||||
|
'currency.code AS transaction_currency_code',
|
||||||
|
'currency.decimal_places AS transaction_currency_decimal_places',
|
||||||
|
'transactions.foreign_currency_id',
|
||||||
|
'foreign_currency.code AS foreign_currency_code',
|
||||||
|
'foreign_currency.decimal_places AS foreign_currency_decimal_places',
|
||||||
|
'transactions.amount',
|
||||||
|
'transactions.foreign_amount',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
@@ -32,8 +32,10 @@ use FireflyIII\Models\TransactionCurrency;
|
|||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\Support\Models\BillDateCalculator;
|
use FireflyIII\Support\Models\BillDateCalculator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BillTransformer
|
* Class BillTransformer
|
||||||
@@ -194,9 +196,9 @@ class BillTransformer extends AbstractTransformer
|
|||||||
*/
|
*/
|
||||||
protected function paidData(Bill $bill): array
|
protected function paidData(Bill $bill): array
|
||||||
{
|
{
|
||||||
app('log')->debug(sprintf('Now in paidData for bill #%d', $bill->id));
|
Log::debug(sprintf('Now in paidData for bill #%d', $bill->id));
|
||||||
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
|
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
|
||||||
app('log')->debug('parameters are NULL, return empty array');
|
Log::debug('parameters are NULL, return empty array');
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -217,27 +219,40 @@ class BillTransformer extends AbstractTransformer
|
|||||||
$searchStart->startOfDay();
|
$searchStart->startOfDay();
|
||||||
$searchEnd->endOfDay();
|
$searchEnd->endOfDay();
|
||||||
|
|
||||||
app('log')->debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
Log::debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||||
app('log')->debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d')));
|
Log::debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d')));
|
||||||
|
|
||||||
// Get from database when bill was paid.
|
// Get from database when bill was paid.
|
||||||
$set = $this->repository->getPaidDatesInRange($bill, $searchStart, $searchEnd);
|
$set = $this->repository->getPaidDatesInRange($bill, $searchStart, $searchEnd);
|
||||||
app('log')->debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count()));
|
Log::debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count()));
|
||||||
|
|
||||||
// Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date.
|
// Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date.
|
||||||
app('log')->debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
|
Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
|
||||||
$lastPaidDate = $this->lastPaidDate($set, $start);
|
$lastPaidDate = $this->lastPaidDate($set, $start);
|
||||||
app('log')->debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
|
Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
|
||||||
|
|
||||||
// At this point the "next match" is exactly after the last time the bill was paid.
|
// At this point the "next match" is exactly after the last time the bill was paid.
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$result[] = [
|
$array = [
|
||||||
'transaction_group_id' => (string)$entry->transaction_group_id,
|
'transaction_group_id' => (string)$entry->transaction_group_id,
|
||||||
'transaction_journal_id' => (string)$entry->id,
|
'transaction_journal_id' => (string)$entry->id,
|
||||||
'date' => $entry->date->format('Y-m-d'),
|
'date' => $entry->date->format('Y-m-d'),
|
||||||
'date_object' => $entry->date,
|
'date_object' => $entry->date,
|
||||||
|
'currency_id' => $entry->transaction_currency_id,
|
||||||
|
'currency_code' => $entry->transaction_currency_code,
|
||||||
|
'currency_decimal_places' => $entry->transaction_currency_decimal_places,
|
||||||
|
'amount' => Steam::bcround($entry->amount,$entry->transaction_currency_decimal_places),
|
||||||
];
|
];
|
||||||
|
if (null !== $entry->foreign_amount && null !== $entry->foreign_currency_code) {
|
||||||
|
$array['foreign_currency_id'] = $entry->foreign_currency_id;
|
||||||
|
$array['foreign_currency_code'] = $entry->foreign_currency_code;
|
||||||
|
$array['foreign_currency_decimal_places'] = $entry->foreign_currency_decimal_places;
|
||||||
|
$array['foreign_amount'] = Steam::bcround($entry->foreign_amount,$entry->foreign_currency_decimal_places);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = $array;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@@ -265,7 +280,7 @@ class BillTransformer extends AbstractTransformer
|
|||||||
|
|
||||||
private function getLastPaidDate(array $paidData): ?Carbon
|
private function getLastPaidDate(array $paidData): ?Carbon
|
||||||
{
|
{
|
||||||
app('log')->debug('getLastPaidDate()');
|
Log::debug('getLastPaidDate()');
|
||||||
$return = null;
|
$return = null;
|
||||||
foreach ($paidData as $entry) {
|
foreach ($paidData as $entry) {
|
||||||
if (null !== $return) {
|
if (null !== $return) {
|
||||||
@@ -274,15 +289,15 @@ class BillTransformer extends AbstractTransformer
|
|||||||
if ($current->gt($return)) {
|
if ($current->gt($return)) {
|
||||||
$return = clone $current;
|
$return = clone $current;
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
|
Log::debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
|
||||||
}
|
}
|
||||||
if (null === $return) {
|
if (null === $return) {
|
||||||
/** @var Carbon $return */
|
/** @var Carbon $return */
|
||||||
$return = $entry['date_object'];
|
$return = $entry['date_object'];
|
||||||
app('log')->debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
|
Log::debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('Last paid date is: "%s"', $return?->format('Y-m-d')));
|
Log::debug(sprintf('Last paid date is: "%s"', $return?->format('Y-m-d')));
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
@@ -31,76 +31,54 @@ let afterPromises = false;
|
|||||||
let apiData = [];
|
let apiData = [];
|
||||||
let subscriptionData = {};
|
let subscriptionData = {};
|
||||||
|
|
||||||
function downloadSubscriptions(params) {
|
function addObjectGroupInfo(data) {
|
||||||
const getter = new Get();
|
let objectGroupId = parseInt(data.object_group_id);
|
||||||
return getter.list(params)
|
|
||||||
// first promise: parse the data:
|
|
||||||
.then((response) => {
|
|
||||||
let data = response.data.data;
|
|
||||||
//console.log(data);
|
|
||||||
for (let i in data) {
|
|
||||||
if (data.hasOwnProperty(i)) {
|
|
||||||
let current = data[i];
|
|
||||||
//console.log(current);
|
|
||||||
if (current.attributes.active && current.attributes.pay_dates.length > 0) {
|
|
||||||
let objectGroupId = null === current.attributes.object_group_id ? 0 : current.attributes.object_group_id;
|
|
||||||
let objectGroupTitle = null === current.attributes.object_group_title ? i18next.t('firefly.default_group_title_name_plain') : current.attributes.object_group_title;
|
|
||||||
let objectGroupOrder = null === current.attributes.object_group_order ? 0 : current.attributes.object_group_order;
|
|
||||||
if (!subscriptionData.hasOwnProperty(objectGroupId)) {
|
if (!subscriptionData.hasOwnProperty(objectGroupId)) {
|
||||||
subscriptionData[objectGroupId] = {
|
subscriptionData[objectGroupId] = {
|
||||||
id: objectGroupId,
|
id: objectGroupId,
|
||||||
title: objectGroupTitle,
|
title: null === data.object_group_title ? i18next.t('firefly.default_group_title_name_plain') : data.object_group_title,
|
||||||
order: objectGroupOrder,
|
order: parseInt(data.object_group_order),
|
||||||
payment_info: {},
|
payment_info: {},
|
||||||
bills: [],
|
bills: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// TODO this conversion needs to be inside some kind of a parsing class.
|
}
|
||||||
let bill = {
|
|
||||||
id: current.id,
|
|
||||||
name: current.attributes.name,
|
|
||||||
// amount
|
|
||||||
amount_min: current.attributes.amount_min,
|
|
||||||
amount_max: current.attributes.amount_max,
|
|
||||||
amount: (parseFloat(current.attributes.amount_max) + parseFloat(current.attributes.amount_min)) / 2,
|
|
||||||
currency_code: current.attributes.currency_code,
|
|
||||||
|
|
||||||
// native amount
|
|
||||||
// native_amount_min: current.attributes.native_amount_min,
|
|
||||||
// native_amount_max: current.attributes.native_amount_max,
|
|
||||||
// native_amount: (parseFloat(current.attributes.native_amount_max) + parseFloat(current.attributes.native_amount_min)) / 2,
|
|
||||||
// native_currency_code: current.attributes.native_currency_code,
|
|
||||||
|
|
||||||
|
function parseBillInfo(data) {
|
||||||
|
let result = {
|
||||||
|
id: data.id,
|
||||||
|
name: data.attributes.name,
|
||||||
|
amount_min: data.attributes.amount_min,
|
||||||
|
amount_max: data.attributes.amount_max,
|
||||||
|
amount: (parseFloat(data.attributes.amount_max) + parseFloat(data.attributes.amount_min)) / 2,
|
||||||
|
currency_code: data.attributes.currency_code,
|
||||||
// paid transactions:
|
// paid transactions:
|
||||||
transactions: [],
|
transactions: [],
|
||||||
|
|
||||||
// unpaid moments
|
// unpaid moments
|
||||||
pay_dates: current.attributes.pay_dates,
|
pay_dates: data.attributes.pay_dates,
|
||||||
paid: current.attributes.paid_dates.length > 0,
|
paid: data.attributes.paid_dates.length > 0,
|
||||||
};
|
};
|
||||||
// set variables
|
// set variables
|
||||||
bill.expected_amount = formatMoney(bill.amount, bill.currency_code);
|
result.expected_amount = formatMoney(result.amount, result.currency_code);
|
||||||
bill.expected_times = i18next.t('firefly.subscr_expected_x_times', {
|
result.expected_times = i18next.t('firefly.subscr_expected_x_times', {
|
||||||
times: current.attributes.pay_dates.length,
|
times: data.attributes.pay_dates.length,
|
||||||
amount: bill.expected_amount
|
amount: result.expected_amount
|
||||||
});
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parsePaidTransactions(paid_dates, bill) {
|
||||||
|
if( !paid_dates || paid_dates.length < 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let result = [];
|
||||||
// add transactions (simpler version)
|
// add transactions (simpler version)
|
||||||
for (let iii in current.attributes.paid_dates) {
|
for (let i in paid_dates) {
|
||||||
if (current.attributes.paid_dates.hasOwnProperty(iii)) {
|
if (paid_dates.hasOwnProperty(i)) {
|
||||||
const currentPayment = current.attributes.paid_dates[iii];
|
const currentPayment = paid_dates[i];
|
||||||
let percentage = 100;
|
|
||||||
// math: -100+(paid/expected)*100
|
|
||||||
if (params.convertToNative) {
|
|
||||||
percentage = Math.round(-100 + ((parseFloat(currentPayment.native_amount) * -1) / parseFloat(bill.native_amount)) * 100);
|
|
||||||
}
|
|
||||||
if (!params.convertToNative) {
|
|
||||||
percentage = Math.round(-100 + ((parseFloat(currentPayment.amount) * -1) / parseFloat(bill.amount)) * 100);
|
|
||||||
}
|
|
||||||
// TODO fix me
|
|
||||||
currentPayment.currency_code = 'EUR';
|
|
||||||
console.log('Currency code: "'+currentPayment+'"');
|
|
||||||
console.log(currentPayment);
|
console.log(currentPayment);
|
||||||
|
// math: -100+(paid/expected)*100
|
||||||
|
let percentage = Math.round(-100 + ((parseFloat(currentPayment.amount) ) / parseFloat(bill.amount)) * 100);
|
||||||
let currentTransaction = {
|
let currentTransaction = {
|
||||||
amount: formatMoney(currentPayment.amount, currentPayment.currency_code),
|
amount: formatMoney(currentPayment.amount, currentPayment.currency_code),
|
||||||
percentage: percentage,
|
percentage: percentage,
|
||||||
@@ -112,9 +90,30 @@ function downloadSubscriptions(params) {
|
|||||||
currentTransaction.foreign_currency_code = currentPayment.foreign_currency_code;
|
currentTransaction.foreign_currency_code = currentPayment.foreign_currency_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
bill.transactions.push(currentTransaction);
|
result.push(currentTransaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadSubscriptions(params) {
|
||||||
|
const getter = new Get();
|
||||||
|
return getter.list(params)
|
||||||
|
// first promise: parse the data:
|
||||||
|
.then((response) => {
|
||||||
|
let data = response.data.data;
|
||||||
|
//console.log(data);
|
||||||
|
for (let i in data) {
|
||||||
|
if (data.hasOwnProperty(i)) {
|
||||||
|
let current = data[i];
|
||||||
|
if (current.attributes.active && current.attributes.pay_dates.length > 0) {
|
||||||
|
// create or update object group
|
||||||
|
let objectGroupId = parseInt(current.attributes.object_group_id);
|
||||||
|
addObjectGroupInfo(current.attributes);
|
||||||
|
|
||||||
|
// create and update the bill.
|
||||||
|
let bill = parseBillInfo(current);
|
||||||
|
bill.transactions = parsePaidTransactions(current.attributes.paid_dates, bill);
|
||||||
|
|
||||||
subscriptionData[objectGroupId].bills.push(bill);
|
subscriptionData[objectGroupId].bills.push(bill);
|
||||||
if (0 === current.attributes.paid_dates.length) {
|
if (0 === current.attributes.paid_dates.length) {
|
||||||
|
@@ -1866,8 +1866,8 @@ return [
|
|||||||
'skip_help_text' => 'Use the skip field to create bi-monthly (skip = 1) or other custom intervals.',
|
'skip_help_text' => 'Use the skip field to create bi-monthly (skip = 1) or other custom intervals.',
|
||||||
'subscription' => 'Subscription',
|
'subscription' => 'Subscription',
|
||||||
'not_expected_period' => 'Not expected this period',
|
'not_expected_period' => 'Not expected this period',
|
||||||
'subscriptions_in_group' => 'Subscriptions in group "%{title}"',
|
'subscriptions_in_group' => 'Subscriptions in group "{{title}}"',
|
||||||
'subscr_expected_x_times' => 'Expect to pay %{amount} %{times} times this period',
|
'subscr_expected_x_times' => 'Expect to pay {{amount}} {{times}} times this period',
|
||||||
'not_or_not_yet' => 'Not (yet)',
|
'not_or_not_yet' => 'Not (yet)',
|
||||||
'visit_bill' => 'Visit subscription ":name" at Firefly III',
|
'visit_bill' => 'Visit subscription ":name" at Firefly III',
|
||||||
'match_between_amounts' => 'Subscription matches transactions between :low and :high.',
|
'match_between_amounts' => 'Subscription matches transactions between :low and :high.',
|
||||||
|
Reference in New Issue
Block a user