Merge pull request #33845 from rohitwaghchaure/fixed-item-not-fetching-issue
fix: item rate not fetching
diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py
index 378983e..8334604 100644
--- a/.github/helper/documentation.py
+++ b/.github/helper/documentation.py
@@ -3,52 +3,71 @@
from urllib.parse import urlparse
-docs_repos = [
- "frappe_docs",
- "erpnext_documentation",
+WEBSITE_REPOS = [
"erpnext_com",
"frappe_io",
]
+DOCUMENTATION_DOMAINS = [
+ "docs.erpnext.com",
+ "frappeframework.com",
+]
-def uri_validator(x):
- result = urlparse(x)
- return all([result.scheme, result.netloc, result.path])
-def docs_link_exists(body):
- for line in body.splitlines():
- for word in line.split():
- if word.startswith('http') and uri_validator(word):
- parsed_url = urlparse(word)
- if parsed_url.netloc == "github.com":
- parts = parsed_url.path.split('/')
- if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos:
- return True
- elif parsed_url.netloc == "docs.erpnext.com":
- return True
+def is_valid_url(url: str) -> bool:
+ parts = urlparse(url)
+ return all((parts.scheme, parts.netloc, parts.path))
+
+
+def is_documentation_link(word: str) -> bool:
+ if not word.startswith("http") or not is_valid_url(word):
+ return False
+
+ parsed_url = urlparse(word)
+ if parsed_url.netloc in DOCUMENTATION_DOMAINS:
+ return True
+
+ if parsed_url.netloc == "github.com":
+ parts = parsed_url.path.split("/")
+ if len(parts) == 5 and parts[1] == "frappe" and parts[2] in WEBSITE_REPOS:
+ return True
+
+ return False
+
+
+def contains_documentation_link(body: str) -> bool:
+ return any(
+ is_documentation_link(word)
+ for line in body.splitlines()
+ for word in line.split()
+ )
+
+
+def check_pull_request(number: str) -> "tuple[int, str]":
+ response = requests.get(f"https://api.github.com/repos/frappe/erpnext/pulls/{number}")
+ if not response.ok:
+ return 1, "Pull Request Not Found! ⚠️"
+
+ payload = response.json()
+ title = (payload.get("title") or "").lower().strip()
+ head_sha = (payload.get("head") or {}).get("sha")
+ body = (payload.get("body") or "").lower()
+
+ if (
+ not title.startswith("feat")
+ or not head_sha
+ or "no-docs" in body
+ or "backport" in body
+ ):
+ return 0, "Skipping documentation checks... 🏃"
+
+ if contains_documentation_link(body):
+ return 0, "Documentation Link Found. You're Awesome! 🎉"
+
+ return 1, "Documentation Link Not Found! ⚠️"
if __name__ == "__main__":
- pr = sys.argv[1]
- response = requests.get("https://api.github.com/repos/frappe/erpnext/pulls/{}".format(pr))
-
- if response.ok:
- payload = response.json()
- title = (payload.get("title") or "").lower().strip()
- head_sha = (payload.get("head") or {}).get("sha")
- body = (payload.get("body") or "").lower()
-
- if (title.startswith("feat")
- and head_sha
- and "no-docs" not in body
- and "backport" not in body
- ):
- if docs_link_exists(body):
- print("Documentation Link Found. You're Awesome! 🎉")
-
- else:
- print("Documentation Link Not Found! ⚠️")
- sys.exit(1)
-
- else:
- print("Skipping documentation checks... 🏃")
+ exit_code, message = check_pull_request(sys.argv[1])
+ print(message)
+ sys.exit(exit_code)
diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py
index 53838fb..4c628a4 100644
--- a/erpnext/accounts/doctype/budget/budget.py
+++ b/erpnext/accounts/doctype/budget/budget.py
@@ -184,6 +184,11 @@
amount = expense_amount or get_amount(args, budget)
yearly_action, monthly_action = get_actions(args, budget)
+ if yearly_action in ("Stop", "Warn"):
+ compare_expense_with_budget(
+ args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
+ )
+
if monthly_action in ["Stop", "Warn"]:
budget_amount = get_accumulated_monthly_budget(
budget.monthly_distribution, args.posting_date, args.fiscal_year, budget.budget_amount
@@ -195,28 +200,28 @@
args, budget_amount, _("Accumulated Monthly"), monthly_action, budget.budget_against, amount
)
- if (
- yearly_action in ("Stop", "Warn")
- and monthly_action != "Stop"
- and yearly_action != monthly_action
- ):
- compare_expense_with_budget(
- args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
- )
-
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
- actual_expense = amount or get_actual_expense(args)
- if actual_expense > budget_amount:
- diff = actual_expense - budget_amount
+ actual_expense = get_actual_expense(args)
+ total_expense = actual_expense + amount
+
+ if total_expense > budget_amount:
+ if actual_expense > budget_amount:
+ error_tense = _("is already")
+ diff = actual_expense - budget_amount
+ else:
+ error_tense = _("will be")
+ diff = total_expense - budget_amount
+
currency = frappe.get_cached_value("Company", args.company, "default_currency")
- msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}").format(
+ msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It {5} exceed by {6}").format(
_(action_for),
frappe.bold(args.account),
- args.budget_against_field,
+ frappe.unscrub(args.budget_against_field),
frappe.bold(budget_against),
frappe.bold(fmt_money(budget_amount, currency=currency)),
+ error_tense,
frappe.bold(fmt_money(diff, currency=currency)),
)
@@ -227,9 +232,9 @@
action = "Warn"
if action == "Stop":
- frappe.throw(msg, BudgetError)
+ frappe.throw(msg, BudgetError, title=_("Budget Exceeded"))
else:
- frappe.msgprint(msg, indicator="orange")
+ frappe.msgprint(msg, indicator="orange", title=_("Budget Exceeded"))
def get_actions(args, budget):
@@ -351,7 +356,9 @@
"""
select sum(gle.debit) - sum(gle.credit)
from `tabGL Entry` gle
- where gle.account=%(account)s
+ where
+ is_cancelled = 0
+ and gle.account=%(account)s
{condition1}
and gle.fiscal_year=%(fiscal_year)s
and gle.company=%(company)s
diff --git a/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.py b/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.py
index d25016f..54ffe21 100644
--- a/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.py
+++ b/erpnext/accounts/doctype/cost_center_allocation/cost_center_allocation.py
@@ -28,9 +28,14 @@
class CostCenterAllocation(Document):
+ def __init__(self, *args, **kwargs):
+ super(CostCenterAllocation, self).__init__(*args, **kwargs)
+ self._skip_from_date_validation = False
+
def validate(self):
self.validate_total_allocation_percentage()
- self.validate_from_date_based_on_existing_gle()
+ if not self._skip_from_date_validation:
+ self.validate_from_date_based_on_existing_gle()
self.validate_backdated_allocation()
self.validate_main_cost_center()
self.validate_child_cost_centers()
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 12c0b7a..154fdc0 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -69,6 +69,10 @@
def get_jv_entries(self):
condition = self.get_conditions()
+
+ if self.get("cost_center"):
+ condition += f" and t2.cost_center = '{self.cost_center}' "
+
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
diff --git a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
index 2ba90b4..00e3934 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/test_payment_reconciliation.py
@@ -747,6 +747,73 @@
self.assertEqual(len(pr.get("invoices")), 0)
self.assertEqual(len(pr.get("payments")), 0)
+ def test_cost_center_filter_on_vouchers(self):
+ """
+ Test Cost Center filter is applied on Invoices, Payment Entries and Journals
+ """
+ transaction_date = nowdate()
+ rate = 100
+
+ # 'Main - PR' Cost Center
+ si1 = self.create_sales_invoice(
+ qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
+ )
+ si1.cost_center = self.main_cc.name
+ si1.submit()
+
+ pe1 = self.create_payment_entry(posting_date=transaction_date, amount=rate)
+ pe1.cost_center = self.main_cc.name
+ pe1 = pe1.save().submit()
+
+ je1 = self.create_journal_entry(self.bank, self.debit_to, 100, transaction_date)
+ je1.accounts[0].cost_center = self.main_cc.name
+ je1.accounts[1].cost_center = self.main_cc.name
+ je1.accounts[1].party_type = "Customer"
+ je1.accounts[1].party = self.customer
+ je1 = je1.save().submit()
+
+ # 'Sub - PR' Cost Center
+ si2 = self.create_sales_invoice(
+ qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
+ )
+ si2.cost_center = self.sub_cc.name
+ si2.submit()
+
+ pe2 = self.create_payment_entry(posting_date=transaction_date, amount=rate)
+ pe2.cost_center = self.sub_cc.name
+ pe2 = pe2.save().submit()
+
+ je2 = self.create_journal_entry(self.bank, self.debit_to, 100, transaction_date)
+ je2.accounts[0].cost_center = self.sub_cc.name
+ je2.accounts[1].cost_center = self.sub_cc.name
+ je2.accounts[1].party_type = "Customer"
+ je2.accounts[1].party = self.customer
+ je2 = je2.save().submit()
+
+ pr = self.create_payment_reconciliation()
+ pr.cost_center = self.main_cc.name
+
+ pr.get_unreconciled_entries()
+
+ # check PR tool output
+ self.assertEqual(len(pr.get("invoices")), 1)
+ self.assertEqual(pr.get("invoices")[0].get("invoice_number"), si1.name)
+ self.assertEqual(len(pr.get("payments")), 2)
+ payment_vouchers = [x.get("reference_name") for x in pr.get("payments")]
+ self.assertCountEqual(payment_vouchers, [pe1.name, je1.name])
+
+ # Change cost center
+ pr.cost_center = self.sub_cc.name
+
+ pr.get_unreconciled_entries()
+
+ # check PR tool output
+ self.assertEqual(len(pr.get("invoices")), 1)
+ self.assertEqual(pr.get("invoices")[0].get("invoice_number"), si2.name)
+ self.assertEqual(len(pr.get("payments")), 2)
+ payment_vouchers = [x.get("reference_name") for x in pr.get("payments")]
+ self.assertCountEqual(payment_vouchers, [je2.name, pe2.name])
+
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index b543016..a1239d6 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -675,7 +675,7 @@
def get_pos_reserved_qty(item_code, warehouse):
reserved_qty = frappe.db.sql(
- """select sum(p_item.qty) as qty
+ """select sum(p_item.stock_qty) as qty
from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
where p.name = p_item.parent
and ifnull(p.consolidated_invoice, '') = ''
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 1ce780e..57feaa0 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -687,11 +687,21 @@
def apply_pricing_rule_for_free_items(doc, pricing_rule_args):
if pricing_rule_args:
- items = tuple((d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item)
+ args = {(d["item_code"], d["pricing_rules"]): d for d in pricing_rule_args}
- for args in pricing_rule_args:
- if not items or (args.get("item_code"), args.get("pricing_rules")) not in items:
- doc.append("items", args)
+ for item in doc.items:
+ if not item.is_free_item:
+ continue
+
+ free_item_data = args.get((item.item_code, item.pricing_rules))
+ if free_item_data:
+ free_item_data.pop("item_name")
+ free_item_data.pop("description")
+ item.update(free_item_data)
+ args.pop((item.item_code, item.pricing_rules))
+
+ for free_item in args.values():
+ doc.append("items", free_item)
def get_pricing_rule_items(pr_doc, other_items=False) -> list:
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index e96847e..0ffd946 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1169,6 +1169,46 @@
frappe.db.sql("delete from `tabPOS Profile`")
+ def test_bin_details_of_packed_item(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ # test Update Items with product bundle
+ if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+ bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+ bundle_item.append(
+ "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+ )
+ bundle_item.save(ignore_permissions=True)
+
+ make_item("_Packed Item New 1", {"is_stock_item": 1})
+ make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+ si = create_sales_invoice(
+ item_code="_Test Product Bundle Item New",
+ update_stock=1,
+ warehouse="_Test Warehouse - _TC",
+ transaction_date=add_days(nowdate(), -1),
+ do_not_submit=1,
+ )
+
+ make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+ bin_details = frappe.db.get_value(
+ "Bin",
+ {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+ ["actual_qty", "projected_qty", "ordered_qty"],
+ as_dict=1,
+ )
+
+ si.transaction_date = nowdate()
+ si.save()
+
+ packed_item = si.packed_items[0]
+ self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+ self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+ self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
def test_pos_si_without_payment(self):
make_pos_profile()
diff --git a/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json b/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
index ce8c0c3..46b430c 100644
--- a/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
+++ b/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
@@ -1,6 +1,6 @@
{
"actions": [],
- "autoname": "autoincrement",
+ "autoname": "hash",
"creation": "2022-09-13 16:18:59.404842",
"doctype": "DocType",
"editable_grid": 1,
@@ -36,11 +36,11 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2022-09-13 23:40:41.479208",
+ "modified": "2023-01-13 13:40:41.479208",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withheld Vouchers",
- "naming_rule": "Autoincrement",
+ "naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 1bce43f..2c829b2 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -410,12 +410,26 @@
tds_amount = 0
invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
+ ## for TDS to be deducted on advances
+ payment_entry_filters = {
+ "party_type": "Supplier",
+ "party": ("in", parties),
+ "docstatus": 1,
+ "apply_tax_withholding_amount": 1,
+ "unallocated_amount": (">", 0),
+ "posting_date": ["between", (tax_details.from_date, tax_details.to_date)],
+ "tax_withholding_category": tax_details.get("tax_withholding_category"),
+ }
+
field = "sum(tax_withholding_net_total)"
if cint(tax_details.consider_party_ledger_amount):
invoice_filters.pop("apply_tds", None)
field = "sum(grand_total)"
+ payment_entry_filters.pop("apply_tax_withholding_amount", None)
+ payment_entry_filters.pop("tax_withholding_category", None)
+
supp_credit_amt = frappe.db.get_value("Purchase Invoice", invoice_filters, field) or 0.0
supp_jv_credit_amt = (
@@ -427,14 +441,28 @@
"party": ("in", parties),
"reference_type": ("!=", "Purchase Invoice"),
},
- "sum(credit_in_account_currency)",
+ "sum(credit_in_account_currency - debit_in_account_currency)",
)
or 0.0
)
+ # Get Amount via payment entry
+ payment_entry_amounts = frappe.db.get_all(
+ "Payment Entry",
+ filters=payment_entry_filters,
+ fields=["sum(unallocated_amount) as amount", "payment_type"],
+ group_by="payment_type",
+ )
+
supp_credit_amt += supp_jv_credit_amt
supp_credit_amt += inv.tax_withholding_net_total
+ for type in payment_entry_amounts:
+ if type.payment_type == "Pay":
+ supp_credit_amt += type.amount
+ else:
+ supp_credit_amt -= type.amount
+
threshold = tax_details.get("threshold", 0)
cumulative_threshold = tax_details.get("cumulative_threshold", 0)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 23caac0..1e86cf5 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -16,7 +16,7 @@
def setUpClass(self):
# create relevant supplier, etc
create_records()
- create_tax_with_holding_category()
+ create_tax_withholding_category_records()
def tearDown(self):
cancel_invoices()
@@ -38,7 +38,7 @@
pi = create_purchase_invoice(supplier="Test TDS Supplier")
pi.submit()
- # assert equal tax deduction on total invoice amount uptil now
+ # assert equal tax deduction on total invoice amount until now
self.assertEqual(pi.taxes_and_charges_deducted, 3000)
self.assertEqual(pi.grand_total, 7000)
invoices.append(pi)
@@ -47,7 +47,7 @@
pi = create_purchase_invoice(supplier="Test TDS Supplier", rate=5000)
pi.submit()
- # assert equal tax deduction on total invoice amount uptil now
+ # assert equal tax deduction on total invoice amount until now
self.assertEqual(pi.taxes_and_charges_deducted, 500)
invoices.append(pi)
@@ -130,7 +130,7 @@
invoices.append(si)
# create another invoice whose total when added to previously created invoice,
- # surpasses cumulative threshhold
+ # surpasses cumulative threshold
si = create_sales_invoice(customer="Test TCS Customer", rate=12000)
si.submit()
@@ -329,6 +329,38 @@
for d in reversed(invoices):
d.cancel()
+ def test_tax_withholding_via_payment_entry_for_advances(self):
+ frappe.db.set_value(
+ "Supplier", "Test TDS Supplier7", "tax_withholding_category", "Advance TDS Category"
+ )
+
+ # create payment entry
+ pe1 = create_payment_entry(
+ payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+ )
+ pe1.submit()
+
+ self.assertFalse(pe1.get("taxes"))
+
+ pe2 = create_payment_entry(
+ payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+ )
+ pe2.submit()
+
+ self.assertFalse(pe2.get("taxes"))
+
+ pe3 = create_payment_entry(
+ payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+ )
+ pe3.apply_tax_withholding_amount = 1
+ pe3.save()
+ pe3.submit()
+
+ self.assertEquals(pe3.get("taxes")[0].tax_amount, 1200)
+ pe1.cancel()
+ pe2.cancel()
+ pe3.cancel()
+
def cancel_invoices():
purchase_invoices = frappe.get_all(
@@ -450,6 +482,32 @@
return si
+def create_payment_entry(**args):
+ # return payment entry doc object
+ args = frappe._dict(args)
+ pe = frappe.get_doc(
+ {
+ "doctype": "Payment Entry",
+ "posting_date": today(),
+ "payment_type": args.payment_type,
+ "party_type": args.party_type,
+ "party": args.party,
+ "company": "_Test Company",
+ "paid_from": "Cash - _TC",
+ "paid_to": "Creditors - _TC",
+ "paid_amount": args.paid_amount or 10000,
+ "received_amount": args.paid_amount or 10000,
+ "reference_no": args.reference_no or "12345",
+ "reference_date": today(),
+ "paid_from_account_currency": "INR",
+ "paid_to_account_currency": "INR",
+ }
+ )
+
+ pe.save()
+ return pe
+
+
def create_records():
# create a new suppliers
for name in [
@@ -460,6 +518,7 @@
"Test TDS Supplier4",
"Test TDS Supplier5",
"Test TDS Supplier6",
+ "Test TDS Supplier7",
]:
if frappe.db.exists("Supplier", name):
continue
@@ -530,142 +589,129 @@
).insert()
-def create_tax_with_holding_category():
+def create_tax_withholding_category_records():
fiscal_year = get_fiscal_year(today(), company="_Test Company")
+ from_date = fiscal_year[1]
+ to_date = fiscal_year[2]
+
# Cumulative threshold
- if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "Cumulative Threshold TDS",
- "category_name": "10% TDS",
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 0,
- "cumulative_threshold": 30000.00,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
- }
- ).insert()
+ create_tax_withholding_category(
+ category_name="Cumulative Threshold TDS",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=0,
+ cumulative_threshold=30000.00,
+ )
- if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TCS"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "Cumulative Threshold TCS",
- "category_name": "10% TCS",
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 0,
- "cumulative_threshold": 30000.00,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TCS - _TC"}],
- }
- ).insert()
+ # Category for TCS
+ create_tax_withholding_category(
+ category_name="Cumulative Threshold TCS",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TCS - _TC",
+ single_threshold=0,
+ cumulative_threshold=30000.00,
+ )
- # Single thresold
- if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "Single Threshold TDS",
- "category_name": "10% TDS",
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 20000.00,
- "cumulative_threshold": 0,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
- }
- ).insert()
+ # Single threshold
+ create_tax_withholding_category(
+ category_name="Single Threshold TDS",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=20000,
+ cumulative_threshold=0,
+ )
- if not frappe.db.exists("Tax Withholding Category", "New TDS Category"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "New TDS Category",
- "category_name": "New TDS Category",
- "round_off_tax_amount": 1,
- "consider_party_ledger_amount": 1,
- "tax_on_excess_amount": 1,
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 0,
- "cumulative_threshold": 30000,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
- }
- ).insert()
+ create_tax_withholding_category(
+ category_name="New TDS Category",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=0,
+ cumulative_threshold=30000,
+ round_off_tax_amount=1,
+ consider_party_ledger_amount=1,
+ tax_on_excess_amount=1,
+ )
- if not frappe.db.exists("Tax Withholding Category", "Test Service Category"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "Test Service Category",
- "category_name": "Test Service Category",
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 2000,
- "cumulative_threshold": 2000,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
- }
- ).insert()
+ create_tax_withholding_category(
+ category_name="Test Service Category",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=2000,
+ cumulative_threshold=2000,
+ )
- if not frappe.db.exists("Tax Withholding Category", "Test Goods Category"):
- frappe.get_doc(
- {
- "doctype": "Tax Withholding Category",
- "name": "Test Goods Category",
- "category_name": "Test Goods Category",
- "rates": [
- {
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 2000,
- "cumulative_threshold": 2000,
- }
- ],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
- }
- ).insert()
+ create_tax_withholding_category(
+ category_name="Test Goods Category",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=2000,
+ cumulative_threshold=2000,
+ )
- if not frappe.db.exists("Tax Withholding Category", "Test Multi Invoice Category"):
+ create_tax_withholding_category(
+ category_name="Test Multi Invoice Category",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=5000,
+ cumulative_threshold=10000,
+ )
+
+ create_tax_withholding_category(
+ category_name="Advance TDS Category",
+ rate=10,
+ from_date=from_date,
+ to_date=to_date,
+ account="TDS - _TC",
+ single_threshold=5000,
+ cumulative_threshold=10000,
+ consider_party_ledger_amount=1,
+ )
+
+
+def create_tax_withholding_category(
+ category_name,
+ rate,
+ from_date,
+ to_date,
+ account,
+ single_threshold=0,
+ cumulative_threshold=0,
+ round_off_tax_amount=0,
+ consider_party_ledger_amount=0,
+ tax_on_excess_amount=0,
+):
+ if not frappe.db.exists("Tax Withholding Category", category_name):
frappe.get_doc(
{
"doctype": "Tax Withholding Category",
- "name": "Test Multi Invoice Category",
- "category_name": "Test Multi Invoice Category",
+ "name": category_name,
+ "category_name": category_name,
+ "round_off_tax_amount": round_off_tax_amount,
+ "consider_party_ledger_amount": consider_party_ledger_amount,
+ "tax_on_excess_amount": tax_on_excess_amount,
"rates": [
{
- "from_date": fiscal_year[1],
- "to_date": fiscal_year[2],
- "tax_withholding_rate": 10,
- "single_threshold": 5000,
- "cumulative_threshold": 10000,
+ "from_date": from_date,
+ "to_date": to_date,
+ "tax_withholding_rate": rate,
+ "single_threshold": single_threshold,
+ "cumulative_threshold": cumulative_threshold,
}
],
- "accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
+ "accounts": [{"company": "_Test Company", "account": account}],
}
).insert()
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index baeed03..b6eb3ed 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -211,7 +211,13 @@
else:
party_details.update(get_company_address(company))
- if doctype and doctype in ["Delivery Note", "Sales Invoice", "Sales Order", "Quotation"]:
+ if doctype and doctype in [
+ "Delivery Note",
+ "Sales Invoice",
+ "Sales Order",
+ "Quotation",
+ "POS Invoice",
+ ]:
if party_details.company_address:
party_details.update(
get_fetch_values(doctype, "company_address", party_details.company_address)
diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
index 6cc86c3..3e11643 100644
--- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
+++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
@@ -378,15 +378,14 @@
ret += [{}]
# add total row
- if ret is not []:
- if self.filters.type == "Revenue":
- total_row = frappe._dict({"name": "Total Deferred Income"})
- elif self.filters.type == "Expense":
- total_row = frappe._dict({"name": "Total Deferred Expense"})
+ if self.filters.type == "Revenue":
+ total_row = frappe._dict({"name": "Total Deferred Income"})
+ elif self.filters.type == "Expense":
+ total_row = frappe._dict({"name": "Total Deferred Expense"})
- for idx, period in enumerate(self.period_list, 0):
- total_row[period.key] = self.period_total[idx].total
- ret.append(total_row)
+ for idx, period in enumerate(self.period_list, 0):
+ total_row[period.key] = self.period_total[idx].total
+ ret.append(total_row)
return ret
diff --git a/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py b/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
index 646dba5..c673be8 100644
--- a/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
+++ b/erpnext/bulk_transaction/doctype/bulk_transaction_log/test_bulk_transaction_log.py
@@ -15,17 +15,6 @@
create_customer()
create_item()
- def test_for_single_record(self):
- so_name = create_so()
- transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
- data = frappe.db.get_list(
- "Sales Invoice",
- filters={"posting_date": date.today(), "customer": "Bulk Customer"},
- fields=["*"],
- )
- if not data:
- self.fail("No Sales Invoice Created !")
-
def test_entry_in_log(self):
so_name = create_so()
transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 572d9d3..f0360b2 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -889,6 +889,11 @@
self.assertEqual(po.status, "Completed")
self.assertEqual(mr.status, "Received")
+ def test_variant_item_po(self):
+ po = create_purchase_order(item_code="_Test Variant Item", qty=1, rate=100, do_not_save=1)
+
+ self.assertRaises(frappe.ValidationError, po.save)
+
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
@@ -994,8 +999,8 @@
},
)
- po.set_missing_values()
if not args.do_not_save:
+ po.set_missing_values()
po.insert()
if not args.do_not_submit:
if po.is_subcontracted:
diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
index 47a66ad..9b53421 100644
--- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py
@@ -15,60 +15,4 @@
class TestProcurementTracker(FrappeTestCase):
- def test_result_for_procurement_tracker(self):
- filters = {"company": "_Test Procurement Company", "cost_center": "Main - _TPC"}
- expected_data = self.generate_expected_data()
- report = execute(filters)
-
- length = len(report[1])
- self.assertEqual(expected_data, report[1][length - 1])
-
- def generate_expected_data(self):
- if not frappe.db.exists("Company", "_Test Procurement Company"):
- frappe.get_doc(
- dict(
- doctype="Company",
- company_name="_Test Procurement Company",
- abbr="_TPC",
- default_currency="INR",
- country="Pakistan",
- )
- ).insert()
- warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
- mr = make_material_request(
- company="_Test Procurement Company", warehouse=warehouse, cost_center="Main - _TPC"
- )
- po = make_purchase_order(mr.name)
- po.supplier = "_Test Supplier"
- po.get("items")[0].cost_center = "Main - _TPC"
- po.submit()
- pr = make_purchase_receipt(po.name)
- pr.get("items")[0].cost_center = "Main - _TPC"
- pr.submit()
- date_obj = datetime.date(datetime.now())
-
- po.load_from_db()
-
- expected_data = {
- "material_request_date": date_obj,
- "cost_center": "Main - _TPC",
- "project": None,
- "requesting_site": "_Test Procurement Warehouse - _TPC",
- "requestor": "Administrator",
- "material_request_no": mr.name,
- "item_code": "_Test Item",
- "quantity": 10.0,
- "unit_of_measurement": "_Test UOM",
- "status": "To Bill",
- "purchase_order_date": date_obj,
- "purchase_order": po.name,
- "supplier": "_Test Supplier",
- "estimated_cost": 0.0,
- "actual_cost": 0.0,
- "purchase_order_amt": po.net_total,
- "purchase_order_amt_in_company_currency": po.base_net_total,
- "expected_delivery_date": date_obj,
- "actual_delivery_date": date_obj,
- }
-
- return expected_data
+ pass
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index cd1168d..8b4d28b 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -22,7 +22,7 @@
def onload(self):
super(SellingController, self).onload()
if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"):
- for item in self.get("items"):
+ for item in self.get("items") + (self.get("packed_items") or []):
item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True))
def validate(self):
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index d497297..dd2a670 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -58,7 +58,7 @@
"eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed == 100 and self.docstatus == 1",
],
["Cancelled", "eval:self.docstatus==2"],
- ["Closed", "eval:self.status=='Closed'"],
+ ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
["On Hold", "eval:self.status=='On Hold'"],
],
"Purchase Order": [
@@ -79,7 +79,7 @@
["Delivered", "eval:self.status=='Delivered'"],
["Cancelled", "eval:self.docstatus==2"],
["On Hold", "eval:self.status=='On Hold'"],
- ["Closed", "eval:self.status=='Closed'"],
+ ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
],
"Delivery Note": [
["Draft", None],
@@ -87,7 +87,7 @@
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
- ["Closed", "eval:self.status=='Closed'"],
+ ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
],
"Purchase Receipt": [
["Draft", None],
@@ -95,7 +95,7 @@
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
- ["Closed", "eval:self.status=='Closed'"],
+ ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
],
"Material Request": [
["Draft", None],
diff --git a/erpnext/e_commerce/doctype/website_item/test_website_item.py b/erpnext/e_commerce/doctype/website_item/test_website_item.py
index 828c655..bbe04d5 100644
--- a/erpnext/e_commerce/doctype/website_item/test_website_item.py
+++ b/erpnext/e_commerce/doctype/website_item/test_website_item.py
@@ -174,7 +174,10 @@
# Website Item Portal Tests Begin
def test_website_item_breadcrumbs(self):
- "Check if breadcrumbs include homepage, product listing navigation page, parent item group(s) and item group."
+ """
+ Check if breadcrumbs include homepage, product listing navigation page,
+ parent item group(s) and item group
+ """
from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
item_code = "Test Breadcrumb Item"
@@ -197,7 +200,7 @@
breadcrumbs = get_parent_item_groups(item.item_group)
self.assertEqual(breadcrumbs[0]["name"], "Home")
- self.assertEqual(breadcrumbs[1]["name"], "Shop by Category")
+ self.assertEqual(breadcrumbs[1]["name"], "All Products")
self.assertEqual(breadcrumbs[2]["name"], "_Test Item Group B") # parent item group
self.assertEqual(breadcrumbs[3]["name"], "_Test Item Group B - 1")
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 4dd8205..4304193 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -65,7 +65,21 @@
});
},
- onload_post_render(frm) {
+ validate: function(frm) {
+ if (frm.doc.fg_based_operating_cost && frm.doc.with_operations) {
+ frappe.throw({message: __("Please check either with operations or FG Based Operating Cost."), title: __("Mandatory")});
+ }
+ },
+
+ with_operations: function(frm) {
+ frm.set_df_property("fg_based_operating_cost", "hidden", frm.doc.with_operations ? 1 : 0);
+ },
+
+ fg_based_operating_cost: function(frm) {
+ frm.set_df_property("with_operations", "hidden", frm.doc.fg_based_operating_cost ? 1 : 0);
+ },
+
+ onload_post_render: function(frm) {
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
},
@@ -532,18 +546,25 @@
};
erpnext.bom.calculate_op_cost = function(doc) {
- var op = doc.operations || [];
doc.operating_cost = 0.0;
doc.base_operating_cost = 0.0;
- for(var i=0;i<op.length;i++) {
- var operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
- var base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
- frappe.model.set_value('BOM Operation',op[i].name, "operating_cost", operating_cost);
- frappe.model.set_value('BOM Operation',op[i].name, "base_operating_cost", base_operating_cost);
+ if(doc.with_operations) {
+ doc.operations.forEach((item) => {
+ let operating_cost = flt(flt(item.hour_rate) * flt(item.time_in_mins) / 60, 2);
+ let base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
+ frappe.model.set_value('BOM Operation',item.name, {
+ "operating_cost": operating_cost,
+ "base_operating_cost": base_operating_cost
+ });
- doc.operating_cost += operating_cost;
- doc.base_operating_cost += base_operating_cost;
+ doc.operating_cost += operating_cost;
+ doc.base_operating_cost += base_operating_cost;
+ });
+ } else if(doc.fg_based_operating_cost) {
+ let total_operating_cost = doc.quantity * flt(doc.operating_cost_per_bom_quantity);
+ doc.operating_cost = total_operating_cost;
+ doc.base_operating_cost = flt(total_operating_cost * doc.conversion_rate, 2);
}
refresh_field(['operating_cost', 'base_operating_cost']);
};
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index c31b69f..c2b331f 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -33,6 +33,9 @@
"column_break_23",
"transfer_material_against",
"routing",
+ "fg_based_operating_cost",
+ "fg_based_section_section",
+ "operating_cost_per_bom_quantity",
"operations_section",
"operations",
"materials_section",
@@ -575,7 +578,26 @@
{
"fieldname": "scrap_items_section",
"fieldtype": "Section Break",
+ "hide_border": 1,
"label": "Scrap Items"
+ },
+ {
+ "default": "0",
+ "fieldname": "fg_based_operating_cost",
+ "fieldtype": "Check",
+ "label": "FG based Operating Cost"
+ },
+ {
+ "depends_on": "fg_based_operating_cost",
+ "fieldname": "fg_based_section_section",
+ "fieldtype": "Section Break",
+ "label": "FG Based Operating Cost Section"
+ },
+ {
+ "depends_on": "fg_based_operating_cost",
+ "fieldname": "operating_cost_per_bom_quantity",
+ "fieldtype": "Currency",
+ "label": "Operating Cost Per BOM Quantity"
}
],
"icon": "fa fa-sitemap",
@@ -583,7 +605,7 @@
"image_field": "image",
"is_submittable": 1,
"links": [],
- "modified": "2023-01-03 18:42:27.732107",
+ "modified": "2023-01-10 07:47:08.652616",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 53af28d..8ab79e6 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -614,18 +614,26 @@
"""Update workstation rate and calculates totals"""
self.operating_cost = 0
self.base_operating_cost = 0
- for d in self.get("operations"):
- if d.workstation:
- self.update_rate_and_time(d, update_hour_rate)
+ if self.get("with_operations"):
+ for d in self.get("operations"):
+ if d.workstation:
+ self.update_rate_and_time(d, update_hour_rate)
- operating_cost = d.operating_cost
- base_operating_cost = d.base_operating_cost
- if d.set_cost_based_on_bom_qty:
- operating_cost = flt(d.cost_per_unit) * flt(self.quantity)
- base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity)
+ operating_cost = d.operating_cost
+ base_operating_cost = d.base_operating_cost
+ if d.set_cost_based_on_bom_qty:
+ operating_cost = flt(d.cost_per_unit) * flt(self.quantity)
+ base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity)
- self.operating_cost += flt(operating_cost)
- self.base_operating_cost += flt(base_operating_cost)
+ self.operating_cost += flt(operating_cost)
+ self.base_operating_cost += flt(base_operating_cost)
+
+ elif self.get("fg_based_operating_cost"):
+ total_operating_cost = flt(self.get("quantity")) * flt(
+ self.get("operating_cost_per_bom_quantity")
+ )
+ self.operating_cost = total_operating_cost
+ self.base_operating_cost = flt(total_operating_cost * self.conversion_rate, 2)
def update_rate_and_time(self, row, update_hour_rate=False):
if not row.hour_rate or update_hour_rate:
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 16f5c79..d60feb2 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -202,6 +202,33 @@
self.assertEqual(bom.items[0].rate, 20)
+ def test_bom_cost_with_fg_based_operating_cost(self):
+ bom = frappe.copy_doc(test_records[4])
+ bom.insert()
+
+ raw_material_cost = 0.0
+ op_cost = 0.0
+
+ op_cost = bom.quantity * bom.operating_cost_per_bom_quantity
+
+ for row in bom.items:
+ raw_material_cost += row.amount
+
+ base_raw_material_cost = raw_material_cost * flt(
+ bom.conversion_rate, bom.precision("conversion_rate")
+ )
+ base_op_cost = op_cost * flt(bom.conversion_rate, bom.precision("conversion_rate"))
+
+ # test amounts in selected currency, almostEqual checks for 7 digits by default
+ self.assertAlmostEqual(bom.operating_cost, op_cost)
+ self.assertAlmostEqual(bom.raw_material_cost, raw_material_cost)
+ self.assertAlmostEqual(bom.total_cost, raw_material_cost + op_cost)
+
+ # test amounts in selected currency
+ self.assertAlmostEqual(bom.base_operating_cost, base_op_cost)
+ self.assertAlmostEqual(bom.base_raw_material_cost, base_raw_material_cost)
+ self.assertAlmostEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost)
+
def test_subcontractor_sourced_item(self):
item_code = "_Test Subcontracted FG Item 1"
set_backflush_based_on("Material Transferred for Subcontract")
diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json
index 507d319..e9cbdfe 100644
--- a/erpnext/manufacturing/doctype/bom/test_records.json
+++ b/erpnext/manufacturing/doctype/bom/test_records.json
@@ -162,5 +162,31 @@
"item": "_Test Variant Item",
"quantity": 1.0,
"with_operations": 1
+ },
+ {
+ "items": [
+ {
+ "amount": 5000.0,
+ "doctype": "BOM Item",
+ "item_code": "_Test Item",
+ "parentfield": "items",
+ "qty": 2.0,
+ "rate": 3000.0,
+ "uom": "_Test UOM",
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC",
+ "include_item_in_manufacturing": 1
+ }
+ ],
+ "docstatus": 1,
+ "doctype": "BOM",
+ "is_active": 1,
+ "is_default": 1,
+ "currency": "USD",
+ "item": "_Test Variant Item",
+ "quantity": 1.0,
+ "with_operations": 0,
+ "fg_based_operating_cost": 1,
+ "operating_cost_per_bom_quantity": 140
}
]
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 41067d8..6744d16 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -324,3 +324,4 @@
erpnext.patches.v14_0.setup_clear_repost_logs
erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request
erpnext.patches.v14_0.update_entry_type_for_journal_entry
+erpnext.patches.v14_0.change_autoname_for_tax_withheld_vouchers
diff --git a/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py b/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py
new file mode 100644
index 0000000..e20ba73
--- /dev/null
+++ b/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+ if (
+ frappe.db.sql(
+ """select data_type FROM information_schema.columns
+ where column_name = 'name' and table_name = 'tabTax Withheld Vouchers'"""
+ )[0][0]
+ == "bigint"
+ ):
+ frappe.db.change_column_type("Tax Withheld Vouchers", "name", "varchar(140)")
diff --git a/erpnext/patches/v14_0/migrate_cost_center_allocations.py b/erpnext/patches/v14_0/migrate_cost_center_allocations.py
index 3bd2693..48f4e6d 100644
--- a/erpnext/patches/v14_0/migrate_cost_center_allocations.py
+++ b/erpnext/patches/v14_0/migrate_cost_center_allocations.py
@@ -18,9 +18,11 @@
cca = frappe.new_doc("Cost Center Allocation")
cca.main_cost_center = main_cc
cca.valid_from = today()
+ cca._skip_from_date_validation = True
for child_cc, percentage in allocations.items():
cca.append("allocation_percentages", ({"cost_center": child_cc, "percentage": percentage}))
+
cca.save()
cca.submit()
diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
index 27c8fe4..3df56e6 100644
--- a/erpnext/portal/doctype/homepage_section/test_homepage_section.py
+++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
@@ -10,62 +10,6 @@
class TestHomepageSection(unittest.TestCase):
- def test_homepage_section_card(self):
- try:
- frappe.get_doc(
- {
- "doctype": "Homepage Section",
- "name": "Card Section",
- "section_based_on": "Cards",
- "section_cards": [
- {
- "title": "Card 1",
- "subtitle": "Subtitle 1",
- "content": "This is test card 1",
- "route": "/card-1",
- },
- {
- "title": "Card 2",
- "subtitle": "Subtitle 2",
- "content": "This is test card 2",
- "image": "test.jpg",
- },
- ],
- "no_of_columns": 3,
- }
- ).insert(ignore_if_duplicate=True)
- except frappe.DuplicateEntryError:
- pass
-
- set_request(method="GET", path="home")
- response = get_response()
-
- self.assertEqual(response.status_code, 200)
-
- html = frappe.safe_decode(response.get_data())
-
- soup = BeautifulSoup(html, "html.parser")
- sections = soup.find("main").find_all("section")
- self.assertEqual(len(sections), 3)
-
- homepage_section = sections[2]
- self.assertEqual(homepage_section.h3.text, "Card Section")
-
- cards = homepage_section.find_all(class_="card")
-
- self.assertEqual(len(cards), 2)
- self.assertEqual(cards[0].h5.text, "Card 1")
- self.assertEqual(cards[0].a["href"], "/card-1")
- self.assertEqual(cards[1].p.text, "Subtitle 2")
-
- img = cards[1].find(class_="card-img-top")
-
- self.assertEqual(img["src"], "test.jpg")
- self.assertEqual(img["loading"], "lazy")
-
- # cleanup
- frappe.db.rollback()
-
def test_homepage_section_custom_html(self):
frappe.get_doc(
{
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 2dde542..ce3ae4f 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -80,7 +80,7 @@
if frappe.db.get_value("Task", d.task, "status") not in ("Completed", "Cancelled"):
frappe.throw(
_(
- "Cannot complete task {0} as its dependant task {1} are not ccompleted / cancelled."
+ "Cannot complete task {0} as its dependant task {1} are not completed / cancelled."
).format(frappe.bold(self.name), frappe.bold(d.task))
)
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 1179364..f3bd09a 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -387,6 +387,9 @@
"timesheets",
{
"time_sheet": timesheet.name,
+ "project_name": time_log.project_name,
+ "from_time": time_log.from_time,
+ "to_time": time_log.to_time,
"billing_hours": time_log.billing_hours,
"billing_amount": time_log.billing_amount,
"timesheet_detail": time_log.name,
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 1f8a5e3..2ce0c7e 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -122,24 +122,16 @@
calculate_item_values() {
var me = this;
if (!this.discount_amount_applied) {
- $.each(this.frm.doc["items"] || [], function(i, item) {
+ for (const item of this.frm.doc.items || []) {
frappe.model.round_floats_in(item);
item.net_rate = item.rate;
-
- if ((!item.qty) && me.frm.doc.is_return) {
- item.amount = flt(item.rate * -1, precision("amount", item));
- } else if ((!item.qty) && me.frm.doc.is_debit_note) {
- item.amount = flt(item.rate, precision("amount", item));
- } else {
- item.amount = flt(item.rate * item.qty, precision("amount", item));
- }
-
- item.net_amount = item.amount;
+ item.qty = item.qty === undefined ? (me.frm.doc.is_return ? -1 : 1) : item.qty;
+ item.net_amount = item.amount = flt(item.rate * item.qty, precision("amount", item));
item.item_tax_amount = 0.0;
item.total_weight = flt(item.weight_per_unit * item.stock_qty);
me.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]);
- });
+ }
}
}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index dd0e0c4..09f2c5d 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1473,6 +1473,7 @@
"parenttype": d.parenttype,
"parent": d.parent,
"pricing_rules": d.pricing_rules,
+ "is_free_item": d.is_free_item,
"warehouse": d.warehouse,
"serial_no": d.serial_no,
"batch_no": d.batch_no,
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 9288f51..a913844 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -13,20 +13,12 @@
erpnext.setup.slides_settings = [
{
- // Brand
- name: 'brand',
- icon: "fa fa-bookmark",
- title: __("The Brand"),
- // help: __('Upload your letter head and logo. (you can edit them later).'),
+ // Organization
+ name: 'organization',
+ title: __("Setup your organization"),
+ icon: "fa fa-building",
fields: [
{
- fieldtype: "Attach Image", fieldname: "attach_logo",
- label: __("Attach Logo"),
- description: __("100px by 100px"),
- is_private: 0,
- align: 'center'
- },
- {
fieldname: 'company_name',
label: __('Company Name'),
fieldtype: 'Data',
@@ -35,54 +27,9 @@
{
fieldname: 'company_abbr',
label: __('Company Abbreviation'),
- fieldtype: 'Data'
- }
- ],
- onload: function(slide) {
- this.bind_events(slide);
- },
- bind_events: function (slide) {
- slide.get_input("company_name").on("change", function () {
- var parts = slide.get_input("company_name").val().split(" ");
- var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
- slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase());
- }).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
-
- slide.get_input("company_abbr").on("change", function () {
- if (slide.get_input("company_abbr").val().length > 10) {
- frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters"));
- slide.get_field("company_abbr").set_value("");
- }
- });
- },
- validate: function() {
- if ((this.values.company_name || "").toLowerCase() == "company") {
- frappe.msgprint(__("Company Name cannot be Company"));
- return false;
- }
- if (!this.values.company_abbr) {
- return false;
- }
- if (this.values.company_abbr.length > 10) {
- return false;
- }
- return true;
- }
- },
- {
- // Organisation
- name: 'organisation',
- title: __("Your Organization"),
- icon: "fa fa-building",
- fields: [
- {
- fieldname: 'company_tagline',
- label: __('What does it do?'),
fieldtype: 'Data',
- placeholder: __('e.g. "Build tools for builders"'),
- reqd: 1
+ hidden: 1
},
- { fieldname: 'bank_account', label: __('Bank Name'), fieldtype: 'Data', reqd: 1 },
{
fieldname: 'chart_of_accounts', label: __('Chart of Accounts'),
options: "", fieldtype: 'Select'
@@ -94,40 +41,24 @@
],
onload: function (slide) {
- this.load_chart_of_accounts(slide);
this.bind_events(slide);
+ this.load_chart_of_accounts(slide);
this.set_fy_dates(slide);
},
-
validate: function () {
- let me = this;
- let exist;
-
if (!this.validate_fy_dates()) {
return false;
}
- // Validate bank name
- if(me.values.bank_account) {
- frappe.call({
- async: false,
- method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.validate_bank_account",
- args: {
- "coa": me.values.chart_of_accounts,
- "bank_account": me.values.bank_account
- },
- callback: function (r) {
- if(r.message){
- exist = r.message;
- me.get_field("bank_account").set_value("");
- let message = __('Account {0} already exists. Please enter a different name for your bank account.',
- [me.values.bank_account]
- );
- frappe.msgprint(message);
- }
- }
- });
- return !exist; // Return False if exist = true
+ if ((this.values.company_name || "").toLowerCase() == "company") {
+ frappe.msgprint(__("Company Name cannot be Company"));
+ return false;
+ }
+ if (!this.values.company_abbr) {
+ return false;
+ }
+ if (this.values.company_abbr.length > 10) {
+ return false;
}
return true;
@@ -151,15 +82,15 @@
var country = frappe.wizard.values.country;
if (country) {
- var fy = erpnext.setup.fiscal_years[country];
- var current_year = moment(new Date()).year();
- var next_year = current_year + 1;
+ let fy = erpnext.setup.fiscal_years[country];
+ let current_year = moment(new Date()).year();
+ let next_year = current_year + 1;
if (!fy) {
fy = ["01-01", "12-31"];
next_year = current_year;
}
- var year_start_date = current_year + "-" + fy[0];
+ let year_start_date = current_year + "-" + fy[0];
if (year_start_date > frappe.datetime.get_today()) {
next_year = current_year;
current_year -= 1;
@@ -171,7 +102,7 @@
load_chart_of_accounts: function (slide) {
- var country = frappe.wizard.values.country;
+ let country = frappe.wizard.values.country;
if (country) {
frappe.call({
@@ -202,12 +133,25 @@
me.charts_modal(slide, chart_template);
});
+
+ slide.get_input("company_name").on("change", function () {
+ let parts = slide.get_input("company_name").val().split(" ");
+ let abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
+ slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase());
+ }).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
+
+ slide.get_input("company_abbr").on("change", function () {
+ if (slide.get_input("company_abbr").val().length > 10) {
+ frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters"));
+ slide.get_field("company_abbr").set_value("");
+ }
+ });
},
charts_modal: function(slide, chart_template) {
let parent = __('All Accounts');
- var dialog = new frappe.ui.Dialog({
+ let dialog = new frappe.ui.Dialog({
title: chart_template,
fields: [
{'fieldname': 'expand_all', 'label': __('Expand All'), 'fieldtype': 'Button',
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index d37b7bb..51dcd64 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -491,7 +491,20 @@
const child_meta = frappe.get_meta(`${frm.doc.doctype} Item`);
const get_precision = (fieldname) => child_meta.fields.find(f => f.fieldname == fieldname).precision;
- this.data = [];
+ this.data = frm.doc[opts.child_docname].map((d) => {
+ return {
+ "docname": d.name,
+ "name": d.name,
+ "item_code": d.item_code,
+ "delivery_date": d.delivery_date,
+ "schedule_date": d.schedule_date,
+ "conversion_factor": d.conversion_factor,
+ "qty": d.qty,
+ "rate": d.rate,
+ "uom": d.uom
+ }
+ });
+
const fields = [{
fieldtype:'Data',
fieldname:"docname",
@@ -588,7 +601,7 @@
})
}
- const dialog = new frappe.ui.Dialog({
+ new frappe.ui.Dialog({
title: __("Update Items"),
fields: [
{
@@ -624,24 +637,7 @@
refresh_field("items");
},
primary_action_label: __('Update')
- });
-
- frm.doc[opts.child_docname].forEach(d => {
- dialog.fields_dict.trans_items.df.data.push({
- "docname": d.name,
- "name": d.name,
- "item_code": d.item_code,
- "delivery_date": d.delivery_date,
- "schedule_date": d.schedule_date,
- "conversion_factor": d.conversion_factor,
- "qty": d.qty,
- "rate": d.rate,
- "uom": d.uom
- });
- this.data = dialog.fields_dict.trans_items.df.data;
- dialog.fields_dict.trans_items.grid.refresh();
- })
- dialog.show();
+ }).show();
}
erpnext.utils.map_current_doc = function(opts) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index accf5f2..ca6a51a 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -26,7 +26,7 @@
from erpnext.selling.doctype.customer.customer import check_credit_limit
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
from erpnext.stock.doctype.item.item import get_item_defaults
-from erpnext.stock.get_item_details import get_default_bom
+from erpnext.stock.get_item_details import get_default_bom, get_price_list_rate
from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
@@ -590,6 +590,23 @@
target.qty = qty - requested_item_qty.get(source.name, 0)
target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
+ args = target.as_dict().copy()
+ args.update(
+ {
+ "company": source_parent.get("company"),
+ "price_list": frappe.db.get_single_value("Buying Settings", "buying_price_list"),
+ "currency": source_parent.get("currency"),
+ "conversion_rate": source_parent.get("conversion_rate"),
+ }
+ )
+
+ target.rate = flt(
+ get_price_list_rate(args=args, item_doc=frappe.get_cached_doc("Item", target.item_code)).get(
+ "price_list_rate"
+ )
+ )
+ target.amount = target.qty * target.rate
+
doc = get_mapped_doc(
"Sales Order",
source_name,
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e777f52..d4d7c58 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -552,6 +552,42 @@
workflow.is_active = 0
workflow.save()
+ def test_bin_details_of_packed_item(self):
+ # test Update Items with product bundle
+ if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+ bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+ bundle_item.append(
+ "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+ )
+ bundle_item.save(ignore_permissions=True)
+
+ make_item("_Packed Item New 1", {"is_stock_item": 1})
+ make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+ so = make_sales_order(
+ item_code="_Test Product Bundle Item New",
+ warehouse="_Test Warehouse - _TC",
+ transaction_date=add_days(nowdate(), -1),
+ do_not_submit=1,
+ )
+
+ make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+ bin_details = frappe.db.get_value(
+ "Bin",
+ {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+ ["actual_qty", "projected_qty", "ordered_qty"],
+ as_dict=1,
+ )
+
+ so.transaction_date = nowdate()
+ so.save()
+
+ packed_item = so.packed_items[0]
+ self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+ self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+ self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
def test_update_child_product_bundle(self):
# test Update Items with product bundle
if not frappe.db.exists("Item", "_Product Bundle Item"):
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 999ddc2..158ac1d 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -17,45 +17,79 @@
def search_by_term(search_term, warehouse, price_list):
result = search_for_serial_or_batch_or_barcode_number(search_term) or {}
- item_code = result.get("item_code") or search_term
- serial_no = result.get("serial_no") or ""
- batch_no = result.get("batch_no") or ""
- barcode = result.get("barcode") or ""
+ item_code = result.get("item_code", search_term)
+ serial_no = result.get("serial_no", "")
+ batch_no = result.get("batch_no", "")
+ barcode = result.get("barcode", "")
- if result:
- item_info = frappe.db.get_value(
- "Item",
- item_code,
- [
- "name as item_code",
- "item_name",
- "description",
- "stock_uom",
- "image as item_image",
- "is_stock_item",
- ],
- as_dict=1,
- )
+ if not result:
+ return
- item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
- price_list_rate, currency = frappe.db.get_value(
- "Item Price",
- {"price_list": price_list, "item_code": item_code},
- ["price_list_rate", "currency"],
- ) or [None, None]
+ item_doc = frappe.get_doc("Item", item_code)
- item_info.update(
+ if not item_doc:
+ return
+
+ item = {
+ "barcode": barcode,
+ "batch_no": batch_no,
+ "description": item_doc.description,
+ "is_stock_item": item_doc.is_stock_item,
+ "item_code": item_doc.name,
+ "item_image": item_doc.image,
+ "item_name": item_doc.item_name,
+ "serial_no": serial_no,
+ "stock_uom": item_doc.stock_uom,
+ "uom": item_doc.stock_uom,
+ }
+
+ if barcode:
+ barcode_info = next(filter(lambda x: x.barcode == barcode, item_doc.get("barcodes", [])), None)
+ if barcode_info and barcode_info.uom:
+ uom = next(filter(lambda x: x.uom == barcode_info.uom, item_doc.uoms), {})
+ item.update(
+ {
+ "uom": barcode_info.uom,
+ "conversion_factor": uom.get("conversion_factor", 1),
+ }
+ )
+
+ item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
+ item_stock_qty = item_stock_qty // item.get("conversion_factor")
+ item.update({"actual_qty": item_stock_qty})
+
+ price = frappe.get_list(
+ doctype="Item Price",
+ filters={
+ "price_list": price_list,
+ "item_code": item_code,
+ },
+ fields=["uom", "stock_uom", "currency", "price_list_rate"],
+ )
+
+ def __sort(p):
+ p_uom = p.get("uom")
+
+ if p_uom == item.get("uom"):
+ return 0
+ elif p_uom == item.get("stock_uom"):
+ return 1
+ else:
+ return 2
+
+ # sort by fallback preference. always pick exact uom match if available
+ price = sorted(price, key=__sort)
+
+ if len(price) > 0:
+ p = price.pop(0)
+ item.update(
{
- "serial_no": serial_no,
- "batch_no": batch_no,
- "barcode": barcode,
- "price_list_rate": price_list_rate,
- "currency": currency,
- "actual_qty": item_stock_qty,
+ "currency": p.get("currency"),
+ "price_list_rate": p.get("price_list_rate"),
}
)
- return {"items": [item_info]}
+ return {"items": [item]}
@frappe.whitelist()
@@ -121,33 +155,43 @@
as_dict=1,
)
- if items_data:
- items = [d.item_code for d in items_data]
- item_prices_data = frappe.get_all(
+ # return (empty) list if there are no results
+ if not items_data:
+ return result
+
+ for item in items_data:
+ uoms = frappe.get_doc("Item", item.item_code).get("uoms", [])
+
+ item.actual_qty, _ = get_stock_availability(item.item_code, warehouse)
+ item.uom = item.stock_uom
+
+ item_price = frappe.get_all(
"Item Price",
- fields=["item_code", "price_list_rate", "currency"],
- filters={"price_list": price_list, "item_code": ["in", items]},
+ fields=["price_list_rate", "currency", "uom"],
+ filters={
+ "price_list": price_list,
+ "item_code": item.item_code,
+ "selling": True,
+ },
)
- item_prices = {}
- for d in item_prices_data:
- item_prices[d.item_code] = d
+ if not item_price:
+ result.append(item)
- for item in items_data:
- item_code = item.item_code
- item_price = item_prices.get(item_code) or {}
- item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
+ for price in item_price:
+ uom = next(filter(lambda x: x.uom == price.uom, uoms), {})
- row = {}
- row.update(item)
- row.update(
+ if price.uom != item.stock_uom and uom and uom.conversion_factor:
+ item.actual_qty = item.actual_qty // uom.conversion_factor
+
+ result.append(
{
- "price_list_rate": item_price.get("price_list_rate"),
- "currency": item_price.get("currency"),
- "actual_qty": item_stock_qty,
+ **item,
+ "price_list_rate": price.get("price_list_rate"),
+ "currency": price.get("currency"),
+ "uom": price.uom or item.uom,
}
)
- result.append(row)
return {"items": result}
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 595b919..c442774 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -542,12 +542,12 @@
if (!this.frm.doc.customer)
return this.raise_customer_selection_alert();
- const { item_code, batch_no, serial_no, rate } = item;
+ const { item_code, batch_no, serial_no, rate, uom } = item;
if (!item_code)
return;
- const new_item = { item_code, batch_no, rate, [field]: value };
+ const new_item = { item_code, batch_no, rate, uom, [field]: value };
if (serial_no) {
await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
@@ -649,6 +649,7 @@
const is_stock_item = resp[1];
frappe.dom.unfreeze();
+ const bold_uom = item_row.stock_uom.bold();
const bold_item_code = item_row.item_code.bold();
const bold_warehouse = warehouse.bold();
const bold_available_qty = available_qty.toString().bold()
@@ -664,7 +665,7 @@
}
} else if (is_stock_item && available_qty < qty_needed) {
frappe.throw({
- message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.', [bold_item_code, bold_warehouse, bold_available_qty]),
+ message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2} {3}.', [bold_item_code, bold_warehouse, bold_available_qty, bold_uom]),
indicator: 'orange'
});
frappe.utils.play_sound("error");
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index e7dd211..12cc629 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -609,7 +609,7 @@
if (item_data.rate && item_data.amount && item_data.rate !== item_data.amount) {
return `
<div class="item-qty-rate">
- <div class="item-qty"><span>${item_data.qty || 0}</span></div>
+ <div class="item-qty"><span>${item_data.qty || 0} ${item_data.uom}</span></div>
<div class="item-rate-amount">
<div class="item-rate">${format_currency(item_data.amount, currency)}</div>
<div class="item-amount">${format_currency(item_data.rate, currency)}</div>
@@ -618,7 +618,7 @@
} else {
return `
<div class="item-qty-rate">
- <div class="item-qty"><span>${item_data.qty || 0}</span></div>
+ <div class="item-qty"><span>${item_data.qty || 0} ${item_data.uom}</span></div>
<div class="item-rate-amount">
<div class="item-rate">${format_currency(item_data.rate, currency)}</div>
</div>
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index b5eb048..ec67bdf 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -78,7 +78,7 @@
get_item_html(item) {
const me = this;
// eslint-disable-next-line no-unused-vars
- const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
+ const { item_image, serial_no, batch_no, barcode, actual_qty, uom, price_list_rate } = item;
const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0;
let indicator_color;
let qty_to_display = actual_qty;
@@ -118,7 +118,7 @@
return (
`<div class="item-wrapper"
data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
- data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
+ data-batch-no="${escape(batch_no)}" data-uom="${escape(uom)}"
data-rate="${escape(price_list_rate || 0)}"
title="${item.item_name}">
@@ -128,7 +128,7 @@
<div class="item-name">
${frappe.ellipsis(item.item_name, 18)}
</div>
- <div class="item-rate">${format_currency(price_list_rate, item.currency, precision) || 0}</div>
+ <div class="item-rate">${format_currency(price_list_rate, item.currency, precision) || 0} / ${uom}</div>
</div>
</div>`
);
diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
index 40165c3..be75bd6 100644
--- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
+++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
@@ -94,7 +94,7 @@
get_item_html(doc, item_data) {
return `<div class="item-row-wrapper">
<div class="item-name">${item_data.item_name}</div>
- <div class="item-qty">${item_data.qty || 0}</div>
+ <div class="item-qty">${item_data.qty || 0} ${item_data.uom}</div>
<div class="item-rate-disc">${get_rate_discount_html()}</div>
</div>`;
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 95bbf84..2fdfcf6 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -148,12 +148,12 @@
def get_parent_item_groups(item_group_name, from_item=False):
- base_nav_page = {"name": _("Shop by Category"), "route": "/shop-by-category"}
+ base_nav_page = {"name": _("All Products"), "route": "/all-products"}
if from_item and frappe.request.environ.get("HTTP_REFERER"):
# base page after 'Home' will vary on Item page
last_page = frappe.request.environ["HTTP_REFERER"].split("/")[-1].split("?")[0]
- if last_page and last_page in ("shop-by-category", "all-products"):
+ if last_page and last_page == "shop-by-category":
base_nav_page_title = " ".join(last_page.split("-")).title()
base_nav_page = {"name": _(base_nav_page_title), "route": "/" + last_page}
diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py
index aadc989..ace5cca 100644
--- a/erpnext/setup/setup_wizard/operations/company_setup.py
+++ b/erpnext/setup/setup_wizard/operations/company_setup.py
@@ -4,7 +4,6 @@
import frappe
from frappe import _
from frappe.utils import cstr, getdate
-from .default_website import website_maker
def create_fiscal_year_and_company(args):
@@ -48,83 +47,6 @@
).insert()
-def create_email_digest():
- from frappe.utils.user import get_system_managers
-
- system_managers = get_system_managers(only_name=True)
-
- if not system_managers:
- return
-
- recipients = []
- for d in system_managers:
- recipients.append({"recipient": d})
-
- companies = frappe.db.sql_list("select name FROM `tabCompany`")
- for company in companies:
- if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
- edigest = frappe.get_doc(
- {
- "doctype": "Email Digest",
- "name": "Default Weekly Digest - " + company,
- "company": company,
- "frequency": "Weekly",
- "recipients": recipients,
- }
- )
-
- for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
- if df.fieldname != "scheduler_errors":
- edigest.set(df.fieldname, 1)
-
- edigest.insert()
-
- # scheduler errors digest
- if companies:
- edigest = frappe.new_doc("Email Digest")
- edigest.update(
- {
- "name": "Scheduler Errors",
- "company": companies[0],
- "frequency": "Daily",
- "recipients": recipients,
- "scheduler_errors": 1,
- "enabled": 1,
- }
- )
- edigest.insert()
-
-
-def create_logo(args):
- if args.get("attach_logo"):
- attach_logo = args.get("attach_logo").split(",")
- if len(attach_logo) == 3:
- filename, filetype, content = attach_logo
- _file = frappe.get_doc(
- {
- "doctype": "File",
- "file_name": filename,
- "attached_to_doctype": "Website Settings",
- "attached_to_name": "Website Settings",
- "decode": True,
- }
- )
- _file.save()
- fileurl = _file.file_url
- frappe.db.set_value(
- "Website Settings",
- "Website Settings",
- "brand_html",
- "<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(
- fileurl, args.get("company_name")
- ),
- )
-
-
-def create_website(args):
- website_maker(args)
-
-
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year
if start_year == getdate(fy_end_date).year:
diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py
deleted file mode 100644
index 40b02b3..0000000
--- a/erpnext/setup/setup_wizard/operations/default_website.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-
-import frappe
-from frappe import _
-from frappe.utils import nowdate
-
-
-class website_maker(object):
- def __init__(self, args):
- self.args = args
- self.company = args.company_name
- self.tagline = args.company_tagline
- self.user = args.get("email")
- self.make_web_page()
- self.make_website_settings()
- self.make_blog()
-
- def make_web_page(self):
- # home page
- homepage = frappe.get_doc("Homepage", "Homepage")
- homepage.company = self.company
- homepage.tag_line = self.tagline
- homepage.setup_items()
- homepage.save()
-
- def make_website_settings(self):
- # update in home page in settings
- website_settings = frappe.get_doc("Website Settings", "Website Settings")
- website_settings.home_page = "home"
- website_settings.brand_html = self.company
- website_settings.copyright = self.company
- website_settings.top_bar_items = []
- website_settings.append(
- "top_bar_items", {"doctype": "Top Bar Item", "label": "Contact", "url": "/contact"}
- )
- website_settings.append(
- "top_bar_items", {"doctype": "Top Bar Item", "label": "Blog", "url": "/blog"}
- )
- website_settings.append(
- "top_bar_items", {"doctype": "Top Bar Item", "label": _("Products"), "url": "/all-products"}
- )
- website_settings.save()
-
- def make_blog(self):
- blog_category = frappe.get_doc(
- {"doctype": "Blog Category", "category_name": "general", "published": 1, "title": _("General")}
- ).insert()
-
- if not self.user:
- # Admin setup
- return
-
- blogger = frappe.new_doc("Blogger")
- user = frappe.get_doc("User", self.user)
- blogger.user = self.user
- blogger.full_name = user.first_name + (" " + user.last_name if user.last_name else "")
- blogger.short_name = user.first_name.lower()
- blogger.avatar = user.user_image
- blogger.insert()
-
- frappe.get_doc(
- {
- "doctype": "Blog Post",
- "title": "Welcome",
- "published": 1,
- "published_on": nowdate(),
- "blogger": blogger.name,
- "blog_category": blog_category.name,
- "blog_intro": "My First Blog",
- "content": frappe.get_template("setup/setup_wizard/data/sample_blog_post.html").render(),
- }
- ).insert()
-
-
-def test():
- frappe.delete_doc("Web Page", "test-company")
- frappe.delete_doc("Blog Post", "welcome")
- frappe.delete_doc("Blogger", "administrator")
- frappe.delete_doc("Blog Category", "general")
- website_maker(
- {
- "company": "Test Company",
- "company_tagline": "Better Tools for Everyone",
- "name": "Administrator",
- }
- )
- frappe.db.commit()
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index bd86a5b..65b268e 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -5,7 +5,6 @@
import frappe
from frappe import _
-from .operations import company_setup
from .operations import install_fixtures as fixtures
@@ -35,7 +34,6 @@
"fail_msg": "Failed to set defaults",
"tasks": [
{"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")},
- {"fn": stage_four, "args": args, "fail_msg": _("Failed to create website")},
],
},
{
@@ -60,12 +58,6 @@
fixtures.install_defaults(frappe._dict(args))
-def stage_four(args):
- company_setup.create_website(args)
- company_setup.create_email_digest()
- company_setup.create_logo(args)
-
-
def fin(args):
frappe.local.message_log = []
login_as_first_user(args)
@@ -81,5 +73,4 @@
stage_fixtures(args)
setup_company(args)
setup_defaults(args)
- stage_four(args)
fin(args)
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index d747383..903e2af 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -490,6 +490,46 @@
self.assertEqual(gle_warehouse_amount, 1400)
+ def test_bin_details_of_packed_item(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ # test Update Items with product bundle
+ if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+ bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+ bundle_item.append(
+ "item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+ )
+ bundle_item.save(ignore_permissions=True)
+
+ make_item("_Packed Item New 1", {"is_stock_item": 1})
+ make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+ si = create_delivery_note(
+ item_code="_Test Product Bundle Item New",
+ update_stock=1,
+ warehouse="_Test Warehouse - _TC",
+ transaction_date=add_days(nowdate(), -1),
+ do_not_submit=1,
+ )
+
+ make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+ bin_details = frappe.db.get_value(
+ "Bin",
+ {"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+ ["actual_qty", "projected_qty", "ordered_qty"],
+ as_dict=1,
+ )
+
+ si.transaction_date = nowdate()
+ si.save()
+
+ packed_item = si.packed_items[0]
+ self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+ self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+ self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
def test_return_for_serialized_items(self):
se = make_serialized_item()
serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
@@ -650,6 +690,11 @@
update_delivery_note_status(dn.name, "Closed")
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
+ # Check cancelling closed delivery note
+ dn.load_from_db()
+ dn.cancel()
+ self.assertEqual(dn.status, "Cancelled")
+
def test_dn_billing_status_case1(self):
# SO -> DN -> SI
so = make_sales_order()
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 391ff06..ac4c313 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -74,11 +74,10 @@
def validate_duplication(self):
values, abbrs = [], []
for d in self.item_attribute_values:
- d.abbr = d.abbr.upper()
- if d.attribute_value in values:
- frappe.throw(_("{0} must appear only once").format(d.attribute_value))
+ if d.attribute_value.lower() in map(str.lower, values):
+ frappe.throw(_("Attribute value: {0} must appear only once").format(d.attribute_value.title()))
values.append(d.attribute_value)
- if d.abbr in abbrs:
- frappe.throw(_("{0} must appear only once").format(d.abbr))
+ if d.abbr.lower() in map(str.lower, abbrs):
+ frappe.throw(_("Abbreviation: {0} must appear only once").format(d.abbr.title()))
abbrs.append(d.abbr)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 9c6f4f4..808f19e 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -11,7 +11,7 @@
from frappe.model.document import Document
from frappe.model.mapper import map_child_doc
from frappe.query_builder import Case
-from frappe.query_builder.functions import Locate
+from frappe.query_builder.functions import IfNull, Locate, Sum
from frappe.utils import cint, floor, flt, today
from frappe.utils.nestedset import get_descendants_of
@@ -503,42 +503,30 @@
def get_available_item_locations_for_batched_item(
item_code, from_warehouses, required_qty, company
):
- warehouse_condition = "and warehouse in %(warehouses)s" if from_warehouses else ""
- batch_locations = frappe.db.sql(
- """
- SELECT
- sle.`warehouse`,
- sle.`batch_no`,
- SUM(sle.`actual_qty`) AS `qty`
- FROM
- `tabStock Ledger Entry` sle, `tabBatch` batch
- WHERE
- sle.batch_no = batch.name
- and sle.`item_code`=%(item_code)s
- and sle.`company` = %(company)s
- and batch.disabled = 0
- and sle.is_cancelled=0
- and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
- {warehouse_condition}
- GROUP BY
- sle.`warehouse`,
- sle.`batch_no`,
- sle.`item_code`
- HAVING `qty` > 0
- ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`, sle.`batch_no`, sle.`warehouse`
- """.format(
- warehouse_condition=warehouse_condition
- ),
- { # nosec
- "item_code": item_code,
- "company": company,
- "today": today(),
- "warehouses": from_warehouses,
- },
- as_dict=1,
+ sle = frappe.qb.DocType("Stock Ledger Entry")
+ batch = frappe.qb.DocType("Batch")
+
+ query = (
+ frappe.qb.from_(sle)
+ .from_(batch)
+ .select(sle.warehouse, sle.batch_no, Sum(sle.actual_qty).as_("qty"))
+ .where(
+ (sle.batch_no == batch.name)
+ & (sle.item_code == item_code)
+ & (sle.company == company)
+ & (batch.disabled == 0)
+ & (sle.is_cancelled == 0)
+ & (IfNull(batch.expiry_date, "2200-01-01") > today())
+ )
+ .groupby(sle.warehouse, sle.batch_no, sle.item_code)
+ .having(Sum(sle.actual_qty) > 0)
+ .orderby(IfNull(batch.expiry_date, "2200-01-01"), batch.creation, sle.batch_no, sle.warehouse)
)
- return batch_locations
+ if from_warehouses:
+ query = query.where(sle.warehouse.isin(from_warehouses))
+
+ return query.run(as_dict=True)
def get_available_item_locations_for_serial_and_batched_item(
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 9321c2c..2a9f091 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -221,7 +221,7 @@
def item_query(doctype, txt, searchfield, start, page_len, filters):
from frappe.desk.reportview import get_match_cond
- from_doctype = cstr(filters.get("doctype"))
+ from_doctype = cstr(filters.get("from"))
if not from_doctype or not frappe.db.exists("DocType", from_doctype):
return []
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 897fca3..fb1f77a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -169,6 +169,8 @@
},
refresh: function(frm) {
+ frm.trigger("get_items_from_transit_entry");
+
if(!frm.doc.docstatus) {
frm.trigger('validate_purpose_consumption');
frm.add_custom_button(__('Material Request'), function() {
@@ -337,6 +339,28 @@
}
},
+ get_items_from_transit_entry: function(frm) {
+ if (frm.doc.docstatus===0) {
+ frm.add_custom_button(__('Transit Entry'), function() {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.stock.doctype.stock_entry.stock_entry.make_stock_in_entry",
+ source_doctype: "Stock Entry",
+ target: frm,
+ date_field: "posting_date",
+ setters: {
+ stock_entry_type: "Material Transfer",
+ purpose: "Material Transfer",
+ },
+ get_query_filters: {
+ docstatus: 1,
+ purpose: "Material Transfer",
+ add_to_transit: 1,
+ }
+ })
+ }, __("Get Items From"));
+ }
+ },
+
before_save: function(frm) {
frm.doc.items.forEach((item) => {
item.uom = item.uom || item.stock_uom;
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index 41a3b89..0f90013 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -117,6 +117,7 @@
args.item = "_Test Item"
s.company = args.company or erpnext.get_default_company()
+ s.add_to_transit = args.add_to_transit or 0
s.purchase_receipt_no = args.purchase_receipt_no
s.delivery_note_no = args.delivery_note_no
s.sales_invoice_no = args.sales_invoice_no
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index b574b71..38bf0a5 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -17,6 +17,7 @@
from erpnext.stock.doctype.serial_no.serial_no import * # noqa
from erpnext.stock.doctype.stock_entry.stock_entry import (
FinishedGoodError,
+ make_stock_in_entry,
move_sample_to_retention_warehouse,
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -160,6 +161,53 @@
self.assertTrue(item_code in items)
+ def test_add_to_transit_entry(self):
+ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+
+ item_code = "_Test Transit Item"
+ company = "_Test Company"
+
+ create_warehouse("Test From Warehouse")
+ create_warehouse("Test Transit Warehouse")
+ create_warehouse("Test To Warehouse")
+
+ create_item(
+ item_code=item_code,
+ is_stock_item=1,
+ is_purchase_item=1,
+ company=company,
+ )
+
+ # create inward stock entry
+ make_stock_entry(
+ item_code=item_code,
+ target="Test From Warehouse - _TC",
+ qty=10,
+ basic_rate=100,
+ expense_account="Stock Adjustment - _TC",
+ cost_center="Main - _TC",
+ )
+
+ transit_entry = make_stock_entry(
+ item_code=item_code,
+ source="Test From Warehouse - _TC",
+ target="Test Transit Warehouse - _TC",
+ add_to_transit=1,
+ stock_entry_type="Material Transfer",
+ purpose="Material Transfer",
+ qty=10,
+ basic_rate=100,
+ expense_account="Stock Adjustment - _TC",
+ cost_center="Main - _TC",
+ )
+
+ end_transit_entry = make_stock_in_entry(transit_entry.name)
+ self.assertEqual(transit_entry.name, end_transit_entry.outgoing_stock_entry)
+ self.assertEqual(transit_entry.name, end_transit_entry.items[0].against_stock_entry)
+ self.assertEqual(transit_entry.items[0].name, end_transit_entry.items[0].ste_detail)
+
+ # create add to transit
+
def test_material_receipt_gl_entry(self):
company = frappe.db.get_value("Warehouse", "Stores - TCP1", "company")
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 363dc0a..5af1441 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -236,8 +236,10 @@
validate_end_of_life(item.name, item.end_of_life, item.disabled)
- if args.transaction_type == "selling" and cint(item.has_variants):
- throw(_("Item {0} is a template, please select one of its variants").format(item.name))
+ if cint(item.has_variants):
+ msg = f"Item {item.name} is a template, please select one of its variants"
+
+ throw(_(msg), title=_("Template Item Selected"))
elif args.transaction_type == "buying" and args.doctype != "Material Request":
if args.get("is_subcontracted"):
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order_list.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order_list.js
index aab2fc9..7ca1264 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order_list.js
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order_list.js
@@ -11,6 +11,7 @@
"Partial Material Transferred": "purple",
"Material Transferred": "blue",
"Closed": "red",
+ "Cancelled": "red",
};
return [__(doc.status), status_colors[doc.status], "status,=," + doc.status];
},
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
index 3675a4e..d77e774 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -1,352 +1,353 @@
{
- "actions": [],
- "autoname": "hash",
- "creation": "2022-04-01 19:26:31.475015",
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "item_code",
- "item_name",
- "bom",
- "include_exploded_items",
- "column_break_3",
- "schedule_date",
- "expected_delivery_date",
- "description_section",
- "description",
- "column_break_8",
- "image",
- "image_view",
- "quantity_and_rate_section",
- "qty",
- "received_qty",
- "returned_qty",
- "column_break_13",
- "stock_uom",
- "conversion_factor",
- "section_break_16",
- "rate",
- "amount",
- "column_break_19",
- "rm_cost_per_qty",
- "service_cost_per_qty",
- "additional_cost_per_qty",
- "warehouse_section",
- "warehouse",
- "accounting_details_section",
- "expense_account",
- "manufacture_section",
- "manufacturer",
- "manufacturer_part_no",
- "accounting_dimensions_section",
- "cost_center",
- "dimension_col_break",
- "project",
- "section_break_34",
- "page_break"
- ],
- "fields": [
- {
- "bold": 1,
- "columns": 2,
- "fieldname": "item_code",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item Code",
- "options": "Item",
- "read_only": 1,
- "reqd": 1,
- "search_index": 1
- },
- {
- "fetch_from": "item_code.item_name",
- "fetch_if_empty": 1,
- "fieldname": "item_name",
- "fieldtype": "Data",
- "in_global_search": 1,
- "label": "Item Name",
- "print_hide": 1,
- "reqd": 1
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "bold": 1,
- "columns": 2,
- "fieldname": "schedule_date",
- "fieldtype": "Date",
- "label": "Required By",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "bold": 1,
- "fieldname": "expected_delivery_date",
- "fieldtype": "Date",
- "label": "Expected Delivery Date",
- "search_index": 1
- },
- {
- "collapsible": 1,
- "fieldname": "description_section",
- "fieldtype": "Section Break",
- "label": "Description"
- },
- {
- "fetch_from": "item_code.description",
- "fetch_if_empty": 1,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "label": "Description",
- "print_width": "300px",
- "reqd": 1,
- "width": "300px"
- },
- {
- "fieldname": "column_break_8",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "image",
- "fieldtype": "Attach",
- "hidden": 1,
- "label": "Image"
- },
- {
- "fieldname": "image_view",
- "fieldtype": "Image",
- "label": "Image View",
- "options": "image",
- "print_hide": 1
- },
- {
- "fieldname": "quantity_and_rate_section",
- "fieldtype": "Section Break",
- "label": "Quantity and Rate"
- },
- {
- "bold": 1,
- "columns": 1,
- "default": "1",
- "fieldname": "qty",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Quantity",
- "print_width": "60px",
- "read_only": 1,
- "reqd": 1,
- "width": "60px"
- },
- {
- "fieldname": "column_break_13",
- "fieldtype": "Column Break",
- "print_hide": 1
- },
- {
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "label": "Stock UOM",
- "options": "UOM",
- "print_width": "100px",
- "read_only": 1,
- "reqd": 1,
- "width": "100px"
- },
- {
- "default": "1",
- "fieldname": "conversion_factor",
- "fieldtype": "Float",
- "hidden": 1,
- "label": "Conversion Factor",
- "read_only": 1
- },
- {
- "fieldname": "section_break_16",
- "fieldtype": "Section Break"
- },
- {
- "bold": 1,
- "columns": 2,
- "fetch_from": "item_code.standard_rate",
- "fetch_if_empty": 1,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Rate",
- "options": "currency",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "column_break_19",
- "fieldtype": "Column Break"
- },
- {
- "columns": 2,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Amount",
- "options": "currency",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "warehouse_section",
- "fieldtype": "Section Break",
- "label": "Warehouse Details"
- },
- {
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "label": "Warehouse",
- "options": "Warehouse",
- "print_hide": 1,
- "reqd": 1
- },
- {
- "collapsible": 1,
- "fieldname": "accounting_details_section",
- "fieldtype": "Section Break",
- "label": "Accounting Details"
- },
- {
- "fieldname": "expense_account",
- "fieldtype": "Link",
- "label": "Expense Account",
- "options": "Account",
- "print_hide": 1
- },
- {
- "collapsible": 1,
- "fieldname": "manufacture_section",
- "fieldtype": "Section Break",
- "label": "Manufacture"
- },
- {
- "fieldname": "manufacturer",
- "fieldtype": "Link",
- "label": "Manufacturer",
- "options": "Manufacturer"
- },
- {
- "fieldname": "manufacturer_part_no",
- "fieldtype": "Data",
- "label": "Manufacturer Part Number"
- },
- {
- "depends_on": "item_code",
- "fetch_from": "item_code.default_bom",
- "fieldname": "bom",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "BOM",
- "options": "BOM",
- "print_hide": 1,
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "include_exploded_items",
- "fieldtype": "Check",
- "label": "Include Exploded Items",
- "print_hide": 1
- },
- {
- "fieldname": "service_cost_per_qty",
- "fieldtype": "Currency",
- "label": "Service Cost Per Qty",
- "read_only": 1,
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "additional_cost_per_qty",
- "fieldtype": "Currency",
- "label": "Additional Cost Per Qty",
- "read_only": 1
- },
- {
- "fieldname": "rm_cost_per_qty",
- "fieldtype": "Currency",
- "label": "Raw Material Cost Per Qty",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "default": "0",
- "fieldname": "page_break",
- "fieldtype": "Check",
- "label": "Page Break",
- "no_copy": 1,
- "print_hide": 1
- },
- {
- "fieldname": "section_break_34",
- "fieldtype": "Section Break"
- },
- {
- "depends_on": "received_qty",
- "fieldname": "received_qty",
- "fieldtype": "Float",
- "label": "Received Qty",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "depends_on": "returned_qty",
- "fieldname": "returned_qty",
- "fieldtype": "Float",
- "label": "Returned Qty",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "accounting_dimensions_section",
- "fieldtype": "Section Break",
- "label": "Accounting Dimensions"
- },
- {
- "fieldname": "cost_center",
- "fieldtype": "Link",
- "label": "Cost Center",
- "options": "Cost Center"
- },
- {
- "fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "project",
- "fieldtype": "Link",
- "label": "Project",
- "options": "Project"
- }
- ],
- "idx": 1,
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2022-08-15 14:25:45.177703",
- "modified_by": "Administrator",
- "module": "Subcontracting",
- "name": "Subcontracting Order Item",
- "naming_rule": "Random",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "search_fields": "item_name",
- "sort_field": "modified",
- "sort_order": "DESC",
- "states": [],
- "track_changes": 1
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2022-04-01 19:26:31.475015",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "item_name",
+ "bom",
+ "include_exploded_items",
+ "column_break_3",
+ "schedule_date",
+ "expected_delivery_date",
+ "description_section",
+ "description",
+ "column_break_8",
+ "image",
+ "image_view",
+ "quantity_and_rate_section",
+ "qty",
+ "received_qty",
+ "returned_qty",
+ "column_break_13",
+ "stock_uom",
+ "conversion_factor",
+ "section_break_16",
+ "rate",
+ "amount",
+ "column_break_19",
+ "rm_cost_per_qty",
+ "service_cost_per_qty",
+ "additional_cost_per_qty",
+ "warehouse_section",
+ "warehouse",
+ "accounting_details_section",
+ "expense_account",
+ "manufacture_section",
+ "manufacturer",
+ "manufacturer_part_no",
+ "accounting_dimensions_section",
+ "cost_center",
+ "dimension_col_break",
+ "project",
+ "section_break_34",
+ "page_break"
+ ],
+ "fields": [
+ {
+ "bold": 1,
+ "columns": 2,
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "item_code.item_name",
+ "fetch_if_empty": 1,
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Item Name",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "bold": 1,
+ "columns": 2,
+ "fieldname": "schedule_date",
+ "fieldtype": "Date",
+ "label": "Required By",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "bold": 1,
+ "fieldname": "expected_delivery_date",
+ "fieldtype": "Date",
+ "label": "Expected Delivery Date",
+ "search_index": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "description_section",
+ "fieldtype": "Section Break",
+ "label": "Description"
+ },
+ {
+ "fetch_from": "item_code.description",
+ "fetch_if_empty": 1,
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "label": "Description",
+ "print_width": "300px",
+ "reqd": 1,
+ "width": "300px"
+ },
+ {
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "image",
+ "fieldtype": "Attach",
+ "hidden": 1,
+ "label": "Image"
+ },
+ {
+ "fieldname": "image_view",
+ "fieldtype": "Image",
+ "label": "Image View",
+ "options": "image",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "quantity_and_rate_section",
+ "fieldtype": "Section Break",
+ "label": "Quantity and Rate"
+ },
+ {
+ "bold": 1,
+ "columns": 1,
+ "default": "1",
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Quantity",
+ "print_width": "60px",
+ "read_only": 1,
+ "reqd": 1,
+ "width": "60px"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock UOM",
+ "options": "UOM",
+ "print_width": "100px",
+ "read_only": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "default": "1",
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Conversion Factor",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_16",
+ "fieldtype": "Section Break"
+ },
+ {
+ "bold": 1,
+ "columns": 2,
+ "fetch_from": "item_code.standard_rate",
+ "fetch_if_empty": 1,
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "options": "currency",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break"
+ },
+ {
+ "columns": 2,
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "options": "currency",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "warehouse_section",
+ "fieldtype": "Section Break",
+ "label": "Warehouse Details"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_details_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Details"
+ },
+ {
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "label": "Expense Account",
+ "options": "Account",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "manufacture_section",
+ "fieldtype": "Section Break",
+ "label": "Manufacture"
+ },
+ {
+ "fieldname": "manufacturer",
+ "fieldtype": "Link",
+ "label": "Manufacturer",
+ "options": "Manufacturer"
+ },
+ {
+ "fieldname": "manufacturer_part_no",
+ "fieldtype": "Data",
+ "label": "Manufacturer Part Number"
+ },
+ {
+ "depends_on": "item_code",
+ "fetch_from": "item_code.default_bom",
+ "fetch_if_empty": 1,
+ "fieldname": "bom",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "BOM",
+ "options": "BOM",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "include_exploded_items",
+ "fieldtype": "Check",
+ "label": "Include Exploded Items",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "service_cost_per_qty",
+ "fieldtype": "Currency",
+ "label": "Service Cost Per Qty",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "additional_cost_per_qty",
+ "fieldtype": "Currency",
+ "label": "Additional Cost Per Qty",
+ "read_only": 1
+ },
+ {
+ "fieldname": "rm_cost_per_qty",
+ "fieldtype": "Currency",
+ "label": "Raw Material Cost Per Qty",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "page_break",
+ "fieldtype": "Check",
+ "label": "Page Break",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "section_break_34",
+ "fieldtype": "Section Break"
+ },
+ {
+ "depends_on": "received_qty",
+ "fieldname": "received_qty",
+ "fieldtype": "Float",
+ "label": "Received Qty",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "returned_qty",
+ "fieldname": "returned_qty",
+ "fieldtype": "Float",
+ "label": "Returned Qty",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ }
+ ],
+ "idx": 1,
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2023-01-20 23:25:45.363281",
+ "modified_by": "Administrator",
+ "module": "Subcontracting",
+ "name": "Subcontracting Order Item",
+ "naming_rule": "Random",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "search_fields": "item_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index e8faa48..f4fd4de 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -262,15 +262,17 @@
def get_gl_entries(self, warehouse_account=None):
from erpnext.accounts.general_ledger import process_gl_map
+ if not erpnext.is_perpetual_inventory_enabled(self.company):
+ return []
+
gl_entries = []
self.make_item_gl_entries(gl_entries, warehouse_account)
return process_gl_map(gl_entries)
def make_item_gl_entries(self, gl_entries, warehouse_account=None):
- if erpnext.is_perpetual_inventory_enabled(self.company):
- stock_rbnb = self.get_company_default("stock_received_but_not_billed")
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+ stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+ expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
warehouse_with_no_account = []
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index e1e12bd..185ec66 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -38,22 +38,27 @@
if not frappe.has_website_permission(context.doc):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
- # check for the loyalty program of the customer
- customer_loyalty_program = frappe.db.get_value(
- "Customer", context.doc.customer, "loyalty_program"
- )
- if customer_loyalty_program:
- from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
- get_loyalty_program_details_with_points,
+ context.available_loyalty_points = 0.0
+ if context.doc.get("customer"):
+ # check for the loyalty program of the customer
+ customer_loyalty_program = frappe.db.get_value(
+ "Customer", context.doc.customer, "loyalty_program"
)
- loyalty_program_details = get_loyalty_program_details_with_points(
- context.doc.customer, customer_loyalty_program
- )
- context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
+ if customer_loyalty_program:
+ from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
+ get_loyalty_program_details_with_points,
+ )
- # show Make Purchase Invoice button based on permission
- context.show_make_pi_button = frappe.has_permission("Purchase Invoice", "create")
+ loyalty_program_details = get_loyalty_program_details_with_points(
+ context.doc.customer, customer_loyalty_program
+ )
+ context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
+
+ context.show_make_pi_button = False
+ if context.doc.get("supplier"):
+ # show Make Purchase Invoice button based on permission
+ context.show_make_pi_button = frappe.has_permission("Purchase Invoice", "create")
def get_attachments(dt, dn):
diff --git a/erpnext/translations/af.csv b/erpnext/translations/af.csv
index 45435d8..265e85c 100644
--- a/erpnext/translations/af.csv
+++ b/erpnext/translations/af.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Reëls vir die toepassing van verskillende promosieskemas.,
Shift,verskuiwing,
Show {0},Wys {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Spesiale karakters behalwe "-", "#", ".", "/", "{" En "}" word nie toegelaat in die naamreekse nie",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Spesiale karakters behalwe "-", "#", ".", "/", "{{" En "}}" word nie toegelaat in die naamreekse nie {0}",
Target Details,Teikenbesonderhede,
{0} already has a Parent Procedure {1}.,{0} het reeds 'n ouerprosedure {1}.,
API,API,
diff --git a/erpnext/translations/am.csv b/erpnext/translations/am.csv
index 554b0a5..d131404 100644
--- a/erpnext/translations/am.csv
+++ b/erpnext/translations/am.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,የተለያዩ የማስተዋወቂያ ዘዴዎችን ለመተግበር ህጎች።,
Shift,ቀይር,
Show {0},አሳይ {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",ከ "-" ፣ "#" ፣ "፣" ፣ "/" ፣ "{" እና "}" በስተቀር ልዩ ቁምፊዎች ከመለያ መሰየሚያ አይፈቀድም,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",ከ "-" ፣ "#" ፣ "፣" ፣ "/" ፣ "{{" እና "}}" በስተቀር ልዩ ቁምፊዎች ከመለያ መሰየሚያ አይፈቀድም {0},
Target Details,የ Detailsላማ ዝርዝሮች።,
{0} already has a Parent Procedure {1}.,{0} ቀድሞውኑ የወላጅ አሰራር ሂደት አለው {1}።,
API,ኤ ፒ አይ,
diff --git a/erpnext/translations/ar.csv b/erpnext/translations/ar.csv
index e62f61a..c0da1c4 100644
--- a/erpnext/translations/ar.csv
+++ b/erpnext/translations/ar.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,قواعد تطبيق المخططات الترويجية المختلفة.,
Shift,تحول,
Show {0},عرض {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",الأحرف الخاصة باستثناء "-" ، "#" ، "." ، "/" ، "{" و "}" غير مسموح في سلسلة التسمية,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",{0} الأحرف الخاصة باستثناء "-" ، "#" ، "." ، "/" ، "{{" و "}}" غير مسموح في سلسلة التسمية,
Target Details,تفاصيل الهدف,
{0} already has a Parent Procedure {1}.,{0} يحتوي بالفعل على إجراء الأصل {1}.,
API,API,
diff --git a/erpnext/translations/bg.csv b/erpnext/translations/bg.csv
index 15278a6..ac6dc78 100644
--- a/erpnext/translations/bg.csv
+++ b/erpnext/translations/bg.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Правила за прилагане на различни промоционални схеми.,
Shift,изместване,
Show {0},Показване на {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Специални символи, с изключение на "-", "#", ".", "/", "{" И "}" не са позволени в именуването на серии",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Специални символи, с изключение на "-", "#", ".", "/", "{{" И "}}" не са позволени в именуването на серии {0}",
Target Details,Детайли за целта,
{0} already has a Parent Procedure {1}.,{0} вече има родителска процедура {1}.,
API,API,
diff --git a/erpnext/translations/bn.csv b/erpnext/translations/bn.csv
index cf09716..52f7b1c 100644
--- a/erpnext/translations/bn.csv
+++ b/erpnext/translations/bn.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,বিভিন্ন প্রচারমূলক স্কিম প্রয়োগ করার নিয়ম।,
Shift,পরিবর্তন,
Show {0},{0} দেখান,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","নামকরণ সিরিজে "-", "#", "।", "/", "{" এবং "}" ব্যতীত বিশেষ অক্ষর অনুমোদিত নয়",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","নামকরণ সিরিজে "-", "#", "।", "/", "{{" এবং "}}" ব্যতীত বিশেষ অক্ষর অনুমোদিত নয় {0}",
Target Details,টার্গেটের বিশদ,
{0} already has a Parent Procedure {1}.,{0} ইতিমধ্যে একটি মূল পদ্ধতি আছে {1}।,
API,এপিআই,
diff --git a/erpnext/translations/bs.csv b/erpnext/translations/bs.csv
index 6ef445a..267434f 100644
--- a/erpnext/translations/bs.csv
+++ b/erpnext/translations/bs.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Pravila za primjenu različitih promotivnih shema.,
Shift,Shift,
Show {0},Prikaži {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Posebni znakovi osim "-", "#", ".", "/", "{" I "}" nisu dozvoljeni u imenovanju serija",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Posebni znakovi osim "-", "#", ".", "/", "{{" I "}}" nisu dozvoljeni u imenovanju serija {0}",
Target Details,Detalji cilja,
{0} already has a Parent Procedure {1}.,{0} već ima roditeljsku proceduru {1}.,
API,API,
diff --git a/erpnext/translations/ca.csv b/erpnext/translations/ca.csv
index 18fa52a..d8c2ef6 100644
--- a/erpnext/translations/ca.csv
+++ b/erpnext/translations/ca.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Normes per aplicar diferents règims promocionals.,
Shift,Majúscules,
Show {0},Mostra {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caràcters especials, excepte "-", "#", ".", "/", "{" I "}" no estan permesos en nomenar sèries",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caràcters especials, excepte "-", "#", ".", "/", "{{" I "}}" no estan permesos en nomenar sèries {0}",
Target Details,Detalls de l'objectiu,
{0} already has a Parent Procedure {1}.,{0} ja té un procediment progenitor {1}.,
API,API,
diff --git a/erpnext/translations/cs.csv b/erpnext/translations/cs.csv
index 705e471..7d570bb 100644
--- a/erpnext/translations/cs.csv
+++ b/erpnext/translations/cs.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Pravidla pro uplatňování různých propagačních programů.,
Shift,Posun,
Show {0},Zobrazit {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Zvláštní znaky kromě "-", "#", ".", "/", "{" A "}" nejsou v názvových řadách povoleny",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Zvláštní znaky kromě "-", "#", ".", "/", "{{" A "}}" nejsou v názvových řadách povoleny {0}",
Target Details,Podrobnosti o cíli,
{0} already has a Parent Procedure {1}.,{0} již má rodičovský postup {1}.,
API,API,
diff --git a/erpnext/translations/da.csv b/erpnext/translations/da.csv
index c0d0146..16b2e87 100644
--- a/erpnext/translations/da.csv
+++ b/erpnext/translations/da.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regler for anvendelse af forskellige salgsfremmende ordninger.,
Shift,Flytte,
Show {0},Vis {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Specialtegn undtagen "-", "#", ".", "/", "{" Og "}" er ikke tilladt i navngivningsserier",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Specialtegn undtagen "-", "#", ".", "/", "{{" Og "}}" er ikke tilladt i navngivningsserier {0}",
Target Details,Måldetaljer,
{0} already has a Parent Procedure {1}.,{0} har allerede en overordnet procedure {1}.,
API,API,
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 1014e27..5a0a863 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -3546,7 +3546,7 @@
Rules for applying different promotional schemes.,Regeln für die Anwendung verschiedener Werbemaßnahmen.,
Shift,Verschiebung,
Show {0},{0} anzeigen,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Sonderzeichen außer "-", "#", ".", "/", "{" Und "}" sind bei der Benennung von Serien nicht zulässig",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Sonderzeichen außer "-", "#", ".", "/", "{{" Und "}}" sind bei der Benennung von Serien nicht zulässig {0}",
Target Details,Zieldetails,
{0} already has a Parent Procedure {1}.,{0} hat bereits eine übergeordnete Prozedur {1}.,
API,API,
diff --git a/erpnext/translations/el.csv b/erpnext/translations/el.csv
index acf5db5..06b8060 100644
--- a/erpnext/translations/el.csv
+++ b/erpnext/translations/el.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Κανόνες εφαρμογής διαφορετικών προγραμμάτων προώθησης.,
Shift,Βάρδια,
Show {0},Εμφάνιση {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Ειδικοί χαρακτήρες εκτός από "-", "#", ".", "/", "" Και "}" δεν επιτρέπονται στη σειρά ονομασίας",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Ειδικοί χαρακτήρες εκτός από "-", "#", ".", "/", "{" Και "}}" δεν επιτρέπονται στη σειρά ονομασίας {0}",
Target Details,Στοιχεία στόχου,
{0} already has a Parent Procedure {1}.,{0} έχει ήδη μια διαδικασία γονέα {1}.,
API,API,
diff --git a/erpnext/translations/es.csv b/erpnext/translations/es.csv
index 0f2259d..b216b86 100644
--- a/erpnext/translations/es.csv
+++ b/erpnext/translations/es.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Reglas para aplicar diferentes esquemas promocionales.,
Shift,Cambio,
Show {0},Mostrar {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caracteres especiales excepto "-", "#", ".", "/", "{" Y "}" no están permitidos en las series de nombres",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caracteres especiales excepto "-", "#", ".", "/", "{{" Y "}}" no están permitidos en las series de nombres {0}",
Target Details,Detalles del objetivo,
{0} already has a Parent Procedure {1}.,{0} ya tiene un Procedimiento principal {1}.,
API,API,
diff --git a/erpnext/translations/et.csv b/erpnext/translations/et.csv
index ba32187..5d67d81 100644
--- a/erpnext/translations/et.csv
+++ b/erpnext/translations/et.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Erinevate reklaamiskeemide rakenduseeskirjad.,
Shift,Vahetus,
Show {0},Kuva {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Erimärgid, välja arvatud "-", "#", ".", "/", "{" Ja "}" pole sarjade nimetamisel lubatud",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Erimärgid, välja arvatud "-", "#", ".", "/", "{{" Ja "}}" pole sarjade nimetamisel lubatud {0}",
Target Details,Sihtkoha üksikasjad,
{0} already has a Parent Procedure {1}.,{0} juba on vanemamenetlus {1}.,
API,API,
diff --git a/erpnext/translations/fa.csv b/erpnext/translations/fa.csv
index 4a7c979..040034d 100644
--- a/erpnext/translations/fa.csv
+++ b/erpnext/translations/fa.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,قوانین استفاده از طرح های تبلیغاتی مختلف.,
Shift,تغییر مکان,
Show {0},نمایش {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",کاراکترهای خاص به جز "-" ، "#" ، "." ، "/" ، "{" و "}" در سریال نامگذاری مجاز نیستند,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",{0} کاراکترهای خاص به جز "-" ، "#" ، "." ، "/" ، "{{" و "}}" در سریال نامگذاری مجاز نیستند,
Target Details,جزئیات هدف,
{0} already has a Parent Procedure {1}.,{0} در حال حاضر یک روش والدین {1} دارد.,
API,API,
diff --git a/erpnext/translations/fi.csv b/erpnext/translations/fi.csv
index 29eb567..27ea3b8 100644
--- a/erpnext/translations/fi.csv
+++ b/erpnext/translations/fi.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Säännöt erilaisten myynninedistämisjärjestelmien soveltamisesta.,
Shift,Siirtää,
Show {0},Näytä {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Erikoismerkit paitsi "-", "#", ".", "/", "{" Ja "}" eivät ole sallittuja nimeämissarjoissa",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Erikoismerkit paitsi "-", "#", ".", "/", "{{" Ja "}}" eivät ole sallittuja nimeämissarjoissa {0}",
Target Details,Kohteen yksityiskohdat,
{0} already has a Parent Procedure {1}.,{0}: llä on jo vanhempainmenettely {1}.,
API,API,
diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv
index 3ba5ade..8367afd 100644
--- a/erpnext/translations/fr.csv
+++ b/erpnext/translations/fr.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Règles d'application de différents programmes promotionnels.,
Shift,Décalage,
Show {0},Montrer {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caractères spéciaux sauf "-", "#", ".", "/", "{" Et "}" non autorisés dans les séries de nommage",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caractères spéciaux sauf "-", "#", ".", "/", "{{" Et "}}" non autorisés dans les séries de nommage {0}",
Target Details,Détails de la cible,
{0} already has a Parent Procedure {1}.,{0} a déjà une procédure parent {1}.,
API,API,
diff --git a/erpnext/translations/gu.csv b/erpnext/translations/gu.csv
index 5c2b520..97adac9 100644
--- a/erpnext/translations/gu.csv
+++ b/erpnext/translations/gu.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,વિવિધ પ્રમોશનલ યોજનાઓ લાગુ કરવાના નિયમો.,
Shift,પાળી,
Show {0},બતાવો {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" અને "}" સિવાયના વિશેષ અક્ષરો નામકરણ શ્રેણીમાં મંજૂરી નથી",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" અને "}}" સિવાયના વિશેષ અક્ષરો નામકરણ શ્રેણીમાં મંજૂરી નથી {0}",
Target Details,લક્ષ્યાંક વિગતો,
{0} already has a Parent Procedure {1}.,{0} પાસે પહેલેથી જ પિતૃ કાર્યવાહી છે {1}.,
API,API,
diff --git a/erpnext/translations/he.csv b/erpnext/translations/he.csv
index 29e6f6a..22b2522 100644
--- a/erpnext/translations/he.csv
+++ b/erpnext/translations/he.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,כללים ליישום תוכניות קידום מכירות שונות.,
Shift,מִשׁמֶרֶת,
Show {0},הצג את {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","תווים מיוחדים למעט "-", "#", ".", "/", "{" ו- "}" אינם מורשים בסדרות שמות",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","{0} תווים מיוחדים למעט "-", "#", ".", "/", "{{" ו- "}}" אינם מורשים בסדרות שמות",
Target Details,פרטי יעד,
{0} already has a Parent Procedure {1}.,{0} כבר יש נוהל הורים {1}.,
API,ממשק API,
diff --git a/erpnext/translations/hi.csv b/erpnext/translations/hi.csv
index c385fc6..ca41cf3 100644
--- a/erpnext/translations/hi.csv
+++ b/erpnext/translations/hi.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,विभिन्न प्रचार योजनाओं को लागू करने के लिए नियम।,
Shift,खिसक जाना,
Show {0},{0} दिखाएं,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", "।", "/", "{" और "}" को छोड़कर विशेष वर्ण श्रृंखला में अनुमति नहीं है",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", "।", "/", "{{" और "}}" को छोड़कर विशेष वर्ण श्रृंखला {0} में अनुमति नहीं है",
Target Details,लक्ष्य विवरण,
{0} already has a Parent Procedure {1}.,{0} पहले से ही एक पेरेंट प्रोसीजर {1} है।,
API,एपीआई,
diff --git a/erpnext/translations/hr.csv b/erpnext/translations/hr.csv
index a544e98..319b80b 100644
--- a/erpnext/translations/hr.csv
+++ b/erpnext/translations/hr.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Pravila za primjenu različitih promotivnih shema.,
Shift,smjena,
Show {0},Prikaži {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Posebni znakovi osim "-", "#", ".", "/", "{" I "}" nisu dopušteni u imenovanju serija",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Posebni znakovi osim "-", "#", ".", "/", "{{" I "}}" nisu dopušteni u imenovanju serija {0}",
Target Details,Pojedinosti cilja,
{0} already has a Parent Procedure {1}.,{0} već ima roditeljski postupak {1}.,
API,API,
diff --git a/erpnext/translations/hu.csv b/erpnext/translations/hu.csv
index 29f347e..0664728 100644
--- a/erpnext/translations/hu.csv
+++ b/erpnext/translations/hu.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Különböző promóciós rendszerek alkalmazásának szabályai.,
Shift,Váltás,
Show {0},Mutasd {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Speciális karakterek, kivéve "-", "#", ".", "/", "{" És "}", a sorozatok elnevezése nem megengedett",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Speciális karakterek, kivéve "-", "#", ".", "/", "{{" És "}}", a sorozatok elnevezése nem megengedett {0}",
Target Details,Cél részletei,
{0} already has a Parent Procedure {1}.,A (z) {0} már rendelkezik szülői eljárással {1}.,
API,API,
diff --git a/erpnext/translations/id.csv b/erpnext/translations/id.csv
index 7175ad2..1e50747 100644
--- a/erpnext/translations/id.csv
+++ b/erpnext/translations/id.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Aturan untuk menerapkan berbagai skema promosi.,
Shift,Bergeser,
Show {0},Tampilkan {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Karakter Khusus kecuali "-", "#", ".", "/", "{" Dan "}" tidak diizinkan dalam rangkaian penamaan",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Karakter Khusus kecuali "-", "#", ".", "/", "{{" Dan "}}" tidak diizinkan dalam rangkaian penamaan {0}",
Target Details,Detail Target,
{0} already has a Parent Procedure {1}.,{0} sudah memiliki Prosedur Induk {1}.,
API,API,
diff --git a/erpnext/translations/is.csv b/erpnext/translations/is.csv
index 5f56aff..c20c21e 100644
--- a/erpnext/translations/is.csv
+++ b/erpnext/translations/is.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Reglur um beitingu mismunandi kynningarkerfa.,
Shift,Vakt,
Show {0},Sýna {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Sérstafir nema "-", "#", ".", "/", "{" Og "}" ekki leyfðar í nafngiftiröð",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Sérstafir nema "-", "#", ".", "/", "{{" Og "}}" ekki leyfðar í nafngiftiröð {0}",
Target Details,Upplýsingar um markmið,
{0} already has a Parent Procedure {1}.,{0} er þegar með foreldraferli {1}.,
API,API,
diff --git a/erpnext/translations/it.csv b/erpnext/translations/it.csv
index 3a1d73f..3d15d55 100644
--- a/erpnext/translations/it.csv
+++ b/erpnext/translations/it.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regole per l'applicazione di diversi schemi promozionali.,
Shift,Cambio,
Show {0},Mostra {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caratteri speciali tranne "-", "#", ".", "/", "{" E "}" non consentiti nelle serie di nomi",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caratteri speciali tranne "-", "#", ".", "/", "{{" E "}}" non consentiti nelle serie di nomi {0}",
Target Details,Dettagli target,
{0} already has a Parent Procedure {1}.,{0} ha già una procedura padre {1}.,
API,API,
diff --git a/erpnext/translations/ja.csv b/erpnext/translations/ja.csv
index 6e2eaae..a11a9a1 100644
--- a/erpnext/translations/ja.csv
+++ b/erpnext/translations/ja.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,さまざまなプロモーションスキームを適用するための規則。,
Shift,シフト,
Show {0},{0}を表示,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series"," - "、 "#"、 "。"、 "/"、 "{"、および "}"以外の特殊文字は、一連の名前付けでは使用できません,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}"," - "、 "#"、 "。"、 "/"、 "{{"、および "}}"以外の特殊文字は、一連の名前付けでは使用できません {0},
Target Details,ターゲット詳細,
{0} already has a Parent Procedure {1}.,{0}にはすでに親プロシージャー{1}があります。,
API,API,
diff --git a/erpnext/translations/km.csv b/erpnext/translations/km.csv
index e2a528c..bd70595 100644
--- a/erpnext/translations/km.csv
+++ b/erpnext/translations/km.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,វិធានសម្រាប់អនុវត្តគម្រោងផ្សព្វផ្សាយផ្សេងៗគ្នា។,
Shift,ប្តូរ។,
Show {0},បង្ហាញ {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","តួអក្សរពិសេសលើកលែងតែ "-", "#", "។ ", "/", "{" និង "}" មិនត្រូវបានអនុញ្ញាតក្នុងស៊េរីដាក់ឈ្មោះ",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","តួអក្សរពិសេសលើកលែងតែ "-", "#", "។ ", "/", "{{" និង "}}" មិនត្រូវបានអនុញ្ញាតក្នុងស៊េរីដាក់ឈ្មោះ {0}",
Target Details,ព័ត៌មានលម្អិតគោលដៅ។,
{0} already has a Parent Procedure {1}.,{0} មាននីតិវិធីឪពុកម្តាយរួចហើយ {1} ។,
API,API,
diff --git a/erpnext/translations/kn.csv b/erpnext/translations/kn.csv
index 4a9173d..7572a09 100644
--- a/erpnext/translations/kn.csv
+++ b/erpnext/translations/kn.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,ವಿಭಿನ್ನ ಪ್ರಚಾರ ಯೋಜನೆಗಳನ್ನು ಅನ್ವಯಿಸುವ ನಿಯಮಗಳು.,
Shift,ಶಿಫ್ಟ್,
Show {0},{0} ತೋರಿಸು,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" ಮತ್ತು "}" ಹೊರತುಪಡಿಸಿ ವಿಶೇಷ ಅಕ್ಷರಗಳನ್ನು ಹೆಸರಿಸುವ ಸರಣಿಯಲ್ಲಿ ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" ಮತ್ತು "}}" ಹೊರತುಪಡಿಸಿ ವಿಶೇಷ ಅಕ್ಷರಗಳನ್ನು ಹೆಸರಿಸುವ ಸರಣಿಯಲ್ಲಿ ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ {0}",
Target Details,ಗುರಿ ವಿವರಗಳು,
{0} already has a Parent Procedure {1}.,{0} ಈಗಾಗಲೇ ಪೋಷಕ ವಿಧಾನವನ್ನು ಹೊಂದಿದೆ {1}.,
API,API,
diff --git a/erpnext/translations/ko.csv b/erpnext/translations/ko.csv
index c051b07..b873b73 100644
--- a/erpnext/translations/ko.csv
+++ b/erpnext/translations/ko.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,다양한 홍보 계획을 적용하기위한 규칙.,
Shift,시프트,
Show {0},{0} 표시,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","이름 계열에 허용되지 않는 "-", "#", ".", "/", "{"및 "}"을 제외한 특수 문자",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","이름 계열에 허용되지 않는 "-", "#", ".", "/", "{{"및 "}}"을 제외한 특수 문자 {0}",
Target Details,대상 세부 정보,
{0} already has a Parent Procedure {1}.,{0}에 이미 상위 절차 {1}이 있습니다.,
API,API,
diff --git a/erpnext/translations/ku.csv b/erpnext/translations/ku.csv
index 6962ea1..89e12c0 100644
--- a/erpnext/translations/ku.csv
+++ b/erpnext/translations/ku.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Qanûnên ji bo bicihanîna nexşeyên cûda yên danasînê,
Shift,Tarloqî,
Show {0},Show {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Di tîpa navnasî de ji bilî "-", "#", ".", "/", "{" Û "}" tîpên Taybet",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Di tîpa navnasî de ji bilî "-", "#", ".", "/", "{{" Û "}}" tîpên Taybet {0}",
Target Details,Hûrgulên armancê,
{0} already has a Parent Procedure {1}.,{0} ji berê ve heye Parent Procedure {1}.,
API,API,
diff --git a/erpnext/translations/lo.csv b/erpnext/translations/lo.csv
index b61476c..778a59b 100644
--- a/erpnext/translations/lo.csv
+++ b/erpnext/translations/lo.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,ກົດລະບຽບໃນການ ນຳ ໃຊ້ແຜນການໂຄສະນາທີ່ແຕກຕ່າງກັນ.,
Shift,ປ່ຽນ,
Show {0},ສະແດງ {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","ຕົວລະຄອນພິເສດຍົກເວັ້ນ "-", "#", ".", "/", "{" ແລະ "}" ບໍ່ໄດ້ຖືກອະນຸຍາດໃນຊຸດຊື່",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","ຕົວລະຄອນພິເສດຍົກເວັ້ນ "-", "#", ".", "/", "{{" ແລະ "}}" ບໍ່ໄດ້ຖືກອະນຸຍາດໃນຊຸດຊື່ {0}",
Target Details,ລາຍລະອຽດເປົ້າ ໝາຍ,
{0} already has a Parent Procedure {1}.,{0} ມີຂັ້ນຕອນການເປັນພໍ່ແມ່ {1} ແລ້ວ.,
API,API,
diff --git a/erpnext/translations/lt.csv b/erpnext/translations/lt.csv
index 78571f9..4721ce4 100644
--- a/erpnext/translations/lt.csv
+++ b/erpnext/translations/lt.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Skirtingų reklamos schemų taikymo taisyklės.,
Shift,Pamaina,
Show {0},Rodyti {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Specialieji simboliai, išskyrus „-“, „#“, „.“, „/“, „{“ Ir „}“, neleidžiami įvardyti serijomis",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Specialieji simboliai, išskyrus "-", "#", "।", "/", "{{" Ir "}}", neleidžiami įvardyti serijomis {0}",
Target Details,Tikslinė informacija,
{0} already has a Parent Procedure {1}.,{0} jau turi tėvų procedūrą {1}.,
API,API,
diff --git a/erpnext/translations/lv.csv b/erpnext/translations/lv.csv
index cbf0485..b8499b2 100644
--- a/erpnext/translations/lv.csv
+++ b/erpnext/translations/lv.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Noteikumi dažādu reklāmas shēmu piemērošanai.,
Shift,Maiņa,
Show {0},Rādīt {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Speciālās rakstzīmes, izņemot "-", "#", ".", "/", "{" Un "}", kas nav atļautas nosaukuma sērijās",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Speciālās rakstzīmes, izņemot "-", "#", ".", "/", "{{" Un "}}", kas nav atļautas nosaukuma sērijās {0}",
Target Details,Mērķa informācija,
{0} already has a Parent Procedure {1}.,{0} jau ir vecāku procedūra {1}.,
API,API,
diff --git a/erpnext/translations/mk.csv b/erpnext/translations/mk.csv
index 7008025..8ecae03 100644
--- a/erpnext/translations/mk.csv
+++ b/erpnext/translations/mk.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Правила за примена на различни промотивни шеми.,
Shift,Смена,
Show {0},Покажи {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Не се дозволени специјални карактери освен "-", "#", ".", "/", "{" И "}" во сериите за именување",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Не се дозволени специјални карактери освен "-", "#", ".", "/", "{{" И "}}" во сериите за именување {0}",
Target Details,Цели детали,
{0} already has a Parent Procedure {1}.,{0} веќе има Матична постапка {1}.,
API,API,
diff --git a/erpnext/translations/ml.csv b/erpnext/translations/ml.csv
index f917969..f649e6c 100644
--- a/erpnext/translations/ml.csv
+++ b/erpnext/translations/ml.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,വ്യത്യസ്ത പ്രമോഷണൽ സ്കീമുകൾ പ്രയോഗിക്കുന്നതിനുള്ള നിയമങ്ങൾ.,
Shift,ഷിഫ്റ്റ്,
Show {0},{0} കാണിക്കുക,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{", "}" എന്നിവ ഒഴികെയുള്ള പ്രത്യേക പ്രതീകങ്ങൾ നാമകരണ ശ്രേണിയിൽ അനുവദനീയമല്ല",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{", "}}" എന്നിവ ഒഴികെയുള്ള പ്രത്യേക പ്രതീകങ്ങൾ നാമകരണ ശ്രേണിയിൽ അനുവദനീയമല്ല {0}",
Target Details,ടാർഗെറ്റ് വിശദാംശങ്ങൾ,
{0} already has a Parent Procedure {1}.,{0} ന് ഇതിനകം ഒരു രക്ഷാകർതൃ നടപടിക്രമം ഉണ്ട് {1}.,
API,API,
diff --git a/erpnext/translations/mr.csv b/erpnext/translations/mr.csv
index 9c41ce6..38effc1 100644
--- a/erpnext/translations/mr.csv
+++ b/erpnext/translations/mr.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,वेगवेगळ्या जाहिरात योजना लागू करण्याचे नियम.,
Shift,शिफ्ट,
Show {0},दर्शवा {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" आणि "}" वगळता विशिष्ट वर्णांना नामांकन मालिकेमध्ये परवानगी नाही",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" आणि "}}" वगळता विशिष्ट वर्णांना नामांकन मालिकेमध्ये परवानगी नाही {0}",
Target Details,लक्ष्य तपशील,
{0} already has a Parent Procedure {1}.,{0} कडे आधीपासूनच पालक प्रक्रिया आहे {1}.,
API,API,
diff --git a/erpnext/translations/ms.csv b/erpnext/translations/ms.csv
index 1483844..4ee650b 100644
--- a/erpnext/translations/ms.csv
+++ b/erpnext/translations/ms.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Kaedah untuk memohon skim promosi yang berbeza.,
Shift,Shift,
Show {0},Tunjukkan {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Watak Khas kecuali "-", "#", ".", "/", "{" Dan "}" tidak dibenarkan dalam siri penamaan",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Watak Khas kecuali "-", "#", ".", "/", "{{" Dan "}}" tidak dibenarkan dalam siri penamaan {0}",
Target Details,Butiran Sasaran,
{0} already has a Parent Procedure {1}.,{0} sudah mempunyai Tatacara Ibu Bapa {1}.,
API,API,
diff --git a/erpnext/translations/my.csv b/erpnext/translations/my.csv
index d15ec1e..f0d216b 100644
--- a/erpnext/translations/my.csv
+++ b/erpnext/translations/my.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,ကွဲပြားခြားနားသောပရိုမိုးရှင်းအစီအစဉ်များလျှောက်ထားမှုအတွက်စည်းကမ်းများ။,
Shift,အဆိုင်း,
Show {0},Show ကို {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","မှလွဲ. အထူးဇာတ်ကောင် "-" "။ ", "#", "/", "{" နှင့် "}" စီးရီးနာမည်အတွက်ခွင့်မပြု",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","မှလွဲ. အထူးဇာတ်ကောင် "-" "။ ", "#", "/", "{{" နှင့် "}}" စီးရီးနာမည်အတွက်ခွင့်မပြု {0}",
Target Details,ပစ်မှတ်အသေးစိတ်,
{0} already has a Parent Procedure {1}.,{0} ပြီးသားမိဘလုပ်ထုံးလုပ်နည်း {1} ရှိပါတယ်။,
API,API ကို,
diff --git a/erpnext/translations/nl.csv b/erpnext/translations/nl.csv
index fbadc02..6ec43a0 100644
--- a/erpnext/translations/nl.csv
+++ b/erpnext/translations/nl.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regels voor het toepassen van verschillende promotieregelingen.,
Shift,Verschuiving,
Show {0},Toon {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Speciale tekens behalve "-", "#", ".", "/", "{" En "}" niet toegestaan in naamgevingsreeks",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Speciale tekens behalve "-", "#", ".", "/", "{{" En "}}" niet toegestaan in naamgevingsreeks {0}",
Target Details,Doelgegevens,
{0} already has a Parent Procedure {1}.,{0} heeft al een ouderprocedure {1}.,
API,API,
diff --git a/erpnext/translations/no.csv b/erpnext/translations/no.csv
index 150e5ca..df87e81 100644
--- a/erpnext/translations/no.csv
+++ b/erpnext/translations/no.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regler for anvendelse av forskjellige kampanjer.,
Shift,Skifte,
Show {0},Vis {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Spesialtegn unntatt "-", "#", ".", "/", "{" Og "}" ikke tillatt i navneserier",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Spesialtegn unntatt "-", "#", ".", "/", "{{" Og "}}" ikke tillatt i navneserier {0}",
Target Details,Måldetaljer,
{0} already has a Parent Procedure {1}.,{0} har allerede en foreldreprosedyre {1}.,
API,API,
diff --git a/erpnext/translations/pl.csv b/erpnext/translations/pl.csv
index 8340b72..be81e29 100644
--- a/erpnext/translations/pl.csv
+++ b/erpnext/translations/pl.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Zasady stosowania różnych programów promocyjnych.,
Shift,Przesunięcie,
Show {0},Pokaż {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Znaki specjalne z wyjątkiem „-”, „#”, „.”, „/”, „{” I „}” niedozwolone w serii nazw",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Znaki specjalne z wyjątkiem "-", "#", "।", "/", "{{" I "}}" niedozwolone w serii nazw {0}",
Target Details,Szczegóły celu,
{0} already has a Parent Procedure {1}.,{0} ma już procedurę nadrzędną {1}.,
API,API,
diff --git a/erpnext/translations/ps.csv b/erpnext/translations/ps.csv
index 1dcaf48..68add60 100644
--- a/erpnext/translations/ps.csv
+++ b/erpnext/translations/ps.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,د مختلف پروموشنل سکیمونو پلي کولو قواعد.,
Shift,شفټ,
Show {0},ښودل {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",ځانګړي نومونه د "-" ، "#" ، "." ، "/" ، "{" او "}" نوم لیکلو کې اجازه نه لري,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",{0} ځانګړي نومونه د "-" ، "#" ، "." ، "/" ، "{{" او "}}" نوم لیکلو کې اجازه نه لري,
Target Details,د هدف توضیحات,
{0} already has a Parent Procedure {1}.,{0} د مخه د والدین پروسیجر {1} لري.,
API,API,
diff --git a/erpnext/translations/pt-BR.csv b/erpnext/translations/pt-BR.csv
index 957cb75..cc1c6af 100644
--- a/erpnext/translations/pt-BR.csv
+++ b/erpnext/translations/pt-BR.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regras para aplicar diferentes esquemas promocionais.,
Shift,Mudança,
Show {0},Mostrar {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caracteres especiais, exceto "-", "#", ".", "/", "{" e "}" não permitidos na série de nomenclatura",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caracteres especiais, exceto "-", "#", ".", "/", "{{" e "}}" não permitidos na série de nomenclatura {0}",
Target Details,Detalhes do Alvo,
{0} already has a Parent Procedure {1}.,{0} já tem um procedimento pai {1}.,
API,API,
diff --git a/erpnext/translations/pt.csv b/erpnext/translations/pt.csv
index 3b8a0a0..43bf227 100644
--- a/erpnext/translations/pt.csv
+++ b/erpnext/translations/pt.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regras para aplicar diferentes esquemas promocionais.,
Shift,Mudança,
Show {0},Mostrar {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caracteres especiais, exceto "-", "#", ".", "/", "{" E "}" não permitidos na série de nomenclatura",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caracteres especiais, exceto "-", "#", ".", "/", "{{" E "}}" não permitidos na série de nomenclatura {0}",
Target Details,Detalhes do Alvo,
{0} already has a Parent Procedure {1}.,{0} já tem um procedimento pai {1}.,
API,API,
diff --git a/erpnext/translations/ro.csv b/erpnext/translations/ro.csv
index 643b8c5..3aab431 100644
--- a/erpnext/translations/ro.csv
+++ b/erpnext/translations/ro.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Reguli pentru aplicarea diferitelor scheme promoționale.,
Shift,Schimb,
Show {0},Afișați {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Caractere speciale, cu excepția "-", "#", ".", "/", "{" Și "}" nu sunt permise în numirea seriei",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Caractere speciale, cu excepția "-", "#", ".", "/", "{{" Și "}}" nu sunt permise în numirea seriei {0}",
Target Details,Detalii despre țintă,
{0} already has a Parent Procedure {1}.,{0} are deja o procedură părinte {1}.,
API,API-ul,
diff --git a/erpnext/translations/ru.csv b/erpnext/translations/ru.csv
index 5f3af77..662346f 100644
--- a/erpnext/translations/ru.csv
+++ b/erpnext/translations/ru.csv
@@ -3535,7 +3535,7 @@
Rules for applying different promotional schemes.,Правила применения разных рекламных схем.,
Shift,Сдвиг,
Show {0},Показать {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Специальные символы, кроме ""-"", ""#"", ""."", ""/"", ""{"" и ""}"", не допускаются в серийных номерах",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Специальные символы, кроме "-", "#", "।", "/", "{{" и "}}", не допускаются в серийных номерах {0}",
Target Details,Детали цели,
{0} already has a Parent Procedure {1}.,{0} уже имеет родительскую процедуру {1}.,
API,API,
diff --git a/erpnext/translations/rw.csv b/erpnext/translations/rw.csv
index 6459139..6c2b5dd 100644
--- a/erpnext/translations/rw.csv
+++ b/erpnext/translations/rw.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Amategeko yo gukoresha gahunda zitandukanye zo kwamamaza.,
Shift,Shift,
Show {0},Erekana {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Inyuguti zidasanzwe usibye "-", "#", ".", "/", "{" Na "}" ntibyemewe mu ruhererekane rwo kwita izina",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Inyuguti zidasanzwe usibye "-", "#", ".", "/", "{{" Na "}}" ntibyemewe mu ruhererekane rwo kwita izina {0}",
Target Details,Intego Ibisobanuro,
{0} already has a Parent Procedure {1}.,{0} isanzwe ifite uburyo bwababyeyi {1}.,
API,API,
diff --git a/erpnext/translations/si.csv b/erpnext/translations/si.csv
index 690c473..5b78235 100644
--- a/erpnext/translations/si.csv
+++ b/erpnext/translations/si.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,විවිධ ප්රවර්ධන යෝජනා ක්රම යෙදීම සඳහා නීති.,
Shift,මාරුව,
Show {0},{0 Show පෙන්වන්න,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" සහ "}" හැර විශේෂ අක්ෂර නම් කිරීමේ ශ්රේණියේ අවසර නැත",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" සහ "}}" හැර විශේෂ අක්ෂර නම් කිරීමේ ශ්රේණියේ අවසර නැත {0}",
Target Details,ඉලක්ක විස්තර,
{0} already has a Parent Procedure {1}.,{0} දැනටමත් දෙමාපිය ක්රියා පටිපාටියක් ඇත {1}.,
API,API,
diff --git a/erpnext/translations/sk.csv b/erpnext/translations/sk.csv
index cb4a7fe..446e0be 100644
--- a/erpnext/translations/sk.csv
+++ b/erpnext/translations/sk.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Pravidlá uplatňovania rôznych propagačných programov.,
Shift,smena,
Show {0},Zobraziť {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Špeciálne znaky s výnimkou „-“, „#“, „.“, „/“, „{“ A „}“ nie sú v názvových sériách povolené.",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Špeciálne znaky s výnimkou "-", "#", "।", "/", "{{" A "}}" nie sú v názvových sériách povolené {0}.",
Target Details,Podrobnosti o cieli,
{0} already has a Parent Procedure {1}.,{0} už má rodičovský postup {1}.,
API,API,
diff --git a/erpnext/translations/sl.csv b/erpnext/translations/sl.csv
index 8beec6b..8b8ed01 100644
--- a/erpnext/translations/sl.csv
+++ b/erpnext/translations/sl.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Pravila za uporabo različnih promocijskih shem.,
Shift,Shift,
Show {0},Prikaži {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Posebni znaki, razen "-", "#", ".", "/", "{" In "}" v poimenovanju ni dovoljen",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Posebni znaki, razen "-", "#", ".", "/", "{{" In "}}" v poimenovanju ni dovoljen {0}",
Target Details,Podrobnosti cilja,
{0} already has a Parent Procedure {1}.,{0} že ima nadrejeni postopek {1}.,
API,API,
diff --git a/erpnext/translations/sq.csv b/erpnext/translations/sq.csv
index 05aefa3..6f4f8e0 100644
--- a/erpnext/translations/sq.csv
+++ b/erpnext/translations/sq.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Rregulla për aplikimin e skemave të ndryshme promovuese.,
Shift,ndryshim,
Show {0},Trego {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Karaktere speciale përveç "-", "#", ".", "/", "{" Dhe "}" nuk lejohen në seritë emërtuese",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Karaktere speciale përveç "-", "#", ".", "/", "{{" Dhe "}}" nuk lejohen në seritë emërtuese {0}",
Target Details,Detaje të synuara,
{0} already has a Parent Procedure {1}.,{0} tashmë ka një procedurë prindërore {1}.,
API,API,
diff --git a/erpnext/translations/sr.csv b/erpnext/translations/sr.csv
index b507f74..853c6f3 100644
--- a/erpnext/translations/sr.csv
+++ b/erpnext/translations/sr.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Правила за примену различитих промотивних шема.,
Shift,Смена,
Show {0},Прикажи {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Посебни знакови осим "-", "#", ".", "/", "{" И "}" нису дозвољени у именовању серија",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Посебни знакови осим "-", "#", ".", "/", "{{" И "}}" нису дозвољени у именовању серија {0}",
Target Details,Детаљи циља,
{0} already has a Parent Procedure {1}.,{0} већ има родитељску процедуру {1}.,
API,АПИ,
diff --git a/erpnext/translations/sv.csv b/erpnext/translations/sv.csv
index 57e0279..2a4d6b1 100644
--- a/erpnext/translations/sv.csv
+++ b/erpnext/translations/sv.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Regler för tillämpning av olika kampanjprogram.,
Shift,Flytta,
Show {0},Visa {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Specialtecken utom "-", "#", ".", "/", "{" Och "}" är inte tillåtna i namnserien",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Specialtecken utom "-", "#", ".", "/", "{{" Och "}}" är inte tillåtna i namnserien {0}",
Target Details,Måldetaljer,
{0} already has a Parent Procedure {1}.,{0} har redan en överordnad procedur {1}.,
API,API,
diff --git a/erpnext/translations/sw.csv b/erpnext/translations/sw.csv
index 3595727..234d33e 100644
--- a/erpnext/translations/sw.csv
+++ b/erpnext/translations/sw.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Sheria za kutumia miradi tofauti ya uendelezaji.,
Shift,Shift,
Show {0},Onyesha {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Tabia maalum isipokuwa "-", "#", ".", "/", "{" Na "}" hairuhusiwi katika kutaja mfululizo",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Tabia maalum isipokuwa "-", "#", ".", "/", "{{" Na "}}" hairuhusiwi katika kutaja mfululizo {0}",
Target Details,Maelezo ya Lengo,
{0} already has a Parent Procedure {1}.,{0} tayari ina Utaratibu wa Mzazi {1}.,
API,API,
diff --git a/erpnext/translations/ta.csv b/erpnext/translations/ta.csv
index 100f0e9..e7384b3 100644
--- a/erpnext/translations/ta.csv
+++ b/erpnext/translations/ta.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,வெவ்வேறு விளம்பர திட்டங்களைப் பயன்படுத்துவதற்கான விதிகள்.,
Shift,ஷிப்ட்,
Show {0},{0 Show ஐக் காட்டு,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" மற்றும் "}" தவிர சிறப்பு எழுத்துக்கள் பெயரிடும் தொடரில் அனுமதிக்கப்படவில்லை",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" மற்றும் "}}" தவிர சிறப்பு எழுத்துக்கள் பெயரிடும் தொடரில் அனுமதிக்கப்படவில்லை {0}",
Target Details,இலக்கு விவரங்கள்,
{0} already has a Parent Procedure {1}.,{0} ஏற்கனவே பெற்றோர் நடைமுறை {1 has ஐக் கொண்டுள்ளது.,
API,ஏபிஐ,
diff --git a/erpnext/translations/te.csv b/erpnext/translations/te.csv
index 047d077..cd14a77 100644
--- a/erpnext/translations/te.csv
+++ b/erpnext/translations/te.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,విభిన్న ప్రచార పథకాలను వర్తింపజేయడానికి నియమాలు.,
Shift,మార్పు,
Show {0},{0 Show చూపించు,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" మరియు "}" మినహా ప్రత్యేక అక్షరాలు పేరు పెట్టే సిరీస్లో అనుమతించబడవు",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" మరియు "}}" మినహా ప్రత్యేక అక్షరాలు పేరు పెట్టే సిరీస్లో అనుమతించబడవు {0}",
Target Details,లక్ష్య వివరాలు,
{0} already has a Parent Procedure {1}.,{0} ఇప్పటికే తల్లిదండ్రుల విధానం {1 has ను కలిగి ఉంది.,
API,API,
diff --git a/erpnext/translations/th.csv b/erpnext/translations/th.csv
index 71233ec..4ab59bc 100644
--- a/erpnext/translations/th.csv
+++ b/erpnext/translations/th.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,กฎสำหรับการใช้รูปแบบการส่งเสริมการขายต่าง ๆ,
Shift,เปลี่ยน,
Show {0},แสดง {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","ห้ามใช้อักขระพิเศษยกเว้น "-", "#", ".", "/", "{" และ "}" ในซีรี่ส์",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","ห้ามใช้อักขระพิเศษยกเว้น "-", "#", ".", "/", "{{" และ "}}" ในซีรี่ส์ {0}",
Target Details,รายละเอียดเป้าหมาย,
{0} already has a Parent Procedure {1}.,{0} มี parent Parent {1} อยู่แล้ว,
API,API,
diff --git a/erpnext/translations/tr.csv b/erpnext/translations/tr.csv
index 9e7ba4d..b65494c 100644
--- a/erpnext/translations/tr.csv
+++ b/erpnext/translations/tr.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Farklı promosyon programlarını uygulama kuralları.,
Shift,vardiya,
Show {0},{0} göster,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" Ve "}" dışındaki Özel Karakterler, seri dizisine izin verilmez",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" Ve "}}" dışındaki Özel Karakterler, seri dizisine izin verilmez {0}",
Target Details,Hedef Detayları,
{0} already has a Parent Procedure {1}.,{0} zaten bir {1} veli prosedürüne sahip.,
API,API,
diff --git a/erpnext/translations/uk.csv b/erpnext/translations/uk.csv
index 53e2df5..4e2f63f 100644
--- a/erpnext/translations/uk.csv
+++ b/erpnext/translations/uk.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Правила застосування різних рекламних схем.,
Shift,Зміна,
Show {0},Показати {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Спеціальні символи, окрім "-", "#", ".", "/", "{" Та "}", не дозволяються в іменуванні серій",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Спеціальні символи, окрім "-", "#", ".", "/", "{{" Та "}}", не дозволяються в іменуванні серій {0}",
Target Details,Деталі цілі,
{0} already has a Parent Procedure {1}.,{0} вже має батьківську процедуру {1}.,
API,API,
diff --git a/erpnext/translations/ur.csv b/erpnext/translations/ur.csv
index aaaef58..db6518e 100644
--- a/erpnext/translations/ur.csv
+++ b/erpnext/translations/ur.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,مختلف پروموشنل اسکیموں کو لاگو کرنے کے قواعد۔,
Shift,شفٹ۔,
Show {0},دکھائیں {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","-" ، "#" ، "." ، "/" ، "{" اور "}" سوائے خصوصی حروف کی نام بندی سیریز میں اجازت نہیں ہے,
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",{0} "-" ، "#" ، "." ، "/" ، "{{" اور "}}" سوائے خصوصی حروف کی نام بندی سیریز میں اجازت نہیں ہے,
Target Details,ہدف کی تفصیلات۔,
{0} already has a Parent Procedure {1}.,{0} پہلے سے ہی والدین کا طریقہ کار {1} ہے.,
API,API,
diff --git a/erpnext/translations/uz.csv b/erpnext/translations/uz.csv
index c983797..bb64a15 100644
--- a/erpnext/translations/uz.csv
+++ b/erpnext/translations/uz.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Turli reklama sxemalarini qo'llash qoidalari.,
Shift,Shift,
Show {0},{0} ni ko'rsatish,
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",""-", "#", ".", "/", "{" Va "}" belgilaridan tashqari maxsus belgilarga ruxsat berilmaydi.",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",""-", "#", ".", "/", "{{" Va "}}" belgilaridan tashqari maxsus belgilarga ruxsat berilmaydi {0}.",
Target Details,Maqsad tafsilotlari,
{0} already has a Parent Procedure {1}.,{0} allaqachon Ota-ona tartibiga ega {1}.,
API,API,
diff --git a/erpnext/translations/vi.csv b/erpnext/translations/vi.csv
index 03ff2cc..7317b4b 100644
--- a/erpnext/translations/vi.csv
+++ b/erpnext/translations/vi.csv
@@ -3537,7 +3537,7 @@
Rules for applying different promotional schemes.,Quy tắc áp dụng các chương trình khuyến mãi khác nhau.,
Shift,Ca,
Show {0},Hiển thị {0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Các ký tự đặc biệt ngoại trừ "-", "#", ".", "/", "{" Và "}" không được phép trong chuỗi đặt tên",
+"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}","Các ký tự đặc biệt ngoại trừ "-", "#", ".", "/", "{{" Và "}}" không được phép trong chuỗi đặt tên {0}",
Target Details,Chi tiết mục tiêu,
{0} already has a Parent Procedure {1}.,{0} đã có Quy trình dành cho phụ huynh {1}.,
API,API,
diff --git a/erpnext/translations/zh.csv b/erpnext/translations/zh.csv
index d1f1b07..2337bcb 100644
--- a/erpnext/translations/zh.csv
+++ b/erpnext/translations/zh.csv
@@ -3537,7 +3537,6 @@
Rules for applying different promotional schemes.,适用不同促销计划的规则。,
Shift,转移,
Show {0},显示{0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",命名系列中不允许使用除“ - ”,“#”,“。”,“/”,“{”和“}”之外的特殊字符,
Target Details,目标细节,
{0} already has a Parent Procedure {1}.,{0}已有父程序{1}。,
API,应用程序界面,
diff --git a/erpnext/translations/zh_tw.csv b/erpnext/translations/zh_tw.csv
index 1cc7d87..1b7e186 100644
--- a/erpnext/translations/zh_tw.csv
+++ b/erpnext/translations/zh_tw.csv
@@ -3311,7 +3311,6 @@
Rules for applying different promotional schemes.,適用不同促銷計劃的規則。,
Shift,轉移,
Show {0},顯示{0},
-"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series",命名系列中不允許使用除“ - ”,“#”,“。”,“/”,“{”和“}”之外的特殊字符,
Target Details,目標細節,
API,API,
Annual,年刊,