Merge pull request #33403 from frappe/version-13-hotfix

chore: release v13
This commit is contained in:
Deepesh Garg
2022-12-20 19:30:24 +05:30
committed by GitHub
12 changed files with 251 additions and 100 deletions

View File

@@ -3,8 +3,10 @@
import frappe import frappe
from frappe import _, msgprint from frappe import _, msgprint, qb
from frappe.model.document import Document from frappe.model.document import Document
from frappe.query_builder import Criterion
from frappe.query_builder.functions import Sum
from frappe.utils import flt, getdate, nowdate, today from frappe.utils import flt, getdate, nowdate, today
import erpnext import erpnext
@@ -120,58 +122,77 @@ class PaymentReconciliation(Document):
return list(journal_entries) return list(journal_entries)
def get_dr_or_cr_notes(self): def get_dr_or_cr_notes(self):
condition = self.get_conditions(get_return_invoices=True) gl = qb.DocType("GL Entry")
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
doc = qb.DocType(voucher_type)
# build conditions
sub_query_conditions = []
conditions = []
sub_query_conditions.append(doc.company == self.company)
if self.get("from_payment_date"):
sub_query_conditions.append(doc.posting_date.gte(self.from_payment_date))
if self.get("to_payment_date"):
sub_query_conditions.append(doc.posting_date.lte(self.to_payment_date))
if self.get("cost_center"): if self.get("cost_center"):
condition += " and doc.cost_center = '{0}' ".format(self.cost_center) sub_query_conditions.append(doc.cost_center == self.cost_center)
dr_or_cr = ( dr_or_cr = (
"credit_in_account_currency" gl["credit_in_account_currency"]
if erpnext.get_party_account_type(self.party_type) == "Receivable" if erpnext.get_party_account_type(self.party_type) == "Receivable"
else "debit_in_account_currency" else gl["debit_in_account_currency"]
) )
reconciled_dr_or_cr = ( reconciled_dr_or_cr = (
"debit_in_account_currency" gl["debit_in_account_currency"]
if dr_or_cr == "credit_in_account_currency" if dr_or_cr == gl["credit_in_account_currency"]
else "credit_in_account_currency" else gl["credit_in_account_currency"]
) )
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" if self.minimum_payment_amount:
conditions.append(dr_or_cr.gte(self.minimum_payment_amount))
if self.maximum_payment_amount:
conditions.append(dr_or_cr.lte(self.maximum_payment_amount))
return frappe.db.sql( sub_query = (
""" SELECT doc.name as reference_name, %(voucher_type)s as reference_type, qb.from_(doc)
(sum(gl.{dr_or_cr}) - sum(gl.{reconciled_dr_or_cr})) as amount, doc.posting_date, .select(doc.name)
account_currency as currency .where(Criterion.all(sub_query_conditions))
FROM `tab{doc}` doc, `tabGL Entry` gl .where(
WHERE (doc.docstatus == 1)
(doc.name = gl.against_voucher or doc.name = gl.voucher_no) & (doc.is_return == 1)
and doc.{party_type_field} = %(party)s & ((doc.return_against == "") | (doc.return_against.isnull()))
and doc.is_return = 1 and ifnull(doc.return_against, "") = "" )
and gl.against_voucher_type = %(voucher_type)s
and doc.docstatus = 1 and gl.party = %(party)s
and gl.party_type = %(party_type)s and gl.account = %(account)s
and gl.is_cancelled = 0 {condition}
GROUP BY doc.name
Having
amount > 0
ORDER BY doc.posting_date
""".format(
doc=voucher_type,
dr_or_cr=dr_or_cr,
reconciled_dr_or_cr=reconciled_dr_or_cr,
party_type_field=frappe.scrub(self.party_type),
condition=condition or "",
),
{
"party": self.party,
"party_type": self.party_type,
"voucher_type": voucher_type,
"account": self.receivable_payable_account,
},
as_dict=1,
) )
query = (
qb.from_(gl)
.select(
gl.voucher_type.as_("reference_type"),
gl.voucher_no.as_("reference_name"),
(Sum(dr_or_cr) - Sum(reconciled_dr_or_cr)).as_("amount"),
gl.posting_date,
gl.account_currency.as_("currency"),
)
.where(
(gl.voucher_type == voucher_type)
& (gl.voucher_no.isin(sub_query))
& (gl.is_cancelled == 0)
& (gl.account == self.receivable_payable_account)
& (gl.party_type == self.party_type)
& (gl.party == self.party)
)
.where(Criterion.all(conditions))
.groupby(gl.voucher_no)
.having(qb.Field("amount") > 0)
)
dr_cr_notes = query.run(as_dict=True)
return dr_cr_notes
def add_payment_entries(self, non_reconciled_payments): def add_payment_entries(self, non_reconciled_payments):
self.set("payments", []) self.set("payments", [])
@@ -369,7 +390,7 @@ class PaymentReconciliation(Document):
if not invoices_to_reconcile: if not invoices_to_reconcile:
frappe.throw(_("No records found in Allocation table")) frappe.throw(_("No records found in Allocation table"))
def get_conditions(self, get_invoices=False, get_payments=False, get_return_invoices=False): def get_conditions(self, get_invoices=False, get_payments=False):
condition = " and company = '{0}' ".format(self.company) condition = " and company = '{0}' ".format(self.company)
if get_invoices: if get_invoices:
@@ -397,35 +418,7 @@ class PaymentReconciliation(Document):
condition += " and {dr_or_cr} <= {amount}".format( condition += " and {dr_or_cr} <= {amount}".format(
dr_or_cr=dr_or_cr, amount=flt(self.maximum_invoice_amount) dr_or_cr=dr_or_cr, amount=flt(self.maximum_invoice_amount)
) )
elif get_payments:
elif get_return_invoices:
condition = " and doc.company = '{0}' ".format(self.company)
condition += (
" and doc.posting_date >= {0}".format(frappe.db.escape(self.from_payment_date))
if self.from_payment_date
else ""
)
condition += (
" and doc.posting_date <= {0}".format(frappe.db.escape(self.to_payment_date))
if self.to_payment_date
else ""
)
dr_or_cr = (
"debit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
else "credit_in_account_currency"
)
if self.minimum_invoice_amount:
condition += " and gl.{dr_or_cr} >= {amount}".format(
dr_or_cr=dr_or_cr, amount=flt(self.minimum_payment_amount)
)
if self.maximum_invoice_amount:
condition += " and gl.{dr_or_cr} <= {amount}".format(
dr_or_cr=dr_or_cr, amount=flt(self.maximum_payment_amount)
)
else:
condition += ( condition += (
" and posting_date >= {0}".format(frappe.db.escape(self.from_payment_date)) " and posting_date >= {0}".format(frappe.db.escape(self.from_payment_date))
if self.from_payment_date if self.from_payment_date

View File

@@ -9,6 +9,7 @@ from six import iteritems
from erpnext.accounts.report.financial_statements import ( from erpnext.accounts.report.financial_statements import (
get_columns, get_columns,
get_cost_centers_with_children,
get_data, get_data,
get_filtered_list_for_consolidated_report, get_filtered_list_for_consolidated_report,
get_period_list, get_period_list,
@@ -161,10 +162,11 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
total = 0 total = 0
for period in period_list: for period in period_list:
start_date = get_start_date(period, accumulated_values, company) start_date = get_start_date(period, accumulated_values, company)
filters.start_date = start_date
filters.end_date = period["to_date"]
filters.account_type = account_type
amount = get_account_type_based_gl_data( amount = get_account_type_based_gl_data(company, filters)
company, start_date, period["to_date"], account_type, filters
)
if amount and account_type == "Depreciation": if amount and account_type == "Depreciation":
amount *= -1 amount *= -1
@@ -176,7 +178,7 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
return data return data
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters=None): def get_account_type_based_gl_data(company, filters=None):
cond = "" cond = ""
filters = frappe._dict(filters or {}) filters = frappe._dict(filters or {})
@@ -192,17 +194,21 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
frappe.db.escape(cstr(filters.finance_book)) frappe.db.escape(cstr(filters.finance_book))
) )
if filters.get("cost_center"):
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
cond += " and cost_center in %(cost_center)s"
gl_sum = frappe.db.sql_list( gl_sum = frappe.db.sql_list(
""" """
select sum(credit) - sum(debit) select sum(credit) - sum(debit)
from `tabGL Entry` from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s where company=%(company)s and posting_date >= %(start_date)s and posting_date <= %(end_date)s
and voucher_type != 'Period Closing Voucher' and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE account_type = %s) {cond} and account in ( SELECT name FROM tabAccount WHERE account_type = %(account_type)s) {cond}
""".format( """.format(
cond=cond cond=cond
), ),
(company, start_date, end_date, account_type), filters,
) )
return gl_sum[0] if gl_sum and gl_sum[0] else 0 return gl_sum[0] if gl_sum and gl_sum[0] else 0

