Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: payers chart in credit cards #437

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 25 additions & 39 deletions app/Domains/Transaction/Services/CreditCardReportService.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,50 +122,36 @@ public function getTopCategoriesByCreditCard($teamId, $startDate = 1, $endDate,
]);
}

public function getTopPayeesByAccount($teamId, $date, $monthsBack = 1, $creditCardId = null, $asToday = null) {
$endCycleDate = Carbon::createFromFormat('Y-m-d', $date)->startOfMonth()->subMonth($monthsBack)->format('Y-m-d');
$startCycleDate = Carbon::createFromFormat('Y-m-d', $date)->startOfMonth()->subMonth($monthsBack+1)->format('Y-m-d');

public function getTopPayeesByAccount($teamId, $startDate, $endDate, $asToday = null) {
$readyToAssign = Category::where([
'team_id' => $teamId,
])
->where('name', BudgetReservedNames::READY_TO_ASSIGN->value)
->first();

return DB::table(DB::raw('accounts a'))
->where("a.team_id", $teamId)
->whereNotNull('a.credit_closing_day')
->when($asToday, fn ($q) => $q->whereRaw("now() >= DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0')))", [
$endCycleDate
]))
->selectRaw("
ABS(COALESCE(SUM(CASE WHEN tl.type = -1 THEN tl.amount * tl.type ELSE 0 END), 0)) AS subtotal,
ABS(COALESCE(SUM(tl.amount * tl.type), 0)) AS total,
ABS(COALESCE(SUM(CASE WHEN tl.type = 1 THEN tl.amount * tl.type ELSE 0 END), 0)) AS discount,
a.name,
a.id,
a.credit_limit,
DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0'))) AS `from`,
DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0'))) AS `until`", [
$startCycleDate,
$endCycleDate
])

->leftJoin(DB::raw('transaction_lines tl'), fn ($q) => $q->on('a.id', 'tl.account_id')
->whereRaw('(tl.type = ? or tl.category_id = ?)', [-1, $readyToAssign->id])
)
// ->where('account_id', $accountId)
->whereRaw("(tl.date >= DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0'))) and tl.type = -1
AND
tl.date < DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0')))
)
OR tl.date = DATE_FORMAT(?, CONCAT('%Y-%m-', LPAD(a.credit_closing_day, 2, '0'))) AND tl.type = 1", [
$startCycleDate,
$endCycleDate,
$endCycleDate
])
->groupBy('a.id')
->get();
return DB::select("
SELECT
ABS(COALESCE(SUM(CASE WHEN tl.type = -1 THEN tl.amount * tl.type ELSE 0 END), 0)) AS subtotal,
ABS(COALESCE(SUM(tl.amount * tl.type), 0)) AS total,
ABS(COALESCE(SUM(CASE WHEN tl.type = 1 THEN tl.amount * tl.type ELSE 0 END), 0)) AS discount,
a.name,
a.id,
p.name as cat_name,
ROW_NUMBER() OVER (PARTITION BY tl.account_id ORDER BY SUM(tl.amount * tl.type)) AS rank
FROM transaction_lines tl
INNER JOIN transactions t on tl.transaction_id = t.id AND t.status = 'verified' AND tl.category_id <> :readyToAssign
INNER JOIN accounts a on tl.account_id = a.id AND a.credit_closing_day IS NOT NULL
INNER JOIN payees p on p.id = tl.payee_id
WHERE tl.date >= :startDate AND tl.date <= :endDate
AND tl.team_id = :teamId
GROUP BY tl.payee_id
ORDER BY ABS(COALESCE(SUM(tl.amount * tl.type), 0)) desc
", [
'teamId' => $teamId,
'startDate' => $startDate,
'endDate' => $endDate,
'readyToAssign' => $readyToAssign->id
]);
}

