mirror of
https://github.com/frappe/erpnext.git
synced 2026-03-18 14:32:13 +00:00
Merge pull request #42832 from frappe/version-15-hotfix
chore: release v15
This commit is contained in:
@@ -202,7 +202,7 @@ class Account(NestedSet):
|
||||
msg = _(
|
||||
"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
|
||||
).format(
|
||||
frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
|
||||
frappe.bold(_("Account Type")), doc_before_save.account_type, doc_before_save.account_type
|
||||
)
|
||||
frappe.msgprint(msg)
|
||||
self.add_comment("Comment", msg)
|
||||
|
||||
@@ -87,19 +87,15 @@ class POSClosingEntry(StatusUpdater):
|
||||
as_dict=1,
|
||||
)[0]
|
||||
if pos_invoice.consolidated_invoice:
|
||||
invalid_row.setdefault("msg", []).append(
|
||||
_("POS Invoice is {}").format(frappe.bold("already consolidated"))
|
||||
)
|
||||
invalid_row.setdefault("msg", []).append(_("POS Invoice is already consolidated"))
|
||||
invalid_rows.append(invalid_row)
|
||||
continue
|
||||
if pos_invoice.pos_profile != self.pos_profile:
|
||||
invalid_row.setdefault("msg", []).append(
|
||||
_("POS Profile doesn't matches {}").format(frappe.bold(self.pos_profile))
|
||||
_("POS Profile doesn't match {}").format(frappe.bold(self.pos_profile))
|
||||
)
|
||||
if pos_invoice.docstatus != 1:
|
||||
invalid_row.setdefault("msg", []).append(
|
||||
_("POS Invoice is not {}").format(frappe.bold("submitted"))
|
||||
)
|
||||
invalid_row.setdefault("msg", []).append(_("POS Invoice is not submitted"))
|
||||
if pos_invoice.owner != self.user:
|
||||
invalid_row.setdefault("msg", []).append(
|
||||
_("POS Invoice isn't created by user {}").format(frappe.bold(self.owner))
|
||||
|
||||
@@ -188,7 +188,7 @@ class POSInvoice(SalesInvoice):
|
||||
def validate(self):
|
||||
if not cint(self.is_pos):
|
||||
frappe.throw(
|
||||
_("POS Invoice should have {} field checked.").format(frappe.bold("Include Payment"))
|
||||
_("POS Invoice should have the field {0} checked.").format(frappe.bold(_("Include Payment")))
|
||||
)
|
||||
|
||||
# run on validate method of selling controller
|
||||
|
||||
@@ -97,16 +97,15 @@ class POSInvoiceMergeLog(Document):
|
||||
return_against_status = frappe.db.get_value("POS Invoice", return_against, "status")
|
||||
if return_against_status != "Consolidated":
|
||||
# if return entry is not getting merged in the current pos closing and if it is not consolidated
|
||||
bold_unconsolidated = frappe.bold("not Consolidated")
|
||||
msg = _("Row #{}: Original Invoice {} of return invoice {} is {}.").format(
|
||||
d.idx, bold_return_against, bold_pos_invoice, bold_unconsolidated
|
||||
)
|
||||
msg = _(
|
||||
"Row #{}: The original Invoice {} of return invoice {} is not consolidated."
|
||||
).format(d.idx, bold_return_against, bold_pos_invoice)
|
||||
msg += " "
|
||||
msg += _(
|
||||
"Original invoice should be consolidated before or along with the return invoice."
|
||||
"The original invoice should be consolidated before or along with the return invoice."
|
||||
)
|
||||
msg += "<br><br>"
|
||||
msg += _("You can add original invoice {} manually to proceed.").format(
|
||||
msg += _("You can add the original invoice {} manually to proceed.").format(
|
||||
bold_return_against
|
||||
)
|
||||
frappe.throw(msg)
|
||||
|
||||
@@ -186,7 +186,8 @@ class PricingRule(Document):
|
||||
if not self.priority:
|
||||
throw(
|
||||
_("As the field {0} is enabled, the field {1} is mandatory.").format(
|
||||
frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")
|
||||
frappe.bold(_("Apply Discount on Discounted Rate")),
|
||||
frappe.bold(_("Priority")),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -194,7 +195,7 @@ class PricingRule(Document):
|
||||
throw(
|
||||
_(
|
||||
"As the field {0} is enabled, the value of the field {1} should be more than 1."
|
||||
).format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority"))
|
||||
).format(frappe.bold(_("Apply Discount on Discounted Rate")), frappe.bold(_("Priority")))
|
||||
)
|
||||
|
||||
def validate_applicable_for_selling_or_buying(self):
|
||||
|
||||
@@ -377,16 +377,16 @@ class PurchaseInvoice(BuyingController):
|
||||
if account.report_type != "Balance Sheet":
|
||||
frappe.throw(
|
||||
_(
|
||||
"Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
|
||||
).format(frappe.bold("Credit To")),
|
||||
"Please ensure that the {0} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account."
|
||||
).format(frappe.bold(_("Credit To"))),
|
||||
title=_("Invalid Account"),
|
||||
)
|
||||
|
||||
if self.supplier and account.account_type != "Payable":
|
||||
frappe.throw(
|
||||
_(
|
||||
"Please ensure {} account {} is a Payable account. Change the account type to Payable or select a different account."
|
||||
).format(frappe.bold("Credit To"), frappe.bold(self.credit_to)),
|
||||
"Please ensure that the {0} account {1} is a Payable account. You can change the account type to Payable or select a different account."
|
||||
).format(frappe.bold(_("Credit To")), frappe.bold(self.credit_to)),
|
||||
title=_("Invalid Account"),
|
||||
)
|
||||
|
||||
@@ -634,7 +634,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"To submit the invoice without purchase order please set {0} as {1} in {2}"
|
||||
).format(
|
||||
frappe.bold(_("Purchase Order Required")),
|
||||
frappe.bold("No"),
|
||||
frappe.bold(_("No")),
|
||||
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
|
||||
)
|
||||
throw(msg, title=_("Mandatory Purchase Order"))
|
||||
@@ -655,7 +655,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"To submit the invoice without purchase receipt please set {0} as {1} in {2}"
|
||||
).format(
|
||||
frappe.bold(_("Purchase Receipt Required")),
|
||||
frappe.bold("No"),
|
||||
frappe.bold(_("No")),
|
||||
get_link_to_form("Buying Settings", "Buying Settings", "Buying Settings"),
|
||||
)
|
||||
throw(msg, title=_("Mandatory Purchase Receipt"))
|
||||
|
||||
@@ -514,7 +514,7 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
if pos_closing_entry and pos_closing_entry[0]:
|
||||
msg = _("To cancel a {} you need to cancel the POS Closing Entry {}.").format(
|
||||
frappe.bold("Consolidated Sales Invoice"),
|
||||
frappe.bold(_("Consolidated Sales Invoice")),
|
||||
get_link_to_form("POS Closing Entry", pos_closing_entry[0]),
|
||||
)
|
||||
frappe.throw(msg, title=_("Not Allowed"))
|
||||
@@ -858,7 +858,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if account.report_type != "Balance Sheet":
|
||||
msg = (
|
||||
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold("Debit To"))
|
||||
_("Please ensure {} account is a Balance Sheet account.").format(frappe.bold(_("Debit To")))
|
||||
+ " "
|
||||
)
|
||||
msg += _(
|
||||
@@ -869,7 +869,7 @@ class SalesInvoice(SellingController):
|
||||
if self.customer and account.account_type != "Receivable":
|
||||
msg = (
|
||||
_("Please ensure {} account {} is a Receivable account.").format(
|
||||
frappe.bold("Debit To"), frappe.bold(self.debit_to)
|
||||
frappe.bold(_("Debit To")), frappe.bold(self.debit_to)
|
||||
)
|
||||
+ " "
|
||||
)
|
||||
|
||||
@@ -336,7 +336,7 @@ def get_tds_docs(filters):
|
||||
def get_tds_docs_query(filters, bank_accounts, tds_accounts):
|
||||
if not tds_accounts:
|
||||
frappe.throw(
|
||||
_("No {0} Accounts found for this company.").format(frappe.bold("Tax Withholding")),
|
||||
_("No {0} Accounts found for this company.").format(frappe.bold(_("Tax Withholding"))),
|
||||
title=_("Accounts Missing Error"),
|
||||
)
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
|
||||
@@ -669,7 +669,7 @@ class Asset(AccountsController):
|
||||
if not fixed_asset_account:
|
||||
frappe.throw(
|
||||
_("Set {0} in asset category {1} for company {2}").format(
|
||||
frappe.bold("Fixed Asset Account"),
|
||||
frappe.bold(_("Fixed Asset Account")),
|
||||
frappe.bold(self.asset_category),
|
||||
frappe.bold(self.company),
|
||||
),
|
||||
@@ -904,7 +904,7 @@ def transfer_asset(args):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_item_details(item_code, asset_category, gross_purchase_amount):
|
||||
asset_category_doc = frappe.get_doc("Asset Category", asset_category)
|
||||
asset_category_doc = frappe.get_cached_doc("Asset Category", asset_category)
|
||||
books = []
|
||||
for d in asset_category_doc.finance_books:
|
||||
books.append(
|
||||
|
||||
@@ -11,6 +11,7 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
|
||||
|
||||
onload() {
|
||||
this.setup_queries();
|
||||
erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
|
||||
@@ -233,7 +233,7 @@ class AccountsController(TransactionBase):
|
||||
).format(
|
||||
frappe.bold(document_type),
|
||||
get_link_to_form(self.doctype, self.get("return_against")),
|
||||
frappe.bold("Update Outstanding for Self"),
|
||||
frappe.bold(_("Update Outstanding for Self")),
|
||||
get_link_to_form("Payment Reconciliation", "Payment Reconciliation"),
|
||||
)
|
||||
)
|
||||
@@ -1962,7 +1962,9 @@ class AccountsController(TransactionBase):
|
||||
|
||||
def raise_missing_debit_credit_account_error(self, party_type, party):
|
||||
"""Raise an error if debit to/credit to account does not exist."""
|
||||
db_or_cr = frappe.bold("Debit To") if self.doctype == "Sales Invoice" else frappe.bold("Credit To")
|
||||
db_or_cr = (
|
||||
frappe.bold(_("Debit To")) if self.doctype == "Sales Invoice" else frappe.bold(_("Credit To"))
|
||||
)
|
||||
rec_or_pay = "Receivable" if self.doctype == "Sales Invoice" else "Payable"
|
||||
|
||||
link_to_party = frappe.utils.get_link_to_form(party_type, party)
|
||||
@@ -3085,9 +3087,9 @@ def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child
|
||||
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||
if not child_item.warehouse:
|
||||
frappe.throw(
|
||||
_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.").format(
|
||||
frappe.bold("default warehouse"), frappe.bold(item.item_code)
|
||||
)
|
||||
_(
|
||||
"Cannot find a default warehouse for item {0}. Please set one in the Item Master or in Stock Settings."
|
||||
).format(frappe.bold(item.item_code))
|
||||
)
|
||||
|
||||
set_child_tax_template_and_map(item, child_item, p_doc)
|
||||
|
||||
@@ -150,7 +150,7 @@ def validate_item_attribute_value(attributes_list, attribute, attribute_value, i
|
||||
)
|
||||
msg += "<br>" + _(
|
||||
"To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings."
|
||||
).format(frappe.bold("Allow Rename Attribute Value"))
|
||||
).format(frappe.bold(_("Allow Rename Attribute Value")))
|
||||
|
||||
frappe.throw(msg, InvalidItemAttributeValueError, title=_("Edit Not Allowed"))
|
||||
|
||||
|
||||
@@ -697,7 +697,7 @@ class SellingController(StockController):
|
||||
duplicate_items_msg = _("Item {0} entered multiple times.").format(frappe.bold(d.item_code))
|
||||
duplicate_items_msg += "<br><br>"
|
||||
duplicate_items_msg += _("Please enable {} in {} to allow same item in multiple rows").format(
|
||||
frappe.bold("Allow Item to Be Added Multiple Times in a Transaction"),
|
||||
frappe.bold(_("Allow Item to Be Added Multiple Times in a Transaction")),
|
||||
get_link_to_form("Selling Settings", "Selling Settings"),
|
||||
)
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
|
||||
|
||||
@@ -27,6 +27,29 @@ class TestProspect(unittest.TestCase):
|
||||
address_doc.reload()
|
||||
self.assertEqual(address_doc.has_link("Prospect", prospect_doc.name), True)
|
||||
|
||||
def test_make_customer_from_prospect(self):
|
||||
from erpnext.crm.doctype.prospect.prospect import make_customer as make_customer_from_prospect
|
||||
|
||||
frappe.delete_doc_if_exists("Customer", "_Test Prospect")
|
||||
|
||||
prospect = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Prospect",
|
||||
"company_name": "_Test Prospect",
|
||||
"customer_group": "_Test Customer Group",
|
||||
}
|
||||
)
|
||||
prospect.insert()
|
||||
|
||||
customer = make_customer_from_prospect("_Test Prospect")
|
||||
|
||||
self.assertEqual(customer.doctype, "Customer")
|
||||
self.assertEqual(customer.company_name, "_Test Prospect")
|
||||
self.assertEqual(customer.customer_group, "_Test Customer Group")
|
||||
|
||||
customer.company = "_Test Company"
|
||||
customer.insert()
|
||||
|
||||
|
||||
def make_prospect(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
@@ -96,7 +96,7 @@ def add_bank_accounts(response, bank, company):
|
||||
frappe.throw(
|
||||
_(
|
||||
"Please setup and enable a group account with the Account Type - {0} for the company {1}"
|
||||
).format(frappe.bold("Bank"), company)
|
||||
).format(frappe.bold(_("Bank")), company)
|
||||
)
|
||||
|
||||
for account in response["accounts"]:
|
||||
|
||||
@@ -371,3 +371,4 @@ erpnext.patches.v15_0.update_warehouse_field_in_asset_repair_consumed_item_docty
|
||||
erpnext.patches.v15_0.update_asset_repair_field_in_stock_entry
|
||||
erpnext.patches.v15_0.update_total_number_of_booked_depreciations
|
||||
erpnext.patches.v15_0.do_not_use_batchwise_valuation
|
||||
erpnext.patches.v15_0.drop_index_posting_datetime_from_sle
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import click
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
table = "tabStock Ledger Entry"
|
||||
index = "posting_datetime_creation_index"
|
||||
|
||||
if not frappe.db.has_index(table, index):
|
||||
return
|
||||
|
||||
try:
|
||||
frappe.db.sql_ddl(f"ALTER TABLE `{table}` DROP INDEX `{index}`")
|
||||
click.echo(f"✓ dropped {index} index from {table}")
|
||||
except Exception:
|
||||
frappe.log_error("Failed to drop index")
|
||||
@@ -374,6 +374,14 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager {
|
||||
label: "Cost Center",
|
||||
options: "Cost Center",
|
||||
depends_on: "eval:doc.action=='Create Voucher' && doc.document_type=='Payment Entry'",
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: {
|
||||
is_group: 0,
|
||||
company: this.company,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldtype: "Section Break",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"gender",
|
||||
"lead_name",
|
||||
"opportunity_name",
|
||||
"prospect_name",
|
||||
"account_manager",
|
||||
"image",
|
||||
"defaults_tab",
|
||||
@@ -570,6 +571,14 @@
|
||||
{
|
||||
"fieldname": "column_break_nwor",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "prospect_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "From Prospect",
|
||||
"no_copy": 1,
|
||||
"options": "Prospect",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-user",
|
||||
|
||||
@@ -77,6 +77,7 @@ class Customer(TransactionBase):
|
||||
payment_terms: DF.Link | None
|
||||
portal_users: DF.Table[PortalUser]
|
||||
primary_address: DF.Text | None
|
||||
prospect_name: DF.Link | None
|
||||
represents_company: DF.Link | None
|
||||
sales_team: DF.Table[SalesTeam]
|
||||
salutation: DF.Link | None
|
||||
|
||||
@@ -347,8 +347,8 @@ def make_sales_order(source_name: str, target_doc=None):
|
||||
return _make_sales_order(source_name, target_doc)
|
||||
|
||||
|
||||
def _make_sales_order(source_name, target_doc=None, customer_group=None, ignore_permissions=False):
|
||||
customer = _make_customer(source_name, ignore_permissions, customer_group)
|
||||
def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
||||
customer = _make_customer(source_name, ignore_permissions)
|
||||
ordered_items = frappe._dict(
|
||||
frappe.db.get_all(
|
||||
"Sales Order Item",
|
||||
@@ -502,51 +502,71 @@ def _make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
return doclist
|
||||
|
||||
|
||||
def _make_customer(source_name, ignore_permissions=False, customer_group=None):
|
||||
def _make_customer(source_name, ignore_permissions=False):
|
||||
quotation = frappe.db.get_value(
|
||||
"Quotation", source_name, ["order_type", "party_name", "customer_name"], as_dict=1
|
||||
"Quotation",
|
||||
source_name,
|
||||
["order_type", "quotation_to", "party_name", "customer_name"],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
if quotation and quotation.get("party_name"):
|
||||
if not frappe.db.exists("Customer", quotation.get("party_name")):
|
||||
lead_name = quotation.get("party_name")
|
||||
customer_name = frappe.db.get_value(
|
||||
"Customer", {"lead_name": lead_name}, ["name", "customer_name"], as_dict=True
|
||||
)
|
||||
if not customer_name:
|
||||
from erpnext.crm.doctype.lead.lead import _make_customer
|
||||
if quotation.quotation_to == "Customer":
|
||||
return frappe.get_doc("Customer", quotation.party_name)
|
||||
|
||||
customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions)
|
||||
customer = frappe.get_doc(customer_doclist)
|
||||
customer.flags.ignore_permissions = ignore_permissions
|
||||
customer.customer_group = customer_group
|
||||
# Check if a Customer already exists for the Lead or Prospect.
|
||||
existing_customer = None
|
||||
if quotation.quotation_to == "Lead":
|
||||
existing_customer = frappe.db.get_value("Customer", {"lead_name": quotation.party_name})
|
||||
elif quotation.quotation_to == "Prospect":
|
||||
existing_customer = frappe.db.get_value("Customer", {"prospect_name": quotation.party_name})
|
||||
|
||||
try:
|
||||
customer.insert()
|
||||
return customer
|
||||
except frappe.NameError:
|
||||
if frappe.defaults.get_global_default("cust_master_name") == "Customer Name":
|
||||
customer.run_method("autoname")
|
||||
customer.name += "-" + lead_name
|
||||
customer.insert()
|
||||
return customer
|
||||
else:
|
||||
raise
|
||||
except frappe.MandatoryError as e:
|
||||
mandatory_fields = e.args[0].split(":")[1].split(",")
|
||||
mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
|
||||
if existing_customer:
|
||||
return frappe.get_doc("Customer", existing_customer)
|
||||
|
||||
frappe.local.message_log = []
|
||||
lead_link = frappe.utils.get_link_to_form("Lead", lead_name)
|
||||
message = (
|
||||
_("Could not auto create Customer due to the following missing mandatory field(s):")
|
||||
+ "<br>"
|
||||
)
|
||||
message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
|
||||
message += _("Please create Customer from Lead {0}.").format(lead_link)
|
||||
# If no Customer exists, create a new Customer or Prospect.
|
||||
if quotation.quotation_to == "Lead":
|
||||
return create_customer_from_lead(quotation.party_name, ignore_permissions=ignore_permissions)
|
||||
elif quotation.quotation_to == "Prospect":
|
||||
return create_customer_from_prospect(quotation.party_name, ignore_permissions=ignore_permissions)
|
||||
|
||||
frappe.throw(message, title=_("Mandatory Missing"))
|
||||
else:
|
||||
return customer_name
|
||||
else:
|
||||
return frappe.get_doc("Customer", quotation.get("party_name"))
|
||||
return None
|
||||
|
||||
|
||||
def create_customer_from_lead(lead_name, ignore_permissions=False):
|
||||
from erpnext.crm.doctype.lead.lead import _make_customer
|
||||
|
||||
customer = _make_customer(lead_name, ignore_permissions=ignore_permissions)
|
||||
customer.flags.ignore_permissions = ignore_permissions
|
||||
|
||||
try:
|
||||
customer.insert()
|
||||
return customer
|
||||
except frappe.MandatoryError as e:
|
||||
handle_mandatory_error(e, customer, lead_name)
|
||||
|
||||
|
||||
def create_customer_from_prospect(prospect_name, ignore_permissions=False):
|
||||
from erpnext.crm.doctype.prospect.prospect import make_customer as make_customer_from_prospect
|
||||
|
||||
customer = make_customer_from_prospect(prospect_name)
|
||||
customer.flags.ignore_permissions = ignore_permissions
|
||||
|
||||
try:
|
||||
customer.insert()
|
||||
return customer
|
||||
except frappe.MandatoryError as e:
|
||||
handle_mandatory_error(e, customer, prospect_name)
|
||||
|
||||
|
||||
def handle_mandatory_error(e, customer, lead_name):
|
||||
from frappe.utils import get_link_to_form
|
||||
|
||||
mandatory_fields = e.args[0].split(":")[1].split(",")
|
||||
mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
|
||||
|
||||
frappe.local.message_log = []
|
||||
message = _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
|
||||
message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
|
||||
message += _("Please create Customer from Lead {0}.").format(get_link_to_form("Lead", lead_name))
|
||||
|
||||
frappe.throw(message, title=_("Mandatory Missing"))
|
||||
|
||||
@@ -936,6 +936,10 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None):
|
||||
}
|
||||
|
||||
def set_missing_values(source, target):
|
||||
if kwargs.get("ignore_pricing_rule"):
|
||||
# Skip pricing rule when the dn is creating from the pick list
|
||||
target.ignore_pricing_rule = 1
|
||||
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("set_po_nos")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
@@ -3,22 +3,14 @@
|
||||
|
||||
frappe.ui.form.on("Brand", {
|
||||
setup: (frm) => {
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("default_warehouse").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("default_warehouse", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: { company: row.company },
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("default_discount_account").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("default_discount_account", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
@@ -27,13 +19,9 @@ frappe.ui.form.on("Brand", {
|
||||
is_group: 0,
|
||||
},
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("buying_cost_center").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("buying_cost_center", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
@@ -41,25 +29,17 @@ frappe.ui.form.on("Brand", {
|
||||
company: row.company,
|
||||
},
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("expense_account").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("expense_account", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_expense_account",
|
||||
filters: { company: row.company },
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("default_provisional_account").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("default_provisional_account", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
@@ -68,13 +48,9 @@ frappe.ui.form.on("Brand", {
|
||||
is_group: 0,
|
||||
},
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("selling_cost_center").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("selling_cost_center", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
@@ -82,18 +58,14 @@ frappe.ui.form.on("Brand", {
|
||||
company: row.company,
|
||||
},
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.fields_dict["brand_defaults"].grid.get_field("income_account").get_query = function (
|
||||
doc,
|
||||
cdt,
|
||||
cdn
|
||||
) {
|
||||
frm.set_query("income_account", "brand_defaults", function (doc, cdt, cdn) {
|
||||
const row = locals[cdt][cdn];
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_income_account",
|
||||
filters: { company: row.company },
|
||||
};
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -56,10 +56,11 @@
|
||||
"idx": 1,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"modified": "2021-03-01 15:57:30.005783",
|
||||
"modified": "2024-08-20 14:10:21.377962",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Brand",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@@ -108,4 +109,4 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class Company(NestedSet):
|
||||
):
|
||||
frappe.throw(
|
||||
_("'{0}' should be in company currency {1}.").format(
|
||||
frappe.bold("Default Advance Received Account"), frappe.bold(self.default_currency)
|
||||
frappe.bold(_("Default Advance Received Account")), frappe.bold(self.default_currency)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -214,7 +214,7 @@ class Company(NestedSet):
|
||||
):
|
||||
frappe.throw(
|
||||
_("'{0}' should be in company currency {1}.").format(
|
||||
frappe.bold("Default Advance Paid Account"), frappe.bold(self.default_currency)
|
||||
frappe.bold(_("Default Advance Paid Account")), frappe.bold(self.default_currency)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -447,7 +447,7 @@ class Company(NestedSet):
|
||||
):
|
||||
frappe.throw(
|
||||
_("Set default {0} account for non stock items").format(
|
||||
frappe.bold("Provisional Account")
|
||||
frappe.bold(_("Provisional Account"))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ class CustomerGroup(NestedSet):
|
||||
|
||||
def validate_currency_for_receivable_and_advance_account(self):
|
||||
for x in self.accounts:
|
||||
company_default_currency = frappe.get_cached_value("Company", x.company, "default_currency")
|
||||
receivable_account_currency = None
|
||||
advance_account_currency = None
|
||||
|
||||
@@ -56,21 +55,6 @@ class CustomerGroup(NestedSet):
|
||||
"Account", x.advance_account, "account_currency"
|
||||
)
|
||||
|
||||
if receivable_account_currency and receivable_account_currency != company_default_currency:
|
||||
frappe.throw(
|
||||
_("Receivable Account: {0} must be in Company default currency: {1}").format(
|
||||
frappe.bold(x.account),
|
||||
frappe.bold(company_default_currency),
|
||||
)
|
||||
)
|
||||
|
||||
if advance_account_currency and advance_account_currency != company_default_currency:
|
||||
frappe.throw(
|
||||
_("Advance Account: {0} must be in Company default currency: {1}").format(
|
||||
frappe.bold(x.advance_account), frappe.bold(company_default_currency)
|
||||
)
|
||||
)
|
||||
|
||||
if (
|
||||
receivable_account_currency
|
||||
and advance_account_currency
|
||||
|
||||
@@ -37,7 +37,6 @@ class SupplierGroup(NestedSet):
|
||||
|
||||
def validate_currency_for_payable_and_advance_account(self):
|
||||
for x in self.accounts:
|
||||
company_default_currency = frappe.get_cached_value("Company", x.company, "default_currency")
|
||||
payable_account_currency = None
|
||||
advance_account_currency = None
|
||||
|
||||
@@ -49,21 +48,6 @@ class SupplierGroup(NestedSet):
|
||||
"Account", x.advance_account, "account_currency"
|
||||
)
|
||||
|
||||
if payable_account_currency and payable_account_currency != company_default_currency:
|
||||
frappe.throw(
|
||||
_("Payable Account: {0} must be in Company default currency: {1}").format(
|
||||
frappe.bold(x.account),
|
||||
frappe.bold(company_default_currency),
|
||||
)
|
||||
)
|
||||
|
||||
if advance_account_currency and advance_account_currency != company_default_currency:
|
||||
frappe.throw(
|
||||
_("Advance Account: {0} must be in Company default currency: {1}").format(
|
||||
frappe.bold(x.advance_account), frappe.bold(company_default_currency)
|
||||
)
|
||||
)
|
||||
|
||||
if (
|
||||
payable_account_currency
|
||||
and advance_account_currency
|
||||
|
||||
@@ -188,9 +188,9 @@ class Batch(Document):
|
||||
if has_expiry_date and not self.expiry_date:
|
||||
frappe.throw(
|
||||
msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.").format(
|
||||
frappe.bold("Shelf Life in Days"),
|
||||
frappe.bold(_("Shelf Life in Days")),
|
||||
get_link_to_form("Item", self.item),
|
||||
frappe.bold("Batch Expiry Date"),
|
||||
frappe.bold(_("Batch Expiry Date")),
|
||||
),
|
||||
title=_("Expiry Date Mandatory"),
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"consider_rejected_warehouses",
|
||||
"get_item_locations",
|
||||
"pick_manually",
|
||||
"ignore_pricing_rule",
|
||||
"section_break_6",
|
||||
"scan_barcode",
|
||||
"column_break_13",
|
||||
@@ -200,11 +201,18 @@
|
||||
"fieldname": "pick_manually",
|
||||
"fieldtype": "Check",
|
||||
"label": "Pick Manually"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If enabled then system won't apply the pricing rule on the delivery note which will be create from the pick list",
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 22:49:16.954637",
|
||||
"modified": "2024-08-14 13:20:42.168827",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Pick List",
|
||||
|
||||
@@ -50,6 +50,7 @@ class PickList(Document):
|
||||
customer_name: DF.Data | None
|
||||
for_qty: DF.Float
|
||||
group_same_items: DF.Check
|
||||
ignore_pricing_rule: DF.Check
|
||||
locations: DF.Table[PickListItem]
|
||||
material_request: DF.Link | None
|
||||
naming_series: DF.Literal["STO-PICK-.YYYY.-"]
|
||||
@@ -1144,7 +1145,7 @@ def create_dn_with_so(sales_dict, pick_list):
|
||||
for customer in sales_dict:
|
||||
for so in sales_dict[customer]:
|
||||
delivery_note = None
|
||||
kwargs = {"skip_item_mapping": True}
|
||||
kwargs = {"skip_item_mapping": True, "ignore_pricing_rule": pick_list.ignore_pricing_rule}
|
||||
delivery_note = create_delivery_note_from_sales_order(so, delivery_note, kwargs=kwargs)
|
||||
break
|
||||
if delivery_note:
|
||||
|
||||
@@ -1205,3 +1205,64 @@ class TestPickList(FrappeTestCase):
|
||||
pl_doc.submit()
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "over_picking_allowance", 0)
|
||||
|
||||
def test_ignore_pricing_rule_in_pick_list(self):
|
||||
frappe.flags.print_stmt = False
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
item = make_item(
|
||||
properties={
|
||||
"is_stock_item": 1,
|
||||
"has_batch_no": 1,
|
||||
"batch_number_series": "IPR-PICKLT-.######",
|
||||
"create_new_batch": 1,
|
||||
}
|
||||
).name
|
||||
|
||||
make_stock_entry(
|
||||
item=item,
|
||||
to_warehouse=warehouse,
|
||||
qty=2,
|
||||
basic_rate=100,
|
||||
)
|
||||
|
||||
pricing_rule = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "Same Free Item",
|
||||
"price_or_product_discount": "Product",
|
||||
"selling": 1,
|
||||
"apply_on": "Item Code",
|
||||
"items": [
|
||||
{
|
||||
"item_code": item,
|
||||
}
|
||||
],
|
||||
"same_item": 1,
|
||||
"is_recursive": 1,
|
||||
"recurse_for": 2,
|
||||
"free_qty": 1,
|
||||
"company": "_Test Company",
|
||||
"customer": "_Test Customer",
|
||||
}
|
||||
)
|
||||
|
||||
pricing_rule.save()
|
||||
frappe.flags.print_stmt = True
|
||||
|
||||
so = make_sales_order(item_code=item, qty=2, rate=100, do_not_save=True)
|
||||
so.set_warehouse = warehouse
|
||||
so.submit()
|
||||
|
||||
self.assertEqual(len(so.items), 2)
|
||||
self.assertTrue(so.items[1].is_free_item)
|
||||
|
||||
pl = create_pick_list(so.name)
|
||||
pl.ignore_pricing_rule = 1
|
||||
pl.save()
|
||||
pl.submit()
|
||||
|
||||
self.assertEqual(len(pl.locations), 1)
|
||||
|
||||
delivery_note = create_delivery_note(pl.name)
|
||||
|
||||
self.assertEqual(len(delivery_note.items), 1)
|
||||
|
||||
@@ -701,6 +701,57 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
||||
serial_nos = get_serial_nos_from_bundle(se.items[0].serial_and_batch_bundle)
|
||||
self.assertEqual(serial_nos, serial_nos1)
|
||||
|
||||
def test_auto_create_serial_and_batch_bundle_for_outward_for_batch_item(self):
|
||||
item_code = make_item(
|
||||
"Test Auto Create Batch Bundle for Outward 1",
|
||||
properties={
|
||||
"is_stock_item": 1,
|
||||
"has_batch_no": 1,
|
||||
"batch_number_series": "ACSBBO-TACSB-.#####",
|
||||
},
|
||||
).name
|
||||
|
||||
if not frappe.db.exists("Batch", "ACSBBO-TACSB-00001"):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Batch",
|
||||
"batch_id": "ACSBBO-TACSB-00001",
|
||||
"item": item_code,
|
||||
"company": "_Test Company",
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
make_stock_entry(
|
||||
item_code=item_code,
|
||||
qty=10,
|
||||
target="_Test Warehouse - _TC",
|
||||
rate=500,
|
||||
use_serial_batch_fields=True,
|
||||
batch_no="ACSBBO-TACSB-00001",
|
||||
)
|
||||
|
||||
dispatch = make_stock_entry(
|
||||
item_code=item_code,
|
||||
qty=10,
|
||||
target="_Test Warehouse - _TC",
|
||||
rate=500,
|
||||
do_not_submit=True,
|
||||
)
|
||||
|
||||
original_value = frappe.db.get_single_value(
|
||||
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward"
|
||||
)
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 0)
|
||||
self.assertRaises(frappe.ValidationError, dispatch.submit)
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1)
|
||||
dispatch.submit()
|
||||
|
||||
frappe.db.set_single_value(
|
||||
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", original_value
|
||||
)
|
||||
|
||||
|
||||
def get_batch_from_bundle(bundle):
|
||||
from erpnext.stock.serial_batch_bundle import get_batch_nos
|
||||
|
||||
@@ -898,8 +898,8 @@ class StockEntry(StockController):
|
||||
).format(
|
||||
item.idx,
|
||||
frappe.bold(label),
|
||||
frappe.bold("Manufacture"),
|
||||
frappe.bold("Material Consumption for Manufacture"),
|
||||
frappe.bold(_("Manufacture")),
|
||||
frappe.bold(_("Material Consumption for Manufacture")),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -909,7 +909,7 @@ class StockEntry(StockController):
|
||||
):
|
||||
frappe.throw(
|
||||
_("Only one {0} entry can be created against the Work Order {1}").format(
|
||||
frappe.bold("Manufacture"), frappe.bold(self.work_order)
|
||||
frappe.bold(_("Manufacture")), frappe.bold(self.work_order)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
from frappe.permissions import add_user_permission, remove_user_permission
|
||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||
from frappe.utils import add_days, flt, nowtime, today
|
||||
from frappe.utils import add_days, cstr, flt, get_time, getdate, nowtime, today
|
||||
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.stock.doctype.item.test_item import (
|
||||
@@ -1780,6 +1780,74 @@ class TestStockEntry(FrappeTestCase):
|
||||
frappe.db.set_value("Serial and Batch Bundle", sbb, "type_of_transaction", "Inward")
|
||||
self.assertRaises(frappe.ValidationError, se.submit)
|
||||
|
||||
def test_stock_entry_for_same_posting_date_and_time(self):
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
item_code = "Test Stock Entry For Same Posting Datetime 1"
|
||||
make_item(item_code, {"is_stock_item": 1})
|
||||
posting_date = nowdate()
|
||||
posting_time = nowtime()
|
||||
|
||||
for index in range(25):
|
||||
se = make_stock_entry(
|
||||
item_code=item_code,
|
||||
qty=1,
|
||||
to_warehouse=warehouse,
|
||||
posting_date=posting_date,
|
||||
posting_time=posting_time,
|
||||
do_not_submit=True,
|
||||
purpose="Material Receipt",
|
||||
basic_rate=100,
|
||||
)
|
||||
|
||||
se.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": item_code,
|
||||
"item_name": se.items[0].item_name,
|
||||
"description": se.items[0].description,
|
||||
"t_warehouse": se.items[0].t_warehouse,
|
||||
"basic_rate": 100,
|
||||
"qty": 1,
|
||||
"stock_qty": 1,
|
||||
"conversion_factor": 1,
|
||||
"expense_account": se.items[0].expense_account,
|
||||
"cost_center": se.items[0].cost_center,
|
||||
"uom": se.items[0].uom,
|
||||
"stock_uom": se.items[0].stock_uom,
|
||||
},
|
||||
)
|
||||
|
||||
se.remarks = f"The current number is {cstr(index)}"
|
||||
|
||||
se.submit()
|
||||
|
||||
sles = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
fields=[
|
||||
"posting_date",
|
||||
"posting_time",
|
||||
"actual_qty",
|
||||
"qty_after_transaction",
|
||||
"incoming_rate",
|
||||
"stock_value_difference",
|
||||
"stock_value",
|
||||
],
|
||||
filters={"item_code": item_code, "warehouse": warehouse},
|
||||
order_by="creation",
|
||||
)
|
||||
|
||||
self.assertEqual(len(sles), 50)
|
||||
i = 0
|
||||
for sle in sles:
|
||||
i += 1
|
||||
self.assertEqual(getdate(sle.posting_date), getdate(posting_date))
|
||||
self.assertEqual(get_time(sle.posting_time), get_time(posting_time))
|
||||
self.assertEqual(sle.actual_qty, 1)
|
||||
self.assertEqual(sle.qty_after_transaction, i)
|
||||
self.assertEqual(sle.incoming_rate, 100)
|
||||
self.assertEqual(sle.stock_value_difference, 100)
|
||||
self.assertEqual(sle.stock_value, 100 * i)
|
||||
|
||||
|
||||
def make_serialized_item(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
@@ -351,4 +351,3 @@ def on_doctype_update():
|
||||
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
|
||||
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
|
||||
frappe.db.add_index("Stock Ledger Entry", ["warehouse", "item_code"], "item_warehouse")
|
||||
frappe.db.add_index("Stock Ledger Entry", ["posting_datetime", "creation"])
|
||||
|
||||
@@ -1043,6 +1043,8 @@ class TestStockLedgerEntry(FrappeTestCase, StockTestMixin):
|
||||
self.assertEqual(50, _get_stock_credit(final_consumption))
|
||||
|
||||
def test_tie_breaking(self):
|
||||
from erpnext.stock.doctype.repost_item_valuation.repost_item_valuation import repost_entries
|
||||
|
||||
frappe.flags.dont_execute_stock_reposts = True
|
||||
self.addCleanup(frappe.flags.pop, "dont_execute_stock_reposts")
|
||||
|
||||
@@ -1085,6 +1087,7 @@ class TestStockLedgerEntry(FrappeTestCase, StockTestMixin):
|
||||
self.assertEqual([10, 11], ordered_qty_after_transaction())
|
||||
|
||||
first.cancel()
|
||||
repost_entries()
|
||||
self.assertEqual([1], ordered_qty_after_transaction())
|
||||
|
||||
backdated = make_stock_entry(
|
||||
|
||||
@@ -255,7 +255,7 @@ class StockReservationEntry(Document):
|
||||
if self.has_batch_no
|
||||
else _("Warehouse"),
|
||||
frappe.bold(self.warehouse),
|
||||
frappe.bold("Stock Reservation Entry"),
|
||||
frappe.bold(_("Stock Reservation Entry")),
|
||||
)
|
||||
|
||||
frappe.throw(msg)
|
||||
@@ -497,7 +497,8 @@ def validate_stock_reservation_settings(voucher: object) -> None:
|
||||
|
||||
if not frappe.db.get_single_value("Stock Settings", "enable_stock_reservation"):
|
||||
msg = _("Please enable {0} in the {1}.").format(
|
||||
frappe.bold("Stock Reservation"), frappe.bold("Stock Settings")
|
||||
frappe.bold(_("Stock Reservation")),
|
||||
frappe.bold(_("Stock Settings")),
|
||||
)
|
||||
frappe.throw(msg)
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ class StockSettings(Document):
|
||||
if self.allow_negative_stock and self.enable_stock_reservation:
|
||||
frappe.throw(
|
||||
_("As {0} is enabled, you can not enable {1}.").format(
|
||||
frappe.bold("Stock Reservation"), frappe.bold("Allow Negative Stock")
|
||||
frappe.bold(_("Stock Reservation")), frappe.bold(_("Allow Negative Stock"))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -187,7 +187,7 @@ class StockSettings(Document):
|
||||
if self.allow_negative_stock:
|
||||
frappe.throw(
|
||||
_("As {0} is enabled, you can not enable {1}.").format(
|
||||
frappe.bold("Allow Negative Stock"), frappe.bold("Stock Reservation")
|
||||
frappe.bold(_("Allow Negative Stock")), frappe.bold(_("Stock Reservation"))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -207,7 +207,7 @@ class StockSettings(Document):
|
||||
if bin_with_negative_stock:
|
||||
frappe.throw(
|
||||
_("As there are negative stock, you can not enable {0}.").format(
|
||||
frappe.bold("Stock Reservation")
|
||||
frappe.bold(_("Stock Reservation"))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -221,7 +221,7 @@ class StockSettings(Document):
|
||||
if has_reserved_stock:
|
||||
frappe.throw(
|
||||
_("As there are reserved stock, you cannot disable {0}.").format(
|
||||
frappe.bold("Stock Reservation")
|
||||
frappe.bold(_("Stock Reservation"))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2024-01-24 16:27:28.299520",
|
||||
"modified": "2024-08-14 16:08:15.733597",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Warehouse",
|
||||
@@ -320,6 +320,5 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "warehouse_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,15 @@ class SerialBatchBundle:
|
||||
not self.sle.is_cancelled
|
||||
and not self.sle.serial_and_batch_bundle
|
||||
and self.item_details.has_batch_no == 1
|
||||
and self.item_details.create_new_batch
|
||||
and (
|
||||
self.item_details.create_new_batch
|
||||
or (
|
||||
frappe.db.get_single_value(
|
||||
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward"
|
||||
)
|
||||
and self.sle.actual_qty < 0
|
||||
)
|
||||
)
|
||||
):
|
||||
self.make_serial_batch_no_bundle()
|
||||
elif not self.sle.is_cancelled:
|
||||
|
||||
@@ -647,6 +647,7 @@ class update_entries_after:
|
||||
and (
|
||||
posting_datetime = %(posting_datetime)s
|
||||
)
|
||||
and creation = %(creation)s
|
||||
order by
|
||||
creation ASC
|
||||
for update
|
||||
@@ -1526,6 +1527,11 @@ def get_previous_sle_of_current_voucher(args, operator="<", exclude_current_vouc
|
||||
voucher_no = args.get("voucher_no")
|
||||
voucher_condition = f"and voucher_no != '{voucher_no}'"
|
||||
|
||||
elif args.get("creation"):
|
||||
creation = args.get("creation")
|
||||
operator = "<="
|
||||
voucher_condition = f"and creation < '{creation}'"
|
||||
|
||||
sle = frappe.db.sql(
|
||||
f"""
|
||||
select *, posting_datetime as "timestamp"
|
||||
|
||||
@@ -144,7 +144,7 @@ class ServiceLevelAgreement(Document):
|
||||
):
|
||||
frappe.throw(
|
||||
_("{0} is not enabled in {1}").format(
|
||||
frappe.bold("Track Service Level Agreement"),
|
||||
frappe.bold(_("Track Service Level Agreement")),
|
||||
get_link_to_form("Support Settings", "Support Settings"),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1095,7 +1095,7 @@ Guardian1 Name,Guardian1 Namen,
|
||||
Guardian2 Email ID,Guardian2 E-Mail-ID,
|
||||
Guardian2 Mobile No,Guardian2 Mobil Nein,
|
||||
Guardian2 Name,Guardian2 Namen,
|
||||
HR Manager,Leiter der Personalabteilung,
|
||||
HR Manager,Personalwesen Leiter,
|
||||
HSN,HSN,
|
||||
HSN/SAC,HSN / SAC,
|
||||
Half Yearly,Halbjährlich,
|
||||
@@ -3728,6 +3728,7 @@ Subdivision,Teilgebiet,
|
||||
Submit Review,Bewertung abschicken,
|
||||
Submitted,Gebucht,
|
||||
Supplier Addresses And Contacts,Lieferanten-Adressen und Kontaktdaten,
|
||||
Supplier Address Details,Vorschau Lieferantenadresse,
|
||||
Synchronize this account,Synchronisieren Sie dieses Konto,
|
||||
Tag,Etikett,
|
||||
Target Location is required while receiving Asset {0} from an employee,"Der Zielspeicherort ist erforderlich, wenn Asset {0} von einem Mitarbeiter empfangen wird",
|
||||
@@ -6027,10 +6028,10 @@ Hotel Room Reservation Item,Hotelzimmer-Reservierungselement,
|
||||
Hotel Settings,Hoteleinstellungen,
|
||||
Default Taxes and Charges,Standard-Steuern und -Abgaben,
|
||||
Default Invoice Naming Series,Standard-Rechnungsnummernkreis,
|
||||
HR,HR,
|
||||
HR,Personalwesen,
|
||||
Date on which this component is applied,"Datum, an dem diese Komponente angewendet wird",
|
||||
Salary Slip,Gehaltsabrechnung,
|
||||
HR User,Nutzer Personalabteilung,
|
||||
HR User,Personalwesen Benutzer,
|
||||
Job Applicant,Bewerber,
|
||||
Body,Körper,
|
||||
Appraisal Template,Bewertungsvorlage,
|
||||
@@ -9917,8 +9918,8 @@ Bank/Cash Account {0} doesn't belong to company {1},Das Bank- / Kassenkonto {0}
|
||||
Base Amount,Basisbetrag,
|
||||
Base Total Billed Amount,Insg. abgerechneter Betrag in Basiswährung,
|
||||
Base Total Costing Amount,Gesamtkosten in Basiswährung,
|
||||
"Based on your HR Policy, select your leave allocation period's end date",Wählen Sie auf der Grundlage Ihrer HR-Richtlinien das Enddatum Ihres Abwesenheitskontingents aus,
|
||||
"Based on your HR Policy, select your leave allocation period's start date",Wählen Sie auf der Grundlage Ihrer HR-Richtlinie das Startdatum Ihres Abwesenheitskontingents aus,
|
||||
"Based on your HR Policy, select your leave allocation period's end date",Wählen Sie auf der Grundlage Ihrer Personal-Richtlinien das Enddatum Ihres Abwesenheitskontingents aus,
|
||||
"Based on your HR Policy, select your leave allocation period's start date",Wählen Sie auf der Grundlage Ihrer Personal-Richtlinie das Startdatum Ihres Abwesenheitskontingents aus,
|
||||
Batch No is mandatory,Chargennummer ist obligatorisch,
|
||||
Batch No {0} does not exists,Charge Nr. {0} existiert nicht,
|
||||
Batch No {0} is linked with Item {1} which has serial no. Please scan serial no instead.,"Die Chargennummer {0} ist mit dem Artikel {1} verknüpft, der eine Seriennummer hat. Bitte scannen Sie stattdessen die Seriennummer.",
|
||||
@@ -11472,7 +11473,7 @@ Shipment Parcel,Versandpaket,
|
||||
Shipment Parcel Template,Versandpaketvorlage,
|
||||
Shipment Type,Sendungstyp,
|
||||
Shipment details,Sendungsdetails,
|
||||
Shipping Address Details,Lieferadressendetails,
|
||||
Shipping Address Details,Vorschau Lieferadresse,
|
||||
Shipping Address Template,Vorlage Lieferadresse,
|
||||
Show Balances in Chart Of Accounts,Saldo in Kontenplan anzeigen,
|
||||
Show Barcode Field in Stock Transactions,Barcode-Feld in Lagerbewegungen anzeigen,
|
||||
@@ -11815,3 +11816,103 @@ will be,wird sein,
|
||||
{} is a child company.,{} ist ein untergeordnetes Unternehmen.,
|
||||
{} {} is already linked with another {},{} {} ist bereits mit einem anderen {} verknüpft,
|
||||
{} {} is already linked with {} {},{} {} ist bereits mit {} {} verknüpft,
|
||||
A Transaction Deletion Document: {0} is triggered for {0},Eine Transaktion Löschungsdokument: {0} wird für {0} ausgelöst,
|
||||
About Us Settings,"Einstellungen zu ""Über uns""",
|
||||
Allow Internal Transfers at Arm's Length Price,Interne Übertragungen zum Fremdvergleichspreis zulassen,
|
||||
Asset decapitalized after Asset Capitalization {0} was submitted,"Vermögenswert freigegeben, nachdem Anlagenaktivierung {0} gebucht wurde",
|
||||
Auto Email Report,Auto Email-Bericht,
|
||||
Auto close Opportunity Replied after the no. of days mentioned above,Automatische Schließungschaltung antwortete nach der oben genannten Anzahl von Tagen,
|
||||
Avg Rate (Balance Stock),Durchschnittliche Rate (Lagerbestand),
|
||||
Billing Interval in Subscription Plan must be Month to follow calendar months,"Abrechnungsintervall im Abonnementplan muss ""Monat"" sein, um Kalendermonate zu folgen",
|
||||
Bulk Update,Massen-Update,
|
||||
Can't disable batch wise valuation for active batches.,Sie können die chargenweise Bewertung für aktive Chargen nicht deaktivieren.,
|
||||
Can't disable batch wise valuation for items with FIFO valuation method.,Sie können die chargenweise Bewertung für Artikel mit FIFO-Bewertungsmethode nicht deaktivieren.,
|
||||
Cannot disable batch wise valuation for FIFO valuation method.,Sie können die chargenweise Bewertung für die FIFO-Bewertungsmethode nicht deaktivieren.,
|
||||
Cannot enqueue multi docs for one company. {0} is already queued/running for company: {1},Mehrere Dokumente für ein Unternehmen können nicht in die Warteschlange gestellt werden. {0} ist bereits in die Warteschlange gestellt/wird für das Unternehmen ausgeführt: {1},
|
||||
Contact Us Settings,Einstellungen zu „Kontaktieren Sie uns“,
|
||||
Create Journal Entries,Buchungssätze erstellen,
|
||||
Create a variant with the template image.,Eine Variante mit dem Vorlagenbild erstellen.,
|
||||
Create in Draft Status,In Entwurfsstatus erstellen,
|
||||
Custom delimiters,Benutzerdefinierte Trennzeichen,
|
||||
Deleted Documents,Gelöschte Dokumente,
|
||||
Delimiter options,Trennzeichenoptionen,
|
||||
Dependent Task {0} is not a Template Task,Abhängige Aufgabe {0} ist keine Vorlage einer Aufgabe,
|
||||
Depreciation Entry Posting Status,Buchungsstatus des Abschreibungseintrags,
|
||||
Depreciation Schedule View,Ansicht Abschreibungsplan,
|
||||
Depreciation cannot be calculated for fully depreciated assets,Für vollständig abgeschriebene Vermögensgegenstände kann keine Abschreibung berechnet werden,
|
||||
Do Not Use Batch-wise Valuation,Keine chargenweise Bewertung verwenden,
|
||||
Domain Settings,Domäneneinstellungen,
|
||||
Email Domain,E-Mail-Domain,
|
||||
Enable Immutable Ledger,Unveränderliches Hauptbuch aktivieren,
|
||||
Enable it if users want to consider rejected materials to dispatch.,"Aktivieren Sie diese Option, wenn Benutzer zurückgewiesenes Material für den Versand berücksichtigen möchten.",
|
||||
Excess Materials Consumed,Überschüssige Materialien verbraucht,
|
||||
Excess Transfer,Überschuss-Übertragung,
|
||||
FIFO Queue vs Qty After Transaction Comparison,Vergleich zwischen FIFO-Warteschlange und Menge nach Transaktion,
|
||||
"For the {0}, the quantity is required to make the return entry","Für die {0} ist die Menge erforderlich, um die Retoure zu erstellen",
|
||||
"If enabled, the item rate won't adjust to the valuation rate during internal transfers, but accounting will still use the valuation rate.","Falls aktiviert, wird der Artikelkurs bei internen Transfers nicht an den Bewertungskurs angepasst, aber die Buchhaltung verwendet weiterhin den Wertansatz.",
|
||||
"If enabled, the system will use the moving average valuation method to calculate the valuation rate for the batched items and will not consider the individual batch-wise incoming rate.","Falls aktiviert, verwendet das System die Bewertungsmethode des gleitenden Durchschnitts zur Berechnung des Wertansatzes für die chargenweisen Artikel und berücksichtigt nicht den individuellen chargenweisen Eingangskurs.",
|
||||
Job Worker,Unterauftragnehmer,
|
||||
Job Worker Address,Unterauftragnehmer Adresse,
|
||||
Job Worker Address Details,Vorschau Adresse Unterauftragnehmer,
|
||||
Job Worker Contact,Vertrag des Unterauftragnehmers,
|
||||
Job Worker Delivery Note,Lieferschein des Unterauftragnehmers,
|
||||
Job Worker Name,Name des Unterauftragnehmer,
|
||||
Job Worker Warehouse,Lagerhaus des Unterauftragnehmers,
|
||||
"Learn about <a href=""https://docs.erpnext.com/docs/v13/user/manual/en/accounts/articles/common_party_accounting#:~:text=Common%20Party%20Accounting%20in%20ERPNext,Invoice%20against%20a%20primary%20Supplier."">Common Party</a>","Erfahren Sie mehr über die <a href=""https://docs.erpnext.com/docs/v13/user/manual/en/accounts/articles/common_party_accounting#:~:text=Common%20Party%20Accounting%20in%20ERPNext,Invoice%20against%20a%20primary%20Supplier."">Verknüpfung von Kunden und Lieferanten</a>",
|
||||
Notification,Benachrichtigung,
|
||||
Notification Settings,Benachrichtigungseinstellungen,
|
||||
Offsetting for Accounting Dimension,Verrechnung für Buchhaltungsdimension,
|
||||
Only Include Allocated Payments,Nur zugeordnete Zahlungen einbeziehen,
|
||||
Only one {0} entry can be created against the Work Order {1},Nur ein {0} Eintrag kann gegen den Arbeitsauftrag {1} erstellt werden,
|
||||
Over Picking Allowance,Überkommissionierzugabe,
|
||||
Over Transfer Allowance,Überschlusstransferzugabe,
|
||||
Overbilling of {} ignored because you have {} role.,"Überhöhte Abrechnung von {} wurde ignoriert, weil Sie die Rolle {} haben.",
|
||||
Payment Reconciliation Job: {0} is running for this party. Can't reconcile now.,Job für Zahlungsabgleich: {0} läuft für diese Partei. Kann jetzt nicht abgleichen.,
|
||||
Payment Request created from Sales Order or Purchase Order will be in Draft status. When disabled document will be in unsaved state.,"Eine Zahlungsanforderung, die aus einem Auftrag oder einer Bestellung erstellt wurde, wird im Entwurfsstatus sein. Wenn deaktiviert, wird das Dokument in ungespeichertem Zustand sein.",
|
||||
Payment Request took too long to respond. Please try requesting for payment again.,"Zahlungsaufforderung hat zu lange gedauert, um zu antworten. Bitte versuchen Sie die Zahlung erneut anzufragen.",
|
||||
Payment Terms Status for Sales Order,Status für Zahlungsbedingungen für Aufträge,
|
||||
Pipeline By,Pipeline von,
|
||||
Please enable Use Old Serial / Batch Fields to make_bundle,"Bitte aktivieren Sie ""Alte Serien-/Batchfelder verwenden"" für make_bundle",
|
||||
Print Style,Druckstil,
|
||||
Reconcile All Serial Nos / Batches,Alle Seriennummern/Chargen abgleichen,
|
||||
Reset Company Default Values,Standardwerte des Unternehmens zurücksetzen,
|
||||
Reset Raw Materials Table,Tabelle Rohstoffe zurücksetzen,
|
||||
Return Against Subcontracting Receipt,Retoure gegen Unterauftragsbeleg,
|
||||
Return Components,Komponenten zurückgeben,
|
||||
Returned Against,Zurückgegeben gegen,
|
||||
Returned exchange rate is neither integer not float.,Der zurückgegebene Wechselkurs ist weder Integer noch Float.,
|
||||
Round Off Tax Amount,Steuerbetrag abrunden,
|
||||
Rounding Loss Allowance,Rundungsverlusttoleranz,
|
||||
Rounding Loss Allowance should be between 0 and 1,Rundungsverlusttoleranz muss zwischen 0 und 1 sein,
|
||||
Row #{0}: Rejected Warehouse is mandatory for the rejected Item {1},Zeile #{0}: Ausschusslager ist für den abgelehnten Artikel {1} obligatorisch,
|
||||
Row #{0}: You cannot use the inventory dimension '{1}' in Stock Reconciliation to modify the quantity or valuation rate. Stock reconciliation with inventory dimensions is intended solely for performing opening entries.,"Zeile #{0}: Sie können die Bestandsdimension '{1}' in der Bestandsabgleich nicht verwenden, um die Menge oder den Wertansatz zu ändern. Die Bestandsabgleich mit Bestandsdimensionen ist ausschließlich für die Durchführung von Eröffnungsbuchungen vorgesehen.",
|
||||
Row {0}: Packed Qty must be equal to {1} Qty.,Zeile {0}: Verpackte Menge muss gleich der {1} Menge sein.,
|
||||
Row {0}: Total Number of Depreciations cannot be less than or equal to Opening Number of Booked Depreciations,Zeile {0}: Die Gesamtzahl der Abschreibungen kann nicht kleiner oder gleich der Anzahl der gebuchten Abschreibungen zu Beginn sein,
|
||||
SCO Supplied Item,Artikel beigestellt für Unterauftrag,
|
||||
SLA Fulfilled On Status,SLA erfüllt am Status,
|
||||
SLA will be applied if {1} is set as {2}{3},"SLA wird angewendet, wenn {1} als {2}{3} eingestellt ist",
|
||||
SMS Settings,SMS-Einstellungen,
|
||||
SO Total Qty,Kd.-Auftr.-Gesamtmenge,
|
||||
"Sales Order {0} already exists against Customer's Purchase Order {1}. To allow multiple Sales Orders, Enable {2} in {3}","Auftrag {0} existiert bereits für die Kundenbestellung {1}. Um mehrere Verkaufsaufträge zuzulassen, aktivieren Sie {2} in {3}",
|
||||
"Scorecard variables can be used, as well as:
|
||||
{total_score} (the total score from that period),
|
||||
{period_number} (the number of periods to present day)
|
||||
","Variablen der Bewertung können verwendet werden, sowie:
|
||||
{total_score} (die Gesamtpunktzahl aus diesem Zeitraum),
|
||||
{period_number} (die Anzahl der Zeiträume bis zum heutigen Tag)
|
||||
",
|
||||
Select Accounting Dimension.,Buchhaltungsdimension auswählen,
|
||||
Select Corrective Operation,Nacharbeit auswählen,
|
||||
Select Date of Birth. This will validate Employees age and prevent hiring of under-age staff.,Wählen Sie Geburtsdatum. Damit wird das Alter der Mitarbeiter überprüft und die Einstellung von minderjährigen Mitarbeitern verhindert.,
|
||||
"Select Date of joining. It will have impact on the first salary calculation, Leave allocation on pro-rata bases.",Wählen Sie Eintrittsdatum. Es wirkt sich auf die erste Gehaltsberechnung und die Zuteilung von Abwesenheiten auf Pro-rata-Basis aus.,
|
||||
Select Dimension,Dimension auswählen,
|
||||
Select Items for Quality Inspection,Artikel für die Qualitätsprüfung auswählen,
|
||||
Select Job Worker Address,Unterauftragnehmer Adresse auswählen,
|
||||
Service Expenses,Wartungsaufwand,
|
||||
Service Level Agreement for {0} {1} already exists.,Service Level Agreement für {0} {1} existiert bereits.,
|
||||
System Settings,Systemverwaltung,
|
||||
Website Script,Webseiten-Skript,
|
||||
Website Theme,Webseiten-Thema,
|
||||
Workflow Action,Workflow-Aktion,
|
||||
Workflow State,Workflow-Status,
|
||||
{0} is not running. Cannot trigger events for this Document,{0} läuft nicht. Ereignisse für dieses Dokument können nicht ausgelöst werden,
|
||||
|
||||
|
Can't render this file because it is too large.
|
Reference in New Issue
Block a user