View File

@@ -268,10 +268,12 @@ def get_cash_flow_data(fiscal_year, companies, filters):
def get_account_type_based_data(account_type, companies, fiscal_year, filters): def get_account_type_based_data(account_type, companies, fiscal_year, filters):
data = {} data = {}
total = 0 total = 0
filters.account_type = account_type
filters.start_date = fiscal_year.year_start_date
filters.end_date = fiscal_year.year_end_date
for company in companies: for company in companies:
amount = get_account_type_based_gl_data( amount = get_account_type_based_gl_data(company, filters)
company, fiscal_year.year_start_date, fiscal_year.year_end_date, account_type, filters
)
if amount and account_type == "Depreciation": if amount and account_type == "Depreciation":
amount *= -1 amount *= -1

View File

@@ -333,16 +333,21 @@ class StatusUpdater(Document):
) )
def warn_about_bypassing_with_role(self, item, qty_or_amount, role): def warn_about_bypassing_with_role(self, item, qty_or_amount, role):
action = _("Over Receipt/Delivery") if qty_or_amount == "qty" else _("Overbilling") if qty_or_amount == "qty":
msg = _("Over Receipt/Delivery of {0} {1} ignored for item {2} because you have {3} role.")
else:
msg = _("Overbilling of {0} {1} ignored for item {2} because you have {3} role.")
msg = _("{} of {} {} ignored for item {} because you have {} role.").format( frappe.msgprint(
action, msg.format(
_(item["target_ref_field"].title()), _(item["target_ref_field"].title()),
frappe.bold(item["reduce_by"]), frappe.bold(item["reduce_by"]),
frappe.bold(item.get("item_code")), frappe.bold(item.get("item_code")),
role, role,
),
indicator="orange",
alert=True,
) )
frappe.msgprint(msg, indicator="orange", alert=True)
def update_qty(self, update_modified=True): def update_qty(self, update_modified=True):
"""Updates qty or amount at row level """Updates qty or amount at row level

