Merge pull request #38086 from frappe/version-14-hotfix

chore: release v14
This commit is contained in:
Deepesh Garg
2023-11-14 18:25:20 +05:30
committed by GitHub
18 changed files with 183 additions and 119 deletions

View File

@@ -112,7 +112,8 @@ class AutoMatchbyPartyNameDescription:
for party in parties:
filters = {"status": "Active"} if party == "Employee" else {"disabled": 0}
names = frappe.get_all(party, filters=filters, pluck=party.lower() + "_name")
field = party.lower() + "_name"
names = frappe.get_all(party, filters=filters, fields=[f"{field} as party_name", "name"])
for field in ["bank_party_name", "description"]:
if not self.get(field):
@@ -131,7 +132,11 @@ class AutoMatchbyPartyNameDescription:
def fuzzy_search_and_return_result(self, party, names, field) -> Union[Tuple, None]:
skip = False
result = process.extract(query=self.get(field), choices=names, scorer=fuzz.token_set_ratio)
result = process.extract(
query=self.get(field),
choices={row.get("name"): row.get("party_name") for row in names},
scorer=fuzz.token_set_ratio,
)
party_name, skip = self.process_fuzzy_result(result)
if not party_name:
@@ -149,14 +154,14 @@ class AutoMatchbyPartyNameDescription:
Returns: Result, Skip (whether or not to discontinue matching)
"""
PARTY, SCORE, CUTOFF = 0, 1, 80
SCORE, PARTY_ID, CUTOFF = 1, 2, 80
if not result or not len(result):
return None, False
first_result = result[0]
if len(result) == 1:
return (first_result[PARTY] if first_result[SCORE] > CUTOFF else None), True
return (first_result[PARTY_ID] if first_result[SCORE] > CUTOFF else None), True
second_result = result[1]
if first_result[SCORE] > CUTOFF:
@@ -165,7 +170,7 @@ class AutoMatchbyPartyNameDescription:
if first_result[SCORE] == second_result[SCORE]:
return None, True
return first_result[PARTY], True
return first_result[PARTY_ID], True
else:
return None, False

View File

@@ -53,10 +53,18 @@ frappe.ui.form.on('Chart of Accounts Importer', {
of Accounts. Please enter the account names and add more rows as per your requirement.`);
}
}
}
},
{
label : "Company",
fieldname: "company",
fieldtype: "Link",
reqd: 1,
hidden: 1,
default: frm.doc.company,
},
],
primary_action: function() {
var data = d.get_values();
let data = d.get_values();
if (!data.template_type) {
frappe.throw(__('Please select <b>Template Type</b> to download template'));
@@ -66,7 +74,8 @@ frappe.ui.form.on('Chart of Accounts Importer', {
'/api/method/erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template',
{
file_type: data.file_type,
template_type: data.template_type
template_type: data.template_type,
company: data.company
}
);

View File

@@ -8,6 +8,7 @@ from functools import reduce
import frappe
from frappe import _
from frappe.desk.form.linked_with import get_linked_fields
from frappe.model.document import Document
from frappe.utils import cint, cstr
from frappe.utils.csvutils import UnicodeWriter
@@ -294,10 +295,8 @@ def build_response_as_excel(writer):
@frappe.whitelist()
def download_template(file_type, template_type):
data = frappe._dict(frappe.local.form_dict)
writer = get_template(template_type)
def download_template(file_type, template_type, company):
writer = get_template(template_type, company)
if file_type == "CSV":
# download csv file
@@ -308,8 +307,7 @@ def download_template(file_type, template_type):
build_response_as_excel(writer)
def get_template(template_type):
def get_template(template_type, company):
fields = [
"Account Name",
"Parent Account",
@@ -335,34 +333,17 @@ def get_template(template_type):
["", "", "", "", 0, account_type.get("account_type"), account_type.get("root_type")]
)
else:
writer = get_sample_template(writer)
writer = get_sample_template(writer, company)
return writer
def get_sample_template(writer):
template = [
["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"],
["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"],
["Equity", "", "", "", 1, "", "Equity"],
["Expenses", "", "", "", 1, "", "Expense"],
["Income", "", "", "", 1, "", "Income"],
["Bank Accounts", "Application Of Funds(Assets)", "", "", 1, "Bank", "Asset"],
["Cash In Hand", "Application Of Funds(Assets)", "", "", 1, "Cash", "Asset"],
["Stock Assets", "Application Of Funds(Assets)", "", "", 1, "Stock", "Asset"],
["Cost Of Goods Sold", "Expenses", "", "", 0, "Cost of Goods Sold", "Expense"],
["Asset Depreciation", "Expenses", "", "", 0, "Depreciation", "Expense"],
["Fixed Assets", "Application Of Funds(Assets)", "", "", 0, "Fixed Asset", "Asset"],
["Accounts Payable", "Sources Of Funds(Liabilities)", "", "", 0, "Payable", "Liability"],
["Accounts Receivable", "Application Of Funds(Assets)", "", "", 1, "Receivable", "Asset"],
["Stock Expenses", "Expenses", "", "", 0, "Stock Adjustment", "Expense"],
["Sample Bank", "Bank Accounts", "", "", 0, "Bank", "Asset"],
["Cash", "Cash In Hand", "", "", 0, "Cash", "Asset"],
["Stores", "Stock Assets", "", "", 0, "Stock", "Asset"],
]
for row in template:
writer.writerow(row)
def get_sample_template(writer, company):
currency = frappe.db.get_value("Company", company, "default_currency")
with open(os.path.join(os.path.dirname(__file__), "coa_sample_template.csv"), "r") as f:
for row in f:
row = row.strip().split(",") + [currency]
writer.writerow(row)
return writer
@@ -453,14 +434,11 @@ def get_mandatory_account_types():
def unset_existing_data(company):
linked = frappe.db.sql(
'''select fieldname from tabDocField
where fieldtype="Link" and options="Account" and parent="Company"''',
as_dict=True,
)
# remove accounts data from company
update_values = {d.fieldname: "" for d in linked}
fieldnames = get_linked_fields("Account").get("Company", {}).get("fieldname", [])
linked = [{"fieldname": name} for name in fieldnames]
update_values = {d.get("fieldname"): "" for d in linked}
frappe.db.set_value("Company", company, update_values, update_values)
# remove accounts data from various doctypes

View File

@@ -0,0 +1,17 @@
Application Of Funds(Assets),,,,1,,Asset
Sources Of Funds(Liabilities),,,,1,,Liability
Equity,,,,1,,Equity
Expenses,,,,1,Expense Account,Expense
Income,,,,1,Income Account,Income
Bank Accounts,Application Of Funds(Assets),,,1,Bank,Asset
Cash In Hand,Application Of Funds(Assets),,,1,Cash,Asset
Stock Assets,Application Of Funds(Assets),,,1,Stock,Asset
Cost Of Goods Sold,Expenses,,,0,Cost of Goods Sold,Expense
Asset Depreciation,Expenses,,,0,Depreciation,Expense
Fixed Assets,Application Of Funds(Assets),,,0,Fixed Asset,Asset
Accounts Payable,Sources Of Funds(Liabilities),,,0,Payable,Liability
Accounts Receivable,Application Of Funds(Assets),,,1,Receivable,Asset
Stock Expenses,Expenses,,,0,Stock Adjustment,Expense
Sample Bank,Bank Accounts,,,0,Bank,Asset
Cash,Cash In Hand,,,0,Cash,Asset
Stores,Stock Assets,,,0,Stock,Asset
1 Application Of Funds(Assets) 1 Asset
2 Sources Of Funds(Liabilities) 1 Liability
3 Equity 1 Equity
4 Expenses 1 Expense Account Expense
5 Income 1 Income Account Income
6 Bank Accounts Application Of Funds(Assets) 1 Bank Asset
7 Cash In Hand Application Of Funds(Assets) 1 Cash Asset
8 Stock Assets Application Of Funds(Assets) 1 Stock Asset
9 Cost Of Goods Sold Expenses 0 Cost of Goods Sold Expense
10 Asset Depreciation Expenses 0 Depreciation Expense
11 Fixed Assets Application Of Funds(Assets) 0 Fixed Asset Asset
12 Accounts Payable Sources Of Funds(Liabilities) 0 Payable Liability
13 Accounts Receivable Application Of Funds(Assets) 1 Receivable Asset
14 Stock Expenses Expenses 0 Stock Adjustment Expense
15 Sample Bank Bank Accounts 0 Bank Asset
16 Cash Cash In Hand 0 Cash Asset
17 Stores Stock Assets 0 Stock Asset

View File

@@ -114,10 +114,13 @@ frappe.query_reports["Accounts Receivable"] = {
"reqd": 1
},
{
"fieldname": "customer_group",
"fieldname":"customer_group",
"label": __("Customer Group"),
"fieldtype": "Link",
"options": "Customer Group"
"fieldtype": "MultiSelectList",
"options": "Customer Group",
get_data: function(txt) {
return frappe.db.get_link_options('Customer Group', txt);
}
},
{
"fieldname": "payment_terms_template",

View File

@@ -849,7 +849,13 @@ class ReceivablePayableReport(object):
self.customer = qb.DocType("Customer")
if self.filters.get("customer_group"):
self.get_hierarchical_filters("Customer Group", "customer_group")
groups = get_customer_group_with_children(self.filters.customer_group)
customers = (
qb.from_(self.customer)
.select(self.customer.name)
.where(self.customer["customer_group"].isin(groups))
)
self.qb_selection_filter.append(self.ple.party.isin(customers))
if self.filters.get("territory"):
self.get_hierarchical_filters("Territory", "territory")
@@ -1141,3 +1147,19 @@ class ReceivablePayableReport(object):
.run()
)
self.err_journals = [x[0] for x in results] if results else []
def get_customer_group_with_children(customer_groups):
if not isinstance(customer_groups, list):
customer_groups = [d.strip() for d in customer_groups.strip().split(",") if d]
all_customer_groups = []
for d in customer_groups:
if frappe.db.exists("Customer Group", d):
lft, rgt = frappe.db.get_value("Customer Group", d, ["lft", "rgt"])
children = frappe.get_all("Customer Group", filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
all_customer_groups += [c.name for c in children]
else:
frappe.throw(_("Customer Group: {0} does not exist").format(d))
return list(set(all_customer_groups))

View File

@@ -475,6 +475,30 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
report = execute(filters)[1]
self.assertEqual(len(report), 0)
def test_multi_customer_group_filter(self):
si = self.create_sales_invoice()
cus_group = frappe.db.get_value("Customer", self.customer, "customer_group")
# Create a list of customer groups, e.g., ["Group1", "Group2"]
cus_groups_list = [cus_group, "_Test Customer Group 1"]
filters = {
"company": self.company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
"customer_group": cus_groups_list, # Use the list of customer groups
}
report = execute(filters)[1]
# Assert that the report contains data for the specified customer groups
self.assertTrue(len(report) > 0)
for row in report:
# Assert that the customer group of each row is in the list of customer groups
self.assertIn(row.customer_group, cus_groups_list)
def test_party_account_filter(self):
si1 = self.create_sales_invoice()
self.customer2 = (

View File

@@ -338,7 +338,7 @@ class BuyingController(SubcontractingController):
{
"item_code": d.item_code,
"warehouse": d.get("from_warehouse"),
"posting_date": self.get("posting_date") or self.get("transation_date"),
"posting_date": self.get("posting_date") or self.get("transaction_date"),
"posting_time": posting_time,
"qty": -1 * flt(d.get("stock_qty")),
"serial_no": d.get("serial_no"),

View File

@@ -89,10 +89,6 @@ frappe.ui.form.on('Production Plan', {
frm.trigger("show_progress");
if (frm.doc.status !== "Completed") {
frm.add_custom_button(__("Work Order Tree"), ()=> {
frappe.set_route('Tree', 'Work Order', {production_plan: frm.doc.name});
}, __('View'));
frm.add_custom_button(__("Production Plan Summary"), ()=> {
frappe.set_route('query-report', 'Production Plan Summary', {production_plan: frm.doc.name});
}, __('View'));

View File

@@ -827,8 +827,6 @@ class ProductionPlan(Document):
# Combine subassembly items
sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
sub_assembly_items_store.sort(key=lambda d: d.bom_level, reverse=True) # sort by bom level
for idx, row in enumerate(sub_assembly_items_store):
row.idx = idx + 1
self.append("sub_assembly_items", row)

View File

@@ -653,49 +653,6 @@ class TestProductionPlan(FrappeTestCase):
frappe.db.rollback()
def test_subassmebly_sorting(self):
"Test subassembly sorting in case of multiple items with nested BOMs."
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
prefix = "_TestLevel_"
boms = {
"Assembly": {
"SubAssembly1": {
"ChildPart1": {},
"ChildPart2": {},
},
"ChildPart6": {},
"SubAssembly4": {"SubSubAssy2": {"ChildPart7": {}}},
},
"MegaDeepAssy": {
"SecretSubassy": {
"SecretPart": {"VerySecret": {"SuperSecret": {"Classified": {}}}},
},
# ^ assert that this is
# first item in subassy table
},
}
create_nested_bom(boms, prefix=prefix)
items = [prefix + item_code for item_code in boms.keys()]
plan = create_production_plan(item_code=items[0], do_not_save=True)
plan.append(
"po_items",
{
"use_multi_level_bom": 1,
"item_code": items[1],
"bom_no": frappe.db.get_value("Item", items[1], "default_bom"),
"planned_qty": 1,
"planned_start_date": now_datetime(),
},
)
plan.get_sub_assembly_items()
bom_level_order = [d.bom_level for d in plan.sub_assembly_items]
self.assertEqual(bom_level_order, sorted(bom_level_order, reverse=True))
# lowest most level of subassembly should be first
self.assertIn("SuperSecret", plan.sub_assembly_items[0].production_item)
def test_multiple_work_order_for_production_plan_item(self):
"Test producing Prod Plan (making WO) in parts."

View File

@@ -22,9 +22,9 @@ frappe.query_reports["Production Plan Summary"] = {
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (column.fieldname == "document_name") {
if (column.fieldname == "item_code") {
var color = data.pending_qty > 0 ? 'red': 'green';
value = `<a style='color:${color}' href="#Form/${data['document_type']}/${data['document_name']}" data-doctype="${data['document_type']}">${data['document_name']}</a>`;
value = `<a style='color:${color}' href="/app/item/${data['item_code']}" data-doctype="Item">${data['item_code']}</a>`;
}
return value;

View File

@@ -44,6 +44,7 @@ def get_production_plan_item_details(filters, data, order_details):
{
"indent": 0,
"item_code": row.item_code,
"sales_order": row.get("sales_order"),
"item_name": frappe.get_cached_value("Item", row.item_code, "item_name"),
"qty": row.planned_qty,
"document_type": "Work Order",
@@ -80,7 +81,7 @@ def get_production_plan_sub_assembly_item_details(
data.append(
{
"indent": 1,
"indent": 1 + item.indent,
"item_code": item.production_item,
"item_name": item.item_name,
"qty": item.qty,
@@ -98,7 +99,7 @@ def get_work_order_details(filters, order_details):
for row in frappe.get_all(
"Work Order",
filters={"production_plan": filters.get("production_plan")},
fields=["name", "produced_qty", "production_plan", "production_item"],
fields=["name", "produced_qty", "production_plan", "production_item", "sales_order"],
):
order_details.setdefault((row.name, row.production_item), row)
@@ -118,10 +119,17 @@ def get_column(filters):
"label": _("Finished Good"),
"fieldtype": "Link",
"fieldname": "item_code",
"width": 300,
"width": 240,
"options": "Item",
},
{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 100},
{"label": _("Item Name"), "fieldtype": "data", "fieldname": "item_name", "width": 150},
{
"label": _("Sales Order"),
"options": "Sales Order",
"fieldtype": "Link",
"fieldname": "sales_order",
"width": 100,
},
{
"label": _("Document Type"),
"fieldtype": "Link",
@@ -133,10 +141,16 @@ def get_column(filters):
"label": _("Document Name"),
"fieldtype": "Dynamic Link",
"fieldname": "document_name",
"width": 150,
"options": "document_type",
"width": 180,
},
{"label": _("BOM Level"), "fieldtype": "Int", "fieldname": "bom_level", "width": 100},
{"label": _("Order Qty"), "fieldtype": "Float", "fieldname": "qty", "width": 120},
{"label": _("Received Qty"), "fieldtype": "Float", "fieldname": "produced_qty", "width": 160},
{
"label": _("Produced / Received Qty"),
"fieldtype": "Float",
"fieldname": "produced_qty",
"width": 200,
},
{"label": _("Pending Qty"), "fieldtype": "Float", "fieldname": "pending_qty", "width": 110},
]

View File

@@ -541,6 +541,7 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
primary_action={
"label": "Send Email",
"server_action": "erpnext.selling.doctype.customer.customer.send_emails",
"hide_on_success": True,
"args": {
"customer": customer,
"customer_outstanding": customer_outstanding,

View File

@@ -80,7 +80,7 @@ def get_data(filters=None):
territory_orders = []
if t_quotation_names and sales_orders:
list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
territory_orders = list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
t_order_names = []
if territory_orders:
t_order_names = [t.name for t in territory_orders]

View File

@@ -108,7 +108,16 @@ class TransactionDeletionRecord(Document):
if no_of_docs > 0:
self.delete_version_log(docfield["parent"], docfield["fieldname"])
self.delete_communications(docfield["parent"], docfield["fieldname"])
reference_docs = frappe.get_all(
docfield["parent"], filters={docfield["fieldname"]: self.company}
)
reference_doc_names = [r.name for r in reference_docs]
self.delete_communications(docfield["parent"], reference_doc_names)
self.delete_comments(docfield["parent"], reference_doc_names)
self.unlink_attachments(docfield["parent"], reference_doc_names)
self.populate_doctypes_table(tables, docfield["parent"], no_of_docs)
self.delete_child_tables(docfield["parent"], docfield["fieldname"])
@@ -197,19 +206,49 @@ class TransactionDeletionRecord(Document):
(versions.ref_doctype == doctype) & (versions.docname.isin(batch))
).run()
def delete_communications(self, doctype, company_fieldname):
reference_docs = frappe.get_all(doctype, filters={company_fieldname: self.company})
reference_doc_names = [r.name for r in reference_docs]
def delete_communications(self, doctype, reference_doc_names):
communications = frappe.get_all(
"Communication",
filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
)
communication_names = [c.name for c in communications]
if not communication_names:
return
for batch in create_batch(communication_names, self.batch_size):
frappe.delete_doc("Communication", batch, ignore_permissions=True)
def delete_comments(self, doctype, reference_doc_names):
comments = frappe.get_all(
"Comment",
filters={"reference_doctype": doctype, "reference_name": ["in", reference_doc_names]},
)
comment_names = [c.name for c in comments]
if not comment_names:
return
for batch in create_batch(comment_names, self.batch_size):
frappe.delete_doc("Comment", batch, ignore_permissions=True)
def unlink_attachments(self, doctype, reference_doc_names):
files = frappe.get_all(
"File",
filters={"attached_to_doctype": doctype, "attached_to_name": ["in", reference_doc_names]},
)
file_names = [c.name for c in files]
if not file_names:
return
file = qb.DocType("File")
for batch in create_batch(file_names, self.batch_size):
qb.update(file).set(file.attached_to_doctype, None).set(file.attached_to_name, None).where(
file.name.isin(batch)
).run()
@frappe.whitelist()
def get_doctypes_to_be_ignored():

View File

@@ -61,6 +61,7 @@
"oldfieldname": "item",
"oldfieldtype": "Link",
"options": "Item",
"read_only_depends_on": "eval:!doc.__islocal",
"reqd": 1
},
{
@@ -207,7 +208,7 @@
"image_field": "image",
"links": [],
"max_attachments": 5,
"modified": "2022-02-21 08:08:23.999236",
"modified": "2023-11-09 12:17:28.339975",
"modified_by": "Administrator",
"module": "Stock",
"name": "Batch",

View File

@@ -3671,7 +3671,7 @@ Cannot Optimize Route as Driver Address is Missing.,"Route kann nicht optimiert
Cannot complete task {0} as its dependant task {1} are not ccompleted / cancelled.,"Aufgabe {0} kann nicht abgeschlossen werden, da die abhängige Aufgabe {1} nicht abgeschlossen / abgebrochen wurde.",
Cannot create loan until application is approved,"Darlehen kann erst erstellt werden, wenn der Antrag genehmigt wurde",
Cannot find a matching Item. Please select some other value for {0}.,Ein passender Artikel kann nicht gefunden werden. Bitte einen anderen Wert für {0} auswählen.,
"Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings","Artikel {0} in Zeile {1} kann nicht mehr als {2} in Rechnung gestellt werden. Um eine Überberechnung zuzulassen, legen Sie die Überberechnung in den Kontoeinstellungen fest",
"Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings","Für Artikel {0} in Zeile {1} kann nicht mehr als {2} zusätzlich in Rechnung gestellt werden. Um diese Überfakturierung zuzulassen, passen Sie bitte die Grenzwerte in den Buchhaltungseinstellungen an.",
"Capacity Planning Error, planned start time can not be same as end time","Kapazitätsplanungsfehler, die geplante Startzeit darf nicht mit der Endzeit übereinstimmen",
Categories,Kategorien,
Changes in {0},Änderungen in {0},
@@ -4125,7 +4125,7 @@ This page keeps track of your items in which buyers have showed some interest.,"
Thursday,Donnerstag,
Timing,Zeitliche Koordinierung,
Title,Bezeichnung,
"To allow over billing, update ""Over Billing Allowance"" in Accounts Settings or the Item.","Aktualisieren Sie &quot;Over Billing Allowance&quot; in den Kontoeinstellungen oder im Artikel, um eine Überberechnung zuzulassen.",
"To allow over billing, update ""Over Billing Allowance"" in Accounts Settings or the Item.","Aktualisieren Sie &quot;Over Billing Allowance&quot; in den Buchhaltungseinstellungen oder im Artikel, um eine Überberechnung zuzulassen.",
"To allow over receipt / delivery, update ""Over Receipt/Delivery Allowance"" in Stock Settings or the Item.","Um eine Überbestätigung / Überlieferung zu ermöglichen, aktualisieren Sie &quot;Überbestätigung / Überlieferung&quot; in den Lagereinstellungen oder im Artikel.",
To date needs to be before from date,Das Datum muss vor dem Datum liegen,
Total,Summe,
@@ -4533,8 +4533,8 @@ Mandatory For Profit and Loss Account,Obligatorisch für Gewinn- und Verlustrech
Accounting Period,Abrechnungszeitraum,
Period Name,Zeitraumname,
Closed Documents,Geschlossene Dokumente,
Accounts Settings,Konteneinstellungen,
Settings for Accounts,Konteneinstellungen,
Accounts Settings,Buchhaltungseinstellungen,
Settings for Accounts,Einstellungen für die Buchhaltung,
Make Accounting Entry For Every Stock Movement,Eine Buchung für jede Lagerbewegung erstellen,
Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts,Benutzer mit dieser Rolle sind berechtigt Konten zu sperren und Buchungen zu gesperrten Konten zu erstellen/verändern,
Determine Address Tax Category From,Adresssteuerkategorie bestimmen von,
@@ -8622,7 +8622,7 @@ Template Title,Vorlagentitel,
Journal Entry Type,Buchungssatz-Typ,
Journal Entry Template Account,Buchungssatzvorlagenkonto,
Process Deferred Accounting,Aufgeschobene Buchhaltung verarbeiten,
Manual entry cannot be created! Disable automatic entry for deferred accounting in accounts settings and try again,Manuelle Eingabe kann nicht erstellt werden! Deaktivieren Sie die automatische Eingabe für die verzögerte Buchhaltung in den Konteneinstellungen und versuchen Sie es erneut,
Manual entry cannot be created! Disable automatic entry for deferred accounting in accounts settings and try again,Manuelle Eingabe kann nicht erstellt werden! Deaktivieren Sie die automatische Eingabe für die verzögerte Buchhaltung in den Buchhaltungseinstellungen und versuchen Sie es erneut,
End date cannot be before start date,Das Enddatum darf nicht vor dem Startdatum liegen,
Total Counts Targeted,Gesamtzahl der anvisierten Zählungen,
Total Counts Completed,Gesamtzahl der abgeschlossenen Zählungen,
Can't render this file because it is too large.