diff --git a/app/Http/Controllers/Barobill/EaccountController.php b/app/Http/Controllers/Barobill/EaccountController.php index e6d73b31..3f011a89 100644 --- a/app/Http/Controllers/Barobill/EaccountController.php +++ b/app/Http/Controllers/Barobill/EaccountController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Barobill; use App\Http\Controllers\Controller; +use App\Models\Barobill\AccountCode; use App\Models\Barobill\BarobillConfig; use App\Models\Barobill\BarobillMember; use App\Models\Barobill\BankTransaction; @@ -535,42 +536,30 @@ private function getBankName(string $code): string */ public function accountCodes(): JsonResponse { - // 자주 사용되는 계정과목 목록 - $codes = [ - ['code' => '101', 'name' => '현금'], - ['code' => '103', 'name' => '보통예금'], - ['code' => '108', 'name' => '외상매출금'], - ['code' => '110', 'name' => '받을어음'], - ['code' => '253', 'name' => '외상매입금'], - ['code' => '255', 'name' => '지급어음'], - ['code' => '401', 'name' => '매출'], - ['code' => '501', 'name' => '매입'], - ['code' => '511', 'name' => '급여'], - ['code' => '521', 'name' => '복리후생비'], - ['code' => '522', 'name' => '여비교통비'], - ['code' => '523', 'name' => '접대비'], - ['code' => '524', 'name' => '통신비'], - ['code' => '525', 'name' => '수도광열비'], - ['code' => '526', 'name' => '세금과공과'], - ['code' => '527', 'name' => '임차료'], - ['code' => '528', 'name' => '수선비'], - ['code' => '529', 'name' => '보험료'], - ['code' => '530', 'name' => '차량유지비'], - ['code' => '531', 'name' => '운반비'], - ['code' => '532', 'name' => '교육훈련비'], - ['code' => '533', 'name' => '도서인쇄비'], - ['code' => '534', 'name' => '사무용품비'], - ['code' => '535', 'name' => '소모품비'], - ['code' => '536', 'name' => '지급수수료'], - ['code' => '537', 'name' => '광고선전비'], - ['code' => '538', 'name' => '대손상각비'], - ['code' => '539', 'name' => '감가상각비'], - ['code' => '540', 'name' => '잡비'], - ['code' => '901', 'name' => '이자수익'], - ['code' => '902', 'name' => '이자비용'], - ['code' => '910', 'name' => '잡이익'], - ['code' => '920', 'name' => '잡손실'], - ]; + $tenantId = session('selected_tenant_id', self::HEADQUARTERS_TENANT_ID); + $codes = AccountCode::getActiveByTenant($tenantId); + + return response()->json([ + 'success' => true, + 'data' => $codes->map(fn($c) => [ + 'id' => $c->id, + 'code' => $c->code, + 'name' => $c->name, + 'category' => $c->category, + ]) + ]); + } + + /** + * 전체 계정과목 목록 조회 (설정용, 비활성 포함) + */ + public function accountCodesAll(): JsonResponse + { + $tenantId = session('selected_tenant_id', self::HEADQUARTERS_TENANT_ID); + $codes = AccountCode::where('tenant_id', $tenantId) + ->orderBy('sort_order') + ->orderBy('code') + ->get(); return response()->json([ 'success' => true, @@ -578,6 +567,145 @@ public function accountCodes(): JsonResponse ]); } + /** + * 계정과목 추가 + */ + public function accountCodeStore(Request $request): JsonResponse + { + try { + $tenantId = session('selected_tenant_id', self::HEADQUARTERS_TENANT_ID); + + $validated = $request->validate([ + 'code' => 'required|string|max:10', + 'name' => 'required|string|max:100', + 'category' => 'nullable|string|max:50', + ]); + + // 중복 체크 + $exists = AccountCode::where('tenant_id', $tenantId) + ->where('code', $validated['code']) + ->exists(); + + if ($exists) { + return response()->json([ + 'success' => false, + 'error' => '이미 존재하는 계정과목 코드입니다.' + ], 422); + } + + $maxSort = AccountCode::where('tenant_id', $tenantId)->max('sort_order') ?? 0; + + $accountCode = AccountCode::create([ + 'tenant_id' => $tenantId, + 'code' => $validated['code'], + 'name' => $validated['name'], + 'category' => $validated['category'] ?? null, + 'sort_order' => $maxSort + 1, + 'is_active' => true, + ]); + + return response()->json([ + 'success' => true, + 'message' => '계정과목이 추가되었습니다.', + 'data' => $accountCode + ]); + } catch (\Throwable $e) { + return response()->json([ + 'success' => false, + 'error' => '추가 실패: ' . $e->getMessage() + ], 500); + } + } + + /** + * 계정과목 수정 + */ + public function accountCodeUpdate(Request $request, int $id): JsonResponse + { + try { + $tenantId = session('selected_tenant_id', self::HEADQUARTERS_TENANT_ID); + + $accountCode = AccountCode::where('tenant_id', $tenantId) + ->where('id', $id) + ->first(); + + if (!$accountCode) { + return response()->json([ + 'success' => false, + 'error' => '계정과목을 찾을 수 없습니다.' + ], 404); + } + + $validated = $request->validate([ + 'code' => 'sometimes|string|max:10', + 'name' => 'sometimes|string|max:100', + 'category' => 'nullable|string|max:50', + 'is_active' => 'sometimes|boolean', + ]); + + // 코드 변경 시 중복 체크 + if (isset($validated['code']) && $validated['code'] !== $accountCode->code) { + $exists = AccountCode::where('tenant_id', $tenantId) + ->where('code', $validated['code']) + ->where('id', '!=', $id) + ->exists(); + + if ($exists) { + return response()->json([ + 'success' => false, + 'error' => '이미 존재하는 계정과목 코드입니다.' + ], 422); + } + } + + $accountCode->update($validated); + + return response()->json([ + 'success' => true, + 'message' => '계정과목이 수정되었습니다.', + 'data' => $accountCode + ]); + } catch (\Throwable $e) { + return response()->json([ + 'success' => false, + 'error' => '수정 실패: ' . $e->getMessage() + ], 500); + } + } + + /** + * 계정과목 삭제 + */ + public function accountCodeDestroy(int $id): JsonResponse + { + try { + $tenantId = session('selected_tenant_id', self::HEADQUARTERS_TENANT_ID); + + $accountCode = AccountCode::where('tenant_id', $tenantId) + ->where('id', $id) + ->first(); + + if (!$accountCode) { + return response()->json([ + 'success' => false, + 'error' => '계정과목을 찾을 수 없습니다.' + ], 404); + } + + $accountCode->delete(); + + return response()->json([ + 'success' => true, + 'message' => '계정과목이 삭제되었습니다.' + ]); + } catch (\Throwable $e) { + return response()->json([ + 'success' => false, + 'error' => '삭제 실패: ' . $e->getMessage() + ], 500); + } + } + /** * 입출금 내역 저장 (계정과목 포함) */ diff --git a/app/Models/Barobill/AccountCode.php b/app/Models/Barobill/AccountCode.php new file mode 100644 index 00000000..aafa2c7d --- /dev/null +++ b/app/Models/Barobill/AccountCode.php @@ -0,0 +1,49 @@ + 'boolean', + 'sort_order' => 'integer', + ]; + + /** + * 테넌트 관계 + */ + public function tenant(): BelongsTo + { + return $this->belongsTo(Tenant::class); + } + + /** + * 테넌트별 활성 계정과목 조회 + */ + public static function getActiveByTenant(int $tenantId) + { + return self::where('tenant_id', $tenantId) + ->where('is_active', true) + ->orderBy('sort_order') + ->orderBy('code') + ->get(); + } +} diff --git a/database/migrations/2026_01_23_140000_create_account_codes_table.php b/database/migrations/2026_01_23_140000_create_account_codes_table.php new file mode 100644 index 00000000..683e2933 --- /dev/null +++ b/database/migrations/2026_01_23_140000_create_account_codes_table.php @@ -0,0 +1,37 @@ +id(); + $table->foreignId('tenant_id')->constrained()->onDelete('cascade'); + $table->string('code', 10)->comment('계정과목 코드'); + $table->string('name', 100)->comment('계정과목 명'); + $table->string('category', 50)->nullable()->comment('분류 (자산/부채/자본/수익/비용)'); + $table->integer('sort_order')->default(0)->comment('정렬순서'); + $table->boolean('is_active')->default(true)->comment('사용여부'); + $table->timestamps(); + + // 테넌트별 계정과목 코드 유니크 + $table->unique(['tenant_id', 'code'], 'account_codes_tenant_code_unique'); + $table->index(['tenant_id', 'is_active'], 'account_codes_tenant_active_idx'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('account_codes'); + } +}; diff --git a/database/seeders/AccountCodeSeeder.php b/database/seeders/AccountCodeSeeder.php new file mode 100644 index 00000000..74e92b69 --- /dev/null +++ b/database/seeders/AccountCodeSeeder.php @@ -0,0 +1,242 @@ +delete(); + + $accountCodes = $this->getDouzonAccountCodes(); + + $sortOrder = 0; + foreach ($accountCodes as $code) { + AccountCode::create([ + 'tenant_id' => $tenantId, + 'code' => $code['code'], + 'name' => $code['name'], + 'category' => $code['category'], + 'sort_order' => $sortOrder++, + 'is_active' => true, + ]); + } + + $this->command->info("계정과목 " . count($accountCodes) . "개 생성 완료"); + } + + /** + * 더존 표준 계정과목 목록 + */ + private function getDouzonAccountCodes(): array + { + return [ + // ===== 자산 (1xx) ===== + // 유동자산 - 당좌자산 + ['code' => '101', 'name' => '현금', 'category' => '자산'], + ['code' => '102', 'name' => '당좌예금', 'category' => '자산'], + ['code' => '103', 'name' => '보통예금', 'category' => '자산'], + ['code' => '104', 'name' => '정기예금', 'category' => '자산'], + ['code' => '105', 'name' => '정기적금', 'category' => '자산'], + ['code' => '106', 'name' => '외화예금', 'category' => '자산'], + ['code' => '107', 'name' => '별단예금', 'category' => '자산'], + ['code' => '108', 'name' => '외상매출금', 'category' => '자산'], + ['code' => '109', 'name' => '대손충당금', 'category' => '자산'], + ['code' => '110', 'name' => '받을어음', 'category' => '자산'], + ['code' => '111', 'name' => '단기대여금', 'category' => '자산'], + ['code' => '112', 'name' => '미수금', 'category' => '자산'], + ['code' => '113', 'name' => '미수수익', 'category' => '자산'], + ['code' => '114', 'name' => '선급금', 'category' => '자산'], + ['code' => '115', 'name' => '선급비용', 'category' => '자산'], + ['code' => '116', 'name' => '가지급금', 'category' => '자산'], + ['code' => '117', 'name' => '부가세대급금', 'category' => '자산'], + ['code' => '118', 'name' => '선납세금', 'category' => '자산'], + ['code' => '119', 'name' => '유가증권', 'category' => '자산'], + ['code' => '120', 'name' => '단기금융상품', 'category' => '자산'], + + // 유동자산 - 재고자산 + ['code' => '141', 'name' => '상품', 'category' => '자산'], + ['code' => '142', 'name' => '제품', 'category' => '자산'], + ['code' => '143', 'name' => '반제품', 'category' => '자산'], + ['code' => '144', 'name' => '재공품', 'category' => '자산'], + ['code' => '145', 'name' => '원재료', 'category' => '자산'], + ['code' => '146', 'name' => '부재료', 'category' => '자산'], + ['code' => '147', 'name' => '저장품', 'category' => '자산'], + ['code' => '148', 'name' => '미착품', 'category' => '자산'], + + // 비유동자산 - 투자자산 + ['code' => '151', 'name' => '장기금융상품', 'category' => '자산'], + ['code' => '152', 'name' => '장기대여금', 'category' => '자산'], + ['code' => '153', 'name' => '투자유가증권', 'category' => '자산'], + ['code' => '154', 'name' => '출자금', 'category' => '자산'], + ['code' => '155', 'name' => '장기성매출채권', 'category' => '자산'], + ['code' => '156', 'name' => '보증금', 'category' => '자산'], + ['code' => '157', 'name' => '임차보증금', 'category' => '자산'], + + // 비유동자산 - 유형자산 + ['code' => '161', 'name' => '토지', 'category' => '자산'], + ['code' => '162', 'name' => '건물', 'category' => '자산'], + ['code' => '163', 'name' => '건물감가상각누계액', 'category' => '자산'], + ['code' => '164', 'name' => '구축물', 'category' => '자산'], + ['code' => '165', 'name' => '구축물감가상각누계액', 'category' => '자산'], + ['code' => '166', 'name' => '기계장치', 'category' => '자산'], + ['code' => '167', 'name' => '기계장치감가상각누계액', 'category' => '자산'], + ['code' => '168', 'name' => '차량운반구', 'category' => '자산'], + ['code' => '169', 'name' => '차량운반구감가상각누계액', 'category' => '자산'], + ['code' => '170', 'name' => '공구와기구', 'category' => '자산'], + ['code' => '171', 'name' => '공구와기구감가상각누계액', 'category' => '자산'], + ['code' => '172', 'name' => '비품', 'category' => '자산'], + ['code' => '173', 'name' => '비품감가상각누계액', 'category' => '자산'], + ['code' => '174', 'name' => '건설중인자산', 'category' => '자산'], + + // 비유동자산 - 무형자산 + ['code' => '181', 'name' => '영업권', 'category' => '자산'], + ['code' => '182', 'name' => '산업재산권', 'category' => '자산'], + ['code' => '183', 'name' => '개발비', 'category' => '자산'], + ['code' => '184', 'name' => '소프트웨어', 'category' => '자산'], + ['code' => '185', 'name' => '창업비', 'category' => '자산'], + + // 기타 비유동자산 + ['code' => '191', 'name' => '이연법인세자산', 'category' => '자산'], + + // ===== 부채 (2xx) ===== + // 유동부채 + ['code' => '201', 'name' => '외상매입금', 'category' => '부채'], + ['code' => '202', 'name' => '지급어음', 'category' => '부채'], + ['code' => '203', 'name' => '단기차입금', 'category' => '부채'], + ['code' => '204', 'name' => '미지급금', 'category' => '부채'], + ['code' => '205', 'name' => '미지급비용', 'category' => '부채'], + ['code' => '206', 'name' => '선수금', 'category' => '부채'], + ['code' => '207', 'name' => '예수금', 'category' => '부채'], + ['code' => '208', 'name' => '부가세예수금', 'category' => '부채'], + ['code' => '209', 'name' => '미지급세금', 'category' => '부채'], + ['code' => '210', 'name' => '미지급법인세', 'category' => '부채'], + ['code' => '211', 'name' => '미지급배당금', 'category' => '부채'], + ['code' => '212', 'name' => '가수금', 'category' => '부채'], + ['code' => '213', 'name' => '선수수익', 'category' => '부채'], + ['code' => '214', 'name' => '유동성장기부채', 'category' => '부채'], + ['code' => '215', 'name' => '당기법인세부채', 'category' => '부채'], + + // 비유동부채 + ['code' => '251', 'name' => '장기차입금', 'category' => '부채'], + ['code' => '252', 'name' => '사채', 'category' => '부채'], + ['code' => '253', 'name' => '장기성매입채무', 'category' => '부채'], + ['code' => '254', 'name' => '퇴직급여충당부채', 'category' => '부채'], + ['code' => '255', 'name' => '장기미지급금', 'category' => '부채'], + ['code' => '256', 'name' => '임대보증금', 'category' => '부채'], + ['code' => '257', 'name' => '이연법인세부채', 'category' => '부채'], + + // ===== 자본 (3xx) ===== + ['code' => '301', 'name' => '자본금', 'category' => '자본'], + ['code' => '311', 'name' => '주식발행초과금', 'category' => '자본'], + ['code' => '312', 'name' => '감자차익', 'category' => '자본'], + ['code' => '313', 'name' => '자기주식처분이익', 'category' => '자본'], + ['code' => '321', 'name' => '이익준비금', 'category' => '자본'], + ['code' => '322', 'name' => '기업합리화적립금', 'category' => '자본'], + ['code' => '323', 'name' => '재무구조개선적립금', 'category' => '자본'], + ['code' => '324', 'name' => '임의적립금', 'category' => '자본'], + ['code' => '331', 'name' => '이월이익잉여금', 'category' => '자본'], + ['code' => '332', 'name' => '당기순이익', 'category' => '자본'], + ['code' => '333', 'name' => '전기이월이익잉여금', 'category' => '자본'], + + // ===== 수익 (4xx) ===== + ['code' => '401', 'name' => '상품매출', 'category' => '수익'], + ['code' => '402', 'name' => '제품매출', 'category' => '수익'], + ['code' => '403', 'name' => '공사수입', 'category' => '수익'], + ['code' => '404', 'name' => '용역수입', 'category' => '수익'], + ['code' => '405', 'name' => '임대수입', 'category' => '수익'], + ['code' => '406', 'name' => '수출매출', 'category' => '수익'], + ['code' => '407', 'name' => '기타매출', 'category' => '수익'], + ['code' => '408', 'name' => '매출에누리', 'category' => '수익'], + ['code' => '409', 'name' => '매출환입', 'category' => '수익'], + ['code' => '410', 'name' => '매출할인', 'category' => '수익'], + + // ===== 매출원가 (5xx) ===== + ['code' => '501', 'name' => '상품매출원가', 'category' => '비용'], + ['code' => '502', 'name' => '기초상품재고액', 'category' => '비용'], + ['code' => '503', 'name' => '당기상품매입액', 'category' => '비용'], + ['code' => '504', 'name' => '기말상품재고액', 'category' => '비용'], + ['code' => '505', 'name' => '제품매출원가', 'category' => '비용'], + ['code' => '506', 'name' => '기초제품재고액', 'category' => '비용'], + ['code' => '507', 'name' => '당기제품제조원가', 'category' => '비용'], + ['code' => '508', 'name' => '기말제품재고액', 'category' => '비용'], + ['code' => '509', 'name' => '타계정대체', 'category' => '비용'], + + // ===== 판매비와관리비 (8xx) ===== + ['code' => '801', 'name' => '급여', 'category' => '비용'], + ['code' => '802', 'name' => '상여금', 'category' => '비용'], + ['code' => '803', 'name' => '잡급', 'category' => '비용'], + ['code' => '804', 'name' => '퇴직급여', 'category' => '비용'], + ['code' => '805', 'name' => '복리후생비', 'category' => '비용'], + ['code' => '806', 'name' => '여비교통비', 'category' => '비용'], + ['code' => '807', 'name' => '접대비', 'category' => '비용'], + ['code' => '808', 'name' => '통신비', 'category' => '비용'], + ['code' => '809', 'name' => '수도광열비', 'category' => '비용'], + ['code' => '810', 'name' => '전력비', 'category' => '비용'], + ['code' => '811', 'name' => '세금과공과', 'category' => '비용'], + ['code' => '812', 'name' => '임차료', 'category' => '비용'], + ['code' => '813', 'name' => '감가상각비', 'category' => '비용'], + ['code' => '814', 'name' => '무형자산상각비', 'category' => '비용'], + ['code' => '815', 'name' => '수선비', 'category' => '비용'], + ['code' => '816', 'name' => '보험료', 'category' => '비용'], + ['code' => '817', 'name' => '차량유지비', 'category' => '비용'], + ['code' => '818', 'name' => '운반비', 'category' => '비용'], + ['code' => '819', 'name' => '교육훈련비', 'category' => '비용'], + ['code' => '820', 'name' => '도서인쇄비', 'category' => '비용'], + ['code' => '821', 'name' => '사무용품비', 'category' => '비용'], + ['code' => '822', 'name' => '소모품비', 'category' => '비용'], + ['code' => '823', 'name' => '지급수수료', 'category' => '비용'], + ['code' => '824', 'name' => '광고선전비', 'category' => '비용'], + ['code' => '825', 'name' => '대손상각비', 'category' => '비용'], + ['code' => '826', 'name' => '건물관리비', 'category' => '비용'], + ['code' => '827', 'name' => '경상연구개발비', 'category' => '비용'], + ['code' => '828', 'name' => '판매수수료', 'category' => '비용'], + ['code' => '829', 'name' => '판매촉진비', 'category' => '비용'], + ['code' => '830', 'name' => '포장비', 'category' => '비용'], + ['code' => '831', 'name' => '하역비', 'category' => '비용'], + ['code' => '832', 'name' => '보관료', 'category' => '비용'], + ['code' => '833', 'name' => '견본비', 'category' => '비용'], + ['code' => '834', 'name' => '회의비', 'category' => '비용'], + ['code' => '835', 'name' => '잡비', 'category' => '비용'], + ['code' => '836', 'name' => '외주가공비', 'category' => '비용'], + ['code' => '837', 'name' => '리스료', 'category' => '비용'], + ['code' => '838', 'name' => '용역비', 'category' => '비용'], + + // ===== 영업외수익 (9xx) ===== + ['code' => '901', 'name' => '이자수익', 'category' => '수익'], + ['code' => '902', 'name' => '배당금수익', 'category' => '수익'], + ['code' => '903', 'name' => '임대료수익', 'category' => '수익'], + ['code' => '904', 'name' => '유가증권처분이익', 'category' => '수익'], + ['code' => '905', 'name' => '유형자산처분이익', 'category' => '수익'], + ['code' => '906', 'name' => '외환차익', 'category' => '수익'], + ['code' => '907', 'name' => '외화환산이익', 'category' => '수익'], + ['code' => '908', 'name' => '대손충당금환입', 'category' => '수익'], + ['code' => '909', 'name' => '잡이익', 'category' => '수익'], + + // ===== 영업외비용 (9xx) ===== + ['code' => '951', 'name' => '이자비용', 'category' => '비용'], + ['code' => '952', 'name' => '기부금', 'category' => '비용'], + ['code' => '953', 'name' => '유가증권처분손실', 'category' => '비용'], + ['code' => '954', 'name' => '유형자산처분손실', 'category' => '비용'], + ['code' => '955', 'name' => '재고자산감모손실', 'category' => '비용'], + ['code' => '956', 'name' => '외환차손', 'category' => '비용'], + ['code' => '957', 'name' => '외화환산손실', 'category' => '비용'], + ['code' => '958', 'name' => '잡손실', 'category' => '비용'], + + // ===== 법인세비용 ===== + ['code' => '991', 'name' => '법인세비용', 'category' => '비용'], + ]; + } +} diff --git a/resources/views/barobill/eaccount/index.blade.php b/resources/views/barobill/eaccount/index.blade.php index c5488018..da2546df 100644 --- a/resources/views/barobill/eaccount/index.blade.php +++ b/resources/views/barobill/eaccount/index.blade.php @@ -70,6 +70,10 @@ accounts: '{{ route("barobill.eaccount.accounts") }}', transactions: '{{ route("barobill.eaccount.transactions") }}', accountCodes: '{{ route("barobill.eaccount.account-codes") }}', + accountCodesAll: '{{ route("barobill.eaccount.account-codes.all") }}', + accountCodesStore: '{{ route("barobill.eaccount.account-codes.store") }}', + accountCodesUpdate: (id) => `/barobill/eaccount/account-codes/${id}`, + accountCodesDestroy: (id) => `/barobill/eaccount/account-codes/${id}`, save: '{{ route("barobill.eaccount.save") }}', export: '{{ route("barobill.eaccount.export") }}', }; @@ -167,6 +171,279 @@ className="w-full px-2 py-1 text-xs border border-stone-200 rounded focus:ring-2 ); + // AccountCodeSettingsModal Component + const AccountCodeSettingsModal = ({ isOpen, onClose, onUpdate }) => { + const [codes, setCodes] = useState([]); + const [loading, setLoading] = useState(false); + const [newCode, setNewCode] = useState(''); + const [newName, setNewName] = useState(''); + const [newCategory, setNewCategory] = useState(''); + const [filter, setFilter] = useState(''); + const [categoryFilter, setCategoryFilter] = useState(''); + + const categories = ['자산', '부채', '자본', '수익', '비용']; + + // 모달 열릴 때 데이터 로드 + useEffect(() => { + if (isOpen) { + loadCodes(); + } + }, [isOpen]); + + const loadCodes = async () => { + setLoading(true); + try { + const res = await fetch(API.accountCodesAll); + const data = await res.json(); + if (data.success) { + setCodes(data.data || []); + } + } catch (err) { + notify('계정과목 로드 실패', 'error'); + } finally { + setLoading(false); + } + }; + + const handleAdd = async () => { + if (!newCode.trim() || !newName.trim()) { + notify('코드와 이름을 입력해주세요.', 'warning'); + return; + } + + try { + const res = await fetch(API.accountCodesStore, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': CSRF_TOKEN + }, + body: JSON.stringify({ + code: newCode.trim(), + name: newName.trim(), + category: newCategory || null + }) + }); + const data = await res.json(); + if (data.success) { + notify('계정과목이 추가되었습니다.', 'success'); + setNewCode(''); + setNewName(''); + setNewCategory(''); + loadCodes(); + onUpdate(); + } else { + notify(data.error || '추가 실패', 'error'); + } + } catch (err) { + notify('추가 실패: ' + err.message, 'error'); + } + }; + + const handleToggleActive = async (item) => { + try { + const res = await fetch(API.accountCodesUpdate(item.id), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': CSRF_TOKEN + }, + body: JSON.stringify({ is_active: !item.is_active }) + }); + const data = await res.json(); + if (data.success) { + loadCodes(); + onUpdate(); + } + } catch (err) { + notify('변경 실패', 'error'); + } + }; + + const handleDelete = async (item) => { + if (!confirm(`"${item.code} ${item.name}" 계정과목을 삭제하시겠습니까?`)) return; + + try { + const res = await fetch(API.accountCodesDestroy(item.id), { + method: 'DELETE', + headers: { + 'X-CSRF-TOKEN': CSRF_TOKEN + } + }); + const data = await res.json(); + if (data.success) { + notify('삭제되었습니다.', 'success'); + loadCodes(); + onUpdate(); + } else { + notify(data.error || '삭제 실패', 'error'); + } + } catch (err) { + notify('삭제 실패: ' + err.message, 'error'); + } + }; + + const filteredCodes = codes.filter(c => { + const matchText = filter === '' || + c.code.includes(filter) || + c.name.includes(filter); + const matchCategory = categoryFilter === '' || c.category === categoryFilter; + return matchText && matchCategory; + }); + + if (!isOpen) return null; + + return ( +
| 코드 | +계정과목명 | +분류 | +상태 | +작업 | +
|---|---|---|---|---|
| {item.code} | +{item.name} | ++ + {item.category || '-'} + + | ++ + | ++ + | +