View File

@@ -526,6 +526,7 @@ scheduler_events = {
"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall", "erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans", "erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
"erpnext.crm.doctype.lead.lead.daily_open_lead", "erpnext.crm.doctype.lead.lead.daily_open_lead",
"erpnext.stock.doctype.stock_entry.stock_entry.audit_incorrect_valuation_entries",
], ],
"weekly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_weekly"], "weekly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_weekly"],
"monthly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_monthly"], "monthly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_monthly"],

View File

@@ -1145,6 +1145,37 @@ class TestWorkOrder(FrappeTestCase):
except frappe.MandatoryError: except frappe.MandatoryError:
self.fail("Batch generation causing failing in Work Order") self.fail("Batch generation causing failing in Work Order")
@change_settings("Manufacturing Settings", {"make_serial_no_batch_from_work_order": 1})
def test_auto_serial_no_creation(self):
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
fg_item = frappe.generate_hash(length=20)
child_item = frappe.generate_hash(length=20)
bom_tree = {fg_item: {child_item: {}}}
create_nested_bom(bom_tree, prefix="")
item = frappe.get_doc("Item", fg_item)
item.has_serial_no = 1
item.serial_no_series = f"{item.name}.#####"
item.save()
try:
wo_order = make_wo_order_test_record(item=fg_item, qty=2, skip_transfer=True)
serial_nos = wo_order.serial_no
stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
stock_entry.set_work_order_details()
stock_entry.set_serial_no_batch_for_finished_good()
for row in stock_entry.items:
if row.item_code == fg_item:
self.assertTrue(row.serial_no)
self.assertEqual(sorted(get_serial_nos(row.serial_no)), sorted(get_serial_nos(serial_nos)))
except frappe.MandatoryError:
self.fail("Batch generation causing failing in Work Order")
@change_settings( @change_settings(
"Manufacturing Settings", "Manufacturing Settings",
{"backflush_raw_materials_based_on": "Material Transferred for Manufacture"}, {"backflush_raw_materials_based_on": "Material Transferred for Manufacture"},

View File

@@ -181,13 +181,13 @@ class PickList(Document):
if item_map.get(key): if item_map.get(key):
item_map[key].qty += item.qty item_map[key].qty += item.qty
item_map[key].stock_qty += item.stock_qty item_map[key].stock_qty += flt(item.stock_qty, item.precision("stock_qty"))
else: else:
item_map[key] = item item_map[key] = item
# maintain count of each item (useful to limit get query) # maintain count of each item (useful to limit get query)
self.item_count_map.setdefault(item_code, 0) self.item_count_map.setdefault(item_code, 0)
self.item_count_map[item_code] += item.stock_qty self.item_count_map[item_code] += flt(item.stock_qty, item.precision("stock_qty"))
return item_map.values() return item_map.values()

View File

@@ -4,13 +4,25 @@
import json import json
from collections import defaultdict from collections import defaultdict
from typing import Dict
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.query_builder.functions import Sum from frappe.query_builder.functions import Sum
from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate
from six import iteritems, itervalues, string_types from six import iteritems, itervalues, string_types
from frappe.utils import (
add_days,
cint,
comma_or,
cstr,
flt,
format_time,
formatdate,
getdate,
nowdate,
today,
)
import erpnext import erpnext
from erpnext.accounts.general_ledger import process_gl_map from erpnext.accounts.general_ledger import process_gl_map
@@ -2192,16 +2204,16 @@ class StockEntry(StockController):
d.qty -= process_loss_dict[d.item_code][1] d.qty -= process_loss_dict[d.item_code][1]
def set_serial_no_batch_for_finished_good(self): def set_serial_no_batch_for_finished_good(self):
serial_nos = "" serial_nos = []
if self.pro_doc.serial_no: if self.pro_doc.serial_no:
serial_nos = self.get_serial_nos_for_fg() serial_nos = self.get_serial_nos_for_fg() or []
for row in self.items: for row in self.items:
if row.is_finished_item and row.item_code == self.pro_doc.production_item: if row.is_finished_item and row.item_code == self.pro_doc.production_item:
if serial_nos: if serial_nos:
row.serial_no = "\n".join(serial_nos[0 : cint(row.qty)]) row.serial_no = "\n".join(serial_nos[0 : cint(row.qty)])
def get_serial_nos_for_fg(self, args): def get_serial_nos_for_fg(self):
fields = [ fields = [
"`tabStock Entry`.`name`", "`tabStock Entry`.`name`",
"`tabStock Entry Detail`.`qty`", "`tabStock Entry Detail`.`qty`",
@@ -2217,9 +2229,7 @@ class StockEntry(StockController):
] ]
stock_entries = frappe.get_all("Stock Entry", fields=fields, filters=filters) stock_entries = frappe.get_all("Stock Entry", fields=fields, filters=filters)
return self.get_available_serial_nos(stock_entries)
if self.pro_doc.serial_no:
return self.get_available_serial_nos(stock_entries)
def get_available_serial_nos(self, stock_entries): def get_available_serial_nos(self, stock_entries):
used_serial_nos = [] used_serial_nos = []
@@ -2556,3 +2566,63 @@ def get_supplied_items(purchase_order):
) )
return supplied_item_details return supplied_item_details
def audit_incorrect_valuation_entries():
# Audit of stock transfer entries having incorrect valuation
from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
stock_entries = get_incorrect_stock_entries()
for stock_entry, values in stock_entries.items():
reposting_data = frappe._dict(
{
"posting_date": values.posting_date,
"posting_time": values.posting_time,
"voucher_type": "Stock Entry",
"voucher_no": stock_entry,
"company": values.company,
}
)
create_repost_item_valuation_entry(reposting_data)
def get_incorrect_stock_entries() -> Dict:
stock_entry = frappe.qb.DocType("Stock Entry")
stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
transfer_purposes = [
"Material Transfer",
"Material Transfer for Manufacture",
"Send to Subcontractor",
]
query = (
frappe.qb.from_(stock_entry)
.inner_join(stock_ledger_entry)
.on(stock_entry.name == stock_ledger_entry.voucher_no)
.select(
stock_entry.name,
stock_entry.company,
stock_entry.posting_date,
stock_entry.posting_time,
Sum(stock_ledger_entry.stock_value_difference).as_("stock_value"),
)
.where(
(stock_entry.docstatus == 1)
& (stock_entry.purpose.isin(transfer_purposes))
& (stock_ledger_entry.modified > add_days(today(), -2))
)
.groupby(stock_ledger_entry.voucher_detail_no)
.having(Sum(stock_ledger_entry.stock_value_difference) != 0)
)
data = query.run(as_dict=True)
stock_entries = {}
for row in data:
if abs(row.stock_value) > 0.1 and row.name not in stock_entries:
stock_entries.setdefault(row.name, row)
return stock_entries

