Added the option management, and moved the configuration of the default currency, the default account for the income and expenses log, and the recurring expenses and incomes to the options.

This commit is contained in:
2023-03-22 15:34:28 +08:00
parent fa3cdace7f
commit 761d5a5824
24 changed files with 1919 additions and 79 deletions

View File

@ -51,6 +51,14 @@ First written: 2023/1/26
{{ A_("Currencies") }}
</a>
</li>
{% if accounting_can_admin() %}
<li>
<a class="dropdown-item {% if request.endpoint and request.endpoint.startswith("accounting.option.") %} active {% endif %}" href="{{ url_for("accounting.option.form") }}">
<i class="fa-solid fa-gear"></i>
{{ A_("Settings") }}
</a>
</li>
{% endif %}
</ul>
</li>
{% endif %}

View File

@ -158,7 +158,7 @@ First written: 2023/2/28
<div id="accounting-description-editor-{{ description_editor.debit_credit }}-recurring-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-recurring-tab">
<div class="accounting-description-editor-buttons">
{% for recurring in description_editor.recurring %}
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-recurring-item" type="button" tabindex="-1" data-template="{{ recurring.template }}" data-accounts="{{ recurring.account_codes|tojson|forceescape }}">
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-recurring-item" type="button" tabindex="-1" data-template="{{ recurring.description_template }}" data-accounts="{{ recurring.account_codes|tojson|forceescape }}">
{{ recurring.name }}
</button>
{% endfor %}

View File

