Added support to sort the accounts under the same base account.
This commit is contained in:
parent
eeb05b8616
commit
5238168b2d
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
from flask import request
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, BooleanField
|
from wtforms import StringField, BooleanField
|
||||||
from wtforms.validators import DataRequired, ValidationError
|
from wtforms.validators import DataRequired, ValidationError
|
||||||
@ -128,3 +129,48 @@ def sort_accounts_in(base_code: str, exclude: int) -> None:
|
|||||||
for i in range(len(accounts)):
|
for i in range(len(accounts)):
|
||||||
if accounts[i].no != i + 1:
|
if accounts[i].no != i + 1:
|
||||||
accounts[i].no = i + 1
|
accounts[i].no = i + 1
|
||||||
|
|
||||||
|
|
||||||
|
class AccountSortForm:
|
||||||
|
"""The form to sort the accounts."""
|
||||||
|
|
||||||
|
def __init__(self, base: BaseAccount):
|
||||||
|
"""Constructs the form to sort the accounts under a base account.
|
||||||
|
|
||||||
|
:param base: The base account.
|
||||||
|
"""
|
||||||
|
self.base: BaseAccount = base
|
||||||
|
self.is_modified: bool = False
|
||||||
|
|
||||||
|
def save_order(self) -> None:
|
||||||
|
"""Saves the order of the account.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
accounts: list[Account] = self.base.accounts
|
||||||
|
|
||||||
|
# Collects the specified order.
|
||||||
|
orders: dict[Account, int] = {}
|
||||||
|
for account in accounts:
|
||||||
|
if f"{account.id}-no" in request.form:
|
||||||
|
try:
|
||||||
|
orders[account] = int(request.form[f"{account.id}-no"])
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Missing and invalid orders are appended to the end.
|
||||||
|
missing: list[Account] = [x for x in accounts if x not in orders]
|
||||||
|
if len(missing) > 0:
|
||||||
|
next_no: int = 1 if len(orders) == 0 else max(orders.values()) + 1
|
||||||
|
for account in missing:
|
||||||
|
orders[account] = next_no
|
||||||
|
|
||||||
|
# Sort by the specified order first, and their original order.
|
||||||
|
accounts = sorted(accounts, key=lambda x: (orders[x], x.no, x.code))
|
||||||
|
|
||||||
|
# Update the orders.
|
||||||
|
with db.session.no_autoflush:
|
||||||
|
for i in range(len(accounts)):
|
||||||
|
if accounts[i].no != i + 1:
|
||||||
|
accounts[i].no = i + 1
|
||||||
|
self.is_modified = True
|
||||||
|
@ -29,7 +29,7 @@ from accounting.models import Account, BaseAccount
|
|||||||
from accounting.utils.next_url import inherit_next, or_next
|
from accounting.utils.next_url import inherit_next, or_next
|
||||||
from accounting.utils.pagination import Pagination
|
from accounting.utils.pagination import Pagination
|
||||||
from accounting.utils.permission import can_view, has_permission, can_edit
|
from accounting.utils.permission import can_view, has_permission, can_edit
|
||||||
from .forms import AccountForm, sort_accounts_in
|
from .forms import AccountForm, sort_accounts_in, AccountSortForm
|
||||||
|
|
||||||
bp: Blueprint = Blueprint("account", __name__)
|
bp: Blueprint = Blueprint("account", __name__)
|
||||||
"""The view blueprint for the account management."""
|
"""The view blueprint for the account management."""
|
||||||
@ -162,3 +162,33 @@ def delete_account(account: Account) -> redirect:
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(lazy_gettext("The account is deleted successfully."), "success")
|
flash(lazy_gettext("The account is deleted successfully."), "success")
|
||||||
return redirect(or_next(url_for("accounting.account.list")))
|
return redirect(or_next(url_for("accounting.account.list")))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.get("/sort/<baseAccount:base>", endpoint="sort-form")
|
||||||
|
@has_permission(can_edit)
|
||||||
|
def show_sort_form(base: BaseAccount) -> str:
|
||||||
|
"""Shows the form to sort the accounts under a base account.
|
||||||
|
|
||||||
|
:param base: The base account.
|
||||||
|
:return: The form to sort the accounts under the base account.
|
||||||
|
"""
|
||||||
|
return render_template("accounting/account/sort.html",
|
||||||
|
base=base)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post("/sort/<baseAccount:base>", endpoint="sort")
|
||||||
|
@has_permission(can_edit)
|
||||||
|
def sort_accounts(base: BaseAccount) -> redirect:
|
||||||
|
"""Sorts the accounts under a base account.
|
||||||
|
|
||||||
|
:param base: The base account.
|
||||||
|
:return: Sorts the accounts under the base account.
|
||||||
|
"""
|
||||||
|
form: AccountSortForm = AccountSortForm(base)
|
||||||
|
form.save_order()
|
||||||
|
if not form.is_modified:
|
||||||
|
flash(lazy_gettext("The order was not modified."), "success")
|
||||||
|
return redirect(or_next(url_for("accounting.account.list")))
|
||||||
|
db.session.commit()
|
||||||
|
flash(lazy_gettext("The order is updated successfully."), "success")
|
||||||
|
return redirect(or_next(url_for("accounting.account.list")))
|
||||||
|
37
src/accounting/static/js/account-sort.js
Normal file
37
src/accounting/static/js/account-sort.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* The Mia! Accounting Flask Project
|
||||||
|
* account-sort.js: The JavaScript for the account sorting 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/2/2
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Initializes the page JavaScript.
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const list = document.getElementById("sort-account-list");
|
||||||
|
const onReorder = function () {
|
||||||
|
const accounts = Array.from(list.children);
|
||||||
|
for (let i = 0; i < accounts.length; i++) {
|
||||||
|
const input = document.getElementById("sort-" + accounts[i].dataset.id + "-no");
|
||||||
|
const code = document.getElementById("sort-" + accounts[i].dataset.id + "-code");
|
||||||
|
input.value = i + 1;
|
||||||
|
code.innerText = list.dataset.baseCode + "-" + ("000" + (i + 1)).slice(-3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
initializeDragAndDropSorting(list, onReorder);
|
||||||
|
});
|
108
src/accounting/static/js/drag-and-drop-sorting.js
Normal file
108
src/accounting/static/js/drag-and-drop-sorting.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/* The Mia! Accounting Flask Project
|
||||||
|
* drag-and-drop-sorting.js: The JavaScript for the sorting with drag-and-drop
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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/2/3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the drag-and-drop sorting on a list.
|
||||||
|
*
|
||||||
|
* @param list {HTMLElement} the list to be sorted
|
||||||
|
* @param onReorder {(function())|*} The callback to reorder the items
|
||||||
|
*/
|
||||||
|
function initializeDragAndDropSorting(list, onReorder) {
|
||||||
|
initializeMouseDragAndDropSorting(list, onReorder);
|
||||||
|
initializeTouchDragAndDropSorting(list, onReorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the drag-and-drop sorting with mouse.
|
||||||
|
*
|
||||||
|
* @param list {HTMLElement} the list to be sorted
|
||||||
|
* @param onReorder {(function())|*} The callback to reorder the items
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function initializeMouseDragAndDropSorting(list, onReorder) {
|
||||||
|
const items = Array.from(list.children);
|
||||||
|
let dragged = null;
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.draggable = true;
|
||||||
|
item.addEventListener("dragstart", function () {
|
||||||
|
dragged = item;
|
||||||
|
dragged.classList.add("list-group-item-dark");
|
||||||
|
});
|
||||||
|
item.addEventListener("dragover", function () {
|
||||||
|
onDragOver(dragged, item);
|
||||||
|
onReorder();
|
||||||
|
});
|
||||||
|
item.addEventListener("dragend", function () {
|
||||||
|
dragged.classList.remove("list-group-item-dark");
|
||||||
|
dragged = null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the drag-and-drop sorting with touch devices.
|
||||||
|
*
|
||||||
|
* @param list {HTMLElement} the list to be sorted
|
||||||
|
* @param onReorder {(function())|*} The callback to reorder the items
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function initializeTouchDragAndDropSorting(list, onReorder) {
|
||||||
|
const items = Array.from(list.children);
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.addEventListener("touchstart", function () {
|
||||||
|
item.classList.add("list-group-item-dark");
|
||||||
|
});
|
||||||
|
item.addEventListener("touchmove", function (event) {
|
||||||
|
const touch = event.targetTouches[0];
|
||||||
|
const target = document.elementFromPoint(touch.pageX, touch.pageY);
|
||||||
|
onDragOver(item, target);
|
||||||
|
onReorder();
|
||||||
|
});
|
||||||
|
item.addEventListener("touchend", function () {
|
||||||
|
item.classList.remove("list-group-item-dark");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles when an item is dragged over the other item.
|
||||||
|
*
|
||||||
|
* @param dragged {Element} the item that was dragged
|
||||||
|
* @param target {Element} the other item that was dragged over
|
||||||
|
*/
|
||||||
|
function onDragOver(dragged, target) {
|
||||||
|
if (target.parentElement !== dragged.parentElement || target === dragged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let isBefore = false;
|
||||||
|
for (let p = target; p !== null; p = p.previousSibling) {
|
||||||
|
if (p === dragged) {
|
||||||
|
isBefore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isBefore) {
|
||||||
|
target.parentElement.insertBefore(dragged, target.nextSibling);
|
||||||
|
} else {
|
||||||
|
target.parentElement.insertBefore(dragged, target);
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,10 @@ First written: 2023/1/31
|
|||||||
<i class="fa-solid fa-gear"></i>
|
<i class="fa-solid fa-gear"></i>
|
||||||
{{ A_("Settings") }}
|
{{ A_("Settings") }}
|
||||||
</a>
|
</a>
|
||||||
|
<a class="btn btn-primary" href="{{ url_for("accounting.account.sort", base=obj.base)|append_next }}">
|
||||||
|
<i class="fa-solid fa-sort"></i>
|
||||||
|
{{ A_("Sort") }}
|
||||||
|
</a>
|
||||||
<button class="btn btn-danger" type="button" data-bs-toggle="modal" data-bs-target="#delete-modal">
|
<button class="btn btn-danger" type="button" data-bs-toggle="modal" data-bs-target="#delete-modal">
|
||||||
<i class="fa-solid fa-trash"></i>
|
<i class="fa-solid fa-trash"></i>
|
||||||
{{ A_("Delete") }}
|
{{ A_("Delete") }}
|
||||||
|
75
src/accounting/templates/accounting/account/sort.html
Normal file
75
src/accounting/templates/accounting/account/sort.html
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
{#
|
||||||
|
The Mia! Accounting Flask Project
|
||||||
|
sort.html: The account sorting 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/2/2
|
||||||
|
#}
|
||||||
|
{% extends "accounting/account/include/form.html" %}
|
||||||
|
|
||||||
|
{% block accounting_scripts %}
|
||||||
|
<script src="{{ url_for("accounting.static", filename="js/drag-and-drop-sorting.js") }}"></script>
|
||||||
|
<script src="{{ url_for("accounting.static", filename="js/account-sort.js") }}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}{% block title %}{{ A_("Sort the Accounts of %(base)s", base=base) }}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="btn-group mb-3">
|
||||||
|
<a class="btn btn-primary" href="{{ url_for("accounting.account.list")|or_next }}">
|
||||||
|
<i class="fa-solid fa-circle-chevron-left"></i>
|
||||||
|
{{ A_("Back") }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ url_for("accounting.account.sort", base=base) }}" method="post">
|
||||||
|
<input id="csrf_token" type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
{% if "next" in request.args %}
|
||||||
|
<input type="hidden" name="next" value="{{ request.args["next"] }}">
|
||||||
|
{% endif %}
|
||||||
|
<ul id="sort-account-list" class="list-group mb-3" data-base-code="{{ base.code }}">
|
||||||
|
{% for account in base.accounts|sort(attribute="no") %}
|
||||||
|
<li class="list-group-item d-flex justify-content-between" data-id="{{ account.id }}">
|
||||||
|
<input id="sort-{{ account.id }}-no" type="hidden" name="{{ account.id }}-no" value="{{ loop.index }}">
|
||||||
|
<div>
|
||||||
|
<span id="sort-{{ account.id }}-code">{{ account.code }}</span>
|
||||||
|
{{ account.title }}
|
||||||
|
</div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none"/>
|
||||||
|
<path d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V5H3z"/>
|
||||||
|
</svg>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<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 material-fab">
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<i class="fa-solid fa-floppy-disk"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -8,8 +8,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Mia! Accounting Flask 0.0.0\n"
|
"Project-Id-Version: Mia! Accounting Flask 0.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: imacat@mail.imacat.idv.tw\n"
|
"Report-Msgid-Bugs-To: imacat@mail.imacat.idv.tw\n"
|
||||||
"POT-Creation-Date: 2023-02-01 19:51+0800\n"
|
"POT-Creation-Date: 2023-02-03 07:40+0800\n"
|
||||||
"PO-Revision-Date: 2023-02-01 19:52+0800\n"
|
"PO-Revision-Date: 2023-02-03 07:42+0800\n"
|
||||||
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
|
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
|
||||||
"Language: zh_Hant\n"
|
"Language: zh_Hant\n"
|
||||||
"Language-Team: zh_Hant <imacat@mail.imacat.idv.tw>\n"
|
"Language-Team: zh_Hant <imacat@mail.imacat.idv.tw>\n"
|
||||||
@ -19,19 +19,25 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.11.0\n"
|
"Generated-By: Babel 2.11.0\n"
|
||||||
|
|
||||||
#: src/accounting/account/forms.py:39
|
#: src/accounting/account/forms.py:41
|
||||||
msgid "The base account does not exist."
|
msgid "The base account does not exist."
|
||||||
msgstr "沒有這個基本科目。"
|
msgstr "沒有這個基本科目。"
|
||||||
|
|
||||||
#: src/accounting/account/forms.py:48
|
#: src/accounting/account/forms.py:50
|
||||||
#: src/accounting/static/js/account-form.js:110
|
#: src/accounting/static/js/account-form.js:110
|
||||||
msgid "Please select the base account."
|
msgid "Please select the base account."
|
||||||
msgstr "請選擇基本科目。"
|
msgstr "請選擇基本科目。"
|
||||||
|
|
||||||
#: src/accounting/account/forms.py:53
|
#: src/accounting/account/forms.py:55
|
||||||
msgid "Please fill in the title"
|
msgid "Please fill in the title"
|
||||||
msgstr "請填上標題。"
|
msgstr "請填上標題。"
|
||||||
|
|
||||||
|
#: src/accounting/account/query.py:50
|
||||||
|
#: src/accounting/templates/accounting/account/detail.html:88
|
||||||
|
#: src/accounting/templates/accounting/account/list.html:62
|
||||||
|
msgid "Offset needed"
|
||||||
|
msgstr "逐筆核銷"
|
||||||
|
|
||||||
#: src/accounting/account/views.py:88
|
#: src/accounting/account/views.py:88
|
||||||
msgid "The account is added successfully"
|
msgid "The account is added successfully"
|
||||||
msgstr "科目加好了。"
|
msgstr "科目加好了。"
|
||||||
@ -48,6 +54,14 @@ msgstr "科目存好了。"
|
|||||||
msgid "The account is deleted successfully."
|
msgid "The account is deleted successfully."
|
||||||
msgstr "科目刪掉了"
|
msgstr "科目刪掉了"
|
||||||
|
|
||||||
|
#: src/accounting/account/views.py:190
|
||||||
|
msgid "The order was not modified."
|
||||||
|
msgstr "順序未異動。"
|
||||||
|
|
||||||
|
#: src/accounting/account/views.py:193
|
||||||
|
msgid "The order is updated successfully."
|
||||||
|
msgstr "順序存好了。"
|
||||||
|
|
||||||
#: src/accounting/static/js/account-form.js:130
|
#: src/accounting/static/js/account-form.js:130
|
||||||
msgid "Please fill in the title."
|
msgid "Please fill in the title."
|
||||||
msgstr "請填上標題。"
|
msgstr "請填上標題。"
|
||||||
@ -58,6 +72,7 @@ msgstr "新增科目"
|
|||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:31
|
#: src/accounting/templates/accounting/account/detail.html:31
|
||||||
#: src/accounting/templates/accounting/account/include/form.html:33
|
#: src/accounting/templates/accounting/account/include/form.html:33
|
||||||
|
#: src/accounting/templates/accounting/account/sort.html:35
|
||||||
#: src/accounting/templates/accounting/base-account/detail.html:31
|
#: src/accounting/templates/accounting/base-account/detail.html:31
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "回上頁"
|
msgstr "回上頁"
|
||||||
@ -67,36 +82,35 @@ msgid "Settings"
|
|||||||
msgstr "設定"
|
msgstr "設定"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:40
|
#: src/accounting/templates/accounting/account/detail.html:40
|
||||||
|
msgid "Sort"
|
||||||
|
msgstr "排序"
|
||||||
|
|
||||||
|
#: src/accounting/templates/accounting/account/detail.html:44
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "刪除"
|
msgstr "刪除"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:63
|
#: src/accounting/templates/accounting/account/detail.html:67
|
||||||
msgid "Delete Account Confirmation"
|
msgid "Delete Account Confirmation"
|
||||||
msgstr "科目刪除確認"
|
msgstr "科目刪除確認"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:67
|
#: src/accounting/templates/accounting/account/detail.html:71
|
||||||
msgid "Do you really want to delete this account?"
|
msgid "Do you really want to delete this account?"
|
||||||
msgstr "你確定要刪掉這個科目嗎?"
|
msgstr "你確定要刪掉這個科目嗎?"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:70
|
#: src/accounting/templates/accounting/account/detail.html:74
|
||||||
#: src/accounting/templates/accounting/account/include/form.html:111
|
#: src/accounting/templates/accounting/account/include/form.html:111
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:71
|
#: src/accounting/templates/accounting/account/detail.html:75
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "確定"
|
msgstr "確定"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:84
|
#: src/accounting/templates/accounting/account/detail.html:92
|
||||||
#: src/accounting/templates/accounting/account/list.html:62
|
|
||||||
msgid "Offset needed"
|
|
||||||
msgstr "逐筆核銷"
|
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:88
|
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "建檔"
|
msgstr "建檔"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/detail.html:89
|
#: src/accounting/templates/accounting/account/detail.html:93
|
||||||
msgid "Updated"
|
msgid "Updated"
|
||||||
msgstr "更新"
|
msgstr "更新"
|
||||||
|
|
||||||
@ -124,6 +138,16 @@ msgstr "搜尋"
|
|||||||
msgid "There is no data."
|
msgid "There is no data."
|
||||||
msgstr "沒有資料。"
|
msgstr "沒有資料。"
|
||||||
|
|
||||||
|
#: src/accounting/templates/accounting/account/sort.html:28
|
||||||
|
#, python-format
|
||||||
|
msgid "Sort the Accounts of %(base)s"
|
||||||
|
msgstr "%(base)s下的科目排序"
|
||||||
|
|
||||||
|
#: src/accounting/templates/accounting/account/include/form.html:75
|
||||||
|
#: src/accounting/templates/accounting/account/sort.html:67
|
||||||
|
msgid "Save"
|
||||||
|
msgstr "儲存"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/include/form.html:45
|
#: src/accounting/templates/accounting/account/include/form.html:45
|
||||||
msgid "Base account"
|
msgid "Base account"
|
||||||
msgstr "基本科目"
|
msgstr "基本科目"
|
||||||
@ -140,10 +164,6 @@ msgstr "標題"
|
|||||||
msgid "The entries in the account need offsets."
|
msgid "The entries in the account need offsets."
|
||||||
msgstr "帳目要逐筆核銷。"
|
msgstr "帳目要逐筆核銷。"
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/include/form.html:75
|
|
||||||
msgid "Save"
|
|
||||||
msgstr "儲存"
|
|
||||||
|
|
||||||
#: src/accounting/templates/accounting/account/include/form.html:90
|
#: src/accounting/templates/accounting/account/include/form.html:90
|
||||||
msgid "Select Base Account"
|
msgid "Select Base Account"
|
||||||
msgstr "選擇基本科目"
|
msgstr "選擇基本科目"
|
||||||
|
Loading…
Reference in New Issue
Block a user