CSV取込機能を実装し、Expenseモデルと関連するStore・ExpenseCategoryモデルを追加。CSVパーサーを作成し、出光CSVに対応。明細編集画面のAJAX保存機能を実装し、取込結果を表示する機能を追加。作業ログをdiary.mdに追記。
This commit is contained in:
@@ -5,6 +5,12 @@
|
||||
{% block content %}
|
||||
<section>
|
||||
<h2>明細編集</h2>
|
||||
{% if imported %}
|
||||
<p>取込件数: {{ imported }} / 重複件数: {{ duplicated }} / 文字コード: {{ encoding }}</p>
|
||||
{% endif %}
|
||||
<form>
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -18,10 +24,127 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="7">データはここに表示されます。</td>
|
||||
</tr>
|
||||
{% for expense in expenses %}
|
||||
<tr data-expense-id="{{ expense.id }}">
|
||||
<td>{{ expense.use_date }}</td>
|
||||
<td>{{ expense.description }}</td>
|
||||
<td>{{ expense.amount }}</td>
|
||||
<td>
|
||||
<select class="js-expense-field" data-field="store_id">
|
||||
<option value="">未設定</option>
|
||||
{% for store in stores %}
|
||||
<option value="{{ store.id }}" {% if expense.store_id == store.id %}selected{% endif %}>
|
||||
{{ store.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select class="js-expense-field" data-field="expense_category_id">
|
||||
<option value="">未設定</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category.id }}" {% if expense.expense_category_id == category.id %}selected{% endif %}>
|
||||
{{ category.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<label>
|
||||
<input
|
||||
class="js-expense-field"
|
||||
data-field="is_business"
|
||||
type="radio"
|
||||
name="is_business_{{ expense.id }}"
|
||||
value="true"
|
||||
{% if expense.is_business is True %}checked{% endif %}
|
||||
>
|
||||
会社
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
class="js-expense-field"
|
||||
data-field="is_business"
|
||||
type="radio"
|
||||
name="is_business_{{ expense.id }}"
|
||||
value="false"
|
||||
{% if expense.is_business is False %}checked{% endif %}
|
||||
>
|
||||
家計
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
class="js-expense-field"
|
||||
data-field="is_business"
|
||||
type="radio"
|
||||
name="is_business_{{ expense.id }}"
|
||||
value=""
|
||||
{% if expense.is_business is None %}checked{% endif %}
|
||||
>
|
||||
未設定
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="js-expense-field"
|
||||
data-field="note"
|
||||
type="text"
|
||||
value="{{ expense.note }}"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="7">データがありません。</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]')?.value;
|
||||
|
||||
async function saveExpense(expenseId, payload) {
|
||||
const response = await fetch(`/expenses/${expenseId}/update/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('保存に失敗しました');
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function coerceValue(field, value) {
|
||||
if (field === 'is_business') {
|
||||
if (value === '') {
|
||||
return null;
|
||||
}
|
||||
return value === 'true';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.js-expense-field').forEach((element) => {
|
||||
const eventName = element.tagName === 'INPUT' ? 'change' : 'change';
|
||||
element.addEventListener(eventName, async (event) => {
|
||||
const row = event.target.closest('tr');
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
const expenseId = row.dataset.expenseId;
|
||||
const field = event.target.dataset.field;
|
||||
const value = coerceValue(field, event.target.value);
|
||||
try {
|
||||
await saveExpense(expenseId, { [field]: value });
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user