Kısayollarınız\n"
#: erpnext/setup/workspace/home/home.json
#: erpnext/support/workspace/support/support.json
msgid "Your Shortcuts"
-msgstr "Kısayollarınız"
+msgstr "Kısayollar"
#: erpnext/accounts/doctype/payment_request/payment_request.py:998
msgid "Grand Total: {0}"
@@ -3903,7 +3903,7 @@ msgstr "Tüm Müşteri Adayları (Açık)"
#: erpnext/accounts/report/general_ledger/general_ledger.html:68
msgid "All Parties "
-msgstr ""
+msgstr "Tüm Partiler "
#. Option for the 'Send To' (Select) field in DocType 'SMS Center'
#: erpnext/selling/doctype/sms_center/sms_center.json
@@ -17641,7 +17641,7 @@ msgstr "Etki Alanı Ayarları"
#. Invoice'
#: erpnext/accounts/doctype/sales_invoice/sales_invoice.json
msgid "Don't Create Loyalty Points"
-msgstr ""
+msgstr "Sadakat Puanları Oluşturma"
#. Label of the dont_reserve_sales_order_qty_on_sales_return (Check) field in
#. DocType 'Selling Settings'
@@ -34467,7 +34467,7 @@ msgstr "Ana Depo"
#: erpnext/edi/doctype/code_list/code_list_import.py:39
msgid "Parsing Error"
-msgstr ""
+msgstr "Birleştirme Hatası"
#. Option for the 'Status' (Select) field in DocType 'Subcontracting Order'
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.json
@@ -39432,7 +39432,7 @@ msgstr "Yayınlanma Tarihi"
#. Label of the publisher (Data) field in DocType 'Code List'
#: erpnext/edi/doctype/code_list/code_list.json
msgid "Publisher"
-msgstr ""
+msgstr "Yayınlayan"
#. Label of the publisher_id (Data) field in DocType 'Code List'
#: erpnext/edi/doctype/code_list/code_list.json
@@ -40175,7 +40175,7 @@ msgstr "Miktar "
#: erpnext/selling/doctype/sales_order_item/sales_order_item.json
#: erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
msgid "Qty (Company)"
-msgstr ""
+msgstr "Miktar (Şirket)"
#. Label of the actual_qty (Float) field in DocType 'Sales Invoice Item'
#. Label of the actual_qty (Float) field in DocType 'Quotation Item'
@@ -40186,7 +40186,7 @@ msgstr ""
#: erpnext/selling/doctype/sales_order_item/sales_order_item.json
#: erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
msgid "Qty (Warehouse)"
-msgstr ""
+msgstr "Miktar (Depo)"
#. Label of the qty_after_transaction (Float) field in DocType 'Stock Ledger
#. Entry'
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 06e01c40f12..72b5395ce88 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -264,6 +264,24 @@ class BOM(WebsiteGenerator):
self.update_cost(update_parent=False, from_child_bom=True, update_hour_rate=False, save=False)
self.set_process_loss_qty()
self.validate_scrap_items()
+ self.set_default_uom()
+
+ def set_default_uom(self):
+ if not self.get("items"):
+ return
+
+ item_wise_uom = frappe._dict(
+ frappe.get_all(
+ "Item",
+ filters={"name": ("in", [item.item_code for item in self.items])},
+ fields=["name", "stock_uom"],
+ as_list=1,
+ )
+ )
+
+ for row in self.get("items"):
+ if row.stock_uom != item_wise_uom.get(row.item_code):
+ row.stock_uom = item_wise_uom.get(row.item_code)
def get_context(self, context):
context.parents = [{"name": "boms", "title": _("All BOMs")}]
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 88c4d4521b9..1f36e773c85 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -763,6 +763,26 @@ class TestBOM(IntegrationTestCase):
self.assertTrue("_Test RM Item 2 Fixed Asset Item" not in items)
self.assertTrue("_Test RM Item 3 Manufacture Item" in items)
+ def test_bom_raw_materials_stock_uom(self):
+ rm_item = make_item(
+ properties={"is_stock_item": 1, "valuation_rate": 1000.0, "stock_uom": "Nos"}
+ ).name
+ fg_item = make_item(properties={"is_stock_item": 1}).name
+
+ from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+ bom = make_bom(item=fg_item, raw_materials=[rm_item], do_not_submit=True)
+ for row in bom.items:
+ self.assertEqual(row.stock_uom, "Nos")
+
+ frappe.db.set_value("Item", rm_item, "stock_uom", "Kg")
+
+ bom.items[0].qty = 2
+ bom.save()
+
+ for row in bom.items:
+ self.assertEqual(row.stock_uom, "Kg")
+
def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index db0e97338e6..25b61e61497 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -243,7 +243,7 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "download_materials_required",
"fieldtype": "Button",
- "label": "Download Materials Request Plan"
+ "label": "Download Required Materials"
},
{
"fieldname": "get_items_for_mr",
@@ -398,7 +398,7 @@
"collapsible": 1,
"fieldname": "download_materials_request_plan_section_section",
"fieldtype": "Section Break",
- "label": "Download Materials Request Plan Section"
+ "label": "Preview Required Materials"
},
{
"default": "0",
@@ -439,7 +439,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2024-03-27 13:10:19.928403",
+ "modified": "2024-12-04 11:55:03.108971",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 3f82a75d302..265f99e47d3 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -44,9 +44,7 @@ class ProductionPlan(Document):
from erpnext.manufacturing.doctype.material_request_plan_item.material_request_plan_item import (
MaterialRequestPlanItem,
)
- from erpnext.manufacturing.doctype.production_plan_item.production_plan_item import (
- ProductionPlanItem,
- )
+ from erpnext.manufacturing.doctype.production_plan_item.production_plan_item import ProductionPlanItem
from erpnext.manufacturing.doctype.production_plan_item_reference.production_plan_item_reference import (
ProductionPlanItemReference,
)
@@ -1085,24 +1083,33 @@ def download_raw_materials(doc, warehouses=None):
frappe.flags.show_qty_in_stock_uom = 1
items = get_items_for_material_requests(doc, warehouses=warehouses, get_parent_warehouse_data=True)
+ duplicate_item_wh_list = frappe._dict()
+
for d in items:
- item_list.append(
- [
- d.get("item_code"),
- d.get("item_name"),
- d.get("description"),
- d.get("stock_uom"),
- d.get("warehouse"),
- d.get("required_bom_qty"),
- d.get("projected_qty"),
- d.get("actual_qty"),
- d.get("ordered_qty"),
- d.get("planned_qty"),
- d.get("reserved_qty_for_production"),
- d.get("safety_stock"),
- d.get("quantity"),
- ]
- )
+ key = (d.get("item_code"), d.get("warehouse"))
+ if key in duplicate_item_wh_list:
+ rm_data = duplicate_item_wh_list[key]
+ rm_data[12] += d.get("quantity")
+ continue
+
+ rm_data = [
+ d.get("item_code"),
+ d.get("item_name"),
+ d.get("description"),
+ d.get("stock_uom"),
+ d.get("warehouse"),
+ d.get("required_bom_qty"),
+ d.get("projected_qty"),
+ d.get("actual_qty"),
+ d.get("ordered_qty"),
+ d.get("planned_qty"),
+ d.get("reserved_qty_for_production"),
+ d.get("safety_stock"),
+ d.get("quantity"),
+ ]
+
+ duplicate_item_wh_list[key] = rm_data
+ item_list.append(rm_data)
if not doc.get("for_warehouse"):
row = {"item_code": d.get("item_code")}
diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js
index ef4595c1733..4c78d939ebc 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.js
+++ b/erpnext/projects/doctype/timesheet/timesheet.js
@@ -58,10 +58,10 @@ frappe.ui.form.on("Timesheet", {
}
if (frm.doc.docstatus < 1) {
- let button = "Start Timer";
+ let button = __("Start Timer");
$.each(frm.doc.time_logs || [], function (i, row) {
if (row.from_time <= frappe.datetime.now_datetime() && !row.completed) {
- button = "Resume Timer";
+ button = __("Resume Timer");
}
});
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index f94a2dd2cf6..dc1d30df3f9 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -448,6 +448,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
get_current_tax_amount(item, tax, item_tax_map) {
var tax_rate = this._get_tax_rate(tax, item_tax_map);
var current_tax_amount = 0.0;
+ var current_net_amount = 0.0;
// To set row_id by default as previous row.
if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
@@ -460,21 +461,27 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
}
}
if(tax.charge_type == "Actual") {
+ current_net_amount = item.net_amount
// distribute the tax amount proportionally to each item row
var actual = flt(tax.tax_amount, precision("tax_amount", tax));
current_tax_amount = this.frm.doc.net_total ?
((item.net_amount / this.frm.doc.net_total) * actual) : 0.0;
} else if(tax.charge_type == "On Net Total") {
+ if (tax.account_head in item_tax_map) {
+ current_net_amount = item.net_amount
+ };
current_tax_amount = (tax_rate / 100.0) * item.net_amount;
} else if(tax.charge_type == "On Previous Row Amount") {
+ current_net_amount = this.frm.doc["taxes"][cint(tax.row_id) - 1].tax_amount_for_current_item
current_tax_amount = (tax_rate / 100.0) *
this.frm.doc["taxes"][cint(tax.row_id) - 1].tax_amount_for_current_item;
-
} else if(tax.charge_type == "On Previous Row Total") {
+ current_net_amount = this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_for_current_item
current_tax_amount = (tax_rate / 100.0) *
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_for_current_item;
} else if (tax.charge_type == "On Item Quantity") {
+ // don't sum current net amount due to the field being a currency field
current_tax_amount = tax_rate * item.qty;
}
@@ -504,17 +511,16 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
item_wise_tax_amount += flt(tax_detail[key].tax_amount, precision("tax_amount", tax));
item_wise_net_amount += flt(tax_detail[key].net_amount, precision("net_amount", tax));
}
- } else {
- if (tax_detail && tax_detail[key])
- item_wise_tax_amount += tax_detail[key].tax_amount;
- item_wise_net_amount += tax_detail[key].net_amount;
+ } else if (tax_detail && tax_detail[key]) {
+ item_wise_tax_amount += tax_detail[key].tax_amount;
+ item_wise_net_amount += tax_detail[key].net_amount;
}
- tax_detail[key] = {
- tax_rate: tax_rate,
- tax_amount: flt(item_wise_tax_amount, precision("base_tax_amount", tax)),
- net_amount: flt(item_wise_net_amount, precision("base_net_amount", tax)),
- };
+ tax_detail[key] = {
+ tax_rate: tax_rate,
+ tax_amount: flt(item_wise_tax_amount, precision("base_tax_amount", tax)),
+ net_amount: flt(item_wise_net_amount, precision("base_net_amount", tax)),
+ };
}
round_off_totals(tax) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e4a264f77f2..911dad9e2d7 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -146,7 +146,7 @@ frappe.ui.form.on("Sales Order", {
target: frm,
setters: [
{
- label: "Supplier",
+ label: __("Supplier"),
fieldname: "supplier",
fieldtype: "Link",
options: "Supplier",
@@ -783,7 +783,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
target: me.frm,
setters: [
{
- label: "Customer",
+ label: __("Customer"),
fieldname: "party_name",
fieldtype: "Link",
options: "Customer",
@@ -830,7 +830,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
} else {
const fields = [
{
- label: "Items",
+ label: __("Items"),
fieldtype: "Table",
fieldname: "items",
description: __("Select BOM and Qty for Production"),
@@ -1191,7 +1191,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
{
fieldname: "items_for_po",
fieldtype: "Table",
- label: "Select Items",
+ label: __("Select Items"),
fields: [
{
fieldtype: "Data",
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 2becd9e9c19..8ae4e9339c4 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -30,7 +30,7 @@ erpnext.PointOfSale.Controller = class {
fieldname: "mode_of_payment",
fieldtype: "Link",
in_list_view: 1,
- label: "Mode of Payment",
+ label: __("Mode of Payment"),
options: "Mode of Payment",
reqd: 1,
},
@@ -38,7 +38,7 @@ erpnext.PointOfSale.Controller = class {
fieldname: "opening_amount",
fieldtype: "Currency",
in_list_view: 1,
- label: "Opening Amount",
+ label: __("Opening Amount"),
options: "company:company_currency",
change: function () {
dialog.fields_dict.balance_details.df.data.some((d) => {
@@ -87,7 +87,7 @@ erpnext.PointOfSale.Controller = class {
{
fieldname: "balance_details",
fieldtype: "Table",
- label: "Opening Balance Details",
+ label: __("Opening Balance Details"),
cannot_add_rows: false,
in_place_edit: true,
reqd: 1,
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 b808b4f8828..6342b237f6e 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -966,13 +966,15 @@ erpnext.PointOfSale.ItemCart = class {
if (!res.length) {
transaction_container.html(
- `No recent transactions found
`
+ `${__("No recent transactions found")}
`
);
return;
}
const elapsed_time = moment(res[0].posting_date + " " + res[0].posting_time).fromNow();
- this.$customer_section.find(".customer-desc").html(`Last transacted ${elapsed_time}`);
+ this.$customer_section
+ .find(".customer-desc")
+ .html(`${__("Last transacted")} ${__(elapsed_time)}`);
res.forEach((invoice) => {
const posting_datetime = moment(invoice.posting_date + " " + invoice.posting_time).format(
@@ -997,7 +999,7 @@ erpnext.PointOfSale.ItemCart = class {
- ${invoice.status}
+ ${__(invoice.status)}
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 c399005643c..4a2d8911d1a 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
@@ -46,7 +46,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
init_email_print_dialog() {
const email_dialog = new frappe.ui.Dialog({
- title: "Email Receipt",
+ title: __("Email Receipt"),
fields: [
{ fieldname: "email_id", fieldtype: "Data", options: "Email", label: "Email ID", reqd: 1 },
{ fieldname: "content", fieldtype: "Small Text", label: "Message (if any)" },
@@ -59,7 +59,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
this.email_dialog = email_dialog;
const print_dialog = new frappe.ui.Dialog({
- title: "Print Receipt",
+ title: __("Print Receipt"),
fields: [{ fieldname: "print", fieldtype: "Data", label: "Print Preview" }],
primary_action: () => {
this.print_receipt();
@@ -112,7 +112,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
get_discount_html(doc) {
if (doc.discount_amount) {
return `
-
Discount (${doc.additional_discount_percentage} %)
+
${__("Discount")} (${doc.additional_discount_percentage} %)
${format_currency(doc.discount_amount, doc.currency)}
`;
} else {
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 204f68320d0..a5957fd96e1 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -589,7 +589,7 @@ erpnext.PointOfSale.Payment = class {
const remaining = grand_total - doc.paid_amount;
const change = doc.change_amount || remaining <= 0 ? -1 * remaining : undefined;
const currency = doc.currency;
- const label = change ? __("Change") : __("To Be Paid");
+ const label = __("Change Amount");
this.$totals.html(
`
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
index 4f8a166932d..661605bdf5f 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
@@ -214,13 +214,10 @@ class InventoryDimension(Document):
dimension_fields = []
if self.apply_to_all_doctypes:
for doctype in get_inventory_documents():
- if field_exists(doctype[0], self.source_fieldname):
- continue
-
dimension_fields = self.get_dimension_fields(doctype[0])
self.add_transfer_field(doctype[0], dimension_fields)
custom_fields.setdefault(doctype[0], dimension_fields)
- elif not field_exists(self.document_type, self.source_fieldname):
+ else:
dimension_fields = self.get_dimension_fields()
self.add_transfer_field(self.document_type, dimension_fields)
@@ -239,8 +236,17 @@ class InventoryDimension(Document):
dimension_field["fieldname"] = self.target_fieldname
custom_fields["Stock Ledger Entry"] = dimension_field
+ filter_custom_fields = {}
if custom_fields:
- create_custom_fields(custom_fields)
+ for doctype, fields in custom_fields.items():
+ if isinstance(fields, dict):
+ fields = [fields]
+
+ for field in fields:
+ if not field_exists(doctype, field["fieldname"]):
+ filter_custom_fields.setdefault(doctype, []).append(field)
+
+ create_custom_fields(filter_custom_fields)
def add_transfer_field(self, doctype, dimension_fields):
if doctype not in [
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index feb4367aa08..c89032c608f 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -1663,6 +1663,46 @@ class TestStockEntry(IntegrationTestCase):
mr.cancel()
mr.delete()
+ def test_auto_reorder_level_with_lead_time_days(self):
+ from erpnext.stock.reorder_item import reorder_item
+
+ item_doc = make_item(
+ "Test Auto Reorder Item - 002",
+ properties={"stock_uom": "Kg", "purchase_uom": "Nos", "is_stock_item": 1, "lead_time_days": 2},
+ uoms=[{"uom": "Nos", "conversion_factor": 5}],
+ )
+
+ if not frappe.db.exists("Item Reorder", {"parent": item_doc.name}):
+ item_doc.append(
+ "reorder_levels",
+ {
+ "warehouse_reorder_level": 0,
+ "warehouse_reorder_qty": 10,
+ "warehouse": "_Test Warehouse - _TC",
+ "material_request_type": "Purchase",
+ },
+ )
+
+ item_doc.save(ignore_permissions=True)
+
+ frappe.db.set_single_value("Stock Settings", "auto_indent", 1)
+
+ mr_list = reorder_item()
+
+ frappe.db.set_single_value("Stock Settings", "auto_indent", 0)
+ mrs = frappe.get_all(
+ "Material Request Item",
+ fields=["schedule_date"],
+ filters={"item_code": item_doc.name, "uom": "Nos"},
+ )
+
+ for mri in mrs:
+ self.assertEqual(getdate(mri.schedule_date), getdate(add_days(today(), 2)))
+
+ for mr in mr_list:
+ mr.cancel()
+ mr.delete()
+
def test_use_serial_and_batch_fields(self):
item = make_item(
"Test Use Serial and Batch Item SN Item",
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 8809e0e3d25..f36795966d9 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -690,8 +690,8 @@ def is_within_valid_range(ctx: ItemDetailsCtx, tax) -> bool:
def get_item_tax_map(*, doc: str | dict | Document, tax_template: str | None = None, as_json=True):
doc = parse_json(doc)
item_tax_map = {}
- for t in (t for t in (doc.get("taxes") or []) if not t.set_by_item_tax_template):
- item_tax_map[t.account_head] = t.rate
+ for t in (t for t in (doc.get("taxes") or []) if not t.get("set_by_item_tax_template")):
+ item_tax_map[t.get("account_head")] = t.get("rate")
if tax_template:
template = frappe.get_cached_doc("Item Tax Template", tax_template)
diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py
index 4f66b342ffa..363b0e0bbe4 100644
--- a/erpnext/stock/reorder_item.py
+++ b/erpnext/stock/reorder_item.py
@@ -98,6 +98,7 @@ def _reorder_item():
"description": d.description,
"stock_uom": d.stock_uom,
"purchase_uom": d.purchase_uom,
+ "lead_time_days": d.lead_time_days,
}
),
)
@@ -129,6 +130,7 @@ def get_items_for_reorder() -> dict[str, list]:
item_table.brand,
item_table.variant_of,
item_table.has_variants,
+ item_table.lead_time_days,
)
.where(
(item_table.disabled == 0)