select box

This commit is contained in:
antv
2026-07-13 16:28:44 +07:00
parent f0a25b840c
commit 47a8892623
24 changed files with 889 additions and 302 deletions
@@ -146,6 +146,31 @@ class AdminController extends Controller
}
}
/**
* Delete card allocation history record.
*/
public function destroyAddCard(Request $request, int $id)
{
try {
$this->adminService->destroyAddCard($id);
if ($request->expectsJson()) {
return response()->json([
'success' => true,
'message' => 'Xóa lịch sử cấp phát thẻ thành công.',
]);
}
return redirect()->back()->with('success', 'Xóa lịch sử cấp phát thẻ thành công.');
} catch (\Exception $e) {
if ($request->expectsJson()) {
return response()->json([
'success' => false,
'message' => $e->getMessage(),
], 422);
}
return redirect()->back()->withErrors(['error' => $e->getMessage()]);
}
}
/**
* Reset all cards for active users.
*/
+2 -2
View File
@@ -116,8 +116,8 @@ class UserController extends Controller
$this->userService->updateProfile(
$user,
$request->file('avatar'),
$request->filled('new_password') ? $request->input('new_password') : null
$request->validated(),
$request->file('avatar')
);
return redirect()->route('user.edit')->with('success', 'Cập nhật hồ sơ thành công');
@@ -29,6 +29,8 @@ class UpdateUserRequest extends FormRequest
*/
public function rules(): array
{
$msnv = $this->route('msnv');
return [
'card' => 'nullable|integer|min:0',
'num_card' => 'nullable|integer|min:1',
@@ -36,6 +38,12 @@ class UpdateUserRequest extends FormRequest
'status' => 'nullable|in:' . config('constants.STATUS_INACTIVE') . ',' . config('constants.STATUS_ACTIVE'),
'flag_send' => 'nullable|in:0,1',
'first_login' => 'nullable|in:' . config('constants.FIRST_LOGIN_FALSE') . ',' . config('constants.FIRST_LOGIN_TRUE'),
// Editable basic info
'name' => 'sometimes|required|string|max:255',
'mail' => 'sometimes|required|email|unique:user,mail,' . $msnv . ',msnv',
'departments' => 'sometimes|required|string|in:' . implode(',', config('constants.DEPARTMENTS')),
'avatar' => 'nullable|image|max:2048',
];
}
}
@@ -20,8 +20,35 @@ class UpdateProfileRequest extends FormRequest
public function rules(): array
{
return [
'avatar' => 'nullable|image|max:2048', // 2MB max
'new_password' => 'nullable|min:6|confirmed',
'name' => 'required|string|max:255',
'avatar' => 'nullable|image|max:2048', // 2MB max
'current_password' => [
'nullable',
'required_with:new_password',
function ($attribute, $value, $fail) {
if ($value && md5($value) !== auth()->user()->pass) {
$fail('Mật khẩu hiện tại không chính xác.');
}
},
],
'new_password' => 'nullable|min:6|confirmed|different:current_password',
];
}
/**
* Get the error messages for the defined validation rules.
*/
public function messages(): array
{
return [
'name.required' => 'Họ và tên không được để trống.',
'name.string' => 'Họ và tên phải là chuỗi ký tự.',
'name.max' => 'Họ và tên không được vượt quá 255 ký tự.',
'avatar.image' => 'Ảnh đại diện phải là tệp ảnh.',
'avatar.max' => 'Ảnh đại diện không được vượt quá 2MB.',
'new_password.min' => 'Mật khẩu mới phải có ít nhất 6 ký tự.',
'new_password.confirmed' => 'Mật khẩu xác nhận không trùng khớp.',
'new_password.different' => 'Mật khẩu mới phải khác mật khẩu hiện tại.',
];
}
}
+85 -11
View File
@@ -16,6 +16,9 @@ use App\DTOs\UserFilterDto;
class AdminService implements AdminServiceInterface
{
public function __construct(
private readonly \App\Services\User\Contracts\UserServiceInterface $userService
) {}
public function getUserListWithStats(
string|UserFilterDto $monthOrFilters,
?string $search = null,
@@ -136,6 +139,19 @@ class AdminService implements AdminServiceInterface
: User::where('msnv', $userOrMsnv)->firstOrFail();
DB::transaction(function () use ($data, $user) {
// Update profile fields (name & avatar) via UserService
$this->userService->updateProfile($user, [
'name' => $data['name'] ?? null,
], request()->file('avatar'));
if (isset($data['mail'])) {
$user->mail = $data['mail'];
}
if (isset($data['departments'])) {
$user->departments = $data['departments'];
}
$newCard = $user->card;
if (isset($data['num_card'])) {
$newCard = $user->card + intval($data['num_card']);
@@ -147,12 +163,21 @@ class AdminService implements AdminServiceInterface
if ($newCard > $oldCard) {
$diff = $newCard - $oldCard;
AddCard::create([
'buyer' => $user->msnv,
'num_card' => $diff,
'seller' => Auth::user()->msnv,
'date' => Carbon::today(),
]);
$todayRecord = AddCard::where('buyer', $user->msnv)
->where('seller', Auth::user()->msnv)
->whereDate('date', Carbon::today())
->first();
if ($todayRecord) {
$todayRecord->num_card += $diff;
$todayRecord->save();
} else {
AddCard::create([
'buyer' => $user->msnv,
'num_card' => $diff,
'seller' => Auth::user()->msnv,
'date' => Carbon::today(),
]);
}
}
$user->card = $newCard;
@@ -173,14 +198,16 @@ class AdminService implements AdminServiceInterface
public function resetAllCards(): void
{
User::where('status', config('constants.STATUS_ACTIVE'))->update(['card' => 0]);
User::where('status', config('constants.STATUS_ACTIVE'))->update([
'card' => 0,
'flag_send' => config('constants.FLAG_SEND_DISABLED'),
]);
}
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');
@@ -195,15 +222,25 @@ class AdminService implements AdminServiceInterface
$user = User::where('msnv', $addCard->buyer)->firstOrFail();
DB::transaction(function () use ($addCard, $user, $data) {
$startOfMonth = Carbon::now()->startOfMonth();
$endOfMonth = Carbon::now()->endOfMonth();
$totalSentThisMonth = Administration::where('msnv', $user->msnv)
->whereBetween('date', [$startOfMonth, $endOfMonth])
->sum('sent');
DB::transaction(function () use ($addCard, $user, $data, $totalSentThisMonth) {
$oldNumCard = intval($addCard->num_card);
$newNumCard = intval($data['num_card']);
$diff = $newNumCard - $oldNumCard;
if ($user->card + $diff < 0) {
$newCardBalance = $user->card + $diff;
if ($newCardBalance < 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.');
}
if ($newCardBalance < $totalSentThisMonth) {
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 số card đã gửi trong tháng (' . $totalSentThisMonth . ' card).');
}
$user->card += $diff;
$user->save();
@@ -214,6 +251,43 @@ class AdminService implements AdminServiceInterface
});
}
public function destroyAddCard(int $id): 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 xóa dữ liệu card của các tháng trước.');
}
$user = User::where('msnv', $addCard->buyer)->firstOrFail();
$startOfMonth = Carbon::now()->startOfMonth();
$endOfMonth = Carbon::now()->endOfMonth();
$totalSentThisMonth = Administration::where('msnv', $user->msnv)
->whereBetween('date', [$startOfMonth, $endOfMonth])
->sum('sent');
DB::transaction(function () use ($addCard, $user, $totalSentThisMonth) {
$newCardBalance = $user->card - intval($addCard->num_card);
if ($newCardBalance < 0) {
throw new \Exception('Không thể xóa lịch sử cấp phát thẻ này vì tổng số card của user không được nhỏ hơn 0.');
}
if ($newCardBalance < $totalSentThisMonth) {
throw new \Exception('Không thể xóa lịch sử cấp phát thẻ này vì tổng số card của user không được nhỏ hơn số card đã gửi trong tháng (' . $totalSentThisMonth . ' card).');
}
$user->card = $newCardBalance;
$user->save();
$addCard->delete();
});
}
public function getUserByMsnv(string $msnv): User
{
return User::where('msnv', $msnv)->firstOrFail();
@@ -27,6 +27,8 @@ interface AdminServiceInterface
public function updateAddCard(int $id, array $data): void;
public function destroyAddCard(int $id): void;
public function getUserByMsnv(string $msnv): \App\Models\User;
public function getAddCardsHistory(string $buyerMsnv, ?string $selectedMonth = null): \Illuminate\Database\Eloquent\Collection;
@@ -19,5 +19,5 @@ interface UserServiceInterface
public function getRankingList(string $type, string $selectedMonth, User $currentUser): array;
public function updateProfile(User $user, ?\Illuminate\Http\UploadedFile $avatarFile, ?string $newPassword): void;
public function updateProfile(User $user, array $data, ?\Illuminate\Http\UploadedFile $avatarFile = null): void;
}
+7 -3
View File
@@ -214,15 +214,19 @@ class UserService implements UserServiceInterface
];
}
public function updateProfile(User $user, ?\Illuminate\Http\UploadedFile $avatarFile, ?string $newPassword): void
public function updateProfile(User $user, array $data, ?\Illuminate\Http\UploadedFile $avatarFile = null): void
{
if (isset($data['name'])) {
$user->name = $data['name'];
}
if ($avatarFile) {
$path = $avatarFile->store('avatars', 'public');
$user->avatar = 'storage/' . $path;
}
if ($newPassword) {
$user->pass = md5($newPassword);
if (!empty($data['new_password'])) {
$user->pass = md5($data['new_password']);
$user->first_login = config('constants.FIRST_LOGIN_FALSE');
}