@ -0,0 +1,101 @@
{#
The Mia! Accounting Flask Project
form.html: The option form
Copyright (c) 2023 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22
#}
{% extends "accounting/base.html" %}
{% block accounting_scripts %}
<script src="{{ url_for("accounting.static", filename="js/option-form.js") }}"></script>
{% endblock %}
{% block header %}{% block title %}{{ A_("Settings") }}{% endblock %}{% endblock %}
{% block content %}
<form id="accounting-form" action="{{ url_for("accounting.option.form") }}" method="post" data-recurring-item-template="{{ form.recurring.item_template }}">
{{ form.csrf_token }}
{% if request.args.next %}
<input type="hidden" name="next" value="{{ request.args.next }}">
{% endif %}
<div class="form-floating mb-3">
<select id="accounting-default-currency" class="form-select {% if form.default_currency.errors %} is-invalid {% endif %}" name="default_currency">
{% for currency in accounting_currency_options() %}
<option value="{{ currency.code }}" {% if currency.code == form.default_currency.data %} selected="selected" {% endif %}>{{ currency }}</option>
{% endfor %}
</select>
<label class="form-label" for="accounting-default-currency">{{ A_("Default Currency") }}</label>
<div id="accounting-default-currency-error" class="invalid-feedback">{% if form.default_currency.errors %}{{ form.default_currency.errors[0] }}{% endif %}</div>
</div>
<div class="form-floating mb-3">
<select id="accounting-default-ie-account" class="form-select {% if form.default_ie_account_code.errors %} is-invalid {% endif %}" name="default_ie_account_code">
{% for account in form.ie_accounts %}
<option value="{{ account.code }}" {% if account.code == form.default_ie_account_code.data %} selected="selected" {% endif %}>{{ account }}</option>
{% endfor %}
</select>
<label class="form-label" for="accounting-default-ie-account">{{ A_("Default Account for the Income and Expenses Log") }}</label>
<div id="accounting-default-ie-account-error" class="invalid-feedback">{% if form.default_ie_account_code.errors %}{{ form.default_ie_account_code.errors[0] }}{% endif %}</div>
</div>
{% with expense_income = "expense",
label = A_("Expense"),
recurring_items = form.recurring.expenses %}
{% include "accounting/option/include/form-recurring-expense-income.html" %}
{% endwith %}
{% with expense_income = "income",
label = A_("Income"),
recurring_items = form.recurring.incomes %}
{% include "accounting/option/include/form-recurring-expense-income.html" %}
{% endwith %}
<div class="d-none d-md-block">
<button class="btn btn-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
{{ A_("Save") }}
</button>
</div>
<div class="d-md-none accounting-material-fab">
<button class="btn btn-primary" type="submit">
<i class="fa-solid fa-floppy-disk"></i>
</button>
</div>
</form>
{% with expense_income = "expense",
title = A_("Recurring Expense") %}
{% include "accounting/option/include/recurring-item-editor-modal.html" %}
{% endwith %}
{% with expense_income = "income",
title = A_("Recurring Income") %}
{% include "accounting/option/include/recurring-item-editor-modal.html" %}
{% endwith %}
{% with expense_income = "expense",
accounts = form.recurring.expense_accounts %}
{% include "accounting/option/include/recurring-account-selector-modal.html" %}
{% endwith %}
{% with expense_income = "income",
accounts = form.recurring.income_accounts %}
{% include "accounting/option/include/recurring-account-selector-modal.html" %}
{% endwith %}
{% endblock %}

View File

@ -0,0 +1,39 @@
{#
The Mia! Accounting Flask Project
form-recurring-item.html: The recurring expense or income sub-form in the option form
Copyright (c) 2023 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22
#}
<div id="accounting-recurring-{{ expense_income }}" class="form-control mb-3 accounting-material-text-field accounting-not-empty">
<label class="form-label" for="accounting-recurring-{{ expense_income }}">{{ label }}</label>
<ul id="accounting-recurring-{{ expense_income }}-list" class="list-group mb-2 mt-2">
{% for recurring_item in recurring_items %}
{% with form = recurring_item.form,
item_index = loop.index %}
{% include "accounting/option/include/form-recurring-item.html" %}
{% endwith %}
{% endfor %}
</ul>
<div>
<button id="accounting-recurring-{{ expense_income }}-add" class="btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">
<i class="fas fa-plus"></i>
{{ A_("New") }}
</button>
</div>
</div>

View File

@ -0,0 +1,45 @@
{#
The Mia! Accounting Flask Project
form-recurring-item.html: The recurring item sub-form in the option form
Copyright (c) 2023 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22
#}
{# <ul> For SonarQube not to complain about incorrect HTML #}
<li id="accounting-recurring-{{ expense_income }}-{{ item_index }}" class="list-group-item list-group-item-action accounting-recurring-{{ expense_income }}-item" data-item-index="{{ item_index }}">
<input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-no" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-no" value="{{ item_index }}">
<input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-name" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-name" value="{{ form.name.data|accounting_default }}">
<input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-account-code" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-account_code" value="{{ form.account_code.data|accounting_default }}" data-text="{{ form.account_text|accounting_default }}">
<input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-description_template" value="{{ form.description_template.data|accounting_default }}">
<div class="d-flex justify-content-between">
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-content" class="w-100">
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-control" class="form-control accounting-clickable {% if form.form_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-account-text" class="small">{{ form.account_text|accounting_default }}</div>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-name-text">{{ form.name.data|accounting_default }}</div>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template-text" class="small">{{ form.description_template.data|accounting_default }}</div>
</div>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-error" class="invalid-feedback">{% if form.form_errors %}{{ form.form_errors[0] }}{% endif %}</div>
</div>
<div class="ms-2">
<button id="accounting-recurring-{{ expense_income }}-{{ item_index }}-delete" class="btn btn-danger rounded-circle" type="button">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
</li>
{# </ul> For SonarQube not to complain about incorrect HTML #}

View File

@ -0,0 +1,53 @@
{#
The Mia! Accounting Flask Project
recurring-account-selector-modal.html: The modal of the account selector for the recurring item editor
Copyright (c) 2023 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22
#}
<div id="accounting-recurring-accounting-selector-{{ expense_income }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-recurring-accounting-selector-{{ expense_income }}-modal-label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="accounting-recurring-accounting-selector-{{ expense_income }}-modal-label">{{ A_("Select Account") }}</h1>
<button type="button" class="btn-close" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal" aria-label="{{ A_("Close") }}"></button>
</div>
<div class="modal-body">
<div class="input-group mb-2">
<input id="accounting-recurring-accounting-selector-{{ expense_income }}-query" class="form-control form-control-sm" type="search" placeholder=" " required="required">
<label class="input-group-text" for="accounting-recurring-accounting-selector-{{ expense_income }}-query">
<i class="fa-solid fa-magnifying-glass"></i>
{{ A_("Search") }}
</label>
</div>
<ul id="accounting-recurring-accounting-selector-{{ expense_income }}-option-list" class="list-group accounting-selector-list">
{% for account in accounts %}
<li id="accounting-recurring-accounting-selector-{{ expense_income }}-option-{{ account.code }}" class="list-group-item accounting-clickable accounting-recurring-accounting-selector-{{ expense_income }}-option" data-code="{{ account.code }}" data-text="{{ account }}" data-query-values="{{ account.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">
{{ account }}
</li>
{% endfor %}
</ul>
<p id="accounting-recurring-accounting-selector-{{ expense_income }}-option-no-result" class="d-none">{{ A_("There is no data.") }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">{{ A_("Cancel") }}</button>
<button id="accounting-recurring-accounting-selector-{{ expense_income }}-clear" type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">{{ A_("Clear") }}</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,71 @@
{#
The Mia! Accounting Flask Project
recurring-item-editor-modal.html: The modal of the recurring item editor
Copyright (c) 2023 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22
#}
<form id="accounting-recurring-item-editor-{{ expense_income }}">
<div id="accounting-recurring-item-editor-{{ expense_income }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-recurring-item-editor-{{ expense_income }}-modal-label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="accounting-recurring-item-editor-{{ expense_income }}-modal-label">{{ title }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ A_("Close") }}"></button>
</div>
<div class="modal-body">
<div class="form-floating mb-3">
<input id="accounting-recurring-item-editor-{{ expense_income }}-name" class="form-control" type="text" value="" placeholder=" " required="required">
<label for="accounting-recurring-item-editor-{{ expense_income }}-name">{{ A_("Name") }}</label>
<div id="accounting-recurring-item-editor-{{ expense_income }}-name-error" class="invalid-feedback"></div>
</div>
<div class="mb-3">
<div id="accounting-recurring-item-editor-{{ expense_income }}-account-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target="#accounting-recurring-accounting-selector-{{ expense_income }}-modal">
<label class="form-label" for="accounting-recurring-item-editor-{{ expense_income }}-account">{{ A_("Account") }}</label>
<div id="accounting-recurring-item-editor-{{ expense_income }}-account"></div>
</div>
<div id="accounting-recurring-item-editor-{{ expense_income }}-account-error" class="invalid-feedback"></div>
</div>
<div class="form-floating mb-3">
<input id="accounting-recurring-item-editor-{{ expense_income }}-description-template" class="form-control" type="text" value="" placeholder=" " required="required">
<label for="accounting-recurring-item-editor-{{ expense_income }}-description-template">{{ A_("Description Template") }}</label>
<div id="accounting-recurring-item-editor-{{ expense_income }}-description-template-error" class="invalid-feedback"></div>
</div>
<div class="mb-3 border-top accounting-recurring-description-template-illustration">
<p>{{ A_("Available template variables:") }}</p>
<ul>
<li><code>{this_month_number}</code>: {{ A_("This month, as a number.") }}</li>
<li><code>{this_month_name}</code>: {{ A_("This month, in its name.") }}</li>
<li><code>{last_month_number}</code>: {{ A_("Last month, as a number.") }}</li>
<li><code>{last_month_name}</code>: {{ A_("Last month, in its name.") }}</li>
<li><code>{last_bimonthly_number}</code>: {{ A_("The previous bimonthly period, as numbers.") }}</li>
<li><code>{last_bimonthly_name}</code>: {{ A_("The previous bimonthly period, as their names.") }}</li>
</ul>
<p>{{ A_("Example:") }} <code>{{ A_("Water bill for {last_bimonthly_name}") }}</code></p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ A_("Cancel") }}</button>
<button type="submit" class="btn btn-primary">{{ A_("Save") }}</button>
</div>
</div>
</div>
</div>
</form>