From 9e60a1cf3956d854be65794d936301a50b5e6185 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Fri, 7 Aug 2026 09:04:16 +0700 Subject: [PATCH] feat: add tiktok and shopee order IDs to transaction model and UI components --- .../Admin/Manage/TransactionService.php | 56 +++++++++---------- .../admin/manage/transaction/columns.tsx | 2 + .../pages/admin/manage/transaction/edit.tsx | 2 +- .../manage/transaction/transaction-card.tsx | 53 ++++++++++-------- 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/app/Services/Admin/Manage/TransactionService.php b/app/Services/Admin/Manage/TransactionService.php index cc45316..7f27b96 100644 --- a/app/Services/Admin/Manage/TransactionService.php +++ b/app/Services/Admin/Manage/TransactionService.php @@ -41,7 +41,7 @@ public function __construct( public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator { $paginator = Order::query() - ->select(['id', 'created_by_id', 'customer_id', 'marketing_id', 'order_number', 'channel', 'price_type', 'status', 'payment_type', 'subtotal', 'discount', 'nego_price', 'total_amount', 'cogs', 'notes', 'created_at']) + ->select(['id', 'created_by_id', 'customer_id', 'marketing_id', 'order_number', 'channel', 'price_type', 'status', 'payment_type', 'tiktok_order_id', 'shopee_order_id', 'subtotal', 'discount', 'nego_price', 'total_amount', 'cogs', 'notes', 'created_at']) ->with([ 'createdBy:id', 'createdBy.userProfile:id,user_id,full_name', @@ -53,18 +53,18 @@ public function paginated(int $perPage = 25, string $search = '', string $sort = 'orderItems.productVariant.product:id,name', ]) ->when($search, function ($q) use ($search) { - $q->whereHas('orderItems.productVariant.product', fn ($sq) => $sq->where('name', 'like', "%{$search}%")) + $q->whereHas('orderItems.productVariant.product', fn($sq) => $sq->where('name', 'like', "%{$search}%")) ->orWhere('order_number', 'like', "%{$search}%") ->orWhere('notes', 'like', "%{$search}%"); }) - ->when($filters['status'] ?? null, fn ($q, $status) => $q->where('status', $status)) - ->when($filters['channel'] ?? null, fn ($q, $channel) => $q->where('channel', $channel)) - ->when($filters['payment_type'] ?? null, fn ($q, $paymentType) => $q->where('payment_type', $paymentType)) - ->when($filters['customer_id'] ?? null, fn ($q, $customerId) => $q->where('customer_id', $customerId)) - ->when($filters['marketing_id'] ?? null, fn ($q, $marketingId) => $q->where('marketing_id', $marketingId)) - ->when($filters['created_by_id'] ?? null, fn ($q, $createdById) => $q->where('created_by_id', $createdById)) - ->when($filters['date_from'] ?? null, fn ($q, $dateFrom) => $q->whereDate('created_at', '>=', $dateFrom)) - ->when($filters['date_to'] ?? null, fn ($q, $dateTo) => $q->whereDate('created_at', '<=', $dateTo)) + ->when($filters['status'] ?? null, fn($q, $status) => $q->where('status', $status)) + ->when($filters['channel'] ?? null, fn($q, $channel) => $q->where('channel', $channel)) + ->when($filters['payment_type'] ?? null, fn($q, $paymentType) => $q->where('payment_type', $paymentType)) + ->when($filters['customer_id'] ?? null, fn($q, $customerId) => $q->where('customer_id', $customerId)) + ->when($filters['marketing_id'] ?? null, fn($q, $marketingId) => $q->where('marketing_id', $marketingId)) + ->when($filters['created_by_id'] ?? null, fn($q, $createdById) => $q->where('created_by_id', $createdById)) + ->when($filters['date_from'] ?? null, fn($q, $dateFrom) => $q->whereDate('created_at', '>=', $dateFrom)) + ->when($filters['date_to'] ?? null, fn($q, $dateTo) => $q->whereDate('created_at', '<=', $dateTo)) ->orderBy($sort, $direction) ->paginate($perPage); @@ -99,14 +99,14 @@ public function getSummary(array $filters = []): array ->selectRaw('COALESCE(SUM(subtotal) - SUM(COALESCE(nego_price, subtotal)), 0) as total_discount') ->selectRaw('COALESCE(SUM(total_amount), 0) as total_amount') ->selectRaw('COALESCE(SUM(cogs), 0) as total_cogs') - ->when($filters['status'] ?? null, fn ($q, $status) => $q->where('status', $status)) - ->when($filters['channel'] ?? null, fn ($q, $channel) => $q->where('channel', $channel)) - ->when($filters['payment_type'] ?? null, fn ($q, $paymentType) => $q->where('payment_type', $paymentType)) - ->when($filters['customer_id'] ?? null, fn ($q, $customerId) => $q->where('customer_id', $customerId)) - ->when($filters['marketing_id'] ?? null, fn ($q, $marketingId) => $q->where('marketing_id', $marketingId)) - ->when($filters['created_by_id'] ?? null, fn ($q, $createdById) => $q->where('created_by_id', $createdById)) - ->when($filters['date_from'] ?? null, fn ($q, $dateFrom) => $q->whereDate('created_at', '>=', $dateFrom)) - ->when($filters['date_to'] ?? null, fn ($q, $dateTo) => $q->whereDate('created_at', '<=', $dateTo)) + ->when($filters['status'] ?? null, fn($q, $status) => $q->where('status', $status)) + ->when($filters['channel'] ?? null, fn($q, $channel) => $q->where('channel', $channel)) + ->when($filters['payment_type'] ?? null, fn($q, $paymentType) => $q->where('payment_type', $paymentType)) + ->when($filters['customer_id'] ?? null, fn($q, $customerId) => $q->where('customer_id', $customerId)) + ->when($filters['marketing_id'] ?? null, fn($q, $marketingId) => $q->where('marketing_id', $marketingId)) + ->when($filters['created_by_id'] ?? null, fn($q, $createdById) => $q->where('created_by_id', $createdById)) + ->when($filters['date_from'] ?? null, fn($q, $dateFrom) => $q->whereDate('created_at', '>=', $dateFrom)) + ->when($filters['date_to'] ?? null, fn($q, $dateTo) => $q->whereDate('created_at', '<=', $dateTo)) ->first(); return [ @@ -134,9 +134,9 @@ public function getFilterOptions(): array ->with('userProfile:id,user_id,full_name') ->orderBy('id') ->get() - ->filter(fn (User $user) => $user->userProfile?->full_name) + ->filter(fn(User $user) => $user->userProfile?->full_name) ->values() - ->map(fn (User $user) => [ + ->map(fn(User $user) => [ 'id' => $user->id, 'name' => $user->userProfile->full_name, ]), @@ -162,7 +162,7 @@ public function getForCreate(): array ? $this->s3Service->getTemporaryUrl($media->file_name) : null; - $prices = $variant->productPrices->mapWithKeys(fn ($p) => [$p->type->value => $p->price]); + $prices = $variant->productPrices->mapWithKeys(fn($p) => [$p->type->value => $p->price]); $variant->prices = $prices; }); }), @@ -176,11 +176,11 @@ public function getForCreate(): array ->with('userProfile:id,user_id,full_name') ->orderBy('id') ->get() - ->filter(fn (User $user) => $user->userProfile?->full_name) + ->filter(fn(User $user) => $user->userProfile?->full_name) ->values(), 'channelOptions' => OrderChannel::toSelect(), 'paymentTypeOptions' => PaymentType::toSelect(), - 'priceTypeOptions' => PriceType::toSelect()->filter(fn ($p) => $p['value'] !== PriceType::CAPITAL->value)->values(), + 'priceTypeOptions' => PriceType::toSelect()->filter(fn($p) => $p['value'] !== PriceType::CAPITAL->value)->values(), ]; } @@ -210,7 +210,7 @@ public function getForEdit(Order $order): array 'photo_url' => $media ? $this->s3Service->getTemporaryUrl($media->file_name) : null, - 'items' => $order->orderItems->map(fn (OrderItem $item) => [ + 'items' => $order->orderItems->map(fn(OrderItem $item) => [ 'id' => $item->id, 'product_variant_id' => $item->product_variant_id, 'quantity' => $item->quantity, @@ -270,7 +270,7 @@ public function create(array $data): Order NotificationService::notify( roles: ['Owner', 'Developer', 'Admin Toko'], title: 'Transaksi Baru', - body: 'Transaksi '.$order->order_number.' sebesar Rp '.number_format($totalAmount, 0, ',', '.').' berhasil dicatat oleh '.auth()->user()->full_name.'.', + body: 'Transaksi ' . $order->order_number . ' sebesar Rp ' . number_format($totalAmount, 0, ',', '.') . ' berhasil dicatat oleh ' . auth()->user()->full_name . '.', url: route('admin.manage.transactions.index'), ); @@ -379,14 +379,14 @@ private function buildItemRows(array $items, string $stockType, string $priceTyp $prices = $variants->mapWithKeys(function (ProductVariant $variant) use ($resolvedPriceType) { $price = $variant->productPrices - ->first(fn ($p) => $p->type === $resolvedPriceType); + ->first(fn($p) => $p->type === $resolvedPriceType); return [$variant->id => $price?->price ?? 0]; }); $capitalPrices = $variants->mapWithKeys(function (ProductVariant $variant) { $price = $variant->productPrices - ->first(fn ($p) => $p->type === PriceType::CAPITAL); + ->first(fn($p) => $p->type === PriceType::CAPITAL); return [$variant->id => $price?->price ?? 0]; }); @@ -429,6 +429,6 @@ private function generateOrderNumber(): string $sequence = 1; } - return $prefix.$date.str_pad($sequence, 4, '0', STR_PAD_LEFT); + return $prefix . $date . str_pad($sequence, 4, '0', STR_PAD_LEFT); } } diff --git a/resources/js/pages/admin/manage/transaction/columns.tsx b/resources/js/pages/admin/manage/transaction/columns.tsx index a77c51e..fc4ad15 100644 --- a/resources/js/pages/admin/manage/transaction/columns.tsx +++ b/resources/js/pages/admin/manage/transaction/columns.tsx @@ -40,6 +40,8 @@ export type Transaction = { payment_type_label: string; channel_label: string; price_type_label: string; + tiktok_order_id: string | null; + shopee_order_id: string | null; profit: number; cogs: number; subtotal: number; diff --git a/resources/js/pages/admin/manage/transaction/edit.tsx b/resources/js/pages/admin/manage/transaction/edit.tsx index bdbebfb..17cf85d 100644 --- a/resources/js/pages/admin/manage/transaction/edit.tsx +++ b/resources/js/pages/admin/manage/transaction/edit.tsx @@ -16,6 +16,7 @@ import { ComboboxItem, ComboboxList, } from '@/components/ui/combobox'; +import { FieldDescription } from '@/components/ui/field'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { @@ -38,7 +39,6 @@ import { formatNumber } from '@/lib/format'; import { getTemporaryUrl } from '@/lib/upload'; import { formatCurrency } from '@/lib/utils'; import { index as transactionIndex, update } from '@/routes/admin/manage/transactions'; -import { FieldDescription } from '@base-ui/react'; import { Form, Head, Link } from '@inertiajs/react'; import { ArrowLeft, Minus, Plus, ShoppingCart, Trash2 } from 'lucide-react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; diff --git a/resources/js/pages/admin/manage/transaction/transaction-card.tsx b/resources/js/pages/admin/manage/transaction/transaction-card.tsx index 0fa6e6d..786f2fa 100644 --- a/resources/js/pages/admin/manage/transaction/transaction-card.tsx +++ b/resources/js/pages/admin/manage/transaction/transaction-card.tsx @@ -51,7 +51,7 @@ export function TransactionCardRow({ ); const statusBadgeClass = STATUS_BADGE_CLASSES[transaction.status] ?? STATUS_BADGE_CLASSES.pending; - +console.log('transaction', transaction); return ( @@ -84,6 +84,11 @@ export function TransactionCardRow({ {transaction.payment_type_label} + {transaction.tiktok_order_id || transaction.shopee_order_id ? ( + + {transaction.tiktok_order_id || transaction.shopee_order_id} + + ) : null}
@@ -188,35 +193,35 @@ export function TransactionCardRow({ actions={[ ...(transaction.status === 'pending' && can('orders.update') ? [ - { - label: 'Kirim', - icon: , - onClick: () => onUpdateStatus(transaction, 'processing'), - }, - ] + { + label: 'Kirim', + icon: , + onClick: () => onUpdateStatus(transaction, 'processing'), + }, + ] : []), ...((transaction.status === 'pending' || transaction.status === 'processing') && can('orders.update') ? [ - { - label: 'Selesai', - icon: , - onClick: () => onUpdateStatus(transaction, 'completed'), - }, - { - label: 'Dibatalkan', - icon: , - onClick: () => onUpdateStatus(transaction, 'cancelled'), - }, - ] + { + label: 'Selesai', + icon: , + onClick: () => onUpdateStatus(transaction, 'completed'), + }, + { + label: 'Dibatalkan', + icon: , + onClick: () => onUpdateStatus(transaction, 'cancelled'), + }, + ] : []), ...(transaction.status === 'completed' && can('orders.update') ? [ - { - label: 'Refund', - icon: , - onClick: () => onUpdateStatus(transaction, 'refunded'), - }, - ] + { + label: 'Refund', + icon: , + onClick: () => onUpdateStatus(transaction, 'refunded'), + }, + ] : []), { label: 'Edit',