feat: 공통 모듈 추가 (엑셀 내보내기, 계정과목 일괄변경)
Phase 0 - 공통 모듈: - ExportService.php 생성 (Maatwebsite/Excel 기반 엑셀 내보내기) - BulkUpdateAccountCodeRequest.php 생성 (계정과목 일괄변경 유효성 검사) Phase 1 - 계정과목 일괄변경: - WithdrawalController/Service: bulkUpdateAccountCode 메서드 추가 - DepositController/Service: bulkUpdateAccountCode 메서드 추가 - POST /v1/withdrawals/bulk-update-account-code - POST /v1/deposits/bulk-update-account-code Phase 2 - 엑셀 내보내기: - AttendanceController/Service: export, getExportData 메서드 추가 - SalaryController/Service: export, getExportData 메서드 추가 - GET /v1/attendances/export - GET /v1/salaries/export Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,12 +11,17 @@
|
||||
use App\Http\Requests\Attendance\StoreRequest;
|
||||
use App\Http\Requests\Attendance\UpdateRequest;
|
||||
use App\Services\AttendanceService;
|
||||
use App\Services\ExportService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class AttendanceController extends Controller
|
||||
{
|
||||
public function __construct(private AttendanceService $service) {}
|
||||
public function __construct(
|
||||
private AttendanceService $service,
|
||||
private ExportService $exportService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 근태 목록 조회
|
||||
@@ -121,4 +126,32 @@ public function monthlyStats(MonthlyStatsRequest $request): JsonResponse
|
||||
return $this->service->monthlyStats($request->validated());
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 근태 엑셀 내보내기
|
||||
* GET /v1/attendances/export
|
||||
*/
|
||||
public function export(Request $request): BinaryFileResponse
|
||||
{
|
||||
$params = $request->only([
|
||||
'user_id',
|
||||
'date',
|
||||
'date_from',
|
||||
'date_to',
|
||||
'status',
|
||||
'department_id',
|
||||
'sort_by',
|
||||
'sort_dir',
|
||||
]);
|
||||
|
||||
$exportData = $this->service->getExportData($params);
|
||||
$filename = '근태현황_'.date('Ymd_His');
|
||||
|
||||
return $this->exportService->download(
|
||||
$exportData['data'],
|
||||
$exportData['headings'],
|
||||
$filename,
|
||||
'근태현황'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Helpers\ApiResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\BulkUpdateAccountCodeRequest;
|
||||
use App\Http\Requests\V1\Deposit\StoreDepositRequest;
|
||||
use App\Http\Requests\V1\Deposit\UpdateDepositRequest;
|
||||
use App\Services\DepositService;
|
||||
@@ -94,4 +95,20 @@ public function summary(Request $request)
|
||||
|
||||
return ApiResponse::success($summary, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 계정과목 일괄 변경
|
||||
*/
|
||||
public function bulkUpdateAccountCode(BulkUpdateAccountCodeRequest $request)
|
||||
{
|
||||
$updatedCount = $this->service->bulkUpdateAccountCode(
|
||||
$request->getIds(),
|
||||
$request->getAccountCode()
|
||||
);
|
||||
|
||||
return ApiResponse::success(
|
||||
['updated_count' => $updatedCount],
|
||||
__('message.bulk_updated')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
use App\Http\Requests\V1\Salary\BulkUpdateStatusRequest;
|
||||
use App\Http\Requests\V1\Salary\StoreSalaryRequest;
|
||||
use App\Http\Requests\V1\Salary\UpdateSalaryRequest;
|
||||
use App\Services\ExportService;
|
||||
use App\Services\SalaryService;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class SalaryController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SalaryService $service
|
||||
private readonly SalaryService $service,
|
||||
private readonly ExportService $exportService
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -123,4 +126,33 @@ public function statistics(Request $request)
|
||||
|
||||
return ApiResponse::success($stats, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 급여 엑셀 내보내기
|
||||
* GET /v1/salaries/export
|
||||
*/
|
||||
public function export(Request $request): BinaryFileResponse
|
||||
{
|
||||
$params = $request->only([
|
||||
'search',
|
||||
'year',
|
||||
'month',
|
||||
'status',
|
||||
'employee_id',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'sort_by',
|
||||
'sort_dir',
|
||||
]);
|
||||
|
||||
$exportData = $this->service->getExportData($params);
|
||||
$filename = '급여현황_'.date('Ymd_His');
|
||||
|
||||
return $this->exportService->download(
|
||||
$exportData['data'],
|
||||
$exportData['headings'],
|
||||
$filename,
|
||||
'급여현황'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Helpers\ApiResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\BulkUpdateAccountCodeRequest;
|
||||
use App\Http\Requests\V1\Withdrawal\StoreWithdrawalRequest;
|
||||
use App\Http\Requests\V1\Withdrawal\UpdateWithdrawalRequest;
|
||||
use App\Services\WithdrawalService;
|
||||
@@ -94,4 +95,20 @@ public function summary(Request $request)
|
||||
|
||||
return ApiResponse::success($summary, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 계정과목 일괄 변경
|
||||
*/
|
||||
public function bulkUpdateAccountCode(BulkUpdateAccountCodeRequest $request)
|
||||
{
|
||||
$updatedCount = $this->service->bulkUpdateAccountCode(
|
||||
$request->getIds(),
|
||||
$request->getAccountCode()
|
||||
);
|
||||
|
||||
return ApiResponse::success(
|
||||
['updated_count' => $updatedCount],
|
||||
__('message.bulk_updated')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
79
app/Http/Requests/BulkUpdateAccountCodeRequest.php
Normal file
79
app/Http/Requests/BulkUpdateAccountCodeRequest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* 계정과목 일괄 변경 요청 검증
|
||||
*
|
||||
* 여러 모듈에서 공통으로 사용:
|
||||
* - 출금관리 (WithdrawalController)
|
||||
* - 입금관리 (DepositController)
|
||||
* - 매출관리 (SaleController)
|
||||
* - 카드거래 (CardTransactionController)
|
||||
*/
|
||||
class BulkUpdateAccountCodeRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* 권한 확인
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 규칙
|
||||
*
|
||||
* @return array<string, array<int, string>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'ids' => ['required', 'array', 'min:1'],
|
||||
'ids.*' => ['required', 'integer', 'min:1'],
|
||||
'account_code' => ['required', 'string', 'max:50'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 메시지
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'ids.required' => __('validation.required', ['attribute' => 'ID 목록']),
|
||||
'ids.array' => __('validation.array', ['attribute' => 'ID 목록']),
|
||||
'ids.min' => __('validation.min.array', ['attribute' => 'ID 목록', 'min' => 1]),
|
||||
'ids.*.required' => __('validation.required', ['attribute' => 'ID']),
|
||||
'ids.*.integer' => __('validation.integer', ['attribute' => 'ID']),
|
||||
'ids.*.min' => __('validation.min.numeric', ['attribute' => 'ID', 'min' => 1]),
|
||||
'account_code.required' => __('validation.required', ['attribute' => '계정과목']),
|
||||
'account_code.string' => __('validation.string', ['attribute' => '계정과목']),
|
||||
'account_code.max' => __('validation.max.string', ['attribute' => '계정과목', 'max' => 50]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 검증된 ID 배열 반환
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
public function getIds(): array
|
||||
{
|
||||
return $this->validated('ids');
|
||||
}
|
||||
|
||||
/**
|
||||
* 검증된 계정과목 코드 반환
|
||||
*/
|
||||
public function getAccountCode(): string
|
||||
{
|
||||
return $this->validated('account_code');
|
||||
}
|
||||
}
|
||||
@@ -356,6 +356,108 @@ public function checkOut(array $data): Attendance
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 내보내기용 데이터 조회
|
||||
*
|
||||
* @return array{data: array<int, array<string, mixed>>, headings: array<int, string>}
|
||||
*/
|
||||
public function getExportData(array $params): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$query = Attendance::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->with([
|
||||
'user:id,name,email',
|
||||
'user.tenantProfiles' => function ($q) use ($tenantId) {
|
||||
$q->where('tenant_id', $tenantId)
|
||||
->with('department:id,name');
|
||||
},
|
||||
]);
|
||||
|
||||
// 사용자 필터
|
||||
if (! empty($params['user_id'])) {
|
||||
$query->where('user_id', $params['user_id']);
|
||||
}
|
||||
|
||||
// 날짜 필터 (단일)
|
||||
if (! empty($params['date'])) {
|
||||
$query->whereDate('base_date', $params['date']);
|
||||
}
|
||||
|
||||
// 날짜 범위 필터
|
||||
if (! empty($params['date_from'])) {
|
||||
$query->whereDate('base_date', '>=', $params['date_from']);
|
||||
}
|
||||
if (! empty($params['date_to'])) {
|
||||
$query->whereDate('base_date', '<=', $params['date_to']);
|
||||
}
|
||||
|
||||
// 상태 필터
|
||||
if (! empty($params['status'])) {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 부서 필터
|
||||
if (! empty($params['department_id'])) {
|
||||
$query->whereHas('user.tenantProfile', function ($q) use ($params) {
|
||||
$q->where('department_id', $params['department_id']);
|
||||
});
|
||||
}
|
||||
|
||||
// 정렬
|
||||
$sortBy = $params['sort_by'] ?? 'base_date';
|
||||
$sortDir = $params['sort_dir'] ?? 'desc';
|
||||
$query->orderBy($sortBy, $sortDir);
|
||||
|
||||
$attendances = $query->get();
|
||||
|
||||
// 상태 레이블 매핑
|
||||
$statusLabels = [
|
||||
'onTime' => '정상출근',
|
||||
'late' => '지각',
|
||||
'absent' => '결근',
|
||||
'vacation' => '휴가',
|
||||
'businessTrip' => '출장',
|
||||
'fieldWork' => '외근',
|
||||
'overtime' => '야근',
|
||||
'remote' => '재택',
|
||||
];
|
||||
|
||||
// 엑셀 데이터 변환
|
||||
$data = $attendances->map(function ($attendance) use ($statusLabels) {
|
||||
$profile = $attendance->user?->tenantProfiles?->first();
|
||||
$jsonDetails = $attendance->json_details ?? [];
|
||||
|
||||
return [
|
||||
$attendance->base_date,
|
||||
$attendance->user?->name ?? '-',
|
||||
$profile?->department?->name ?? '-',
|
||||
$statusLabels[$attendance->status] ?? $attendance->status,
|
||||
$attendance->check_in ?? '-',
|
||||
$attendance->check_out ?? '-',
|
||||
isset($jsonDetails['work_minutes']) ? round($jsonDetails['work_minutes'] / 60, 1) : '-',
|
||||
$attendance->remarks ?? '',
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
$headings = [
|
||||
'날짜',
|
||||
'직원명',
|
||||
'부서',
|
||||
'상태',
|
||||
'출근시간',
|
||||
'퇴근시간',
|
||||
'근무시간(h)',
|
||||
'비고',
|
||||
];
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'headings' => $headings,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 월간 통계 조회
|
||||
*/
|
||||
|
||||
@@ -179,6 +179,27 @@ public function destroy(int $id): bool
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계정과목 일괄 변경
|
||||
*
|
||||
* @param array<int, int> $ids 변경할 입금 ID 목록
|
||||
* @param string $accountCode 새 계정과목 코드
|
||||
* @return int 변경된 레코드 수
|
||||
*/
|
||||
public function bulkUpdateAccountCode(array $ids, string $accountCode): int
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return Deposit::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $ids)
|
||||
->update([
|
||||
'account_code' => $accountCode,
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 입금 요약 (기간별 합계)
|
||||
*/
|
||||
|
||||
129
app/Services/ExportService.php
Normal file
129
app/Services/ExportService.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\FromArray;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||
use Maatwebsite\Excel\Concerns\WithTitle;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
/**
|
||||
* 범용 엑셀 내보내기 서비스
|
||||
*
|
||||
* 여러 모듈에서 공통으로 사용할 수 있는 엑셀 내보내기 기능 제공
|
||||
* - 근태관리 (AttendanceController)
|
||||
* - 급여관리 (SalaryController)
|
||||
* - 기타 데이터 내보내기가 필요한 모듈
|
||||
*/
|
||||
class ExportService extends Service
|
||||
{
|
||||
/**
|
||||
* 엑셀 파일 다운로드
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $data 내보낼 데이터 배열
|
||||
* @param array<int, string> $headings 컬럼 헤더 배열
|
||||
* @param string $filename 다운로드 파일명 (확장자 제외)
|
||||
* @param string $sheetTitle 시트 제목
|
||||
*/
|
||||
public function download(
|
||||
array $data,
|
||||
array $headings,
|
||||
string $filename,
|
||||
string $sheetTitle = 'Sheet1'
|
||||
): BinaryFileResponse {
|
||||
$export = new GenericExport($data, $headings, $sheetTitle);
|
||||
|
||||
return Excel::download($export, $filename.'.xlsx');
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 파일 저장 (서버에 저장)
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $data 내보낼 데이터 배열
|
||||
* @param array<int, string> $headings 컬럼 헤더 배열
|
||||
* @param string $path 저장 경로 (storage/app 기준)
|
||||
* @param string $sheetTitle 시트 제목
|
||||
*/
|
||||
public function store(
|
||||
array $data,
|
||||
array $headings,
|
||||
string $path,
|
||||
string $sheetTitle = 'Sheet1'
|
||||
): bool {
|
||||
$export = new GenericExport($data, $headings, $sheetTitle);
|
||||
|
||||
return Excel::store($export, $path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 범용 엑셀 내보내기 클래스
|
||||
*
|
||||
* ExportService에서 내부적으로 사용하는 Maatwebsite Excel 구현체
|
||||
*/
|
||||
class GenericExport implements FromArray, ShouldAutoSize, WithHeadings, WithStyles, WithTitle
|
||||
{
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $data 내보낼 데이터
|
||||
* @param array<int, string> $headings 컬럼 헤더
|
||||
* @param string $sheetTitle 시트 제목
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $data,
|
||||
private readonly array $headings,
|
||||
private readonly string $sheetTitle
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 데이터 배열 반환
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function array(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 헤더 배열 반환
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return $this->headings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 시트 제목 반환
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return $this->sheetTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 스타일 적용
|
||||
*
|
||||
* @return array<int|string, array<string, mixed>>
|
||||
*/
|
||||
public function styles(Worksheet $sheet): array
|
||||
{
|
||||
return [
|
||||
// 헤더 행 스타일 (굵게, 배경색)
|
||||
1 => [
|
||||
'font' => ['bold' => true],
|
||||
'fill' => [
|
||||
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
|
||||
'startColor' => ['rgb' => 'E2E8F0'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,113 @@ public function bulkUpdateStatus(array $ids, string $status): int
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 내보내기용 데이터 조회
|
||||
*
|
||||
* @return array{data: array<int, array<string, mixed>>, headings: array<int, string>}
|
||||
*/
|
||||
public function getExportData(array $params): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$query = Salary::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->with([
|
||||
'employee:id,name,user_id,email',
|
||||
'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
|
||||
'employeeProfile.department:id,name',
|
||||
]);
|
||||
|
||||
// 검색 필터 (직원명)
|
||||
if (! empty($params['search'])) {
|
||||
$search = $params['search'];
|
||||
$query->whereHas('employee', function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// 연도 필터
|
||||
if (! empty($params['year'])) {
|
||||
$query->where('year', $params['year']);
|
||||
}
|
||||
|
||||
// 월 필터
|
||||
if (! empty($params['month'])) {
|
||||
$query->where('month', $params['month']);
|
||||
}
|
||||
|
||||
// 상태 필터
|
||||
if (! empty($params['status'])) {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 기간 필터
|
||||
if (! empty($params['start_date']) && ! empty($params['end_date'])) {
|
||||
$query->whereBetween('payment_date', [$params['start_date'], $params['end_date']]);
|
||||
}
|
||||
|
||||
// 직원 ID 필터
|
||||
if (! empty($params['employee_id'])) {
|
||||
$query->where('employee_id', $params['employee_id']);
|
||||
}
|
||||
|
||||
// 정렬
|
||||
$sortBy = $params['sort_by'] ?? 'year';
|
||||
$sortDir = $params['sort_dir'] ?? 'desc';
|
||||
|
||||
if ($sortBy === 'year') {
|
||||
$query->orderBy('year', $sortDir)
|
||||
->orderBy('month', $sortDir);
|
||||
} else {
|
||||
$query->orderBy($sortBy, $sortDir);
|
||||
}
|
||||
|
||||
$salaries = $query->get();
|
||||
|
||||
// 상태 레이블 매핑
|
||||
$statusLabels = [
|
||||
'scheduled' => '지급예정',
|
||||
'completed' => '지급완료',
|
||||
'pending' => '보류',
|
||||
];
|
||||
|
||||
// 엑셀 데이터 변환
|
||||
$data = $salaries->map(function ($salary) use ($statusLabels) {
|
||||
return [
|
||||
$salary->year.'년 '.$salary->month.'월',
|
||||
$salary->employee?->name ?? '-',
|
||||
$salary->employeeProfile?->department?->name ?? '-',
|
||||
number_format($salary->base_salary),
|
||||
number_format($salary->total_allowance),
|
||||
number_format($salary->total_overtime),
|
||||
number_format($salary->total_bonus),
|
||||
number_format($salary->total_deduction),
|
||||
number_format($salary->net_payment),
|
||||
$statusLabels[$salary->status] ?? $salary->status,
|
||||
$salary->payment_date ?? '-',
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
$headings = [
|
||||
'급여월',
|
||||
'직원명',
|
||||
'부서',
|
||||
'기본급',
|
||||
'수당',
|
||||
'야근수당',
|
||||
'상여금',
|
||||
'공제액',
|
||||
'실지급액',
|
||||
'상태',
|
||||
'지급일',
|
||||
];
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'headings' => $headings,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 급여 통계 조회
|
||||
*/
|
||||
|
||||
@@ -179,6 +179,27 @@ public function destroy(int $id): bool
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계정과목 일괄 변경
|
||||
*
|
||||
* @param array<int, int> $ids 변경할 출금 ID 목록
|
||||
* @param string $accountCode 새 계정과목 코드
|
||||
* @return int 변경된 레코드 수
|
||||
*/
|
||||
public function bulkUpdateAccountCode(array $ids, string $accountCode): int
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return Withdrawal::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $ids)
|
||||
->update([
|
||||
'account_code' => $accountCode,
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 출금 요약 (기간별 합계)
|
||||
*/
|
||||
|
||||
@@ -340,6 +340,7 @@
|
||||
Route::get('', [AttendanceController::class, 'index'])->name('v1.attendances.index');
|
||||
Route::post('', [AttendanceController::class, 'store'])->name('v1.attendances.store');
|
||||
Route::get('/monthly-stats', [AttendanceController::class, 'monthlyStats'])->name('v1.attendances.monthlyStats');
|
||||
Route::get('/export', [AttendanceController::class, 'export'])->name('v1.attendances.export');
|
||||
Route::post('/check-in', [AttendanceController::class, 'checkIn'])->name('v1.attendances.checkIn');
|
||||
Route::post('/check-out', [AttendanceController::class, 'checkOut'])->name('v1.attendances.checkOut');
|
||||
Route::get('/{id}', [AttendanceController::class, 'show'])->name('v1.attendances.show');
|
||||
@@ -503,6 +504,7 @@
|
||||
Route::get('', [DepositController::class, 'index'])->name('v1.deposits.index');
|
||||
Route::post('', [DepositController::class, 'store'])->name('v1.deposits.store');
|
||||
Route::get('/summary', [DepositController::class, 'summary'])->name('v1.deposits.summary');
|
||||
Route::post('/bulk-update-account-code', [DepositController::class, 'bulkUpdateAccountCode'])->name('v1.deposits.bulk-update-account-code');
|
||||
Route::get('/{id}', [DepositController::class, 'show'])->whereNumber('id')->name('v1.deposits.show');
|
||||
Route::put('/{id}', [DepositController::class, 'update'])->whereNumber('id')->name('v1.deposits.update');
|
||||
Route::delete('/{id}', [DepositController::class, 'destroy'])->whereNumber('id')->name('v1.deposits.destroy');
|
||||
@@ -513,6 +515,7 @@
|
||||
Route::get('', [WithdrawalController::class, 'index'])->name('v1.withdrawals.index');
|
||||
Route::post('', [WithdrawalController::class, 'store'])->name('v1.withdrawals.store');
|
||||
Route::get('/summary', [WithdrawalController::class, 'summary'])->name('v1.withdrawals.summary');
|
||||
Route::post('/bulk-update-account-code', [WithdrawalController::class, 'bulkUpdateAccountCode'])->name('v1.withdrawals.bulk-update-account-code');
|
||||
Route::get('/{id}', [WithdrawalController::class, 'show'])->whereNumber('id')->name('v1.withdrawals.show');
|
||||
Route::put('/{id}', [WithdrawalController::class, 'update'])->whereNumber('id')->name('v1.withdrawals.update');
|
||||
Route::delete('/{id}', [WithdrawalController::class, 'destroy'])->whereNumber('id')->name('v1.withdrawals.destroy');
|
||||
@@ -538,6 +541,7 @@
|
||||
Route::get('', [SalaryController::class, 'index'])->name('v1.salaries.index');
|
||||
Route::post('', [SalaryController::class, 'store'])->name('v1.salaries.store');
|
||||
Route::get('/statistics', [SalaryController::class, 'statistics'])->name('v1.salaries.statistics');
|
||||
Route::get('/export', [SalaryController::class, 'export'])->name('v1.salaries.export');
|
||||
Route::post('/bulk-update-status', [SalaryController::class, 'bulkUpdateStatus'])->name('v1.salaries.bulk-update-status');
|
||||
Route::get('/{id}', [SalaryController::class, 'show'])->whereNumber('id')->name('v1.salaries.show');
|
||||
Route::put('/{id}', [SalaryController::class, 'update'])->whereNumber('id')->name('v1.salaries.update');
|
||||
|
||||
Reference in New Issue
Block a user