feat:카드 사용내역 공제/증빙/내역 필드 수정 기능 추가
- 공제 필드: 공제/불공 선택 가능 (불공은 적색 표시) - 증빙/판매자상호 필드: 텍스트 입력으로 수정 가능 - 내역 필드: 텍스트 입력으로 수정 가능 - CardTransaction 모델에 deduction_type, evidence_name, description 필드 추가 - 마이그레이션 추가 - 컨트롤러에서 새 필드 저장/로드 처리 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -548,6 +548,10 @@ private function parseTransactionLogs($resultData, $savedData = null): array
|
||||
// 저장된 계정과목 정보 병합
|
||||
'accountCode' => $savedItem?->account_code ?? '',
|
||||
'accountName' => $savedItem?->account_name ?? '',
|
||||
// 수정 가능한 필드들 (저장된 값 또는 기본값)
|
||||
'deductionType' => $savedItem?->deduction_type ?? ($log->UseStoreCorpNum ? 'deductible' : 'non_deductible'),
|
||||
'evidenceName' => $savedItem?->evidence_name ?? ($log->UseStoreName ?? ''),
|
||||
'description' => $savedItem?->description ?? ($log->UseStoreBizType ?? $log->Memo ?? ''),
|
||||
'isSaved' => $savedItem !== null,
|
||||
];
|
||||
|
||||
@@ -716,6 +720,9 @@ public function save(Request $request): JsonResponse
|
||||
'use_key' => $trans['useKey'] ?? '',
|
||||
'account_code' => $trans['accountCode'] ?? null,
|
||||
'account_name' => $trans['accountName'] ?? null,
|
||||
'deduction_type' => $trans['deductionType'] ?? null,
|
||||
'evidence_name' => $trans['evidenceName'] ?? null,
|
||||
'description' => $trans['description'] ?? null,
|
||||
];
|
||||
|
||||
// Upsert: 있으면 업데이트, 없으면 생성
|
||||
@@ -727,10 +734,13 @@ public function save(Request $request): JsonResponse
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
// 계정과목만 업데이트
|
||||
// 계정과목 및 수정 가능한 필드들 업데이트
|
||||
$existing->update([
|
||||
'account_code' => $data['account_code'],
|
||||
'account_name' => $data['account_name'],
|
||||
'deduction_type' => $data['deduction_type'],
|
||||
'evidence_name' => $data['evidence_name'],
|
||||
'description' => $data['description'],
|
||||
]);
|
||||
$updated++;
|
||||
} else {
|
||||
|
||||
@@ -38,6 +38,9 @@ class CardTransaction extends Model
|
||||
'use_key',
|
||||
'account_code',
|
||||
'account_name',
|
||||
'deduction_type',
|
||||
'evidence_name',
|
||||
'description',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
* 카드 거래 내역에 수정 가능한 필드 추가
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('barobill_card_transactions', function (Blueprint $table) {
|
||||
// 공제 유형: 공제(deductible) / 불공(non_deductible)
|
||||
$table->string('deduction_type', 20)->nullable()->after('account_name')->comment('공제유형: deductible/non_deductible');
|
||||
// 증빙/판매자상호 (사용자 수정용)
|
||||
$table->string('evidence_name', 255)->nullable()->after('deduction_type')->comment('증빙/판매자상호 (수정용)');
|
||||
// 내역 (사용자 수정용)
|
||||
$table->string('description', 500)->nullable()->after('evidence_name')->comment('내역 (수정용)');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('barobill_card_transactions', function (Blueprint $table) {
|
||||
$table->dropColumn(['deduction_type', 'evidence_name', 'description']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -471,6 +471,7 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
|
||||
totalCount,
|
||||
accountCodes,
|
||||
onAccountCodeChange,
|
||||
onFieldChange,
|
||||
onSave,
|
||||
onExport,
|
||||
saving,
|
||||
@@ -644,22 +645,39 @@ className="p-1.5 text-purple-500 hover:bg-purple-100 rounded-lg transition-color
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-center">
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
log.merchantBizNum
|
||||
? 'bg-green-100 text-green-700'
|
||||
: 'bg-stone-100 text-stone-500'
|
||||
}`}>
|
||||
{log.merchantBizNum ? '공제' : '불공제'}
|
||||
</span>
|
||||
<select
|
||||
value={log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible')}
|
||||
onChange={(e) => onFieldChange(index, 'deductionType', e.target.value)}
|
||||
className={`px-2 py-1 rounded text-xs font-medium border-0 cursor-pointer ${
|
||||
(log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible')) === 'deductible'
|
||||
? 'bg-green-100 text-green-700'
|
||||
: 'bg-red-100 text-red-600'
|
||||
}`}
|
||||
>
|
||||
<option value="deductible">공제</option>
|
||||
<option value="non_deductible">불공</option>
|
||||
</select>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<div className="font-medium text-stone-900">{log.merchantName || '-'}</div>
|
||||
<input
|
||||
type="text"
|
||||
value={log.evidenceName ?? log.merchantName ?? ''}
|
||||
onChange={(e) => onFieldChange(index, 'evidenceName', e.target.value)}
|
||||
className="w-full px-2 py-1 text-sm border border-stone-200 rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500"
|
||||
placeholder="판매자상호"
|
||||
/>
|
||||
{log.merchantBizNum && (
|
||||
<div className="text-xs text-stone-400">{log.merchantBizNum}</div>
|
||||
<div className="text-xs text-stone-400 mt-1">{log.merchantBizNum}</div>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-stone-600 text-sm">
|
||||
{log.merchantBizType || log.memo || '-'}
|
||||
<td className="px-4 py-3">
|
||||
<input
|
||||
type="text"
|
||||
value={log.description ?? log.merchantBizType ?? log.memo ?? ''}
|
||||
onChange={(e) => onFieldChange(index, 'description', e.target.value)}
|
||||
className="w-full px-2 py-1 text-sm border border-stone-200 rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500"
|
||||
placeholder="내역"
|
||||
/>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-right font-medium">
|
||||
<span className={log.approvalType === '1' ? 'text-purple-600' : 'text-red-600'}>
|
||||
@@ -935,6 +953,19 @@ className="text-xs text-amber-600 hover:text-amber-700 underline"
|
||||
setHasChanges(true);
|
||||
}, []);
|
||||
|
||||
// 필드 변경 핸들러 (공제, 증빙/판매자상호, 내역)
|
||||
const handleFieldChange = useCallback((index, field, value) => {
|
||||
setLogs(prevLogs => {
|
||||
const newLogs = [...prevLogs];
|
||||
newLogs[index] = {
|
||||
...newLogs[index],
|
||||
[field]: value
|
||||
};
|
||||
return newLogs;
|
||||
});
|
||||
setHasChanges(true);
|
||||
}, []);
|
||||
|
||||
// 저장 핸들러
|
||||
const handleSave = async () => {
|
||||
if (logs.length === 0) return;
|
||||
@@ -1095,6 +1126,7 @@ className="text-xs text-amber-600 hover:text-amber-700 underline"
|
||||
totalCount={summary.count || logs.length}
|
||||
accountCodes={accountCodes}
|
||||
onAccountCodeChange={handleAccountCodeChange}
|
||||
onFieldChange={handleFieldChange}
|
||||
onSave={handleSave}
|
||||
onExport={handleExport}
|
||||
saving={saving}
|
||||
|
||||
Reference in New Issue
Block a user