diff --git a/app/Http/Controllers/Admin/AnalysisController.php b/app/Http/Controllers/Admin/AnalysisController.php index f576168..5d85fbc 100644 --- a/app/Http/Controllers/Admin/AnalysisController.php +++ b/app/Http/Controllers/Admin/AnalysisController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use App\Services\System\DashboardService; +use App\Services\System\AnalysisService; use Carbon\Carbon; use Illuminate\Http\Request; use Inertia\Inertia; @@ -12,7 +12,7 @@ class AnalysisController extends Controller { public function __construct( - private readonly DashboardService $dashboardService, + private readonly AnalysisService $analysisService, ) {} public function index(Request $request): Response @@ -25,18 +25,19 @@ public function index(Request $request): Response 'start_date' => $request->query('start_date', ''), 'end_date' => $request->query('end_date', ''), ], - 'rawMaterialStock' => $this->dashboardService->getRawMaterialStock(), - 'productStock' => $this->dashboardService->getProductStock(), - 'kasbonSummary' => $this->dashboardService->getKasbonSummary($startDate, $endDate), - 'leaveRequestSummary' => $this->dashboardService->getLeaveRequestSummary($startDate, $endDate), - 'lowStockProducts' => $this->dashboardService->getLowStockProducts(), - 'lowStockMaterials' => $this->dashboardService->getLowStockMaterials(), - 'attendanceToday' => $this->dashboardService->getAttendanceToday($startDate, $endDate), - 'cashAccounts' => $this->dashboardService->getCashAccounts(), - 'cashSummary' => $this->dashboardService->getCashSummary($startDate, $endDate), - 'purchaseSummary' => $this->dashboardService->getPurchaseSummary($startDate, $endDate), - 'monthlyExpenses' => $this->dashboardService->getMonthlyExpenses($startDate, $endDate), - 'revenueSummary' => $this->dashboardService->getRevenueSummary($startDate, $endDate), + 'attendance' => $this->analysisService->getAttendance(), + 'cashOverview' => $this->analysisService->getCashOverview(), + 'rawMaterialStock' => $this->analysisService->getRawMaterialStock(), + 'productStock' => $this->analysisService->getProductStock(), + 'revenueSummary' => $this->analysisService->getRevenueSummary($startDate, $endDate), + 'monthlyRevenue' => $this->analysisService->getMonthlyRevenue($startDate, $endDate), + 'expenseSummary' => $this->analysisService->getExpenseSummary($startDate, $endDate), + 'monthlyExpense' => $this->analysisService->getMonthlyExpense($startDate, $endDate), + 'busyHours' => $this->analysisService->getBusyHours($startDate, $endDate), + 'profitMetrics' => $this->analysisService->getProfitMetrics($startDate, $endDate), + 'topSuppliers' => $this->analysisService->getTopSuppliers($startDate, $endDate), + 'topCustomers' => $this->analysisService->getTopCustomers($startDate, $endDate), + 'topProducts' => $this->analysisService->getTopProducts($startDate, $endDate), ]); } } diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php index a99c3aa..f0901c8 100644 --- a/app/Http/Controllers/Admin/DashboardController.php +++ b/app/Http/Controllers/Admin/DashboardController.php @@ -21,10 +21,6 @@ public function index(): Response 'revenueSummary' => $this->dashboardService->getRevenueSummary(), 'expenseSummary' => $this->dashboardService->getExpenseSummary(), - 'topSuppliers' => $this->dashboardService->getTopSuppliers(), - 'topCustomers' => $this->dashboardService->getTopCustomers(), - 'topProducts' => $this->dashboardService->getTopProducts(), - 'orderStats' => $this->dashboardService->getOrderStats(), ]); } diff --git a/app/Services/System/AnalysisService.php b/app/Services/System/AnalysisService.php new file mode 100644 index 0000000..4b00618 --- /dev/null +++ b/app/Services/System/AnalysisService.php @@ -0,0 +1,466 @@ +count(); + $today = Carbon::today(); + + $present = Attendance::query() + ->where('attendance_date', $today) + ->distinct('employee_id') + ->count('employee_id'); + + $onLeave = LeaveRequest::query() + ->approved() + ->where('start_date', '<=', $today) + ->where('end_date', '>=', $today) + ->distinct('employee_id') + ->count('employee_id'); + + $absent = max(0, $totalEmployees - $present - $onLeave); + + return [ + 'total_employees' => $totalEmployees, + 'percentage' => $totalEmployees > 0 ? round($present / $totalEmployees * 100) : 0, + 'present' => $present, + 'absent' => $absent, + 'on_leave' => $onLeave, + ]; + } + + public function getCashOverview(): array + { + $totalBalance = CashAccount::query()->sum('balance'); + + $summary = CashTransaction::query() + ->whereDate('created_at', Carbon::today()) + ->selectRaw(" + COUNT(*) as total_transactions, + COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as total_deposit, + COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as total_withdrawal + ") + ->first(); + + return [ + 'total_balance' => (int) $totalBalance, + 'total_transactions' => (int) ($summary->total_transactions ?? 0), + 'total_deposit' => (int) ($summary->total_deposit ?? 0), + 'total_withdrawal' => (int) ($summary->total_withdrawal ?? 0), + ]; + } + + public function getTopSuppliers(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + return Purchase::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('purchases.created_at', [$startDate, $endDate])) + ->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id') + ->selectRaw('suppliers.name, SUM(purchases.total) as total_amount, COUNT(purchases.id) as purchase_count') + ->groupBy('suppliers.id', 'suppliers.name') + ->orderByDesc('total_amount') + ->limit(5) + ->get() + ->map(fn ($item) => [ + 'name' => $item->name, + 'total_amount' => (int) $item->total_amount, + 'purchase_count' => (int) $item->purchase_count, + ]) + ->toArray(); + } + + public function getTopCustomers(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + return Order::query() + ->completed() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->join('customers', 'orders.customer_id', '=', 'customers.id') + ->selectRaw('customers.name, SUM(orders.total_amount) as total_amount, COUNT(orders.id) as order_count') + ->groupBy('customers.id', 'customers.name') + ->orderByDesc('total_amount') + ->limit(5) + ->get() + ->map(fn ($item) => [ + 'name' => $item->name, + 'total_amount' => (int) $item->total_amount, + 'order_count' => (int) $item->order_count, + ]) + ->toArray(); + } + + public function getRevenueSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $revenueSummary = Order::query() + ->completed() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->selectRaw('SUM(total_amount) as total_revenue, SUM(discount) as total_discount, SUM(shipping_cost) as total_shipping, COUNT(*) as total_orders, AVG(total_amount) as avg_order') + ->first(); + + $totalMarketplaceFees = Order::query() + ->completed() + ->whereNotNull('marketplace_settings_snapshot') + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->get() + ->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0)); + + return [ + 'total_revenue' => (int) ($revenueSummary->total_revenue ?? 0), + 'total_discount' => (int) ($revenueSummary->total_discount ?? 0), + 'total_marketplace_fees' => $totalMarketplaceFees, + 'total_potongan' => (int) ($revenueSummary->total_discount ?? 0) + $totalMarketplaceFees, + 'total_shipping' => (int) ($revenueSummary->total_shipping ?? 0), + 'total_orders' => (int) ($revenueSummary->total_orders ?? 0), + 'avg_order' => (int) ($revenueSummary->avg_order ?? 0), + ]; + } + + public function getMonthlyRevenue(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $query = Order::query()->completed(); + $feeQuery = Order::query()->completed()->whereNotNull('marketplace_settings_snapshot'); + + if ($startDate && $endDate) { + $query->whereBetween('orders.created_at', [$startDate, $endDate]); + $feeQuery->whereBetween('orders.created_at', [$startDate, $endDate]); + } + + $monthlyData = $query + ->selectRaw(" + DATE_FORMAT(orders.created_at, '%Y-%m') as month_key, + SUM(total_amount) as total_revenue, + SUM(discount) as total_discount, + SUM(shipping_cost) as total_shipping + ") + ->groupBy('month_key') + ->orderBy('month_key') + ->get(); + + $monthlyFees = $feeQuery + ->selectRaw("DATE_FORMAT(orders.created_at, '%Y-%m') as month_key") + ->get() + ->groupBy('month_key') + ->map(fn ($orders) => $orders->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0))); + + if ($monthlyData->isEmpty()) { + return []; + } + + $start = $startDate ?? Carbon::parse($monthlyData->first()->month_key.'-01'); + $end = $endDate ?? Carbon::parse($monthlyData->last()->month_key.'-01')->endOfMonth(); + + $result = []; + $current = $start->copy()->startOfMonth(); + while ($current->lte($end)) { + $key = $current->format('Y-m'); + $monthLabel = $current->locale('id')->translatedFormat('M Y'); + + $revenue = $monthlyData->firstWhere('month_key', $key); + $fees = $monthlyFees->get($key, 0); + $discount = (int) ($revenue->total_discount ?? 0); + $potongan = $discount + $fees; + + $result[] = [ + 'month' => $monthLabel, + 'total' => (int) ($revenue->total_revenue ?? 0), + 'net' => (int) ($revenue->total_revenue ?? 0) - $potongan, + 'potongan' => $potongan, + 'ongkir' => (int) ($revenue->total_shipping ?? 0), + ]; + + $current->addMonth(); + } + + return $result; + } + + public function getExpenseSummary(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $purchase = Purchase::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('purchases.created_at', [$startDate, $endDate])) + ->selectRaw('COALESCE(SUM(total), 0) as total') + ->first(); + + $expenses = Expense::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('expenses.created_at', [$startDate, $endDate])) + ->selectRaw('COALESCE(SUM(amount), 0) as total') + ->first(); + + $employeeAdvance = EmployeeAdvance::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate])) + ->selectRaw('COALESCE(SUM(amount), 0) as total') + ->first(); + + $purchaseTotal = (int) ($purchase->total ?? 0); + $expenseTotal = (int) ($expenses->total ?? 0); + $advanceTotal = (int) ($employeeAdvance->total ?? 0); + + return [ + 'total' => $purchaseTotal + $expenseTotal + $advanceTotal, + 'purchase_total' => $purchaseTotal, + 'expense_total' => $expenseTotal, + 'advance_total' => $advanceTotal, + ]; + } + + public function getMonthlyExpense(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $purchases = Purchase::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('purchases.created_at', [$startDate, $endDate])) + ->selectRaw("DATE_FORMAT(purchases.created_at, '%Y-%m') as month_key, COALESCE(SUM(total), 0) as total") + ->groupBy('month_key') + ->orderBy('month_key') + ->get(); + + $expenses = Expense::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('expenses.created_at', [$startDate, $endDate])) + ->selectRaw("DATE_FORMAT(expenses.created_at, '%Y-%m') as month_key, COALESCE(SUM(amount), 0) as total") + ->groupBy('month_key') + ->orderBy('month_key') + ->get(); + + $advances = EmployeeAdvance::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate])) + ->selectRaw("DATE_FORMAT(employee_advances.created_at, '%Y-%m') as month_key, COALESCE(SUM(amount), 0) as total") + ->groupBy('month_key') + ->orderBy('month_key') + ->get(); + + $allMonths = collect() + ->merge($purchases->pluck('month_key')) + ->merge($expenses->pluck('month_key')) + ->merge($advances->pluck('month_key')) + ->unique() + ->sort() + ->values(); + + if ($allMonths->isEmpty()) { + return []; + } + + $start = $startDate ?? Carbon::parse($allMonths->first().'-01'); + $end = $endDate ?? Carbon::parse($allMonths->last().'-01')->endOfMonth(); + + $result = []; + $current = $start->copy()->startOfMonth(); + while ($current->lte($end)) { + $key = $current->format('Y-m'); + $monthLabel = $current->locale('id')->translatedFormat('M Y'); + + $purchaseAmount = (int) ($purchases->firstWhere('month_key', $key)->total ?? 0); + $expenseAmount = (int) ($expenses->firstWhere('month_key', $key)->total ?? 0); + $advanceAmount = (int) ($advances->firstWhere('month_key', $key)->total ?? 0); + + $result[] = [ + 'month' => $monthLabel, + 'total' => $purchaseAmount + $expenseAmount + $advanceAmount, + 'belanja' => $purchaseAmount, + 'pengeluaran' => $expenseAmount, + 'kasbon' => $advanceAmount, + ]; + + $current->addMonth(); + } + + return $result; + } + + public function getProfitMetrics(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $orderQuery = Order::query()->completed(); + if ($startDate && $endDate) { + $orderQuery->whereBetween('orders.created_at', [$startDate, $endDate]); + } + + $revenueData = (clone $orderQuery) + ->selectRaw(' + COUNT(*) as total_orders, + SUM(total_amount) as total_revenue, + SUM(discount) as total_discount, + SUM(subtotal) as total_subtotal + ') + ->first(); + + $totalRevenue = (int) ($revenueData->total_revenue ?? 0); + $totalDiscount = (int) ($revenueData->total_discount ?? 0); + $totalSubtotal = (int) ($revenueData->total_subtotal ?? 0); + $totalOrders = (int) ($revenueData->total_orders ?? 0); + + $marketplaceFees = (clone $orderQuery) + ->whereNotNull('marketplace_settings_snapshot') + ->get() + ->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0)); + + $itemsData = OrderItem::query() + ->join('orders', 'order_items.order_id', '=', 'orders.id') + ->where('orders.status', OrderStatus::COMPLETED) + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->selectRaw(' + SUM(order_items.quantity) as total_qty, + COUNT(order_items.id) as total_items + ') + ->first(); + + $totalQty = (int) ($itemsData->total_qty ?? 0); + $totalItems = (int) ($itemsData->total_items ?? 0); + + // HPP from cutting_result_prices + $hpp = OrderItem::query() + ->join('orders', 'order_items.order_id', '=', 'orders.id') + ->leftJoin('cutting_result_prices', 'order_items.product_variant_id', '=', 'cutting_result_prices.product_variant_id') + ->where('orders.status', OrderStatus::COMPLETED) + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->selectRaw('COALESCE(SUM(order_items.quantity * cutting_result_prices.cost_per_unit), 0) as total_hpp') + ->value('total_hpp'); + + $totalHpp = (int) ($hpp ?? 0); + + // Expenses + $purchaseTotal = Purchase::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('purchases.created_at', [$startDate, $endDate])) + ->sum('total'); + + $expenseTotal = Expense::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('expenses.created_at', [$startDate, $endDate])) + ->sum('amount'); + + $advanceTotal = EmployeeAdvance::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('employee_advances.created_at', [$startDate, $endDate])) + ->sum('amount'); + + $totalExpenses = (int) $purchaseTotal + (int) $expenseTotal + (int) $advanceTotal; + + $labaKotor = $totalRevenue - $totalHpp - $totalDiscount - $marketplaceFees; + $labaBersih = $labaKotor - $totalExpenses; + $profitMargin = $totalRevenue > 0 ? round(($labaBersih / $totalRevenue) * 100, 1) : 0; + $aov = $totalOrders > 0 ? (int) round($totalRevenue / $totalOrders) : 0; + $itemsPerTransaction = $totalOrders > 0 ? round($totalItems / $totalOrders, 1) : 0; + + return [ + 'total_orders' => $totalOrders, + 'total_products_sold' => $totalQty, + 'hpp' => $totalHpp, + 'laba_kotor' => $labaKotor, + 'laba_bersih' => $labaBersih, + 'profit_margin' => $profitMargin, + 'aov' => $aov, + 'items_per_transaction' => $itemsPerTransaction, + ]; + } + + public function getRawMaterialStock(): array + { + $prices = RawMaterialPrice::query() + ->join('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id') + ->selectRaw(' + raw_materials.unit, + SUM(raw_material_prices.stock) as total_stock, + SUM(raw_material_prices.stock * raw_material_prices.price) as total_value + ') + ->groupBy('raw_materials.unit') + ->get() + ->keyBy('unit'); + + $totalStock = (float) $prices->sum('total_stock'); + $totalValue = (int) $prices->sum('total_value'); + + return [ + 'total_stock' => round($totalStock, 2), + 'total_value' => $totalValue, + 'by_unit' => [ + 'yard' => round((float) ($prices->get('yard')->total_stock ?? 0), 2), + 'meter' => round((float) ($prices->get('meter')->total_stock ?? 0), 2), + 'kilogram' => round((float) ($prices->get('kilogram')->total_stock ?? 0), 2), + ], + ]; + } + + public function getProductStock(): array + { + $variants = ProductVariant::query() + ->join('products', 'product_variants.product_id', '=', 'products.id') + ->selectRaw(' + SUM(product_variants.stock) as total_stock, + SUM(product_variants.reject_stock) as total_reject, + COUNT(product_variants.id) as total_variants, + COUNT(DISTINCT products.id) as total_products + ') + ->first(); + + $totalValue = \DB::table('product_prices') + ->join('product_variants', 'product_prices.variant_id', '=', 'product_variants.id') + ->selectRaw('SUM(product_variants.stock * product_prices.price) as total') + ->value('total'); + + $totalCategories = \DB::table('product_categories') + ->distinct('category_id') + ->count('category_id'); + + return [ + 'total_stock' => (int) ($variants->total_stock ?? 0), + 'total_reject' => (int) ($variants->total_reject ?? 0), + 'total_value' => (int) ($totalValue ?? 0), + 'total_products' => (int) ($variants->total_products ?? 0), + 'total_variants' => (int) ($variants->total_variants ?? 0), + 'total_categories' => (int) $totalCategories, + ]; + } + + public function getBusyHours(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + $hourlyData = Order::query() + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->selectRaw('HOUR(orders.created_at) as hour, COUNT(*) as order_count') + ->groupBy('hour') + ->orderBy('hour') + ->get() + ->keyBy('hour'); + + $result = []; + for ($h = 0; $h < 24; $h++) { + $result[] = [ + 'hour' => str_pad($h, 2, '0', STR_PAD_LEFT).':00', + 'orders' => (int) ($hourlyData->get($h)->order_count ?? 0), + ]; + } + + return $result; + } + + public function getTopProducts(?Carbon $startDate = null, ?Carbon $endDate = null): array + { + return OrderItem::query() + ->join('orders', 'order_items.order_id', '=', 'orders.id') + ->join('product_variants', 'order_items.product_variant_id', '=', 'product_variants.id') + ->join('products', 'product_variants.product_id', '=', 'products.id') + ->where('orders.status', OrderStatus::COMPLETED) + ->when($startDate && $endDate, fn ($q) => $q->whereBetween('orders.created_at', [$startDate, $endDate])) + ->selectRaw("CONCAT(products.name, ' - ', product_variants.name) as full_name, SUM(order_items.quantity) as total_qty, SUM(order_items.subtotal) as total_revenue") + ->groupBy('order_items.product_variant_id', 'products.name', 'product_variants.name') + ->orderByDesc('total_qty') + ->limit(5) + ->get() + ->map(fn ($item) => [ + 'name' => $item->full_name, + 'total_qty' => (int) $item->total_qty, + 'total_revenue' => (int) $item->total_revenue, + ]) + ->toArray(); + } +} diff --git a/app/Services/System/DashboardService.php b/app/Services/System/DashboardService.php index c41dc7e..c0999c1 100644 --- a/app/Services/System/DashboardService.php +++ b/app/Services/System/DashboardService.php @@ -13,7 +13,6 @@ use App\Models\Expense; use App\Models\LeaveRequest; use App\Models\Order; -use App\Models\OrderItem; use App\Models\Purchase; use Carbon\Carbon; @@ -125,64 +124,6 @@ public function getExpenseSummary(): array ]; } - public function getTopSuppliers(): array - { - return Purchase::query() - ->whereDate('purchases.created_at', Carbon::today()) - ->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id') - ->selectRaw('suppliers.name, SUM(purchases.total) as total_amount, COUNT(purchases.id) as purchase_count') - ->groupBy('suppliers.id', 'suppliers.name') - ->orderByDesc('total_amount') - ->limit(5) - ->get() - ->map(fn ($item) => [ - 'name' => $item->name, - 'total_amount' => (int) $item->total_amount, - 'purchase_count' => (int) $item->purchase_count, - ]) - ->toArray(); - } - - public function getTopCustomers(): array - { - return Order::query() - ->completed() - ->whereDate('orders.created_at', Carbon::today()) - ->join('customers', 'orders.customer_id', '=', 'customers.id') - ->selectRaw('customers.name, SUM(orders.total_amount) as total_amount, COUNT(orders.id) as order_count') - ->groupBy('customers.id', 'customers.name') - ->orderByDesc('total_amount') - ->limit(5) - ->get() - ->map(fn ($item) => [ - 'name' => $item->name, - 'total_amount' => (int) $item->total_amount, - 'order_count' => (int) $item->order_count, - ]) - ->toArray(); - } - - public function getTopProducts(): array - { - return OrderItem::query() - ->join('orders', 'order_items.order_id', '=', 'orders.id') - ->join('product_variants', 'order_items.product_variant_id', '=', 'product_variants.id') - ->join('products', 'product_variants.product_id', '=', 'products.id') - ->where('orders.status', OrderStatus::COMPLETED) - ->whereDate('orders.created_at', Carbon::today()) - ->selectRaw("CONCAT(products.name, ' - ', product_variants.name) as full_name, SUM(order_items.quantity) as total_qty, SUM(order_items.subtotal) as total_revenue") - ->groupBy('order_items.product_variant_id', 'products.name', 'product_variants.name') - ->orderByDesc('total_qty') - ->limit(5) - ->get() - ->map(fn ($item) => [ - 'name' => $item->full_name, - 'total_qty' => (int) $item->total_qty, - 'total_revenue' => (int) $item->total_revenue, - ]) - ->toArray(); - } - public function getOrderStats(): array { $byChannel = Order::query() diff --git a/resources/js/pages/admin/Analysis.vue b/resources/js/pages/admin/Analysis.vue index f3bbb87..5680ffd 100644 --- a/resources/js/pages/admin/Analysis.vue +++ b/resources/js/pages/admin/Analysis.vue @@ -1,7 +1,9 @@