public function getBillingCyclesByCardInPeriod($teamId, $startDate = 1, $endDate, $creditCardId = null) {
Expand Down Expand Up @@ -226,7 +212,7 @@ public function creditCards($teamId, $date)
"creditLineUsage" => round($creditTotal / $lastCycleBalances->sum('credit_limit') * 100, 2),
'topCategoriesByCard' => $this->getTopCategoriesByCreditCard($teamId, $startPeriodDate, $date),
'billingCyclesByCard' => $this->getBillingCyclesByCardInPeriod($teamId, $startPeriodDate, $date),
'topPayeesByCard' => [],
'topPayeesByCard' => $this->getTopPayeesByAccount($teamId, $startPeriodDate->format('Y-m-d'), $date),
'topTransaction' => [],
'billingCyclePayments' => [],
];
Expand Down
3 changes: 3 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
IFluentFoodApple20Filled: typeof import('~icons/fluent/food-apple20-filled')['default']
IIonEllipsisVertical: typeof import('~icons/ion/ellipsis-vertical')['default']
IMaterialSymbolsBrightnessAlertOutlineRounded: typeof import('~icons/material-symbols/brightness-alert-outline-rounded')['default']
IMdiBankTransfer: typeof import('~icons/mdi/bank-transfer')['default']
Expand All @@ -15,8 +16,10 @@ declare module 'vue' {
IMdiBell: typeof import('~icons/mdi/bell')['default']
IMdiCallSplit: typeof import('~icons/mdi/call-split')['default']
IMdiCheck: typeof import('~icons/mdi/check')['default']
IMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
IMdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default']
IMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
IMdiChevronUp: typeof import('~icons/mdi/chevron-up')['default']
IMdiClose: typeof import('~icons/mdi/close')['default']
IMdiEdit: typeof import('~icons/mdi/edit')['default']
IMdiEllipsisVertical: typeof import('~icons/mdi/ellipsis-vertical')['default']
Expand Down
44 changes: 27 additions & 17 deletions resources/js/Components/ChartTopCreditCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,19 @@ import ChartHeaderScroller from "./ChartHeaderScroller.vue";
import NumberHider from "./molecules/NumberHider.vue";
import { formatMonth, nameToColor } from "@/utils";

const props = defineProps({
title: {
type: String
},
type: {
type: String,
default: "bar"
},
data: {
type: Object,
required: true
},
hideHeaders: {
type: Boolean
}
const props = withDefaults(defineProps<{
title?: string;
type: "bar" | "circle",
data: Record<string, string>[];
groupName?: string;
hideHeaders?: boolean;
}>(), {
type: 'bar'
});

const selectedDate = ref()
const currentSeries = computed(() => {
if (props.groupName) {
const groupByCard = props.data.reduce((creditCards, item) => {
if (creditCards[item.name]) {
creditCards[item.name].data.push(item.total),
Expand All @@ -41,8 +35,17 @@ const currentSeries = computed(() => {
}, {});

return Object.values(groupByCard);
}

return [{
name: 'Payees',
data: props.data.map(item => item.total),
labels: props.data.map(item => item.cat_name)
}];
})

const isGroup = computed(() => props.groupName);

const state = computed(() => ({
headers: Object.entries(props.data).map(([dateString, item]) => ({
label: `${item.cat_name} - ${item.name}`,
Expand All @@ -52,9 +55,16 @@ const state = computed(() => ({
options: {
colors: currentSeries.value.map((series, i) => nameToColor(series.name)),
},
series: currentSeries.value
series: isGroup.value ? currentSeries.value : currentSeries.value.map(item => {
console.log(item);
return item;
})
}));

const labels =computed(() => {
return currentSeries.value[0].labels.map(formatMonth)
})

const hasHiddenValues = inject('hasHiddenValues', ref(false))

</script>
Expand Down Expand Up @@ -84,7 +94,7 @@ const hasHiddenValues = inject('hasHiddenValues', ref(false))
<LogerChart
label="name"
:type="type"
:labels="currentSeries[0].labels.map(formatMonth)"
:labels="labels"
:options="state.options"
:series="state.series"
:has-hidden-values="hasHiddenValues"
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Components/organisms/DonutChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const chartData = computed(() => {
labels: series.value.map((item) => item[props.label]),
datasets: [
{
data: series.value.map((item) => item[props.value]),
data: series.value.map((item) => item[props.value]).sort(),
backgroundColor: series.value.map((item) => item.color || nameToColor(item[props.label])),
borderJoinStyle: "mittr",
},
Expand Down
7 changes: 7 additions & 0 deletions resources/js/Pages/Trends/CreditCards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,17 @@ const {state: pageState, executeSearchWithDelay } = useServerSearch(serverSearch
<section class="w-8/12">
<ChartTopCreditCard
class="bg-white rounded-md overflow-hidden"
group-name="name"
:data="data.topCategoriesByCard"
/>
</section>
</section>
<section class="w-full mt-4">
<ChartTopCreditCard
class="bg-white rounded-md overflow-hidden"
:data="data.topPayeesByCard"
/>
</section>
</article>
</TrendTemplate>
</AppLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { computed, ref } from 'vue';
import DonutChart from '@/Components/organisms/DonutChart.vue';
import WidgetTitleCard from '@/Components/molecules/WidgetTitleCard.vue';

const props = withDefaults(defineProps<{
withDefaults(defineProps<{
creditCardData: any[];
}>(), {});

Expand Down
Loading