View File

@@ -5,7 +5,7 @@
import frappe import frappe
from frappe.permissions import add_user_permission, remove_user_permission from frappe.permissions import add_user_permission, remove_user_permission
from frappe.tests.utils import FrappeTestCase, change_settings from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, flt, nowdate, nowtime, today from frappe.utils import add_days, flt, now, nowdate, nowtime, today
from six import iteritems from six import iteritems
from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.accounts.doctype.account.test_account import get_inventory_account
@@ -18,6 +18,8 @@ from erpnext.stock.doctype.item.test_item import (
from erpnext.stock.doctype.serial_no.serial_no import * # noqa from erpnext.stock.doctype.serial_no.serial_no import * # noqa
from erpnext.stock.doctype.stock_entry.stock_entry import ( from erpnext.stock.doctype.stock_entry.stock_entry import (
FinishedGoodError, FinishedGoodError,
audit_incorrect_valuation_entries,
get_incorrect_stock_entries,
move_sample_to_retention_warehouse, move_sample_to_retention_warehouse,
) )
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -1571,6 +1573,44 @@ class TestStockEntry(FrappeTestCase):
self.assertRaises(BatchExpiredError, se.save) self.assertRaises(BatchExpiredError, se.save)
def test_audit_incorrect_stock_entries(self):
item_code = "Test Incorrect Valuation Rate Item - 001"
create_item(item_code=item_code, is_stock_item=1)
make_stock_entry(
item_code=item_code,
purpose="Material Receipt",
posting_date=add_days(nowdate(), -10),
qty=2,
rate=500,
to_warehouse="_Test Warehouse - _TC",
)
transfer_entry = make_stock_entry(
item_code=item_code,
purpose="Material Transfer",
qty=2,
rate=500,
from_warehouse="_Test Warehouse - _TC",
to_warehouse="_Test Warehouse 1 - _TC",
)
sle_name = frappe.db.get_value(
"Stock Ledger Entry", {"voucher_no": transfer_entry.name, "actual_qty": (">", 0)}, "name"
)
frappe.db.set_value(
"Stock Ledger Entry", sle_name, {"modified": add_days(now(), -1), "stock_value_difference": 10}
)
stock_entries = get_incorrect_stock_entries()
self.assertTrue(transfer_entry.name in stock_entries)
audit_incorrect_valuation_entries()
stock_entries = get_incorrect_stock_entries()
self.assertFalse(transfer_entry.name in stock_entries)
def make_serialized_item(**args): def make_serialized_item(**args):
args = frappe._dict(args) args = frappe._dict(args)

View File

@@ -813,9 +813,9 @@ def insert_item_price(args):
): ):
if frappe.has_permission("Item Price", "write"): if frappe.has_permission("Item Price", "write"):
price_list_rate = ( price_list_rate = (
(args.rate + args.discount_amount) / args.get("conversion_factor") (flt(args.rate) + flt(args.discount_amount)) / args.get("conversion_factor")
if args.get("conversion_factor") if args.get("conversion_factor")
else (args.rate + args.discount_amount) else (flt(args.rate) + flt(args.discount_amount))
) )
item_price = frappe.db.get_value( item_price = frappe.db.get_value(

View File

@@ -75,6 +75,7 @@ def get_item_info(filters):
if filters.get("brand"): if filters.get("brand"):
conditions.append("item.brand=%(brand)s") conditions.append("item.brand=%(brand)s")
conditions.append("is_stock_item = 1") conditions.append("is_stock_item = 1")
conditions.append("disabled = 0")
return frappe.db.sql( return frappe.db.sql(
"""select name, item_name, description, brand, item_group, """select name, item_name, description, brand, item_group,

View File

@@ -1844,6 +1844,8 @@ Outstanding Amt,Offener Betrag,
Outstanding Cheques and Deposits to clear,Ausstehende Schecks und Anzahlungen zum verbuchen, Outstanding Cheques and Deposits to clear,Ausstehende Schecks und Anzahlungen zum verbuchen,
Outstanding for {0} cannot be less than zero ({1}),Ausstände für {0} können nicht kleiner als Null sein ({1}), Outstanding for {0} cannot be less than zero ({1}),Ausstände für {0} können nicht kleiner als Null sein ({1}),
Outward taxable supplies(zero rated),Steuerpflichtige Lieferungen aus dem Ausland (null bewertet), Outward taxable supplies(zero rated),Steuerpflichtige Lieferungen aus dem Ausland (null bewertet),
Over Receipt/Delivery of {0} {1} ignored for item {2} because you have {3} role.,"Überhöhte Annahme bzw. Lieferung von Artikel {2} mit {0} {1} wurde ignoriert, weil Sie die Rolle {3} haben."
Overbilling of {0} {1} ignored for item {2} because you have {3} role.,"Überhöhte Abrechnung von Artikel {2} mit {0} {1} wurde ignoriert, weil Sie die Rolle {3} haben."
Overdue,Überfällig, Overdue,Überfällig,
Overlap in scoring between {0} and {1},Überlappung beim Scoring zwischen {0} und {1}, Overlap in scoring between {0} and {1},Überlappung beim Scoring zwischen {0} und {1},
Overlapping conditions found between:,Überlagernde Bedingungen gefunden zwischen:, Overlapping conditions found between:,Überlagernde Bedingungen gefunden zwischen:,
Can't render this file because it is too large.