update
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -53,28 +53,44 @@ class DashboardController extends Controller
|
||||
return round((($current - $previous) / $previous) * 100, 2);
|
||||
}
|
||||
|
||||
public function stats(): JsonResponse
|
||||
/**
|
||||
* @return array{0: Carbon, 1: Carbon, 2: Carbon, 3: Carbon}
|
||||
*/
|
||||
private function periodFromRequest(Request $request): array
|
||||
{
|
||||
$request->validate([
|
||||
'from' => ['nullable', 'date_format:Y-m-d', 'required_with:to'],
|
||||
'to' => ['nullable', 'date_format:Y-m-d', 'required_with:from', 'after_or_equal:from'],
|
||||
]);
|
||||
|
||||
$start = $request->date('from', 'Y-m-d')?->startOfDay() ?? now()->startOfMonth();
|
||||
$end = $request->date('to', 'Y-m-d')?->endOfDay() ?? now();
|
||||
|
||||
$days = (int) $start->diffInDays($end->copy()->startOfDay()) + 1;
|
||||
|
||||
return [$start, $end, $start->copy()->subDays($days), $start->copy()->subSecond()];
|
||||
}
|
||||
|
||||
public function stats(Request $request): JsonResponse
|
||||
{
|
||||
$now = now();
|
||||
$startOfMonth = $now->copy()->startOfMonth();
|
||||
$startOfPrevMonth = $now->copy()->subMonthNoOverflow()->startOfMonth();
|
||||
$endOfPrevMonth = $now->copy()->subMonthNoOverflow()->endOfMonth();
|
||||
[$start, $end, $prevStart, $prevEnd] = $this->periodFromRequest($request);
|
||||
|
||||
// Customers
|
||||
$totalCustomers = Customer::count();
|
||||
$newThisMonth = Customer::where('created_at', '>=', $startOfMonth)->count();
|
||||
$newPrevMonth = Customer::whereBetween('created_at', [$startOfPrevMonth, $endOfPrevMonth])->count();
|
||||
$newInPeriod = Customer::whereBetween('created_at', [$start, $end])->count();
|
||||
$newPrevPeriod = Customer::whereBetween('created_at', [$prevStart, $prevEnd])->count();
|
||||
|
||||
// Deposits (transactions completed, type ∈ DEPOSIT_TYPES)
|
||||
$depositBase = Transaction::whereIn('type', self::DEPOSIT_TYPES)
|
||||
->where('status', TransactionStatus::COMPLETED->value);
|
||||
|
||||
$totalDeposits = (float) (clone $depositBase)->sum('amount');
|
||||
$depositsThisMonth = (float) (clone $depositBase)
|
||||
->where('created_at', '>=', $startOfMonth)
|
||||
$depositsInPeriod = (float) (clone $depositBase)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->sum('amount');
|
||||
$depositsPrevMonth = (float) (clone $depositBase)
|
||||
->whereBetween('created_at', [$startOfPrevMonth, $endOfPrevMonth])
|
||||
$depositsPrevPeriod = (float) (clone $depositBase)
|
||||
->whereBetween('created_at', [$prevStart, $prevEnd])
|
||||
->sum('amount');
|
||||
|
||||
// Số dư ví khách hàng (cột customers.total)
|
||||
@@ -88,29 +104,29 @@ class DashboardController extends Controller
|
||||
->count();
|
||||
|
||||
// Orders
|
||||
$totalOrdersThisMonth = Order::where('created_at', '>=', $startOfMonth)->count();
|
||||
$totalOrdersPrevMonth = Order::whereBetween('created_at', [$startOfPrevMonth, $endOfPrevMonth])->count();
|
||||
$ordersInPeriod = Order::whereBetween('created_at', [$start, $end])->count();
|
||||
$ordersPrevPeriod = Order::whereBetween('created_at', [$prevStart, $prevEnd])->count();
|
||||
$pendingOrders = Order::where('status', OrderStatus::PENDING->value)->count();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
'total_customers' => $totalCustomers,
|
||||
'new_customers_this_month' => $newThisMonth,
|
||||
'new_customers_delta_pct' => $this->deltaPct($newThisMonth, $newPrevMonth),
|
||||
'new_customers_in_period' => $newInPeriod,
|
||||
'new_customers_delta_pct' => $this->deltaPct($newInPeriod, $newPrevPeriod),
|
||||
|
||||
'total_deposits' => $totalDeposits,
|
||||
'deposits_this_month' => $depositsThisMonth,
|
||||
'deposits_delta_pct' => $this->deltaPct($depositsThisMonth, $depositsPrevMonth),
|
||||
'deposits_in_period' => $depositsInPeriod,
|
||||
'deposits_delta_pct' => $this->deltaPct($depositsInPeriod, $depositsPrevPeriod),
|
||||
|
||||
'total_balance' => $totalBalance,
|
||||
|
||||
'total_active_services' => $totalActiveServices,
|
||||
'expiring_services_7d' => $expiring7d,
|
||||
|
||||
'total_orders_this_month' => $totalOrdersThisMonth,
|
||||
'orders_in_period' => $ordersInPeriod,
|
||||
'pending_orders' => $pendingOrders,
|
||||
'orders_delta_pct' => $this->deltaPct($totalOrdersThisMonth, $totalOrdersPrevMonth),
|
||||
'orders_delta_pct' => $this->deltaPct($ordersInPeriod, $ordersPrevPeriod),
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -192,7 +208,7 @@ class DashboardController extends Controller
|
||||
$limit = max(1, min(50, $limit));
|
||||
|
||||
$orders = Order::with([
|
||||
'customer:id,fullname,email',
|
||||
'customer:id,uuid,fullname,email',
|
||||
'orderItems:id,order_id,product_id',
|
||||
'orderItems.product:id,name',
|
||||
'invoice:id,order_id,status',
|
||||
@@ -203,16 +219,18 @@ class DashboardController extends Controller
|
||||
|
||||
$items = $orders->map(function (Order $o) {
|
||||
$firstItem = $o->orderItems->first();
|
||||
$serviceName = $firstItem?->product?->name ?? '—';
|
||||
$product = $firstItem?->product;
|
||||
$invoiceStatus = $o->invoice?->status ?? null;
|
||||
|
||||
return [
|
||||
'id' => $o->id,
|
||||
'code' => $o->order_num,
|
||||
'customer_id' => $o->customer_id,
|
||||
'customer_uuid' => $o->customer?->uuid,
|
||||
'customer_name' => $o->customer->fullname ?? '—',
|
||||
'customer_email' => $o->customer->email ?? '',
|
||||
'service_name' => $serviceName,
|
||||
'product_id' => $product?->id,
|
||||
'service_name' => $product?->name ?? '—',
|
||||
'amount' => (float) $o->total,
|
||||
'payment_status' => $this->paymentStatusFromInvoice($invoiceStatus),
|
||||
'status' => $this->orderStatusLabel((int) $o->status),
|
||||
@@ -271,9 +289,7 @@ class DashboardController extends Controller
|
||||
$limit = (int) $request->integer('limit', 5);
|
||||
$limit = max(1, min(20, $limit));
|
||||
|
||||
$startOfMonth = now()->startOfMonth();
|
||||
$startOfPrevMonth = now()->copy()->subMonthNoOverflow()->startOfMonth();
|
||||
$endOfPrevMonth = now()->copy()->subMonthNoOverflow()->endOfMonth();
|
||||
[$start, $end, $prevStart, $prevEnd] = $this->periodFromRequest($request);
|
||||
|
||||
// Top theo số service đang active của từng product
|
||||
$rows = Service::query()
|
||||
@@ -297,7 +313,7 @@ class DashboardController extends Controller
|
||||
$soldCurrent = DB::table('order_items')
|
||||
->join('orders', 'orders.id', '=', 'order_items.order_id')
|
||||
->whereIn('order_items.product_id', $productIds)
|
||||
->where('orders.created_at', '>=', $startOfMonth)
|
||||
->whereBetween('orders.created_at', [$start, $end])
|
||||
->selectRaw('order_items.product_id, COUNT(*) as sold, SUM(order_items.price * order_items.quantity) as revenue')
|
||||
->groupBy('order_items.product_id')
|
||||
->get()
|
||||
@@ -306,7 +322,7 @@ class DashboardController extends Controller
|
||||
$soldPrev = DB::table('order_items')
|
||||
->join('orders', 'orders.id', '=', 'order_items.order_id')
|
||||
->whereIn('order_items.product_id', $productIds)
|
||||
->whereBetween('orders.created_at', [$startOfPrevMonth, $endOfPrevMonth])
|
||||
->whereBetween('orders.created_at', [$prevStart, $prevEnd])
|
||||
->selectRaw('order_items.product_id, SUM(order_items.price * order_items.quantity) as revenue')
|
||||
->groupBy('order_items.product_id')
|
||||
->get()
|
||||
|
||||
@@ -22,7 +22,11 @@ class StaffOnlineController extends Controller
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$users = User::whereHas('staffOnline')->with('staffOnline')->get();
|
||||
$onlineSince = fn ($q) => $q->where('last_visited', '>=', time() - self::ONLINE_THRESHOLD_SECONDS);
|
||||
|
||||
$users = User::whereHas('staffOnline', $onlineSince)
|
||||
->with(['staffOnline' => $onlineSince])
|
||||
->get();
|
||||
|
||||
$online = $users->map(fn ($user) => [
|
||||
'user_id' => $user->id,
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Services\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Order;
|
||||
use App\Models\Transaction;
|
||||
use App\Repositories\Customer\CustomerRepositoryInterface;
|
||||
use App\Repositories\Invoice\InvoiceRepositoryInterface;
|
||||
use App\Repositories\Order\OrderRepositoryInterface;
|
||||
use App\Repositories\Transaction\TransactionRepositoryInterface;
|
||||
@@ -16,6 +17,7 @@ class CustomerBillingService
|
||||
use ResolvesCustomer;
|
||||
|
||||
public function __construct(
|
||||
private readonly CustomerRepositoryInterface $customerRepository,
|
||||
private readonly InvoiceRepositoryInterface $invoiceRepository,
|
||||
private readonly TransactionRepositoryInterface $transactionRepository,
|
||||
private readonly OrderRepositoryInterface $orderRepository,
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Services\Customer;
|
||||
use App\Http\Resources\Api\Client\ClientResource;
|
||||
use App\Models\Log;
|
||||
use App\Models\User;
|
||||
use App\Repositories\Customer\CustomerRepositoryInterface;
|
||||
use App\Services\Api\Client\ClientAuthService;
|
||||
use App\Services\Customer\Concerns\ResolvesCustomer;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -19,6 +20,7 @@ class CustomerImpersonationService
|
||||
private const TTL_SECONDS = 120;
|
||||
|
||||
public function __construct(
|
||||
private readonly CustomerRepositoryInterface $customerRepository,
|
||||
private readonly ClientAuthService $clientAuthService,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Services\Customer;
|
||||
|
||||
use App\Models\Note;
|
||||
use App\Repositories\Customer\CustomerRepositoryInterface;
|
||||
use App\Services\Customer\Concerns\ResolvesCustomer;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@@ -10,6 +11,10 @@ class CustomerNoteService
|
||||
{
|
||||
use ResolvesCustomer;
|
||||
|
||||
public function __construct(
|
||||
private readonly CustomerRepositoryInterface $customerRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Ghi chú của khách hàng (không gắn với dịch vụ cụ thể).
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Models\Product;
|
||||
use App\Models\Service;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\VirtualMachines;
|
||||
use App\Repositories\Customer\CustomerRepositoryInterface;
|
||||
use App\Repositories\Module\Hosting\HostingRepositoryInterface as ModuleHostingRepositoryInterface;
|
||||
use App\Repositories\Module\Vmware\VmwareRepositoryInterface;
|
||||
use App\Repositories\Service\ServiceRepositoryInterface;
|
||||
@@ -32,6 +33,7 @@ class CustomerServiceProvisioningService
|
||||
use ResolvesCustomer;
|
||||
|
||||
public function __construct(
|
||||
private readonly CustomerRepositoryInterface $customerRepository,
|
||||
private readonly ModuleHostingRepositoryInterface $moduleHostingRepository,
|
||||
private readonly VmwareRepositoryInterface $vmwareRepository,
|
||||
private readonly ServiceRepositoryInterface $serviceRepository,
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\Invoice\InvoiceStatus;
|
||||
use App\Enums\Order\OrderStatus;
|
||||
use App\Enums\TransactionStatus;
|
||||
use App\Helpers\OrderHelper;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceItem;
|
||||
use App\Models\Order;
|
||||
use App\Models\OrderItem;
|
||||
use App\Models\Product;
|
||||
use App\Models\Service;
|
||||
use App\Models\Transaction;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Chạy: php artisan db:seed --class=CustomerBillingDemoSeeder
|
||||
*/
|
||||
class CustomerBillingDemoSeeder extends Seeder
|
||||
{
|
||||
private const MARKER = 'seed:customer-billing-demo';
|
||||
|
||||
private const SCENARIOS = [
|
||||
['product' => 'email-doanh-nghiep-goi-10-tai-khoan', 'cycle' => 'monthly', 'status' => InvoiceStatus::PAID, 'paid' => 1.0, 'created' => -25, 'due' => -18],
|
||||
['product' => 'switch-cisco-catalyst-24-port', 'cycle' => 'onetime', 'status' => InvoiceStatus::PAID, 'paid' => 1.0, 'created' => -60, 'due' => -53],
|
||||
['product' => 'thue-may-chu-vat-ly-dell-r740', 'cycle' => 'monthly', 'status' => InvoiceStatus::UNPAID, 'paid' => 0.0, 'created' => -1, 'due' => 6],
|
||||
['product' => 'it-support-goi-doanh-nghiep', 'cycle' => 'monthly', 'status' => InvoiceStatus::UNPAID, 'paid' => 0.5, 'created' => -3, 'due' => 4],
|
||||
['product' => 'website-landing-page-co-ban', 'cycle' => 'onetime', 'status' => InvoiceStatus::OVERDUE, 'paid' => 0.0, 'created' => -17, 'due' => -10],
|
||||
['product' => 'email-doanh-nghiep-goi-10-tai-khoan', 'cycle' => 'monthly', 'status' => InvoiceStatus::OVERDUE, 'paid' => 0.3, 'created' => -10, 'due' => -3],
|
||||
['product' => 'it-support-goi-doanh-nghiep', 'cycle' => 'monthly', 'status' => InvoiceStatus::CANCELLED, 'paid' => 0.0, 'created' => -40, 'due' => -33],
|
||||
['product' => 'thue-may-chu-vat-ly-dell-r740', 'cycle' => 'monthly', 'status' => InvoiceStatus::REFUNDED, 'paid' => 1.0, 'created' => -45, 'due' => -38],
|
||||
];
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->call([TestAccountSeeder::class, ProductCategorySeeder::class, ProductTypeFieldSeeder::class, ProductMockupSeeder::class]);
|
||||
|
||||
$customer = Customer::where('email', 'pbao.dev@gmail.com')->firstOrFail();
|
||||
|
||||
DB::transaction(function () use ($customer) {
|
||||
$this->purgePreviousRun($customer);
|
||||
|
||||
foreach (self::SCENARIOS as $scenario) {
|
||||
$this->seedScenario($customer, $scenario);
|
||||
}
|
||||
});
|
||||
|
||||
$this->command?->info('Đã tạo ' . count(self::SCENARIOS) . ' đơn hàng/hoá đơn mẫu cho ' . $customer->email . '.');
|
||||
}
|
||||
|
||||
private function purgePreviousRun(Customer $customer): void
|
||||
{
|
||||
$orderIds = Order::withTrashed()->where('customer_id', $customer->id)->where('note', self::MARKER)->pluck('id');
|
||||
$invoices = Invoice::withTrashed()->whereIn('order_id', $orderIds)->get(['id', 'invoice_number']);
|
||||
|
||||
Transaction::withTrashed()
|
||||
->where('customer_id', $customer->id)
|
||||
->where(function ($query) use ($invoices) {
|
||||
foreach ($invoices->pluck('invoice_number') as $number) {
|
||||
$query->orWhere('trans', 'like', $number . '%');
|
||||
}
|
||||
})
|
||||
->when($invoices->isNotEmpty(), fn ($query) => $query->forceDelete());
|
||||
|
||||
$orderItemIds = OrderItem::whereIn('order_id', $orderIds)->pluck('id');
|
||||
Service::withTrashed()->whereIn('order_item_id', $orderItemIds)->forceDelete();
|
||||
InvoiceItem::whereIn('invoice_id', $invoices->pluck('id'))->delete();
|
||||
Invoice::withTrashed()->whereIn('id', $invoices->pluck('id'))->forceDelete();
|
||||
OrderItem::whereIn('id', $orderItemIds)->delete();
|
||||
Order::withTrashed()->whereIn('id', $orderIds)->forceDelete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{product: string, cycle: string, status: InvoiceStatus, paid: float, created: int, due: int} $scenario
|
||||
*/
|
||||
private function seedScenario(Customer $customer, array $scenario): void
|
||||
{
|
||||
$product = Product::where('slug', $scenario['product'])->firstOrFail();
|
||||
$price = (int) $product->pricings()->where('billing_cycle', $scenario['cycle'])->value('price');
|
||||
$months = OrderHelper::cycleToMonths($scenario['cycle']);
|
||||
$status = $scenario['status'];
|
||||
$createdAt = Carbon::now()->addDays($scenario['created']);
|
||||
$amountPaid = (int) round($price * $scenario['paid'], -3);
|
||||
$isSettled = in_array($status, [InvoiceStatus::PAID, InvoiceStatus::REFUNDED], true);
|
||||
$paidAt = $isSettled ? $createdAt->copy()->addHour() : null;
|
||||
|
||||
$order = Order::query()->forceCreate([
|
||||
'order_num' => OrderHelper::generateOrderNumber(),
|
||||
'date' => $createdAt->toDateString(),
|
||||
'customer_id' => $customer->id,
|
||||
'sub_total' => $price,
|
||||
'discount_amount' => 0,
|
||||
'total' => $price,
|
||||
'status' => match ($status) {
|
||||
InvoiceStatus::PAID => OrderStatus::ACTIVE->value,
|
||||
InvoiceStatus::CANCELLED, InvoiceStatus::REFUNDED => OrderStatus::CANCELLED->value,
|
||||
default => OrderStatus::PENDING->value,
|
||||
},
|
||||
'payment_method' => $amountPaid > 0 ? 'balance' : null,
|
||||
'paid_at' => $paidAt,
|
||||
'note' => self::MARKER,
|
||||
'created_at' => $createdAt,
|
||||
'updated_at' => $createdAt,
|
||||
]);
|
||||
|
||||
$orderItem = OrderItem::query()->forceCreate([
|
||||
'order_id' => $order->id,
|
||||
'product_id' => $product->id,
|
||||
'product_pricing_id' => $product->pricings()->where('billing_cycle', $scenario['cycle'])->value('id'),
|
||||
'billing_cycle' => $scenario['cycle'],
|
||||
'months' => $months,
|
||||
'quantity' => 1,
|
||||
'price' => $price,
|
||||
'created_at' => $createdAt,
|
||||
'updated_at' => $createdAt,
|
||||
]);
|
||||
|
||||
$invoice = Invoice::query()->forceCreate([
|
||||
'invoice_number' => OrderHelper::generateOrderNumber('INV'),
|
||||
'date' => $createdAt->toDateString(),
|
||||
'customer_id' => $customer->id,
|
||||
'order_id' => $order->id,
|
||||
'invoice_type' => 1,
|
||||
'sub_total' => $price,
|
||||
'discount_amount' => 0,
|
||||
'tax' => 0,
|
||||
'total' => $price,
|
||||
'amount_paid' => $amountPaid,
|
||||
'status' => $status->value,
|
||||
'payment_method' => $amountPaid > 0 ? 'balance' : null,
|
||||
'due_date' => Carbon::now()->addDays($scenario['due'])->toDateString(),
|
||||
'billing_period_start' => $createdAt->toDateString(),
|
||||
'billing_period_end' => $createdAt->copy()->addMonths($months)->toDateString(),
|
||||
'paid_at' => $paidAt,
|
||||
'created_at' => $createdAt,
|
||||
'updated_at' => $createdAt,
|
||||
]);
|
||||
|
||||
InvoiceItem::query()->forceCreate([
|
||||
'invoice_id' => $invoice->id,
|
||||
'product_id' => $product->id,
|
||||
'type' => 'service',
|
||||
'description' => $product->name,
|
||||
'months' => $months,
|
||||
'quantity' => 1,
|
||||
'unit_price' => $price,
|
||||
'total_price' => $price,
|
||||
'created_at' => $createdAt,
|
||||
'updated_at' => $createdAt,
|
||||
]);
|
||||
|
||||
if ($amountPaid > 0) {
|
||||
$this->recordPayment($invoice, $amountPaid, $isSettled, $paidAt ?? $createdAt->copy()->addHour());
|
||||
}
|
||||
|
||||
if ($isSettled) {
|
||||
$this->seedService($order, $orderItem, $invoice, $status, $paidAt);
|
||||
}
|
||||
}
|
||||
|
||||
private function recordPayment(Invoice $invoice, int $amount, bool $isSettled, Carbon $paidAt): void
|
||||
{
|
||||
Transaction::query()->forceCreate([
|
||||
'uuid' => (string) Str::uuid(),
|
||||
'trans' => $invoice->invoice_number . ($isSettled ? '' : '-P' . $amount),
|
||||
'public_code' => 'INV-PAY-' . $paidAt->format('Ymd') . '-' . strtoupper(Str::random(6)),
|
||||
'amount' => $amount,
|
||||
'received_amount' => $amount,
|
||||
'customer_id' => $invoice->customer_id,
|
||||
'status' => TransactionStatus::COMPLETED->value,
|
||||
'type' => 'invoice',
|
||||
'note' => 'Khách hàng thanh toán hóa đơn #' . $invoice->invoice_number . ' (balance)',
|
||||
'created_at' => $paidAt,
|
||||
'updated_at' => $paidAt,
|
||||
]);
|
||||
}
|
||||
|
||||
private function seedService(Order $order, OrderItem $orderItem, Invoice $invoice, InvoiceStatus $status, Carbon $startedAt): void
|
||||
{
|
||||
$isRefunded = $status === InvoiceStatus::REFUNDED;
|
||||
$refundedAt = $startedAt->copy()->addDays(2);
|
||||
|
||||
Service::query()->forceCreate([
|
||||
'uuid' => (string) Str::uuid(),
|
||||
'customer_id' => $order->customer_id,
|
||||
'product_id' => $orderItem->product_id,
|
||||
'order_item_id' => $orderItem->id,
|
||||
'invoice_id' => $invoice->id,
|
||||
'status' => $isRefunded ? 'cancelled' : 'active',
|
||||
'auto_renew' => false,
|
||||
'started_at' => $startedAt,
|
||||
'expires_at' => $startedAt->copy()->addMonths($orderItem->months),
|
||||
'cancelled_at' => $isRefunded ? $refundedAt : null,
|
||||
'refunded_at' => $isRefunded ? $refundedAt : null,
|
||||
'created_at' => $startedAt,
|
||||
'updated_at' => $isRefunded ? $refundedAt : $startedAt,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ use Illuminate\Support\Str;
|
||||
class TestAccountSeeder extends Seeder
|
||||
{
|
||||
private const CUSTOMER_EMAIL = 'pbao.dev@gmail.com';
|
||||
private const CUSTOMER_PASSWORD = 'password123';
|
||||
private const CUSTOMER_PASSWORD = '!admin@123!@#';
|
||||
private const ADMIN_USERNAME = 'admin';
|
||||
private const ADMIN_PASSWORD = '!admin@123!@#';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user