feat: update AnalysisService to include employee advance status filtering and adjust calculations for total amounts; enhance rupiah parsing to handle negative values; refine Analysis.vue for improved display of profit metrics and expenses
This commit is contained in:
parent
fbd5bd7b6d
commit
070e1e52d1
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services\System;
|
namespace App\Services\System;
|
||||||
|
|
||||||
|
use App\Enums\EmployeeAdvanceStatus;
|
||||||
use App\Enums\OrderStatus;
|
use App\Enums\OrderStatus;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
use App\Enums\Role;
|
use App\Enums\Role;
|
||||||
@ -19,6 +20,7 @@
|
|||||||
use App\Models\RawMaterialPrice;
|
use App\Models\RawMaterialPrice;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class AnalysisService
|
class AnalysisService
|
||||||
{
|
{
|
||||||
@ -352,9 +354,10 @@ public function getExpenseSummary(?Carbon $startDate = null, ?Carbon $endDate =
|
|||||||
->first();
|
->first();
|
||||||
|
|
||||||
$employeeAdvance = EmployeeAdvance::query()
|
$employeeAdvance = EmployeeAdvance::query()
|
||||||
|
->whereIn('status', [EmployeeAdvanceStatus::APPROVED, EmployeeAdvanceStatus::PARTIALLY_PAID])
|
||||||
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
||||||
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
||||||
->selectRaw('COALESCE(SUM(amount), 0) as total')
|
->selectRaw('COALESCE(SUM(amount - paid_amount), 0) as total')
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
$purchaseTotal = (int) ($purchase->total ?? 0);
|
$purchaseTotal = (int) ($purchase->total ?? 0);
|
||||||
@ -395,9 +398,10 @@ public function getMonthlyExpense(?Carbon $startDate = null, ?Carbon $endDate =
|
|||||||
->get();
|
->get();
|
||||||
|
|
||||||
$advances = EmployeeAdvance::query()
|
$advances = EmployeeAdvance::query()
|
||||||
|
->whereIn('status', [EmployeeAdvanceStatus::APPROVED, EmployeeAdvanceStatus::PARTIALLY_PAID])
|
||||||
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
||||||
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
||||||
->selectRaw("DATE_FORMAT(employee_advances.created_at, '%Y-%m') as month_key, COALESCE(SUM(amount), 0) as total")
|
->selectRaw("DATE_FORMAT(employee_advances.created_at, '%Y-%m') as month_key, COALESCE(SUM(amount - paid_amount), 0) as total")
|
||||||
->groupBy('month_key')
|
->groupBy('month_key')
|
||||||
->orderBy('month_key')
|
->orderBy('month_key')
|
||||||
->get();
|
->get();
|
||||||
@ -524,9 +528,10 @@ public function getProfitMetrics(?Carbon $startDate = null, ?Carbon $endDate = n
|
|||||||
->sum('amount');
|
->sum('amount');
|
||||||
|
|
||||||
$advanceTotal = EmployeeAdvance::query()
|
$advanceTotal = EmployeeAdvance::query()
|
||||||
|
->whereIn('status', [EmployeeAdvanceStatus::APPROVED, EmployeeAdvanceStatus::PARTIALLY_PAID])
|
||||||
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate]))
|
||||||
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
->when(! $isSuper, fn ($q) => $q->where('employee_id', $user->employee?->id))
|
||||||
->sum('amount');
|
->sum(DB::raw('amount - paid_amount'));
|
||||||
|
|
||||||
$totalExpenses = (int) $purchaseTotal + (int) $expenseTotal + (int) $advanceTotal;
|
$totalExpenses = (int) $purchaseTotal + (int) $expenseTotal + (int) $advanceTotal;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
export function parseRupiah(value: string | number): string {
|
export function parseRupiah(value: string | number): string {
|
||||||
return String(value).replace(/\D/g, '');
|
const str = String(value);
|
||||||
|
const isNegative = str.startsWith('-') || (typeof value === 'number' && value < 0);
|
||||||
|
|
||||||
|
return isNegative ? '-' + str.replace(/[^0-9]/g, '') : str.replace(/[^0-9]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatRupiah(value: string | number): string {
|
export function formatRupiah(value: string | number): string {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, router } from '@inertiajs/vue3';
|
import { Head, router } from '@inertiajs/vue3';
|
||||||
import { Banknote, Package, Percent, ShoppingCart, TrendingUp, UserCheck } from '@lucide/vue';
|
import { Banknote, Package, ShoppingCart, TrendingUp, UserCheck } from '@lucide/vue';
|
||||||
import { GroupedBar } from '@unovis/ts';
|
import { GroupedBar } from '@unovis/ts';
|
||||||
import { VisAxis, VisGroupedBar, VisTooltip, VisXYContainer } from '@unovis/vue';
|
import { VisAxis, VisGroupedBar, VisTooltip, VisXYContainer } from '@unovis/vue';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
@ -716,7 +716,7 @@ watch([startDate, endDate], () => {
|
|||||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
<StatCard v-if="can('analysis.profit_orders')" title="Total Order" :icon="ShoppingCart"
|
<StatCard v-if="can('analysis.profit_orders')" title="Total Order" :icon="ShoppingCart"
|
||||||
main-label="Pesanan Selesai" :main-value="profitMetrics.total_orders.toLocaleString('id-ID')"
|
main-label="Pesanan Selesai" :main-value="profitMetrics.total_orders.toLocaleString('id-ID')"
|
||||||
:sub-label="'AOV: Rp' + formatRupiah(profitMetrics.aov)" :items="[
|
:items="[
|
||||||
{
|
{
|
||||||
label: 'Produk Terjual',
|
label: 'Produk Terjual',
|
||||||
value: profitMetrics.total_products_sold.toLocaleString('id-ID'),
|
value: profitMetrics.total_products_sold.toLocaleString('id-ID'),
|
||||||
@ -725,33 +725,27 @@ watch([startDate, endDate], () => {
|
|||||||
label: 'Item/Transaksi',
|
label: 'Item/Transaksi',
|
||||||
value: profitMetrics.items_per_transaction,
|
value: profitMetrics.items_per_transaction,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'AOV',
|
||||||
|
value: 'Rp' + formatRupiah(profitMetrics.aov),
|
||||||
|
},
|
||||||
]" />
|
]" />
|
||||||
|
|
||||||
<StatCard v-if="can('analysis.profit_gross') || can('analysis.profit_hpp')" title="Laba Kotor"
|
<StatCard v-if="can('analysis.profit_gross') || can('analysis.profit_hpp')" title="Laba Kotor"
|
||||||
:icon="TrendingUp" main-label="Gross Profit"
|
:icon="TrendingUp" main-label="Laba Kotor"
|
||||||
:main-value="'Rp' + formatRupiah(profitMetrics.laba_kotor)"
|
:main-value="'Rp' + formatRupiah(profitMetrics.laba_kotor)" :items="[
|
||||||
:sub-label="profitMetrics.laba_kotor >= 0 ? 'Positif' : 'Negatif'" :items="[
|
|
||||||
{
|
{
|
||||||
label: 'Revenue',
|
label: 'Pendapatan',
|
||||||
value: 'Rp' + formatRupiah(revenueSummary.total_revenue),
|
value: 'Rp' + formatRupiah(revenueSummary.total_revenue),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Laba Bersih',
|
label: 'Pengeluaran',
|
||||||
value: 'Rp' + formatRupiah(profitMetrics.laba_bersih),
|
|
||||||
},
|
|
||||||
]" />
|
|
||||||
|
|
||||||
<StatCard v-if="can('analysis.profit_margin')" title="Profit Margin" :icon="Percent" main-label="Margin"
|
|
||||||
:main-value="profitMetrics.profit_margin + '%'"
|
|
||||||
:sub-label="'Laba Bersih: Rp' + formatRupiah(profitMetrics.laba_bersih)" :items="[
|
|
||||||
{
|
|
||||||
label: 'Laba Kotor',
|
|
||||||
value: 'Rp' + formatRupiah(profitMetrics.laba_kotor),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Total Pengeluaran',
|
|
||||||
value: 'Rp' + formatRupiah(expenseSummary.total),
|
value: 'Rp' + formatRupiah(expenseSummary.total),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Laba Bersih',
|
||||||
|
value: 'Rp' + formatRupiah(profitMetrics.laba_bersih) + ' (' + profitMetrics.profit_margin + '%)',
|
||||||
|
},
|
||||||
]" />
|
]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user