feature: user list
This commit is contained in:
@@ -18,18 +18,23 @@ class AdminController extends Controller
|
|||||||
{
|
{
|
||||||
$selectedMonth = $request->input('month', Carbon::now()->format('Y-m'));
|
$selectedMonth = $request->input('month', Carbon::now()->format('Y-m'));
|
||||||
$search = $request->input('search');
|
$search = $request->input('search');
|
||||||
$status = $request->input('status', (string)User::STATUS_ACTIVE);
|
$status = $request->input('status', (string)config('constants.STATUS_ACTIVE'));
|
||||||
$role = $request->input('role');
|
$role = $request->input('role');
|
||||||
$department = $request->input('department');
|
$department = $request->input('department');
|
||||||
$flagSend = $request->input('flag_send');
|
$flagSend = $request->input('flag_send');
|
||||||
|
|
||||||
['users' => $users, 'topReceivedUser' => $topReceivedUser, 'topSentUser' => $topSentUser]
|
[
|
||||||
= $this->adminService->getUserListWithStats($selectedMonth, $search, $status, $role, $department, $flagSend);
|
'users' => $users,
|
||||||
|
'topReceivedUser' => $topReceivedUser,
|
||||||
|
'topSentUser' => $topSentUser,
|
||||||
|
'topReceivedUsers' => $topReceivedUsers,
|
||||||
|
'topSentUsers' => $topSentUsers
|
||||||
|
] = $this->adminService->getUserListWithStats($selectedMonth, $search, $status, $role, $department, $flagSend);
|
||||||
|
|
||||||
if ($request->ajax() || $request->wantsJson()) {
|
if ($request->ajax() || $request->wantsJson()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'title' => view('admin.users.partials.title', compact('selectedMonth'))->render(),
|
'title' => view('admin.users.partials.title', compact('selectedMonth'))->render(),
|
||||||
'stats' => view('admin.users.partials.stats', compact('topReceivedUser', 'topSentUser'))->render(),
|
'stats' => view('admin.users.partials.stats', compact('topReceivedUser', 'topSentUser', 'topReceivedUsers', 'topSentUsers'))->render(),
|
||||||
'table' => view('admin.users.partials.table', compact('users'))->render(),
|
'table' => view('admin.users.partials.table', compact('users'))->render(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -39,6 +44,8 @@ class AdminController extends Controller
|
|||||||
'selectedMonth',
|
'selectedMonth',
|
||||||
'topReceivedUser',
|
'topReceivedUser',
|
||||||
'topSentUser',
|
'topSentUser',
|
||||||
|
'topReceivedUsers',
|
||||||
|
'topSentUsers',
|
||||||
'search',
|
'search',
|
||||||
'status',
|
'status',
|
||||||
'role',
|
'role',
|
||||||
@@ -58,9 +65,9 @@ class AdminController extends Controller
|
|||||||
'msnv' => 'required|integer|unique:user,msnv',
|
'msnv' => 'required|integer|unique:user,msnv',
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'mail' => 'required|email|unique:user,mail',
|
'mail' => 'required|email|unique:user,mail',
|
||||||
'departments' => 'required|integer|min:1|max:5',
|
'departments' => 'required|string|in:' . implode(',', config('constants.DEPARTMENTS')),
|
||||||
'password' => 'required|string',
|
'password' => 'required|string',
|
||||||
'role' => 'required|in:' . User::ROLE_MEMBER . ',' . User::ROLE_ADMIN,
|
'role' => 'required|in:' . config('constants.ROLE_MEMBER') . ',' . config('constants.ROLE_ADMIN'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->adminService->createUser($request->only('msnv', 'name', 'mail', 'departments', 'password', 'role'));
|
$this->adminService->createUser($request->only('msnv', 'name', 'mail', 'departments', 'password', 'role'));
|
||||||
@@ -75,17 +82,30 @@ class AdminController extends Controller
|
|||||||
|
|
||||||
$administrations = $this->adminService->getUserTransactions($msnv, $selectedMonth);
|
$administrations = $this->adminService->getUserTransactions($msnv, $selectedMonth);
|
||||||
|
|
||||||
return view('admin.users.edit', compact('user', 'administrations', 'selectedMonth'));
|
$addCards = \App\Models\AddCard::with('sellerUser')
|
||||||
|
->where('buyer', $user->msnv)
|
||||||
|
->orderBy('date', 'desc')
|
||||||
|
->orderBy('id', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$admins = User::where('role', config('constants.ROLE_ADMIN'))
|
||||||
|
->where('status', config('constants.STATUS_ACTIVE'))
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('admin.users.edit', compact('user', 'administrations', 'selectedMonth', 'addCards', 'admins'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request, $msnv)
|
public function update(Request $request, $msnv)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'num_card' => 'nullable|integer|min:1',
|
'card' => 'required|integer|min:0',
|
||||||
'flag_send' => 'nullable|boolean',
|
'role' => 'required|in:' . config('constants.ROLE_MEMBER') . ',' . config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => 'required|in:' . config('constants.STATUS_INACTIVE') . ',' . config('constants.STATUS_ACTIVE'),
|
||||||
|
'flag_send' => 'required|in:' . config('constants.FLAG_SEND_DISABLED') . ',' . config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => 'required|in:' . config('constants.FIRST_LOGIN_FALSE') . ',' . config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->adminService->updateUser($msnv, $request->only('num_card', 'flag_send'));
|
$this->adminService->updateUser($msnv, $request->only('card', 'role', 'status', 'flag_send', 'first_login'));
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('messages.user_update_success'));
|
return redirect()->back()->with('success', __('messages.user_update_success'));
|
||||||
}
|
}
|
||||||
@@ -97,6 +117,22 @@ class AdminController extends Controller
|
|||||||
return redirect()->route('admin.users.index')->with('success', __('messages.user_deactivate_success'));
|
return redirect()->route('admin.users.index')->with('success', __('messages.user_deactivate_success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateAddCard(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'num_card' => 'required|integer|min:1',
|
||||||
|
'seller' => 'required|exists:user,msnv',
|
||||||
|
'date' => 'required|date',
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->adminService->updateAddCard(intval($id), $request->only('num_card', 'seller', 'date'));
|
||||||
|
return redirect()->back()->with('success', 'Cập nhật lịch sử cấp phát thẻ thành công.');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return redirect()->back()->withErrors(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function resetCards()
|
public function resetCards()
|
||||||
{
|
{
|
||||||
$this->adminService->resetAllCards();
|
$this->adminService->resetAllCards();
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class AuthController extends Controller
|
|||||||
\Illuminate\Support\Facades\RateLimiter::clear($throttleKey);
|
\Illuminate\Support\Facades\RateLimiter::clear($throttleKey);
|
||||||
|
|
||||||
$user = $result['user'];
|
$user = $result['user'];
|
||||||
if ($user->role != \App\Models\User::ROLE_ADMIN && $user->first_login == \App\Models\User::FIRST_LOGIN_TRUE) {
|
if ($user->role != config('constants.ROLE_ADMIN') && $user->first_login == config('constants.FIRST_LOGIN_TRUE')) {
|
||||||
return redirect()->route('login')->with('dialog_first_login', true);
|
return redirect()->route('login')->with('dialog_first_login', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class UserController extends Controller
|
|||||||
$request->validate([
|
$request->validate([
|
||||||
'receiver' => [
|
'receiver' => [
|
||||||
'required',
|
'required',
|
||||||
\Illuminate\Validation\Rule::exists('user', 'msnv')->where('status', \App\Models\User::STATUS_ACTIVE)
|
\Illuminate\Validation\Rule::exists('user', 'msnv')->where('status', config('constants.STATUS_ACTIVE'))
|
||||||
],
|
],
|
||||||
'amount' => 'required|integer|min:1|max:' . Administration::MAX_SEND_CARD_PER_MONTH,
|
'amount' => 'required|integer|min:1|max:' . Administration::MAX_SEND_CARD_PER_MONTH,
|
||||||
]);
|
]);
|
||||||
@@ -84,7 +84,7 @@ class UserController extends Controller
|
|||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$this->userService->updatePassword($user, $request->password);
|
$this->userService->updatePassword($user, $request->password);
|
||||||
|
|
||||||
$route = $user->role == \App\Models\User::ROLE_ADMIN ? 'admin.dashboard' : 'user.dashboard';
|
$route = $user->role == config('constants.ROLE_ADMIN') ? 'admin.dashboard' : 'user.dashboard';
|
||||||
return redirect()->route($route)->with('success', __('messages.password_change_success'));
|
return redirect()->route($route)->with('success', __('messages.password_change_success'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class AdminMiddleware
|
|||||||
{
|
{
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if (Auth::check() && Auth::user()->role == User::ROLE_ADMIN && Auth::user()->status == User::STATUS_ACTIVE) {
|
if (Auth::check() && Auth::user()->role == config('constants.ROLE_ADMIN') && Auth::user()->status == config('constants.STATUS_ACTIVE')) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
return redirect()->route('login');
|
return redirect()->route('login');
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class ForceChangePasswordMiddleware
|
|||||||
{
|
{
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if (Auth::check() && Auth::user()->role != User::ROLE_ADMIN && Auth::user()->first_login == User::FIRST_LOGIN_TRUE) {
|
if (Auth::check() && Auth::user()->role != config('constants.ROLE_ADMIN') && Auth::user()->first_login == config('constants.FIRST_LOGIN_TRUE')) {
|
||||||
if (!$request->routeIs('user.change_password') && !$request->routeIs('user.update_password') && !$request->routeIs('logout')) {
|
if (!$request->routeIs('user.change_password') && !$request->routeIs('user.update_password') && !$request->routeIs('logout')) {
|
||||||
return redirect()->route('user.change_password');
|
return redirect()->route('user.change_password');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class MemberMiddleware
|
|||||||
{
|
{
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if (Auth::check() && in_array(Auth::user()->role, [User::ROLE_MEMBER, User::ROLE_ADMIN]) && Auth::user()->status == User::STATUS_ACTIVE) {
|
if (Auth::check() && in_array(Auth::user()->role, [config('constants.ROLE_MEMBER'), config('constants.ROLE_ADMIN')]) && Auth::user()->status == config('constants.STATUS_ACTIVE')) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
return redirect()->route('login');
|
return redirect()->route('login');
|
||||||
|
|||||||
@@ -19,4 +19,9 @@ class AddCard extends Model
|
|||||||
'seller',
|
'seller',
|
||||||
'date',
|
'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function sellerUser()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'seller', 'msnv');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,6 @@ class User extends Authenticatable
|
|||||||
{
|
{
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, Notifiable;
|
||||||
|
|
||||||
const ROLE_MEMBER = 0;
|
|
||||||
const ROLE_ADMIN = 1;
|
|
||||||
|
|
||||||
const STATUS_INACTIVE = 0;
|
|
||||||
const STATUS_ACTIVE = 1;
|
|
||||||
|
|
||||||
const FLAG_SEND_DISABLED = 0;
|
|
||||||
const FLAG_SEND_ENABLED = 1;
|
|
||||||
|
|
||||||
const FIRST_LOGIN_FALSE = 0;
|
|
||||||
const FIRST_LOGIN_TRUE = 1;
|
|
||||||
|
|
||||||
|
|
||||||
protected $table = 'user';
|
protected $table = 'user';
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|||||||
@@ -35,8 +35,21 @@ class AdminService implements AdminServiceInterface
|
|||||||
->whereBetween('date', [$startOfMonth, $endOfMonth])
|
->whereBetween('date', [$startOfMonth, $endOfMonth])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$topReceivedUser = (clone $usersQuery)->where('status', User::STATUS_ACTIVE)->orderByDesc('total_received')->first();
|
$activeUsers = (clone $usersQuery)->where('status', config('constants.STATUS_ACTIVE'))->get();
|
||||||
$topSentUser = (clone $usersQuery)->where('status', User::STATUS_ACTIVE)->orderByDesc('total_sent')->first();
|
|
||||||
|
$maxReceived = $activeUsers->max('total_received') ?? 0;
|
||||||
|
$maxSent = $activeUsers->max('total_sent') ?? 0;
|
||||||
|
|
||||||
|
$topReceivedUsers = $maxReceived > 0
|
||||||
|
? $activeUsers->filter(fn($u) => $u->total_received == $maxReceived)->values()
|
||||||
|
: collect();
|
||||||
|
|
||||||
|
$topSentUsers = $maxSent > 0
|
||||||
|
? $activeUsers->filter(fn($u) => $u->total_sent == $maxSent)->values()
|
||||||
|
: collect();
|
||||||
|
|
||||||
|
$topReceivedUser = $topReceivedUsers->first();
|
||||||
|
$topSentUser = $topSentUsers->first();
|
||||||
|
|
||||||
if (!is_null($status) && $status !== '') {
|
if (!is_null($status) && $status !== '') {
|
||||||
$usersQuery->where('status', intval($status));
|
$usersQuery->where('status', intval($status));
|
||||||
@@ -47,7 +60,7 @@ class AdminService implements AdminServiceInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($department) && $department !== '') {
|
if (!is_null($department) && $department !== '') {
|
||||||
$usersQuery->where('departments', intval($department));
|
$usersQuery->where('departments', $department);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($flagSend) && $flagSend !== '') {
|
if (!is_null($flagSend) && $flagSend !== '') {
|
||||||
@@ -62,10 +75,9 @@ class AdminService implements AdminServiceInterface
|
|||||||
->orWhereRaw('LOWER(mail) LIKE ?', ['%' . strtolower($search) . '%']);
|
->orWhereRaw('LOWER(mail) LIKE ?', ['%' . strtolower($search) . '%']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$users = $usersQuery->paginate(20)->withQueryString();
|
$users = $usersQuery->paginate(20)->withQueryString();
|
||||||
|
|
||||||
return compact('users', 'topReceivedUser', 'topSentUser');
|
return compact('users', 'topReceivedUser', 'topSentUser', 'topReceivedUsers', 'topSentUsers');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserTransactions(string $msnv, string $selectedMonth): LengthAwarePaginator
|
public function getUserTransactions(string $msnv, string $selectedMonth): LengthAwarePaginator
|
||||||
@@ -89,10 +101,10 @@ class AdminService implements AdminServiceInterface
|
|||||||
'pass' => md5($data['password']),
|
'pass' => md5($data['password']),
|
||||||
'departments' => $data['departments'],
|
'departments' => $data['departments'],
|
||||||
'role' => $data['role'],
|
'role' => $data['role'],
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 0,
|
'card' => 0,
|
||||||
'flag_send' => User::FLAG_SEND_DISABLED,
|
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
|
||||||
'first_login' => $data['role'] == User::ROLE_ADMIN ? User::FIRST_LOGIN_FALSE : User::FIRST_LOGIN_TRUE,
|
'first_login' => $data['role'] == config('constants.ROLE_ADMIN') ? config('constants.FIRST_LOGIN_FALSE') : config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,17 +113,24 @@ class AdminService implements AdminServiceInterface
|
|||||||
$user = User::where('msnv', $msnv)->firstOrFail();
|
$user = User::where('msnv', $msnv)->firstOrFail();
|
||||||
|
|
||||||
DB::transaction(function () use ($data, $user) {
|
DB::transaction(function () use ($data, $user) {
|
||||||
if (!empty($data['num_card'])) {
|
$newCard = intval($data['card']);
|
||||||
|
$oldCard = intval($user->card);
|
||||||
|
|
||||||
|
if ($newCard > $oldCard) {
|
||||||
|
$diff = $newCard - $oldCard;
|
||||||
AddCard::create([
|
AddCard::create([
|
||||||
'buyer' => $user->msnv,
|
'buyer' => $user->msnv,
|
||||||
'num_card' => $data['num_card'],
|
'num_card' => $diff,
|
||||||
'seller' => Auth::user()->msnv,
|
'seller' => Auth::user()->msnv,
|
||||||
'date' => Carbon::today(),
|
'date' => Carbon::today(),
|
||||||
]);
|
]);
|
||||||
$user->card += $data['num_card'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->flag_send = isset($data['flag_send']) ? User::FLAG_SEND_ENABLED : User::FLAG_SEND_DISABLED;
|
$user->card = $newCard;
|
||||||
|
$user->role = intval($data['role']);
|
||||||
|
$user->status = intval($data['status']);
|
||||||
|
$user->flag_send = intval($data['flag_send']);
|
||||||
|
$user->first_login = intval($data['first_login']);
|
||||||
$user->save();
|
$user->save();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -119,12 +138,50 @@ class AdminService implements AdminServiceInterface
|
|||||||
public function deactivateUser(string $msnv): void
|
public function deactivateUser(string $msnv): void
|
||||||
{
|
{
|
||||||
$user = User::where('msnv', $msnv)->firstOrFail();
|
$user = User::where('msnv', $msnv)->firstOrFail();
|
||||||
$user->status = User::STATUS_INACTIVE;
|
$user->status = config('constants.STATUS_INACTIVE');
|
||||||
$user->save();
|
$user->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetAllCards(): void
|
public function resetAllCards(): void
|
||||||
{
|
{
|
||||||
User::where('status', User::STATUS_ACTIVE)->update(['card' => 0]);
|
User::where('status', config('constants.STATUS_ACTIVE'))->update(['card' => 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAddCard(int $id, array $data): void
|
||||||
|
{
|
||||||
|
$addCard = AddCard::findOrFail($id);
|
||||||
|
|
||||||
|
|
||||||
|
$currentMonth = Carbon::now()->format('Y-m');
|
||||||
|
$recordMonth = Carbon::parse($addCard->date)->format('Y-m');
|
||||||
|
|
||||||
|
if ($recordMonth !== $currentMonth) {
|
||||||
|
throw new \Exception('Không cho phép chỉnh sửa dữ liệu card của các tháng trước.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$newDateMonth = Carbon::parse($data['date'])->format('Y-m');
|
||||||
|
if ($newDateMonth !== $currentMonth) {
|
||||||
|
throw new \Exception('Chỉ được phép chỉnh sửa dữ liệu của tháng hiện tại.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::where('msnv', $addCard->buyer)->firstOrFail();
|
||||||
|
|
||||||
|
DB::transaction(function () use ($addCard, $user, $data) {
|
||||||
|
$oldNumCard = intval($addCard->num_card);
|
||||||
|
$newNumCard = intval($data['num_card']);
|
||||||
|
$diff = $newNumCard - $oldNumCard;
|
||||||
|
|
||||||
|
if ($user->card + $diff < 0) {
|
||||||
|
throw new \Exception('Số lượng card cập nhật không hợp lệ vì tổng số card của user không được nhỏ hơn 0.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->card += $diff;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$addCard->num_card = $newNumCard;
|
||||||
|
$addCard->seller = $data['seller'];
|
||||||
|
$addCard->date = $data['date'];
|
||||||
|
$addCard->save();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,4 +24,6 @@ interface AdminServiceInterface
|
|||||||
public function deactivateUser(string $msnv): void;
|
public function deactivateUser(string $msnv): void;
|
||||||
|
|
||||||
public function resetAllCards(): void;
|
public function resetAllCards(): void;
|
||||||
|
|
||||||
|
public function updateAddCard(int $id, array $data): void;
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ class AuthService implements AuthServiceInterface
|
|||||||
// Log the user in manually
|
// Log the user in manually
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
if ($user->status != User::STATUS_ACTIVE) {
|
if ($user->status != config('constants.STATUS_ACTIVE')) {
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
return ['success' => false, 'error_key' => 'permission', 'error_msg' => 'Bạn không có quyền truy cập. Vui lòng liên hệ quản trị viên'];
|
return ['success' => false, 'error_key' => 'permission', 'error_msg' => 'Bạn không có quyền truy cập. Vui lòng liên hệ quản trị viên'];
|
||||||
}
|
}
|
||||||
@@ -37,11 +37,11 @@ class AuthService implements AuthServiceInterface
|
|||||||
|
|
||||||
public function getRedirectRouteForUser(User $user): string
|
public function getRedirectRouteForUser(User $user): string
|
||||||
{
|
{
|
||||||
if ($user->role == User::ROLE_ADMIN) {
|
if ($user->role == config('constants.ROLE_ADMIN')) {
|
||||||
return route('admin.dashboard');
|
return route('admin.dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user->first_login == User::FIRST_LOGIN_TRUE) {
|
if ($user->first_login == config('constants.FIRST_LOGIN_TRUE')) {
|
||||||
return route('user.change_password');
|
return route('user.change_password');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,19 +27,19 @@ class UserService implements UserServiceInterface
|
|||||||
|
|
||||||
public function getOtherActiveUsers(User $currentUser): Collection
|
public function getOtherActiveUsers(User $currentUser): Collection
|
||||||
{
|
{
|
||||||
return User::where('status', User::STATUS_ACTIVE)
|
return User::where('status', config('constants.STATUS_ACTIVE'))
|
||||||
->where('msnv', '!=', $currentUser->msnv)
|
->where('msnv', '!=', $currentUser->msnv)
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendThankcards(User $sender, string $receiverMsnv, int $amount): void
|
public function sendThankcards(User $sender, string $receiverMsnv, int $amount): void
|
||||||
{
|
{
|
||||||
if ($sender->flag_send == User::FLAG_SEND_DISABLED) {
|
if ($sender->flag_send == config('constants.FLAG_SEND_DISABLED')) {
|
||||||
throw new \RuntimeException(__('messages.error.no_send_permission'));
|
throw new \RuntimeException(__('messages.error.no_send_permission'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$receiver = User::where('msnv', $receiverMsnv)->first();
|
$receiver = User::where('msnv', $receiverMsnv)->first();
|
||||||
if (!$receiver || $receiver->status != User::STATUS_ACTIVE) {
|
if (!$receiver || $receiver->status != config('constants.STATUS_ACTIVE')) {
|
||||||
throw new \RuntimeException(__('messages.error.receiver_invalid'));
|
throw new \RuntimeException(__('messages.error.receiver_invalid'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ class UserService implements UserServiceInterface
|
|||||||
public function updatePassword(User $user, string $newPassword): void
|
public function updatePassword(User $user, string $newPassword): void
|
||||||
{
|
{
|
||||||
$user->pass = md5($newPassword);
|
$user->pass = md5($newPassword);
|
||||||
$user->first_login = User::FIRST_LOGIN_FALSE;
|
$user->first_login = config('constants.FIRST_LOGIN_FALSE');
|
||||||
$user->save();
|
$user->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ class UserService implements UserServiceInterface
|
|||||||
->sum('sent');
|
->sum('sent');
|
||||||
|
|
||||||
// Calculate current rank (based on received)
|
// Calculate current rank (based on received)
|
||||||
$rankings = User::where('status', User::STATUS_ACTIVE)
|
$rankings = User::where('status', config('constants.STATUS_ACTIVE'))
|
||||||
->addSelect([
|
->addSelect([
|
||||||
'score' => Administration::selectRaw('COALESCE(SUM(received), 0)')
|
'score' => Administration::selectRaw('COALESCE(SUM(received), 0)')
|
||||||
->whereColumn('msnv', 'user.msnv')
|
->whereColumn('msnv', 'user.msnv')
|
||||||
@@ -156,7 +156,7 @@ class UserService implements UserServiceInterface
|
|||||||
|
|
||||||
$column = $type === 'sent' ? 'sent' : 'received';
|
$column = $type === 'sent' ? 'sent' : 'received';
|
||||||
|
|
||||||
$allActiveUsers = User::where('status', User::STATUS_ACTIVE)
|
$allActiveUsers = User::where('status', config('constants.STATUS_ACTIVE'))
|
||||||
->addSelect([
|
->addSelect([
|
||||||
'score' => Administration::selectRaw('COALESCE(SUM(' . $column . '), 0)')
|
'score' => Administration::selectRaw('COALESCE(SUM(' . $column . '), 0)')
|
||||||
->whereColumn('msnv', 'user.msnv')
|
->whereColumn('msnv', 'user.msnv')
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'ROLE_MEMBER' => 0,
|
||||||
|
'ROLE_ADMIN' => 1,
|
||||||
|
|
||||||
|
'STATUS_INACTIVE' => 0,
|
||||||
|
'STATUS_ACTIVE' => 1,
|
||||||
|
|
||||||
|
'FLAG_SEND_DISABLED' => 0,
|
||||||
|
'FLAG_SEND_ENABLED' => 1,
|
||||||
|
|
||||||
|
'FIRST_LOGIN_FALSE' => 0,
|
||||||
|
'FIRST_LOGIN_TRUE' => 1,
|
||||||
|
|
||||||
|
'DEPARTMENTS' => [
|
||||||
|
'BIZ-IID - Internet Infra Business Division / BIZ-IID - Sales Enterprise Team (HCM)',
|
||||||
|
'BIZ-ITOVN - Vietnam Business Division / BIZ-ITOVN - Ho Chi Minh',
|
||||||
|
'BIZ-SSD - Smart Solutions Business Division / BIZ-SSD - Ho Chi Minh',
|
||||||
|
'CoE - Center of Excellence / CoE - Data (Ho Chi Minh)',
|
||||||
|
'CoE - Center of Excellence / CoE - R&D (Ho Chi Minh)',
|
||||||
|
'CoE - Center of Excellence / CoE - UI/UX (Ho Chi Minh)',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch)',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch) / DL-ITOHCM - BrSE Team',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch) / DL-ITOHCM-DU1 - Delivery Unit 1',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch) / DL-ITOHCM-DU2 - Delivery Unit 2',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch) / DL-ITOHCM-DU3 - Delivery Unit 3',
|
||||||
|
'DL-ITOHCM - ITO Delivery Division (HCM Branch) / DL-ITOHCM-DU4 - Delivery Unit 4',
|
||||||
|
'DL-SSD - Smart Solutions Delivery Division / DL-SSD - Ho Chi Minh',
|
||||||
|
'FC-HRD - Human Resources Division / FC-HRD - Ho Chi Minh',
|
||||||
|
'FC-RMD - Risk Management Division / FC-RMD - Ho Chi Minh'
|
||||||
|
]
|
||||||
|
];
|
||||||
@@ -35,11 +35,11 @@ class MockDataSeeder extends Seeder
|
|||||||
'mail' => 'admin@runsystem.net',
|
'mail' => 'admin@runsystem.net',
|
||||||
'pass' => $password,
|
'pass' => $password,
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 0,
|
'card' => 0,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
User::create([
|
User::create([
|
||||||
@@ -48,20 +48,20 @@ class MockDataSeeder extends Seeder
|
|||||||
'mail' => 'admin2@runsystem.net',
|
'mail' => 'admin2@runsystem.net',
|
||||||
'pass' => $password,
|
'pass' => $password,
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 0,
|
'card' => 0,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Active Users (Initialize with specific users needed for logs/transactions)
|
// Active Users (Initialize with specific users needed for logs/transactions)
|
||||||
$users = [
|
$users = [
|
||||||
['msnv' => 1001, 'name' => 'Nguyễn Văn A', 'mail' => 'nguyenvana@runsystem.net', 'card' => 10, 'flag' => User::FLAG_SEND_ENABLED, 'first_login' => User::FIRST_LOGIN_FALSE],
|
['msnv' => 1001, 'name' => 'Nguyễn Văn A', 'mail' => 'nguyenvana@runsystem.net', 'card' => 10, 'flag' => config('constants.FLAG_SEND_ENABLED'), 'first_login' => config('constants.FIRST_LOGIN_FALSE')],
|
||||||
['msnv' => 1002, 'name' => 'Trần Thị Ngọc', 'mail' => 'tranthingoc@runsystem.net', 'card' => 3, 'flag' => User::FLAG_SEND_ENABLED, 'first_login' => User::FIRST_LOGIN_FALSE],
|
['msnv' => 1002, 'name' => 'Trần Thị Ngọc', 'mail' => 'tranthingoc@runsystem.net', 'card' => 3, 'flag' => config('constants.FLAG_SEND_ENABLED'), 'first_login' => config('constants.FIRST_LOGIN_FALSE')],
|
||||||
['msnv' => 1003, 'name' => 'Lê Kim Thư', 'mail' => 'lekiemthu@runsystem.net', 'card' => 6, 'flag' => User::FLAG_SEND_ENABLED, 'first_login' => User::FIRST_LOGIN_TRUE], // First-time login
|
['msnv' => 1003, 'name' => 'Lê Kim Thư', 'mail' => 'lekiemthu@runsystem.net', 'card' => 6, 'flag' => config('constants.FLAG_SEND_ENABLED'), 'first_login' => config('constants.FIRST_LOGIN_TRUE')], // First-time login
|
||||||
['msnv' => 1004, 'name' => 'Phòng Nhân Sự', 'mail' => 'phongnhansu@runsystem.net', 'card' => 0, 'flag' => User::FLAG_SEND_DISABLED, 'first_login' => User::FIRST_LOGIN_FALSE], // Disabled sending permission
|
['msnv' => 1004, 'name' => 'Phòng Nhân Sự', 'mail' => 'phongnhansu@runsystem.net', 'card' => 0, 'flag' => config('constants.FLAG_SEND_DISABLED'), 'first_login' => config('constants.FIRST_LOGIN_FALSE')], // Disabled sending permission
|
||||||
['msnv' => 1005, 'name' => 'Bản Giang', 'mail' => 'bangiang@runsystem.net', 'card' => 36, 'flag' => User::FLAG_SEND_ENABLED, 'first_login' => User::FIRST_LOGIN_FALSE],
|
['msnv' => 1005, 'name' => 'Bản Giang', 'mail' => 'bangiang@runsystem.net', 'card' => 36, 'flag' => config('constants.FLAG_SEND_ENABLED'), 'first_login' => config('constants.FIRST_LOGIN_FALSE')],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Generate additional users to reach exactly 100 member users
|
// Generate additional users to reach exactly 100 member users
|
||||||
@@ -76,8 +76,8 @@ class MockDataSeeder extends Seeder
|
|||||||
'name' => $randomName,
|
'name' => $randomName,
|
||||||
'mail' => 'dev' . str_pad($i, 3, '0', STR_PAD_LEFT) . '@runsystem.net',
|
'mail' => 'dev' . str_pad($i, 3, '0', STR_PAD_LEFT) . '@runsystem.net',
|
||||||
'card' => rand(0, 30),
|
'card' => rand(0, 30),
|
||||||
'flag' => rand(0, 5) > 0 ? User::FLAG_SEND_ENABLED : User::FLAG_SEND_DISABLED,
|
'flag' => rand(0, 5) > 0 ? config('constants.FLAG_SEND_ENABLED') : config('constants.FLAG_SEND_DISABLED'),
|
||||||
'first_login' => rand(0, 4) == 0 ? User::FIRST_LOGIN_TRUE : User::FIRST_LOGIN_FALSE
|
'first_login' => rand(0, 4) == 0 ? config('constants.FIRST_LOGIN_TRUE') : config('constants.FIRST_LOGIN_FALSE')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,8 +88,8 @@ class MockDataSeeder extends Seeder
|
|||||||
'mail' => $u['mail'],
|
'mail' => $u['mail'],
|
||||||
'pass' => $password,
|
'pass' => $password,
|
||||||
'departments' => rand(1, 5),
|
'departments' => rand(1, 5),
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => $u['card'],
|
'card' => $u['card'],
|
||||||
'flag_send' => $u['flag'],
|
'flag_send' => $u['flag'],
|
||||||
'first_login' => $u['first_login'],
|
'first_login' => $u['first_login'],
|
||||||
@@ -115,11 +115,11 @@ class MockDataSeeder extends Seeder
|
|||||||
'mail' => 'nghiduy@runsystem.net',
|
'mail' => 'nghiduy@runsystem.net',
|
||||||
'pass' => $password,
|
'pass' => $password,
|
||||||
'departments' => 2,
|
'departments' => 2,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_INACTIVE,
|
'status' => config('constants.STATUS_INACTIVE'),
|
||||||
'card' => 0,
|
'card' => 0,
|
||||||
'flag_send' => User::FLAG_SEND_DISABLED,
|
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 2. CREATE CARD ADDITION LOGS (add_card table)
|
// 2. CREATE CARD ADDITION LOGS (add_card table)
|
||||||
@@ -195,5 +195,49 @@ class MockDataSeeder extends Seeder
|
|||||||
'date' => $t['date']
|
'date' => $t['date']
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. CREATE 10 USERS FOR TIE-RANKING IN CURRENT MONTH
|
||||||
|
$currentMonth = Carbon::now()->format('Y-m');
|
||||||
|
$currentDate = Carbon::now()->format('Y-m-d');
|
||||||
|
$depts = config('constants.DEPARTMENTS');
|
||||||
|
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
$tieMsnv = 8000 + $i;
|
||||||
|
User::create([
|
||||||
|
'msnv' => $tieMsnv,
|
||||||
|
'name' => "Top 1 User {$i}",
|
||||||
|
'mail' => "top1_user_{$i}@runsystem.net",
|
||||||
|
'pass' => $password,
|
||||||
|
'departments' => $depts[($i - 1) % count($depts)],
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 100,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$senderMsnv = 8000 + $i;
|
||||||
|
$receiverMsnv = 8000 + ($i % 10 + 1);
|
||||||
|
|
||||||
|
// Sender record
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => $senderMsnv,
|
||||||
|
'received' => 0,
|
||||||
|
'sender' => null,
|
||||||
|
'sent' => 100,
|
||||||
|
'receiver' => $receiverMsnv,
|
||||||
|
'date' => $currentDate,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Receiver record
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => $receiverMsnv,
|
||||||
|
'received' => 100,
|
||||||
|
'sender' => $senderMsnv,
|
||||||
|
'sent' => 0,
|
||||||
|
'receiver' => null,
|
||||||
|
'date' => $currentDate,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-27
@@ -29,79 +29,79 @@ file_put_contents('app/Models/Administration.php', $content);
|
|||||||
// 3. Update app/Http/Middleware/AdminMiddleware.php
|
// 3. Update app/Http/Middleware/AdminMiddleware.php
|
||||||
$content = file_get_contents('app/Http/Middleware/AdminMiddleware.php');
|
$content = file_get_contents('app/Http/Middleware/AdminMiddleware.php');
|
||||||
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
||||||
$content = str_replace('Auth::user()->role == 1', 'Auth::user()->role == User::ROLE_ADMIN', $content);
|
$content = str_replace('Auth::user()->role == 1', 'Auth::user()->role == config('constants.ROLE_ADMIN')', $content);
|
||||||
$content = str_replace('Auth::user()->status == 1', 'Auth::user()->status == User::STATUS_ACTIVE', $content);
|
$content = str_replace('Auth::user()->status == 1', 'Auth::user()->status == config('constants.STATUS_ACTIVE')', $content);
|
||||||
file_put_contents('app/Http/Middleware/AdminMiddleware.php', $content);
|
file_put_contents('app/Http/Middleware/AdminMiddleware.php', $content);
|
||||||
|
|
||||||
// 4. Update app/Http/Middleware/MemberMiddleware.php
|
// 4. Update app/Http/Middleware/MemberMiddleware.php
|
||||||
$content = file_get_contents('app/Http/Middleware/MemberMiddleware.php');
|
$content = file_get_contents('app/Http/Middleware/MemberMiddleware.php');
|
||||||
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
||||||
$content = str_replace('Auth::user()->role == 0', 'Auth::user()->role == User::ROLE_MEMBER', $content);
|
$content = str_replace('Auth::user()->role == 0', 'Auth::user()->role == config('constants.ROLE_MEMBER')', $content);
|
||||||
$content = str_replace('Auth::user()->status == 1', 'Auth::user()->status == User::STATUS_ACTIVE', $content);
|
$content = str_replace('Auth::user()->status == 1', 'Auth::user()->status == config('constants.STATUS_ACTIVE')', $content);
|
||||||
file_put_contents('app/Http/Middleware/MemberMiddleware.php', $content);
|
file_put_contents('app/Http/Middleware/MemberMiddleware.php', $content);
|
||||||
|
|
||||||
// 5. Update app/Http/Middleware/ForceChangePasswordMiddleware.php
|
// 5. Update app/Http/Middleware/ForceChangePasswordMiddleware.php
|
||||||
$content = file_get_contents('app/Http/Middleware/ForceChangePasswordMiddleware.php');
|
$content = file_get_contents('app/Http/Middleware/ForceChangePasswordMiddleware.php');
|
||||||
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
||||||
$content = str_replace('Auth::user()->first_login == 1', 'Auth::user()->first_login == User::FIRST_LOGIN_TRUE', $content);
|
$content = str_replace('Auth::user()->first_login == 1', 'Auth::user()->first_login == config('constants.FIRST_LOGIN_TRUE')', $content);
|
||||||
file_put_contents('app/Http/Middleware/ForceChangePasswordMiddleware.php', $content);
|
file_put_contents('app/Http/Middleware/ForceChangePasswordMiddleware.php', $content);
|
||||||
|
|
||||||
// 6. Update app/Http/Controllers/AuthController.php
|
// 6. Update app/Http/Controllers/AuthController.php
|
||||||
$content = file_get_contents('app/Http/Controllers/AuthController.php');
|
$content = file_get_contents('app/Http/Controllers/AuthController.php');
|
||||||
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
$content = str_replace('use Illuminate\Support\Facades\Auth;', "use Illuminate\Support\Facades\Auth;\nuse App\Models\User;", $content);
|
||||||
$content = str_replace('$user->status != 1', '$user->status != User::STATUS_ACTIVE', $content);
|
$content = str_replace('$user->status != 1', '$user->status != config('constants.STATUS_ACTIVE')', $content);
|
||||||
$content = str_replace('$user->first_login == 1', '$user->first_login == User::FIRST_LOGIN_TRUE', $content);
|
$content = str_replace('$user->first_login == 1', '$user->first_login == config('constants.FIRST_LOGIN_TRUE')', $content);
|
||||||
$content = str_replace('$user->role == 1', '$user->role == User::ROLE_ADMIN', $content);
|
$content = str_replace('$user->role == 1', '$user->role == config('constants.ROLE_ADMIN')', $content);
|
||||||
file_put_contents('app/Http/Controllers/AuthController.php', $content);
|
file_put_contents('app/Http/Controllers/AuthController.php', $content);
|
||||||
|
|
||||||
// 7. Update app/Http/Controllers/AdminController.php
|
// 7. Update app/Http/Controllers/AdminController.php
|
||||||
$content = file_get_contents('app/Http/Controllers/AdminController.php');
|
$content = file_get_contents('app/Http/Controllers/AdminController.php');
|
||||||
$content = str_replace("where('status', 1)", "where('status', User::STATUS_ACTIVE)", $content);
|
$content = str_replace("where('status', 1)", "where('status', config('constants.STATUS_ACTIVE'))", $content);
|
||||||
$content = str_replace("'role' => 'required|in:0,1'", "'role' => 'required|in:' . User::ROLE_MEMBER . ',' . User::ROLE_ADMIN", $content);
|
$content = str_replace("'role' => 'required|in:0,1'", "'role' => 'required|in:' . config('constants.ROLE_MEMBER') . ',' . config('constants.ROLE_ADMIN')", $content);
|
||||||
$content = str_replace("'status' => 1", "'status' => User::STATUS_ACTIVE", $content);
|
$content = str_replace("'status' => 1", "'status' => config('constants.STATUS_ACTIVE')", $content);
|
||||||
$content = str_replace("'flag_send' => 0", "'flag_send' => User::FLAG_SEND_DISABLED", $content);
|
$content = str_replace("'flag_send' => 0", "'flag_send' => config('constants.FLAG_SEND_DISABLED')", $content);
|
||||||
$content = str_replace("'first_login' => 1", "'first_login' => User::FIRST_LOGIN_TRUE", $content);
|
$content = str_replace("'first_login' => 1", "'first_login' => config('constants.FIRST_LOGIN_TRUE')", $content);
|
||||||
$content = str_replace("\$request->has('flag_send') ? 1 : 0", "\$request->has('flag_send') ? User::FLAG_SEND_ENABLED : User::FLAG_SEND_DISABLED", $content);
|
$content = str_replace("\$request->has('flag_send') ? 1 : 0", "\$request->has('flag_send') ? config('constants.FLAG_SEND_ENABLED') : config('constants.FLAG_SEND_DISABLED')", $content);
|
||||||
$content = str_replace("\$user->status = 0", "\$user->status = User::STATUS_INACTIVE", $content);
|
$content = str_replace("\$user->status = 0", "\$user->status = config('constants.STATUS_INACTIVE')", $content);
|
||||||
file_put_contents('app/Http/Controllers/AdminController.php', $content);
|
file_put_contents('app/Http/Controllers/AdminController.php', $content);
|
||||||
|
|
||||||
// 8. Update app/Http/Controllers/UserController.php
|
// 8. Update app/Http/Controllers/UserController.php
|
||||||
$content = file_get_contents('app/Http/Controllers/UserController.php');
|
$content = file_get_contents('app/Http/Controllers/UserController.php');
|
||||||
$content = str_replace("where('status', 1)", "where('status', User::STATUS_ACTIVE)", $content);
|
$content = str_replace("where('status', 1)", "where('status', config('constants.STATUS_ACTIVE'))", $content);
|
||||||
$content = str_replace("max:5'", "max:' . Administration::MAX_SEND_CARD_PER_MONTH", $content);
|
$content = str_replace("max:5'", "max:' . Administration::MAX_SEND_CARD_PER_MONTH", $content);
|
||||||
$content = str_replace("\$sender->flag_send == 0", "\$sender->flag_send == User::FLAG_SEND_DISABLED", $content);
|
$content = str_replace("\$sender->flag_send == 0", "\$sender->flag_send == config('constants.FLAG_SEND_DISABLED')", $content);
|
||||||
$content = str_replace("> 5)", "> Administration::MAX_SEND_CARD_PER_MONTH)", $content);
|
$content = str_replace("> 5)", "> Administration::MAX_SEND_CARD_PER_MONTH)", $content);
|
||||||
$content = str_replace("tối đa 5 card", 'tối đa " . Administration::MAX_SEND_CARD_PER_MONTH . " card', $content);
|
$content = str_replace("tối đa 5 card", 'tối đa " . Administration::MAX_SEND_CARD_PER_MONTH . " card', $content);
|
||||||
$content = str_replace("\$user->first_login = 0", "\$user->first_login = User::FIRST_LOGIN_FALSE", $content);
|
$content = str_replace("\$user->first_login = 0", "\$user->first_login = config('constants.FIRST_LOGIN_FALSE')", $content);
|
||||||
$content = str_replace("\$user->role == 1", "\$user->role == User::ROLE_ADMIN", $content);
|
$content = str_replace("\$user->role == 1", "\$user->role == config('constants.ROLE_ADMIN')", $content);
|
||||||
file_put_contents('app/Http/Controllers/UserController.php', $content);
|
file_put_contents('app/Http/Controllers/UserController.php', $content);
|
||||||
|
|
||||||
// 9. Update app/Console/Commands/ResetCardsCommand.php
|
// 9. Update app/Console/Commands/ResetCardsCommand.php
|
||||||
$content = file_get_contents('app/Console/Commands/ResetCardsCommand.php');
|
$content = file_get_contents('app/Console/Commands/ResetCardsCommand.php');
|
||||||
$content = str_replace("where('status', 1)", "where('status', User::STATUS_ACTIVE)", $content);
|
$content = str_replace("where('status', 1)", "where('status', config('constants.STATUS_ACTIVE'))", $content);
|
||||||
file_put_contents('app/Console/Commands/ResetCardsCommand.php', $content);
|
file_put_contents('app/Console/Commands/ResetCardsCommand.php', $content);
|
||||||
|
|
||||||
// 10. Update resources/views/layouts/app.blade.php
|
// 10. Update resources/views/layouts/app.blade.php
|
||||||
$content = file_get_contents('resources/views/layouts/app.blade.php');
|
$content = file_get_contents('resources/views/layouts/app.blade.php');
|
||||||
$content = str_replace("Auth::user()->role == 1", "Auth::user()->role == \App\Models\User::ROLE_ADMIN", $content);
|
$content = str_replace("Auth::user()->role == 1", "Auth::user()->role == config('constants.ROLE_ADMIN')", $content);
|
||||||
file_put_contents('resources/views/layouts/app.blade.php', $content);
|
file_put_contents('resources/views/layouts/app.blade.php', $content);
|
||||||
|
|
||||||
// 11. Update resources/views/admin/users/create.blade.php
|
// 11. Update resources/views/admin/users/create.blade.php
|
||||||
$content = file_get_contents('resources/views/admin/users/create.blade.php');
|
$content = file_get_contents('resources/views/admin/users/create.blade.php');
|
||||||
$content = str_replace('value="0"', 'value="{{ \App\Models\User::ROLE_MEMBER }}"', $content);
|
$content = str_replace('value="0"', 'value="{{ config('constants.ROLE_MEMBER') }}"', $content);
|
||||||
$content = str_replace('value="1"', 'value="{{ \App\Models\User::ROLE_ADMIN }}"', $content);
|
$content = str_replace('value="1"', 'value="{{ config('constants.ROLE_ADMIN') }}"', $content);
|
||||||
$content = str_replace("old('role') == '0'", "old('role') == \App\Models\User::ROLE_MEMBER", $content);
|
$content = str_replace("old('role') == '0'", "old('role') == config('constants.ROLE_MEMBER')", $content);
|
||||||
$content = str_replace("old('role') == '1'", "old('role') == \App\Models\User::ROLE_ADMIN", $content);
|
$content = str_replace("old('role') == '1'", "old('role') == config('constants.ROLE_ADMIN')", $content);
|
||||||
file_put_contents('resources/views/admin/users/create.blade.php', $content);
|
file_put_contents('resources/views/admin/users/create.blade.php', $content);
|
||||||
|
|
||||||
// 12. Update resources/views/admin/users/edit.blade.php
|
// 12. Update resources/views/admin/users/edit.blade.php
|
||||||
$content = file_get_contents('resources/views/admin/users/edit.blade.php');
|
$content = file_get_contents('resources/views/admin/users/edit.blade.php');
|
||||||
$content = str_replace("\$user->role == 1", "\$user->role == \App\Models\User::ROLE_ADMIN", $content);
|
$content = str_replace("\$user->role == 1", "\$user->role == config('constants.ROLE_ADMIN')", $content);
|
||||||
file_put_contents('resources/views/admin/users/edit.blade.php', $content);
|
file_put_contents('resources/views/admin/users/edit.blade.php', $content);
|
||||||
|
|
||||||
// 13. Update resources/views/user/change_password.blade.php
|
// 13. Update resources/views/user/change_password.blade.php
|
||||||
$content = file_get_contents('resources/views/user/change_password.blade.php');
|
$content = file_get_contents('resources/views/user/change_password.blade.php');
|
||||||
$content = str_replace("Auth::user()->first_login == 1", "Auth::user()->first_login == \App\Models\User::FIRST_LOGIN_TRUE", $content);
|
$content = str_replace("Auth::user()->first_login == 1", "Auth::user()->first_login == config('constants.FIRST_LOGIN_TRUE')", $content);
|
||||||
file_put_contents('resources/views/user/change_password.blade.php', $content);
|
file_put_contents('resources/views/user/change_password.blade.php', $content);
|
||||||
|
|
||||||
echo "Refactored successfully!";
|
echo "Refactored successfully!";
|
||||||
|
|||||||
@@ -1,45 +1,69 @@
|
|||||||
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 border border-white hover:shadow-md transition-all flex items-center justify-between">
|
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 border border-white hover:shadow-md transition-all flex items-start justify-between">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<div class="w-14 h-14 rounded-2xl bg-purple-50 flex items-center justify-center text-purple-500 shrink-0">
|
<div class="w-14 h-14 rounded-2xl bg-purple-50 flex items-center justify-center text-purple-500 shrink-0">
|
||||||
<svg class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
<svg class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-[13px] font-bold text-gray-400 uppercase tracking-wider mb-1">User nhận nhiều nhất</span>
|
<span class="text-[13px] font-bold text-gray-400 uppercase tracking-wider mb-2">User nhận nhiều nhất</span>
|
||||||
@if($topReceivedUser)
|
@if(isset($topReceivedUsers) && $topReceivedUsers->isNotEmpty())
|
||||||
<span class="text-[16px] font-extrabold text-[#1a2b49] leading-tight">{{ $topReceivedUser->name }}</span>
|
<div class="flex flex-col gap-3">
|
||||||
<span class="text-[12px] text-gray-500 font-semibold mt-0.5">MSNV: {{ $topReceivedUser->msnv }}</span>
|
@foreach($topReceivedUsers as $user)
|
||||||
|
<div class="flex flex-col leading-tight">
|
||||||
|
<span class="text-[16px] font-extrabold text-[#1a2b49]">{{ $user->name }}</span>
|
||||||
|
<div class="text-[12px] text-gray-500 font-semibold mt-0.5 flex flex-wrap gap-x-2 gap-y-0.5">
|
||||||
|
<span>MSNV: {{ $user->msnv }}</span>
|
||||||
|
@if($user->mail)
|
||||||
|
<span class="text-gray-300">•</span>
|
||||||
|
<span>Email: {{ $user->mail }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
@else
|
@else
|
||||||
<span class="text-[15px] font-semibold text-gray-400">Không có dữ liệu</span>
|
<span class="text-[15px] font-semibold text-gray-400">Không có dữ liệu</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right">
|
<div class="text-right shrink-0">
|
||||||
<span class="text-[36px] font-extrabold text-purple-600 leading-none">{{ $topReceivedUser?->total_received ?? 0 }}</span>
|
<span class="text-[36px] font-extrabold text-purple-600 leading-none">{{ isset($topReceivedUsers) && $topReceivedUsers->isNotEmpty() ? $topReceivedUsers->first()->total_received : 0 }}</span>
|
||||||
<span class="block text-[11px] text-gray-400 font-bold uppercase mt-1">Thẻ Nhận</span>
|
<span class="block text-[11px] text-gray-400 font-bold uppercase mt-1">Thẻ Nhận</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 border border-white hover:shadow-md transition-all flex items-center justify-between">
|
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 border border-white hover:shadow-md transition-all flex items-start justify-between">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<div class="w-14 h-14 rounded-2xl bg-blue-50 flex items-center justify-center text-blue-500 shrink-0">
|
<div class="w-14 h-14 rounded-2xl bg-blue-50 flex items-center justify-center text-blue-500 shrink-0">
|
||||||
<svg class="w-7 h-7 transform -rotate-45" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
<svg class="w-7 h-7 transform -rotate-45" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-[13px] font-bold text-gray-400 uppercase tracking-wider mb-1">User gửi nhiều nhất</span>
|
<span class="text-[13px] font-bold text-gray-400 uppercase tracking-wider mb-2">User gửi nhiều nhất</span>
|
||||||
@if($topSentUser)
|
@if(isset($topSentUsers) && $topSentUsers->isNotEmpty())
|
||||||
<span class="text-[16px] font-extrabold text-[#1a2b49] leading-tight">{{ $topSentUser->name }}</span>
|
<div class="flex flex-col gap-3">
|
||||||
<span class="text-[12px] text-gray-500 font-semibold mt-0.5">MSNV: {{ $topSentUser->msnv }}</span>
|
@foreach($topSentUsers as $user)
|
||||||
|
<div class="flex flex-col leading-tight">
|
||||||
|
<span class="text-[16px] font-extrabold text-[#1a2b49]">{{ $user->name }}</span>
|
||||||
|
<div class="text-[12px] text-gray-500 font-semibold mt-0.5 flex flex-wrap gap-x-2 gap-y-0.5">
|
||||||
|
<span>MSNV: {{ $user->msnv }}</span>
|
||||||
|
@if($user->mail)
|
||||||
|
<span class="text-gray-300">•</span>
|
||||||
|
<span>Email: {{ $user->mail }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
@else
|
@else
|
||||||
<span class="text-[15px] font-semibold text-gray-400">Không có dữ liệu</span>
|
<span class="text-[15px] font-semibold text-gray-400">Không có dữ liệu</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right">
|
<div class="text-right shrink-0">
|
||||||
<span class="text-[36px] font-extrabold text-blue-600 leading-none">{{ $topSentUser?->total_sent ?? 0 }}</span>
|
<span class="text-[36px] font-extrabold text-blue-600 leading-none">{{ isset($topSentUsers) && $topSentUsers->isNotEmpty() ? $topSentUsers->first()->total_sent : 0 }}</span>
|
||||||
<span class="block text-[11px] text-gray-400 font-bold uppercase mt-1">Thẻ Gửi</span>
|
<span class="block text-[11px] text-gray-400 font-bold uppercase mt-1">Thẻ Gửi</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,19 +11,24 @@
|
|||||||
<table class="min-w-full divide-y divide-gray-100 text-sm">
|
<table class="min-w-full divide-y divide-gray-100 text-sm">
|
||||||
<thead class="bg-gray-50/50">
|
<thead class="bg-gray-50/50">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th class="table-header-cell">Thao tác</th>
|
||||||
<th class="table-header-cell">MSNV</th>
|
<th class="table-header-cell">MSNV</th>
|
||||||
<th class="table-header-cell">Nhân viên</th>
|
<th class="table-header-cell">Nhân viên</th>
|
||||||
|
<th class="table-header-cell">Phòng ban</th>
|
||||||
<th class="table-header-cell">Đã Nhận</th>
|
<th class="table-header-cell">Đã Nhận</th>
|
||||||
<th class="table-header-cell">Đã Gửi</th>
|
<th class="table-header-cell">Đã Gửi</th>
|
||||||
<th class="table-header-cell">Số dư thẻ</th>
|
<th class="table-header-cell">Số dư thẻ</th>
|
||||||
<th class="table-header-cell">Quyền gửi</th>
|
<th class="table-header-cell">Quyền gửi</th>
|
||||||
|
<th class="table-header-cell">Vai trò</th>
|
||||||
<th class="table-header-cell">Trạng thái</th>
|
<th class="table-header-cell">Trạng thái</th>
|
||||||
<th class="table-header-cell text-right">Thao tác</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-100">
|
<tbody class="bg-white divide-y divide-gray-100">
|
||||||
@forelse($users as $u)
|
@forelse($users as $u)
|
||||||
<tr class="hover:bg-slate-50/60 transition-colors">
|
<tr class="hover:bg-slate-50/60 transition-colors">
|
||||||
|
<td class="table-body-cell font-medium space-x-3">
|
||||||
|
<a href="{{ route('admin.users.edit', $u->msnv) }}" class="table-action-link !text-[#3462f7] hover:!text-blue-800">Chỉnh sửa</a>
|
||||||
|
</td>
|
||||||
<td class="table-body-cell font-bold text-text-dark">{{ $u->msnv }}</td>
|
<td class="table-body-cell font-bold text-text-dark">{{ $u->msnv }}</td>
|
||||||
<td class="table-body-cell">
|
<td class="table-body-cell">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@@ -31,6 +36,20 @@
|
|||||||
<span class="text-xs text-gray-400 mt-0.5">{{ $u->mail }}</span>
|
<span class="text-xs text-gray-400 mt-0.5">{{ $u->mail }}</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="table-body-cell">
|
||||||
|
@php
|
||||||
|
$deptVal = $u->departments;
|
||||||
|
if (is_numeric($deptVal)) {
|
||||||
|
$idx = ((int)$deptVal) - 1;
|
||||||
|
$deptName = config('constants.DEPARTMENTS')[$idx] ?? 'Team';
|
||||||
|
} else {
|
||||||
|
$deptName = $deptVal ?? 'Team';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
<div class="max-w-[200px] truncate font-medium text-gray-600" title="{{ $deptName }}">
|
||||||
|
{{ $deptName }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td class="table-body-cell font-extrabold text-green-600">+{{ $u->total_received }}</td>
|
<td class="table-body-cell font-extrabold text-green-600">+{{ $u->total_received }}</td>
|
||||||
<td class="table-body-cell font-extrabold text-blue-600">{{ $u->total_sent }}</td>
|
<td class="table-body-cell font-extrabold text-blue-600">{{ $u->total_sent }}</td>
|
||||||
<td class="table-body-cell font-extrabold text-orange-500">{{ $u->card }}</td>
|
<td class="table-body-cell font-extrabold text-orange-500">{{ $u->card }}</td>
|
||||||
@@ -42,19 +61,23 @@
|
|||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="table-body-cell">
|
<td class="table-body-cell">
|
||||||
@if($u->status == \App\Models\User::STATUS_ACTIVE)
|
@if($u->role == config('constants.ROLE_ADMIN'))
|
||||||
|
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold rounded-full bg-blue-50 text-blue-700 border border-blue-100">Admin</span>
|
||||||
|
@else
|
||||||
|
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold text-gray-500">Member</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td class="table-body-cell">
|
||||||
|
@if($u->status == config('constants.STATUS_ACTIVE'))
|
||||||
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold rounded-full bg-blue-50 text-blue-700 border border-blue-100">Đang làm việc</span>
|
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold rounded-full bg-blue-50 text-blue-700 border border-blue-100">Đang làm việc</span>
|
||||||
@else
|
@else
|
||||||
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold rounded-full bg-red-50 text-red-700 border border-red-100">Đã nghỉ việc</span>
|
<span class="px-2.5 py-1 inline-flex text-[10px] leading-5 font-bold rounded-full bg-red-50 text-red-700 border border-red-100">Đã nghỉ việc</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="table-body-cell text-right font-medium space-x-3">
|
|
||||||
<a href="{{ route('admin.users.edit', $u->msnv) }}" class="table-action-link !text-[#3462f7] hover:!text-blue-800">Quản lý</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="8" class="px-6 py-10 text-center text-text-light font-medium">Chưa có user nào đang hoạt động.</td>
|
<td colspan="10" class="px-6 py-10 text-center text-text-light font-medium">Chưa có user nào đang hoạt động.</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
@props(['rank', 'name', 'team', 'avatar', 'score', 'isCurrent' => false, 'unit' => 'điểm'])
|
@props(['rank', 'name', 'team', 'avatar', 'score', 'isCurrent' => false, 'unit' => 'điểm'])
|
||||||
|
|
||||||
<div class="flex items-center justify-between py-3 border-b border-gray-50 last:border-0 hover:bg-gray-50 rounded-xl px-3 transition-colors {{ $isCurrent ? 'bg-[#F5F8FF]' : '' }}">
|
<div class="flex items-center justify-between py-3 border-b border-gray-50 last:border-0 hover:bg-gray-50 rounded-xl px-3 transition-colors {{ $isCurrent ? 'bg-[#F5F8FF]' : '' }}">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||||
<!-- Rank -->
|
<!-- Rank -->
|
||||||
<div class="w-6 flex justify-center items-center">
|
<div class="w-6 flex justify-center items-center flex-shrink-0">
|
||||||
@if($rank == 1)
|
@if($rank == 1)
|
||||||
<span class="text-xl">👑</span>
|
<span class="text-xl">👑</span>
|
||||||
<span class="absolute text-[10px] font-bold text-amber-500 translate-y-3">1</span>
|
<span class="absolute text-[10px] font-bold text-amber-500 translate-y-3">1</span>
|
||||||
@@ -17,17 +17,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Avatar & Info -->
|
<!-- Avatar & Info -->
|
||||||
<div class="flex items-center gap-3 ml-1">
|
<div class="flex items-center gap-3 ml-1 min-w-0 flex-1">
|
||||||
<img src="{{ $avatar }}" alt="{{ $name }}" class="w-10 h-10 rounded-full object-cover shadow-sm border border-gray-100">
|
<img src="{{ $avatar }}" alt="{{ $name }}" class="w-10 h-10 rounded-full object-cover shadow-sm border border-gray-100 flex-shrink-0">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col min-w-0 flex-1">
|
||||||
<span class="text-[14px] font-bold {{ $isCurrent ? 'text-[#1a2b49]' : 'text-gray-800' }} leading-tight mb-0.5">{{ $name }}</span>
|
<span class="text-[14px] font-bold {{ $isCurrent ? 'text-[#1a2b49]' : 'text-gray-800' }} leading-tight mb-0.5 truncate">{{ $name }}</span>
|
||||||
<span class="text-[12px] text-gray-500 font-medium">{{ $team }}</span>
|
<span class="text-[12px] text-gray-500 font-medium truncate" title="{{ $team }}">{{ $team }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Score -->
|
<!-- Score -->
|
||||||
<div class="text-[14px]">
|
<div class="text-[14px] flex-shrink-0 ml-3">
|
||||||
<span class="font-extrabold {{ $isCurrent ? 'text-blue-600' : 'text-gray-800' }}">{{ number_format($score, 0, ',', '.') }}</span>
|
<span class="font-extrabold {{ $isCurrent ? 'text-blue-600' : 'text-gray-800' }}">{{ number_format($score, 0, ',', '.') }}</span>
|
||||||
<span class="text-gray-400 font-medium ml-1 text-[13px]">{{ $unit }}</span>
|
<span class="text-gray-400 font-medium ml-1 text-[13px]">{{ $unit }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</x-sidebar-item>
|
</x-sidebar-item>
|
||||||
|
|
||||||
|
|
||||||
@if(Auth::check() && Auth::user()->role == \App\Models\User::ROLE_ADMIN)
|
@if(Auth::check() && Auth::user()->role == config('constants.ROLE_ADMIN'))
|
||||||
<x-sidebar-item href="{{ route('admin.users.index') }}" :active="request()->routeIs('admin.users.index')" icon="users">
|
<x-sidebar-item href="{{ route('admin.users.index') }}" :active="request()->routeIs('admin.users.index')" icon="users">
|
||||||
Quản lý User
|
Quản lý User
|
||||||
</x-sidebar-item>
|
</x-sidebar-item>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-[14px] font-bold text-[#1e293b] leading-tight truncate max-w-[130px]">{{ Auth::check() ? (Auth::user()->name ?? 'Nguyễn Minh Anh') : 'Nguyễn Minh Anh' }}</span>
|
<span class="text-[14px] font-bold text-[#1e293b] leading-tight truncate max-w-[130px]">{{ Auth::check() ? (Auth::user()->name ?? 'Nguyễn Minh Anh') : 'Nguyễn Minh Anh' }}</span>
|
||||||
<span class="text-[12px] text-gray-500 font-medium">{{ Auth::check() ? (Auth::user()->role == \App\Models\User::ROLE_ADMIN ? 'Administrator' : 'Product Team') : 'Product Team' }}</span>
|
<span class="text-[12px] text-gray-500 font-medium">{{ Auth::check() ? (Auth::user()->role == config('constants.ROLE_ADMIN') ? 'Administrator' : 'Product Team') : 'Product Team' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<svg class="w-4 h-4 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" /></svg>
|
<svg class="w-4 h-4 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" /></svg>
|
||||||
|
|||||||
@@ -38,11 +38,9 @@
|
|||||||
<!-- Department Filter -->
|
<!-- Department Filter -->
|
||||||
<select name="department" id="departmentFilter" class="form-input !py-1.5 !text-sm !w-full md:!w-[170px] border-[#d9dfe7] rounded-xl bg-white shrink-0">
|
<select name="department" id="departmentFilter" class="form-input !py-1.5 !text-sm !w-full md:!w-[170px] border-[#d9dfe7] rounded-xl bg-white shrink-0">
|
||||||
<option value="" {{ $department === '' ? 'selected' : '' }}>Tất cả phòng ban</option>
|
<option value="" {{ $department === '' ? 'selected' : '' }}>Tất cả phòng ban</option>
|
||||||
<option value="1" {{ $department === '1' ? 'selected' : '' }}>Phòng Phát Triển (Dev)</option>
|
@foreach(config('constants.DEPARTMENTS') as $dept)
|
||||||
<option value="2" {{ $department === '2' ? 'selected' : '' }}>Phòng Nhân Sự (HR)</option>
|
<option value="{{ $dept }}" {{ $department === $dept ? 'selected' : '' }}>{{ $dept }}</option>
|
||||||
<option value="3" {{ $department === '3' ? 'selected' : '' }}>Phòng Kinh Doanh (Sale)</option>
|
@endforeach
|
||||||
<option value="4" {{ $department === '4' ? 'selected' : '' }}>Ban Giám Đốc (Board)</option>
|
|
||||||
<option value="5" {{ $department === '5' ? 'selected' : '' }}>Phòng Marketing</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- Flag Send Filter -->
|
<!-- Flag Send Filter -->
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<p class="text-xs text-gray-500 font-medium truncate mb-1">{{ $user->mail }}</p>
|
<p class="text-xs text-gray-500 font-medium truncate mb-1">{{ $user->mail }}</p>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="px-2 py-0.5 text-[10px] font-bold rounded-full bg-blue-50 text-blue-700 border border-blue-100">
|
<span class="px-2 py-0.5 text-[10px] font-bold rounded-full bg-blue-50 text-blue-700 border border-blue-100">
|
||||||
{{ $user->role == \App\Models\User::ROLE_ADMIN ? 'Admin' : 'Member' }}
|
{{ $user->role == config('constants.ROLE_ADMIN') ? 'Admin' : 'Member' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs text-gray-300 font-semibold">•</span>
|
<span class="text-xs text-gray-300 font-semibold">•</span>
|
||||||
<span class="text-xs font-bold text-gray-600">Thẻ: <span class="text-orange-500 font-extrabold text-sm">{{ $user->card }}</span></span>
|
<span class="text-xs font-bold text-gray-600">Thẻ: <span class="text-orange-500 font-extrabold text-sm">{{ $user->card }}</span></span>
|
||||||
@@ -105,11 +105,10 @@
|
|||||||
<div class="relative">
|
<div class="relative">
|
||||||
<label class="block text-[14px] font-bold text-[#1a2b49] mb-2" for="departments">Phòng ban <span class="text-red-500">*</span></label>
|
<label class="block text-[14px] font-bold text-[#1a2b49] mb-2" for="departments">Phòng ban <span class="text-red-500">*</span></label>
|
||||||
<select name="departments" id="departments" class="form-input !rounded-xl !focus:border-[#3462f7] !focus:ring-[#3462f7]/20" required>
|
<select name="departments" id="departments" class="form-input !rounded-xl !focus:border-[#3462f7] !focus:ring-[#3462f7]/20" required>
|
||||||
<option value="1" {{ old('departments') == '1' ? 'selected' : '' }}>Phòng Phát Triển (Dev)</option>
|
<option value="">-- Chọn phòng ban --</option>
|
||||||
<option value="2" {{ old('departments') == '2' ? 'selected' : '' }}>Phòng Nhân Sự (HR)</option>
|
@foreach(config('constants.DEPARTMENTS') as $dept)
|
||||||
<option value="3" {{ old('departments') == '3' ? 'selected' : '' }}>Phòng Kinh Doanh (Sale)</option>
|
<option value="{{ $dept }}" {{ old('departments') == $dept ? 'selected' : '' }}>{{ $dept }}</option>
|
||||||
<option value="4" {{ old('departments') == '4' ? 'selected' : '' }}>Ban Giám Đốc (Board)</option>
|
@endforeach
|
||||||
<option value="5" {{ old('departments') == '5' ? 'selected' : '' }}>Phòng Marketing</option>
|
|
||||||
</select>
|
</select>
|
||||||
@error('departments')<span class="text-red-500 text-[13px] font-semibold mt-1.5 block">{{ $message }}</span>@enderror
|
@error('departments')<span class="text-red-500 text-[13px] font-semibold mt-1.5 block">{{ $message }}</span>@enderror
|
||||||
</div>
|
</div>
|
||||||
@@ -131,8 +130,8 @@
|
|||||||
<div class="relative">
|
<div class="relative">
|
||||||
<label class="block text-[14px] font-bold text-[#1a2b49] mb-2" for="role">Quyền hạn <span class="text-red-500">*</span></label>
|
<label class="block text-[14px] font-bold text-[#1a2b49] mb-2" for="role">Quyền hạn <span class="text-red-500">*</span></label>
|
||||||
<select name="role" id="role" class="form-input !rounded-xl !focus:border-[#3462f7] !focus:ring-[#3462f7]/20" required>
|
<select name="role" id="role" class="form-input !rounded-xl !focus:border-[#3462f7] !focus:ring-[#3462f7]/20" required>
|
||||||
<option value="{{ \App\Models\User::ROLE_MEMBER }}" {{ old('role') == \App\Models\User::ROLE_MEMBER ? 'selected' : '' }}>Nhân viên (Member)</option>
|
<option value="{{ config('constants.ROLE_MEMBER') }}" {{ old('role') == config('constants.ROLE_MEMBER') ? 'selected' : '' }}>Nhân viên (Member)</option>
|
||||||
<option value="{{ \App\Models\User::ROLE_ADMIN }}" {{ old('role') == \App\Models\User::ROLE_ADMIN ? 'selected' : '' }}>Quản trị viên (Admin)</option>
|
<option value="{{ config('constants.ROLE_ADMIN') }}" {{ old('role') == config('constants.ROLE_ADMIN') ? 'selected' : '' }}>Quản trị viên (Admin)</option>
|
||||||
</select>
|
</select>
|
||||||
@error('role')<span class="text-red-500 text-[13px] font-semibold mt-1.5 block">{{ $message }}</span>@enderror
|
@error('role')<span class="text-red-500 text-[13px] font-semibold mt-1.5 block">{{ $message }}</span>@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@props(['mode', 'user' => null, 'administrations' => null, 'selectedMonth' => null])
|
@props(['mode', 'user' => null, 'administrations' => null, 'selectedMonth' => null, 'addCards' => null, 'admins' => null])
|
||||||
|
|
||||||
@if($mode === 'self' && $user)
|
@if($mode === 'self' && $user)
|
||||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
|
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
|
||||||
@@ -29,11 +29,114 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- RIGHT PANEL: Transaction History -->
|
<!-- RIGHT PANEL: Transaction History & Add Card History -->
|
||||||
@if(in_array($mode, ['edit', 'delete', 'self']) && $user && $administrations)
|
@if(in_array($mode, ['edit', 'delete', 'self']) && $user && $administrations)
|
||||||
<div class="col-span-1 lg:col-span-2">
|
<div class="col-span-1 lg:col-span-2 flex flex-col gap-6">
|
||||||
<x-transaction-history :mode="$mode" :user="$user" :administrations="$administrations" :selectedMonth="$selectedMonth" />
|
<x-transaction-history :mode="$mode" :user="$user" :administrations="$administrations" :selectedMonth="$selectedMonth" />
|
||||||
|
|
||||||
|
@if($mode === 'edit' && isset($addCards))
|
||||||
|
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] border border-white overflow-hidden flex flex-col">
|
||||||
|
<div class="px-6 py-5 border-b border-gray-100 bg-white">
|
||||||
|
<h3 class="text-[17px] font-extrabold text-[#1a2b49] leading-tight">
|
||||||
|
Lịch sử cấp phát thẻ
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-0 overflow-y-auto max-h-[600px]">
|
||||||
|
<table class="min-w-full divide-y divide-gray-100 text-sm">
|
||||||
|
<thead class="bg-gray-50/50 sticky top-0">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Ngày cấp</th>
|
||||||
|
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Người cấp (Admin)</th>
|
||||||
|
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Số lượng thẻ</th>
|
||||||
|
<th class="px-6 py-4 text-center text-xs font-bold text-text-light uppercase tracking-wider w-24">Hành động</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-100">
|
||||||
|
@forelse($addCards as $addCard)
|
||||||
|
@php
|
||||||
|
$isCurrentMonth = Carbon\Carbon::parse($addCard->date)->format('Y-m') === Carbon\Carbon::now()->format('Y-m');
|
||||||
|
@endphp
|
||||||
|
<tr class="hover:bg-slate-50/60 transition-colors">
|
||||||
|
<td class="px-6 py-3.5 whitespace-nowrap text-text-medium font-medium">{{ Carbon\Carbon::parse($addCard->date)->format('d/m/Y') }}</td>
|
||||||
|
<td class="px-6 py-3.5 whitespace-nowrap font-bold text-[#1a2b49]">
|
||||||
|
@if($addCard->sellerUser)
|
||||||
|
{{ $addCard->sellerUser->name }} <span class="text-xs font-medium text-gray-500">(MSNV: {{ $addCard->seller }})</span>
|
||||||
|
@else
|
||||||
|
MSNV: {{ $addCard->seller }}
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-3.5 whitespace-nowrap font-extrabold text-base text-green-600">+{{ $addCard->num_card }}</td>
|
||||||
|
<td class="px-6 py-3.5 whitespace-nowrap text-center">
|
||||||
|
@if($isCurrentMonth)
|
||||||
|
<button type="button" onclick="openEditAddCardModal({{ json_encode($addCard) }})" class="text-blue-600 hover:text-blue-900 font-bold transition-colors">Sửa</button>
|
||||||
|
@else
|
||||||
|
<span class="text-gray-400 font-semibold text-xs cursor-not-allowed" title="Không thể chỉnh sửa giao dịch tháng trước">Tháng trước</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="px-6 py-12 text-center text-text-light font-medium text-base">
|
||||||
|
Chưa có lịch sử cấp phát thẻ nào.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if($mode === 'edit' && isset($addCards) && isset($admins))
|
||||||
|
<x-modal id="editAddCardModal" title="Chỉnh sửa giao dịch cấp phát thẻ">
|
||||||
|
<form id="editAddCardForm" method="POST" action="">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="modal_num_card" class="block text-sm font-bold text-gray-700 mb-2">Số lượng card</label>
|
||||||
|
<input type="number" id="modal_num_card" name="num_card" min="1" required class="w-full border border-gray-300 rounded-xl px-4 py-2.5 text-sm focus:border-blue-500 focus:ring focus:ring-blue-200 outline-none transition-all">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="modal_seller" class="block text-sm font-bold text-gray-700 mb-2">Người cấp (Admin)</label>
|
||||||
|
<select id="modal_seller" name="seller" required class="w-full border border-gray-300 rounded-xl px-4 py-2.5 text-sm focus:border-blue-500 focus:ring focus:ring-blue-200 outline-none transition-all">
|
||||||
|
@foreach($admins as $admin)
|
||||||
|
<option value="{{ $admin->msnv }}">{{ $admin->name }} (MSNV: {{ $admin->msnv }})</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="modal_date" class="block text-sm font-bold text-gray-700 mb-2">Ngày cấp</label>
|
||||||
|
<input type="date" id="modal_date" name="date" required min="{{ Carbon\Carbon::now()->startOfMonth()->format('Y-m-d') }}" max="{{ Carbon\Carbon::now()->endOfMonth()->format('Y-m-d') }}" class="w-full border border-gray-300 rounded-xl px-4 py-2.5 text-sm focus:border-blue-500 focus:ring focus:ring-blue-200 outline-none transition-all">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-3 pt-4 border-t border-gray-100">
|
||||||
|
<button type="button" onclick="closeModal('editAddCardModal')" class="btn-secondary !px-5">Hủy bỏ</button>
|
||||||
|
<button type="submit" class="btn-primary !px-5 bg-[#3462f7] hover:bg-blue-700">Lưu thay đổi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-modal>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openEditAddCardModal(record) {
|
||||||
|
const form = document.getElementById('editAddCardForm');
|
||||||
|
form.action = `/admin/add-cards/${record.id}`;
|
||||||
|
|
||||||
|
document.getElementById('modal_num_card').value = record.num_card;
|
||||||
|
document.getElementById('modal_seller').value = record.seller;
|
||||||
|
|
||||||
|
if (record.date) {
|
||||||
|
document.getElementById('modal_date').value = record.date.substring(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
openModal('editAddCardModal');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
|||||||
@@ -37,6 +37,16 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded relative">
|
||||||
|
<ul class="list-disc pl-5">
|
||||||
|
@foreach($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@yield('content')
|
@yield('content')
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<form action="{{ route('user.update_password') }}" method="POST">
|
<form action="{{ route('user.update_password') }}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
@if(Auth::user()->first_login == \App\Models\User::FIRST_LOGIN_TRUE)
|
@if(Auth::user()->first_login == config('constants.FIRST_LOGIN_TRUE'))
|
||||||
<div class="p-4 bg-amber-50/70 border border-amber-100 text-amber-800 rounded-2xl text-xs font-medium leading-relaxed flex items-start gap-2 shadow-sm">
|
<div class="p-4 bg-amber-50/70 border border-amber-100 text-amber-800 rounded-2xl text-xs font-medium leading-relaxed flex items-start gap-2 shadow-sm">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 shrink-0 text-amber-600">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 shrink-0 text-amber-600">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-3 pt-4">
|
<div class="flex items-center gap-3 pt-4">
|
||||||
@if(Auth::user()->first_login != \App\Models\User::FIRST_LOGIN_TRUE)
|
@if(Auth::user()->first_login != config('constants.FIRST_LOGIN_TRUE'))
|
||||||
<a href="{{ route('user.dashboard') }}" class="cursor-pointer flex-1 flex items-center justify-center h-[46px] rounded-xl border border-gray-200 bg-white hover:bg-gray-50 text-gray-600 text-[14px] font-bold shadow-sm transition-all duration-200">Hủy bỏ</a>
|
<a href="{{ route('user.dashboard') }}" class="cursor-pointer flex-1 flex items-center justify-center h-[46px] rounded-xl border border-gray-200 bg-white hover:bg-gray-50 text-gray-600 text-[14px] font-bold shadow-sm transition-all duration-200">Hủy bỏ</a>
|
||||||
@endif
|
@endif
|
||||||
<button type="submit" class="cursor-pointer flex-1 flex items-center justify-center h-[46px] rounded-xl bg-[#3462f7] hover:bg-[#254edb] text-white text-[14px] font-bold shadow-md shadow-blue-500/10 transition-all duration-200">Xác nhận đổi mật khẩu</button>
|
<button type="submit" class="cursor-pointer flex-1 flex items-center justify-center h-[46px] rounded-xl bg-[#3462f7] hover:bg-[#254edb] text-white text-[14px] font-bold shadow-md shadow-blue-500/10 transition-all duration-200">Xác nhận đổi mật khẩu</button>
|
||||||
|
|||||||
@@ -2,17 +2,19 @@
|
|||||||
@if(count($rankers) > 0)
|
@if(count($rankers) > 0)
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@foreach($rankers as $item)
|
@foreach($rankers as $item)
|
||||||
|
@php
|
||||||
|
$deptVal = $item->departments;
|
||||||
|
if (is_numeric($deptVal)) {
|
||||||
|
$idx = ((int)$deptVal) - 1;
|
||||||
|
$teamName = config('constants.DEPARTMENTS')[$idx] ?? 'Team';
|
||||||
|
} else {
|
||||||
|
$teamName = $deptVal ?? 'Team';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
<x-ranking-item
|
<x-ranking-item
|
||||||
rank="{{ $item->rank }}"
|
rank="{{ $item->rank }}"
|
||||||
name="{{ $item->name }}"
|
name="{{ $item->name }}"
|
||||||
team="{{ match((int) $item->departments) {
|
team="{{ $teamName }}"
|
||||||
1 => 'Dev Team',
|
|
||||||
2 => 'HR Team',
|
|
||||||
3 => 'Sale Team',
|
|
||||||
4 => 'Board Team',
|
|
||||||
5 => 'Marketing Team',
|
|
||||||
default => 'Team'
|
|
||||||
} }}"
|
|
||||||
avatar="{{ $item->avatar ?? 'https://api.dicebear.com/7.x/notionists/svg?seed=' . urlencode($item->name) . '&backgroundColor=bfdbfe' }}"
|
avatar="{{ $item->avatar ?? 'https://api.dicebear.com/7.x/notionists/svg?seed=' . urlencode($item->name) . '&backgroundColor=bfdbfe' }}"
|
||||||
score="{{ $item->score }}"
|
score="{{ $item->score }}"
|
||||||
unit="thẻ"
|
unit="thẻ"
|
||||||
@@ -30,17 +32,19 @@
|
|||||||
@if($currentUserRankItem)
|
@if($currentUserRankItem)
|
||||||
<div class="mt-auto">
|
<div class="mt-auto">
|
||||||
<div class="my-3 border-t border-dashed border-gray-100 mx-2"></div>
|
<div class="my-3 border-t border-dashed border-gray-100 mx-2"></div>
|
||||||
|
@php
|
||||||
|
$currDeptVal = $currentUserRankItem->departments;
|
||||||
|
if (is_numeric($currDeptVal)) {
|
||||||
|
$idx = ((int)$currDeptVal) - 1;
|
||||||
|
$currTeamName = config('constants.DEPARTMENTS')[$idx] ?? 'Team';
|
||||||
|
} else {
|
||||||
|
$currTeamName = $currDeptVal ?? 'Team';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
<x-ranking-item
|
<x-ranking-item
|
||||||
rank="{{ $currentUserRankItem->rank > 0 ? $currentUserRankItem->rank : '-' }}"
|
rank="{{ $currentUserRankItem->rank > 0 ? $currentUserRankItem->rank : '-' }}"
|
||||||
name="{{ $currentUserRankItem->name }}"
|
name="{{ $currentUserRankItem->name }}"
|
||||||
team="{{ match((int) $currentUserRankItem->departments) {
|
team="{{ $currTeamName }}"
|
||||||
1 => 'Dev Team',
|
|
||||||
2 => 'HR Team',
|
|
||||||
3 => 'Sale Team',
|
|
||||||
4 => 'Board Team',
|
|
||||||
5 => 'Marketing Team',
|
|
||||||
default => 'Team'
|
|
||||||
} }}"
|
|
||||||
avatar="{{ $currentUserRankItem->avatar ?? 'https://api.dicebear.com/7.x/notionists/svg?seed=' . urlencode($currentUserRankItem->name) . '&backgroundColor=bfdbfe' }}"
|
avatar="{{ $currentUserRankItem->avatar ?? 'https://api.dicebear.com/7.x/notionists/svg?seed=' . urlencode($currentUserRankItem->name) . '&backgroundColor=bfdbfe' }}"
|
||||||
score="{{ $currentUserRankItem->score }}"
|
score="{{ $currentUserRankItem->score }}"
|
||||||
unit="thẻ"
|
unit="thẻ"
|
||||||
|
|||||||
@@ -13,5 +13,7 @@ Route::middleware(['auth', 'force_change_password', 'admin'])->prefix('admin')->
|
|||||||
Route::put('/users/{msnv}', [AdminController::class, 'update'])->name('users.update');
|
Route::put('/users/{msnv}', [AdminController::class, 'update'])->name('users.update');
|
||||||
Route::delete('/users/{msnv}', [AdminController::class, 'destroy'])->name('users.destroy');
|
Route::delete('/users/{msnv}', [AdminController::class, 'destroy'])->name('users.destroy');
|
||||||
|
|
||||||
|
Route::put('/add-cards/{id}', [AdminController::class, 'updateAddCard'])->name('add_cards.update');
|
||||||
|
|
||||||
Route::post('/reset-cards', [AdminController::class, 'resetCards'])->name('reset_cards');
|
Route::post('/reset-cards', [AdminController::class, 'resetCards'])->name('reset_cards');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'usera@example.com',
|
'mail' => 'usera@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$userB = User::create([
|
$userB = User::create([
|
||||||
@@ -43,11 +43,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'userb@example.com',
|
'mail' => 'userb@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$selectedMonth = '2026-07';
|
$selectedMonth = '2026-07';
|
||||||
@@ -110,11 +110,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'usera@example.com',
|
'mail' => 'usera@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$selectedMonth = '2026-07';
|
$selectedMonth = '2026-07';
|
||||||
@@ -167,11 +167,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'alpha@example.com',
|
'mail' => 'alpha@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
User::create([
|
User::create([
|
||||||
@@ -180,11 +180,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'beta@example.com',
|
'mail' => 'beta@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 2. Fetch statistics via AdminService with search for '2001' (msnv)
|
// 2. Fetch statistics via AdminService with search for '2001' (msnv)
|
||||||
@@ -211,11 +211,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'active@example.com',
|
'mail' => 'active@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
User::create([
|
User::create([
|
||||||
@@ -224,11 +224,11 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'mail' => 'inactive@example.com',
|
'mail' => 'inactive@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_INACTIVE,
|
'status' => config('constants.STATUS_INACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_DISABLED,
|
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 2. Fetch statistics via AdminService with status = '1'
|
// 2. Fetch statistics via AdminService with status = '1'
|
||||||
@@ -252,12 +252,12 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'name' => 'ADMIN DEV ENABLED',
|
'name' => 'ADMIN DEV ENABLED',
|
||||||
'mail' => 'admin_dev@example.com',
|
'mail' => 'admin_dev@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => config('constants.DEPARTMENTS')[0],
|
||||||
'role' => User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
User::create([
|
User::create([
|
||||||
@@ -265,12 +265,12 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
'name' => 'MEMBER HR DISABLED',
|
'name' => 'MEMBER HR DISABLED',
|
||||||
'mail' => 'member_hr@example.com',
|
'mail' => 'member_hr@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 2,
|
'departments' => config('constants.DEPARTMENTS')[13],
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_DISABLED,
|
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Filter by role = Admin ('1')
|
// Filter by role = Admin ('1')
|
||||||
@@ -279,8 +279,8 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
$this->assertTrue($users->contains('msnv', 4001));
|
$this->assertTrue($users->contains('msnv', 4001));
|
||||||
$this->assertFalse($users->contains('msnv', 4002));
|
$this->assertFalse($users->contains('msnv', 4002));
|
||||||
|
|
||||||
// Filter by department = HR ('2')
|
// Filter by department = HR (config('constants.DEPARTMENTS')[13])
|
||||||
$stats2 = $this->adminService->getUserListWithStats('2026-07', null, '1', null, '2');
|
$stats2 = $this->adminService->getUserListWithStats('2026-07', null, '1', null, config('constants.DEPARTMENTS')[13]);
|
||||||
$users2 = collect($stats2['users']->items());
|
$users2 = collect($stats2['users']->items());
|
||||||
$this->assertTrue($users2->contains('msnv', 4002));
|
$this->assertTrue($users2->contains('msnv', 4002));
|
||||||
$this->assertFalse($users2->contains('msnv', 4001));
|
$this->assertFalse($users2->contains('msnv', 4001));
|
||||||
@@ -291,4 +291,483 @@ class AdminUserListStatsTest extends TestCase
|
|||||||
$this->assertTrue($users3->contains('msnv', 4001));
|
$this->assertTrue($users3->contains('msnv', 4001));
|
||||||
$this->assertFalse($users3->contains('msnv', 4002));
|
$this->assertFalse($users3->contains('msnv', 4002));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_admin_can_update_user_fields_including_card_role_status_flag_send_first_login(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 5,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.users.update', 9002), [
|
||||||
|
'card' => 20, // increased by 15
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_INACTIVE'),
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_TRUE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
|
||||||
|
$member->refresh();
|
||||||
|
$this->assertEquals(20, $member->card);
|
||||||
|
$this->assertEquals(config('constants.ROLE_ADMIN'), $member->role);
|
||||||
|
$this->assertEquals(config('constants.STATUS_INACTIVE'), $member->status);
|
||||||
|
$this->assertEquals(config('constants.FLAG_SEND_DISABLED'), $member->flag_send);
|
||||||
|
$this->assertEquals(config('constants.FIRST_LOGIN_TRUE'), $member->first_login);
|
||||||
|
|
||||||
|
// Assert AddCard record was created with diff (15)
|
||||||
|
$this->assertDatabaseHas('add_card', [
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 15,
|
||||||
|
'seller' => 9001,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_user_list_stats_handles_ties_for_top_sender_receiver(): void
|
||||||
|
{
|
||||||
|
// Clear existing mock data first to have a clean slate for ties
|
||||||
|
User::truncate();
|
||||||
|
Administration::truncate();
|
||||||
|
|
||||||
|
// 1. Create three users
|
||||||
|
$user1 = User::create([
|
||||||
|
'msnv' => 3001,
|
||||||
|
'name' => 'User One',
|
||||||
|
'mail' => 'user1@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => config('constants.DEPARTMENTS')[0],
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user2 = User::create([
|
||||||
|
'msnv' => 3002,
|
||||||
|
'name' => 'User Two',
|
||||||
|
'mail' => 'user2@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => config('constants.DEPARTMENTS')[0],
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user3 = User::create([
|
||||||
|
'msnv' => 3003,
|
||||||
|
'name' => 'User Three',
|
||||||
|
'mail' => 'user3@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => config('constants.DEPARTMENTS')[0],
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$selectedMonth = '2026-07';
|
||||||
|
$testDate = '2026-07-15';
|
||||||
|
|
||||||
|
// User 1 sends 5 cards to User 2
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => 3001,
|
||||||
|
'received' => 0,
|
||||||
|
'sender' => null,
|
||||||
|
'sent' => 5,
|
||||||
|
'receiver' => 3002,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => 3002,
|
||||||
|
'received' => 5,
|
||||||
|
'sender' => 3001,
|
||||||
|
'sent' => 0,
|
||||||
|
'receiver' => null,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// User 3 sends 5 cards to User 1
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => 3003,
|
||||||
|
'received' => 0,
|
||||||
|
'sender' => null,
|
||||||
|
'sent' => 5,
|
||||||
|
'receiver' => 3001,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => 3001,
|
||||||
|
'received' => 5,
|
||||||
|
'sender' => 3003,
|
||||||
|
'sent' => 0,
|
||||||
|
'receiver' => null,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Now:
|
||||||
|
// User 1 has sent = 5, received = 5
|
||||||
|
// User 2 has sent = 0, received = 5
|
||||||
|
// User 3 has sent = 5, received = 0
|
||||||
|
// Top senders should be: User 1 and User 3 (both sent 5)
|
||||||
|
// Top receivers should be: User 1 and User 2 (both received 5)
|
||||||
|
|
||||||
|
$stats = $this->adminService->getUserListWithStats($selectedMonth);
|
||||||
|
|
||||||
|
$this->assertCount(2, $stats['topReceivedUsers']);
|
||||||
|
$this->assertCount(2, $stats['topSentUsers']);
|
||||||
|
|
||||||
|
$topReceivedMsnvs = $stats['topReceivedUsers']->pluck('msnv')->toArray();
|
||||||
|
$this->assertContains(3001, $topReceivedMsnvs);
|
||||||
|
$this->assertContains(3002, $topReceivedMsnvs);
|
||||||
|
|
||||||
|
$topSentMsnvs = $stats['topSentUsers']->pluck('msnv')->toArray();
|
||||||
|
$this->assertContains(3001, $topSentMsnvs);
|
||||||
|
$this->assertContains(3003, $topSentMsnvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_user_list_stats_handles_10_way_tie_for_top_sender_receiver(): void
|
||||||
|
{
|
||||||
|
$users = [];
|
||||||
|
$selectedMonth = '2026-07';
|
||||||
|
$testDate = '2026-07-15';
|
||||||
|
|
||||||
|
// Create 10 users
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
$users[$i] = User::create([
|
||||||
|
'msnv' => 5000 + $i,
|
||||||
|
'name' => "User Tenfold {$i}",
|
||||||
|
'mail' => "user_tenfold_{$i}@example.com",
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => config('constants.DEPARTMENTS')[0],
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each user sends 1 card to the next user, and user 10 sends to user 1
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
$senderMsnv = 5000 + $i;
|
||||||
|
$receiverMsnv = 5000 + ($i % 10 + 1);
|
||||||
|
|
||||||
|
// Sender record
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => $senderMsnv,
|
||||||
|
'received' => 0,
|
||||||
|
'sender' => null,
|
||||||
|
'sent' => 1,
|
||||||
|
'receiver' => $receiverMsnv,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Receiver record
|
||||||
|
Administration::create([
|
||||||
|
'msnv' => $receiverMsnv,
|
||||||
|
'received' => 1,
|
||||||
|
'sender' => $senderMsnv,
|
||||||
|
'sent' => 0,
|
||||||
|
'receiver' => null,
|
||||||
|
'date' => $testDate,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the service call
|
||||||
|
$stats = $this->adminService->getUserListWithStats($selectedMonth);
|
||||||
|
|
||||||
|
// Assert all 10 users are returned in topReceivedUsers and topSentUsers
|
||||||
|
$this->assertCount(10, $stats['topReceivedUsers']);
|
||||||
|
$this->assertCount(10, $stats['topSentUsers']);
|
||||||
|
|
||||||
|
// Verify all their MSNVs are present
|
||||||
|
for ($i = 1; $i <= 10; $i++) {
|
||||||
|
$msnv = 5000 + $i;
|
||||||
|
$this->assertContains($msnv, $stats['topReceivedUsers']->pluck('msnv')->toArray());
|
||||||
|
$this->assertContains($msnv, $stats['topSentUsers']->pluck('msnv')->toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_add_card_successfully_updates_balance(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10, // currently has 10 cards
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Created in the current month
|
||||||
|
$addCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 5,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Action: Update it from 5 to 3 (decrease of 2, new user balance should be 10 - 2 = 8)
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.add_cards.update', $addCard->id), [
|
||||||
|
'num_card' => 3,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
|
||||||
|
$addCard->refresh();
|
||||||
|
$this->assertEquals(3, $addCard->num_card);
|
||||||
|
|
||||||
|
$member->refresh();
|
||||||
|
$this->assertEquals(8, $member->card);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_add_card_fails_if_past_month(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Created in a past month
|
||||||
|
$addCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 5,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->subMonth()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.add_cards.update', $addCard->id), [
|
||||||
|
'num_card' => 3,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
$response->assertSessionHasErrors('error');
|
||||||
|
$this->assertTrue(session('errors')->has('error'));
|
||||||
|
$this->assertEquals('Không cho phép chỉnh sửa dữ liệu card của các tháng trước.', session('errors')->first('error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_add_card_fails_if_new_date_not_current_month(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Created in current month
|
||||||
|
$addCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 5,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update with date in a past month
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.add_cards.update', $addCard->id), [
|
||||||
|
'num_card' => 3,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->subMonth()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
$response->assertSessionHasErrors('error');
|
||||||
|
$this->assertEquals('Chỉ được phép chỉnh sửa dữ liệu của tháng hiện tại.', session('errors')->first('error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_add_card_fails_if_new_balance_negative(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 2, // has 2 cards left
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Created in current month
|
||||||
|
$addCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 5,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Decrease it from 5 to 1 (decrease of 4). Since member only has 2 cards, this would make balance -2 (2 - 4 = -2), which is illegal
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.add_cards.update', $addCard->id), [
|
||||||
|
'num_card' => 1,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
$response->assertSessionHasErrors('error');
|
||||||
|
$this->assertEquals('Số lượng card cập nhật không hợp lệ vì tổng số card của user không được nhỏ hơn 0.', session('errors')->first('error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_add_card_succeeds_for_older_transaction_in_current_month(): void
|
||||||
|
{
|
||||||
|
$admin = User::create([
|
||||||
|
'msnv' => 9001,
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'mail' => 'admin@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 10,
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$member = User::create([
|
||||||
|
'msnv' => 9002,
|
||||||
|
'name' => 'Member User',
|
||||||
|
'mail' => 'member@example.com',
|
||||||
|
'pass' => md5('password'),
|
||||||
|
'departments' => 1,
|
||||||
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
|
'card' => 15, // has 15 cards
|
||||||
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Transaction 1 (older)
|
||||||
|
$oldAddCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 5,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Transaction 2 (newest)
|
||||||
|
$newAddCard = \App\Models\AddCard::create([
|
||||||
|
'buyer' => 9002,
|
||||||
|
'num_card' => 10,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Try to update older Transaction 1: change num_card from 5 to 6 (increase of 1)
|
||||||
|
$response = $this->actingAs($admin)->put(route('admin.add_cards.update', $oldAddCard->id), [
|
||||||
|
'num_card' => 6,
|
||||||
|
'seller' => 9001,
|
||||||
|
'date' => Carbon::now()->format('Y-m-d'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
$response->assertSessionHasNoErrors();
|
||||||
|
|
||||||
|
$oldAddCard->refresh();
|
||||||
|
$this->assertEquals(6, $oldAddCard->num_card);
|
||||||
|
|
||||||
|
$member->refresh();
|
||||||
|
$this->assertEquals(16, $member->card);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'test@example.com',
|
'mail' => 'test@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->post('/login', [
|
$response = $this->post('/login', [
|
||||||
@@ -88,11 +88,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'test@example.com',
|
'mail' => 'test@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_INACTIVE, // 0
|
'status' => config('constants.STATUS_INACTIVE'), // 0
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->post('/login', [
|
$response = $this->post('/login', [
|
||||||
@@ -128,11 +128,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'member@example.com',
|
'mail' => 'member@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->post('/login', [
|
$response = $this->post('/login', [
|
||||||
@@ -153,11 +153,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'admin@example.com',
|
'mail' => 'admin@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response2 = $this->post('/login', [
|
$response2 = $this->post('/login', [
|
||||||
@@ -180,11 +180,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'first@example.com',
|
'mail' => 'first@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_TRUE,
|
'first_login' => config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->post('/login', [
|
$response = $this->post('/login', [
|
||||||
@@ -205,11 +205,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'first_admin@example.com',
|
'mail' => 'first_admin@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_TRUE,
|
'first_login' => config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->post('/login', [
|
$response = $this->post('/login', [
|
||||||
@@ -233,11 +233,11 @@ class LoginNotificationTest extends TestCase
|
|||||||
'mail' => 'test@example.com',
|
'mail' => 'test@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// First 5 attempts fail
|
// First 5 attempts fail
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ class PasswordMd5Test extends TestCase
|
|||||||
'mail' => 'test@example.com',
|
'mail' => 'test@example.com',
|
||||||
'pass' => md5('old_password'),
|
'pass' => md5('old_password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_TRUE,
|
'first_login' => config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->userService->updatePassword($user, 'new_secret_password');
|
$this->userService->updatePassword($user, 'new_secret_password');
|
||||||
@@ -42,7 +42,7 @@ class PasswordMd5Test extends TestCase
|
|||||||
$user->refresh();
|
$user->refresh();
|
||||||
|
|
||||||
$this->assertEquals(md5('new_secret_password'), $user->pass);
|
$this->assertEquals(md5('new_secret_password'), $user->pass);
|
||||||
$this->assertEquals(User::FIRST_LOGIN_FALSE, $user->first_login);
|
$this->assertEquals(config('constants.FIRST_LOGIN_FALSE'), $user->first_login);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_admin_service_create_user_stores_password_as_md5(): void
|
public function test_admin_service_create_user_stores_password_as_md5(): void
|
||||||
@@ -53,7 +53,7 @@ class PasswordMd5Test extends TestCase
|
|||||||
'mail' => 'created@example.com',
|
'mail' => 'created@example.com',
|
||||||
'departments' => 2,
|
'departments' => 2,
|
||||||
'password' => 'admin_created_pass',
|
'password' => 'admin_created_pass',
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->adminService->createUser($data);
|
$this->adminService->createUser($data);
|
||||||
@@ -62,6 +62,6 @@ class PasswordMd5Test extends TestCase
|
|||||||
|
|
||||||
$this->assertNotNull($user);
|
$this->assertNotNull($user);
|
||||||
$this->assertEquals(md5('admin_created_pass'), $user->pass);
|
$this->assertEquals(md5('admin_created_pass'), $user->pass);
|
||||||
$this->assertEquals(User::FIRST_LOGIN_TRUE, $user->first_login);
|
$this->assertEquals(config('constants.FIRST_LOGIN_TRUE'), $user->first_login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class PasswordValidationTest extends TestCase
|
|||||||
'mail' => 'test@example.com',
|
'mail' => 'test@example.com',
|
||||||
'pass' => md5('password123'),
|
'pass' => md5('password123'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_TRUE,
|
'first_login' => config('constants.FIRST_LOGIN_TRUE'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ class SendThankCardTest extends TestCase
|
|||||||
'mail' => 'sender@example.com',
|
'mail' => 'sender@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->receiver = User::create([
|
$this->receiver = User::create([
|
||||||
@@ -41,11 +41,11 @@ class SendThankCardTest extends TestCase
|
|||||||
'mail' => 'receiver@example.com',
|
'mail' => 'receiver@example.com',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 0,
|
'card' => 0,
|
||||||
'flag_send' => User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'admin@runsystem.net',
|
'mail' => 'admin@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_ADMIN,
|
'role' => config('constants.ROLE_ADMIN'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -46,11 +46,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'usera@runsystem.net',
|
'mail' => 'usera@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user2 = \App\Models\User::create([
|
$user2 = \App\Models\User::create([
|
||||||
@@ -59,11 +59,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'userb@runsystem.net',
|
'mail' => 'userb@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 2,
|
'departments' => 2,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\App\Models\Administration::create([
|
\App\Models\Administration::create([
|
||||||
@@ -101,11 +101,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'usera@runsystem.net',
|
'mail' => 'usera@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@@ -126,11 +126,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => "user{$char}@runsystem.net",
|
'mail' => "user{$char}@runsystem.net",
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\App\Models\Administration::create([
|
\App\Models\Administration::create([
|
||||||
@@ -163,11 +163,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'active@runsystem.net',
|
'mail' => 'active@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$inactiveUser = \App\Models\User::create([
|
$inactiveUser = \App\Models\User::create([
|
||||||
@@ -176,11 +176,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'inactive@runsystem.net',
|
'mail' => 'inactive@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_INACTIVE,
|
'status' => config('constants.STATUS_INACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\App\Models\Administration::create([
|
\App\Models\Administration::create([
|
||||||
@@ -218,11 +218,11 @@ class UserDashboardLayoutTest extends TestCase
|
|||||||
'mail' => 'usera@runsystem.net',
|
'mail' => 'usera@runsystem.net',
|
||||||
'pass' => md5('password'),
|
'pass' => md5('password'),
|
||||||
'departments' => 1,
|
'departments' => 1,
|
||||||
'role' => \App\Models\User::ROLE_MEMBER,
|
'role' => config('constants.ROLE_MEMBER'),
|
||||||
'status' => \App\Models\User::STATUS_ACTIVE,
|
'status' => config('constants.STATUS_ACTIVE'),
|
||||||
'card' => 10,
|
'card' => 10,
|
||||||
'flag_send' => \App\Models\User::FLAG_SEND_ENABLED,
|
'flag_send' => config('constants.FLAG_SEND_ENABLED'),
|
||||||
'first_login' => \App\Models\User::FIRST_LOGIN_FALSE,
|
'first_login' => config('constants.FIRST_LOGIN_FALSE'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\App\Models\Administration::create([
|
\App\Models\Administration::create([
|
||||||
|
|||||||
Reference in New Issue
Block a user