Compare commits

..

9 Commits

Author SHA1 Message Date
MochaMind
690a0da177 fix: Bosnian translations 2026-08-06 15:32:28 +05:30
MochaMind
5ae3a31fa7 fix: Croatian translations 2026-08-06 15:32:23 +05:30
MochaMind
401cd3da5e fix: Persian translations 2026-08-06 15:32:18 +05:30
MochaMind
0c4ad0a9e0 fix: Swedish translations 2026-08-06 15:32:07 +05:30
rohitwaghchaure
a49fcfe888 fix: purchase return of batchwise valuation batch valued at original receipt rate instead of batch avg rate (#57835)
* fix: use current batch avg rate for outward returns of batchwise valuation batches

* fix: honor zero batch average and avoid duplicate batch classification query
2026-08-06 15:21:44 +05:30
Diptanil Saha
12359c36bc Merge pull request #57825 from diptanilsaha/st/72599/arpbmd/pinv
refactor(accounts)!: rework Purchase Invoice hold actions and enforce them on Journal Entry
2026-08-06 13:11:51 +05:30
diptanilsaha
1a8d438b21 test(journal_entry): added test cases for blocked purchase invoices 2026-08-06 12:31:00 +05:30
diptanilsaha
cbafa16fbc fix(journal_entry): validate blocked purchase invoices 2026-08-06 11:56:58 +05:30
diptanilsaha
6c33ede45c refactor(purchase_invoice): expose invoice hold actions as document methods 2026-08-06 11:18:46 +05:30
13 changed files with 642 additions and 287 deletions

View File

@@ -184,6 +184,7 @@ class JournalEntryReferenceValidator:
continue
invoice = frappe.get_doc(reference_type, reference_name)
self._validate_invoice_outstanding(invoice, total, reference_type, reference_name)
self._validate_block_invoice(invoice)
def _validate_invoice_outstanding(self, invoice, total, reference_type, reference_name) -> None:
"""Payment booked against an invoice cannot exceed its outstanding amount."""
@@ -197,3 +198,15 @@ class JournalEntryReferenceValidator:
reference_type, reference_name, invoice.outstanding_amount
)
)
def _validate_block_invoice(self, invoice):
"""Payment cannnot be booked against blocked Purchase Invoices"""
if invoice.doctype != "Purchase Invoice":
return
if invoice.invoice_is_blocked():
frappe.throw(
_("{0} {1} is blocked and on hold until {2}.").format(
invoice.doctype, invoice.name, invoice.release_date
)
)

View File

@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.utils import flt, nowdate
from frappe.utils import add_days, flt, nowdate
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.accounts.doctype.journal_entry.journal_entry import StockAccountInvalidTransaction
@@ -748,6 +748,69 @@ class TestJournalEntry(ERPNextTestSuite):
self.assertEqual(jv.reference_types[invoice.name], "Sales Invoice")
self.assertEqual(jv.reference_accounts[invoice.name], "Debtors - _TC")
def make_jv_against_purchase_invoice(self, invoice, amount=100):
jv = make_journal_entry("Creditors - _TC", "_Test Cash - _TC", amount, save=False)
jv.accounts[0].party_type = "Supplier"
jv.accounts[0].party = invoice.supplier
jv.accounts[0].reference_type = "Purchase Invoice"
jv.accounts[0].reference_name = invoice.name
return jv
def test_jv_against_purchase_invoice_respects_hold_state(self):
"""Payment can be booked against a Purchase Invoice only while it is not on hold."""
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
release_date = add_days(nowdate(), 10)
def never_held():
return make_purchase_invoice()
def held_until_a_future_date():
invoice = make_purchase_invoice()
invoice.block_invoice(hold_comment="Waiting for the goods", release_date=release_date)
return invoice
def held_without_a_release_date():
invoice = make_purchase_invoice()
invoice.block_invoice(hold_comment="Under dispute")
return invoice
def held_until_a_date_that_has_passed():
invoice = held_until_a_future_date()
frappe.db.set_value("Purchase Invoice", invoice.name, "release_date", add_days(nowdate(), -1))
return invoice
def unblocked_again():
invoice = held_until_a_future_date()
invoice.unblock_invoice()
return invoice
for build_invoice in (held_until_a_future_date, held_without_a_release_date):
with self.subTest(build_invoice.__name__):
jv = self.make_jv_against_purchase_invoice(build_invoice())
self.assertRaisesRegex(frappe.ValidationError, "is blocked and on hold until", jv.insert)
for build_invoice in (never_held, held_until_a_date_that_has_passed, unblocked_again):
with self.subTest(build_invoice.__name__):
invoice = build_invoice()
jv = self.make_jv_against_purchase_invoice(invoice)
jv.insert()
self.assertEqual(jv.reference_types[invoice.name], "Purchase Invoice")
def test_jv_against_blocked_sales_invoice_reference_is_not_checked(self):
"""A Sales Invoice has no hold state, so the check must skip it rather than fail."""
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
invoice = create_sales_invoice(rate=500)
jv = make_journal_entry("_Test Cash - _TC", "Debtors - _TC", 100, save=False)
jv.accounts[1].party_type = "Customer"
jv.accounts[1].party = "_Test Customer"
jv.accounts[1].reference_type = "Sales Invoice"
jv.accounts[1].reference_name = invoice.name
jv.insert()
self.assertEqual(jv.reference_types[invoice.name], "Sales Invoice")
def test_get_balance_places_difference_on_blank_row(self):
"""Characterize: get_balance puts the unbalanced difference on an amountless row."""
jv = frappe.new_doc("Journal Entry")

View File

@@ -240,10 +240,8 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
unblock_invoice() {
const me = this;
frappe.call({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.unblock_invoice",
args: { name: me.frm.doc.name },
callback: (r) => me.frm.reload_doc(),
me.frm.call("unblock_invoice", null, () => {
me.frm.reload_doc();
});
}
@@ -294,15 +292,16 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
this.dialog.set_primary_action(__("Save"), function () {
const dialog_data = me.dialog.get_values();
frappe.call({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.block_invoice",
args: {
name: me.frm.doc.name,
me.frm.call(
"block_invoice",
{
hold_comment: dialog_data.hold_comment,
release_date: dialog_data.release_date,
},
callback: (r) => me.frm.reload_doc(),
});
() => {
me.frm.reload_doc();
}
);
me.dialog.hide();
});
@@ -341,10 +340,9 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
}
set_release_date(data) {
return frappe.call({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.change_release_date",
args: data,
callback: (r) => this.frm.reload_doc(),
const me = this;
return me.frm.call("change_release_date", { release_date: data.release_date }, () => {
me.frm.reload_doc();
});
}

View File

@@ -360,6 +360,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "eval:doc.on_hold",
"depends_on": "eval:doc.on_hold",
"fieldname": "sb_14",
"fieldtype": "Section Break",
"label": "Hold Invoice"
@@ -1694,7 +1695,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2026-07-12 23:54:21.263951",
"modified": "2026-08-05 15:40:16.519774",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -5,7 +5,7 @@
import frappe
from frappe import _, throw
from frappe.model.document import Document
from frappe.utils import cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
from frappe.utils import DateTimeLikeObject, cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
import erpnext
from erpnext.accounts.deferred_revenue import validate_service_stop_date
@@ -306,6 +306,9 @@ class PurchaseInvoice(BuyingController):
PurchaseTaxWithholding(self).on_validate()
self.set_percentage_received()
if self.on_hold:
self.validate_invoice_hold()
def set_percentage_received(self):
total_billed_qty = 0.0
total_received_qty = 0.0
@@ -317,6 +320,13 @@ class PurchaseInvoice(BuyingController):
if total_billed_qty and total_received_qty:
self.per_received = total_received_qty / total_billed_qty * 100
def validate_invoice_hold(self):
if self.is_return:
frappe.throw(_("Return Purchase Invoice cannot be held."))
if self.docstatus < 1:
frappe.throw(_("Purchase Invoice can be held after submitting."))
def validate_release_date(self):
if self.release_date and getdate(nowdate()) >= getdate(self.release_date):
frappe.throw(_("Release date must be in the future"))
@@ -820,14 +830,38 @@ class PurchaseInvoice(BuyingController):
def on_recurring(self, reference_doc, auto_repeat_doc):
self.due_date = None
def block_invoice(self, hold_comment=None, release_date=None):
self.db_set("on_hold", 1)
self.db_set("hold_comment", cstr(hold_comment))
@frappe.whitelist(methods=["POST"])
def block_invoice(self, hold_comment: str | None = None, release_date: DateTimeLikeObject | None = None):
self.check_permission("write")
self.on_hold = 1
self.release_date = release_date
self.validate_block_invoice()
self.db_set({"on_hold": 1, "hold_comment": cstr(hold_comment), "release_date": release_date})
@frappe.whitelist(methods=["POST"])
def unblock_invoice(self):
self.check_permission("write")
self.db_set({"on_hold": 0, "release_date": None})
@frappe.whitelist(methods=["POST"])
def change_release_date(self, release_date: DateTimeLikeObject | None = None):
self.check_permission("write")
if not self.on_hold:
frappe.throw(_("Invoice is not blocked. Block the invoice to change the release date."))
self.release_date = release_date
self.validate_block_invoice()
self.db_set("release_date", release_date)
def unblock_invoice(self):
self.db_set("on_hold", 0)
self.db_set("release_date", None)
def validate_block_invoice(self):
self.validate_invoice_hold()
if self.outstanding_amount <= 0:
frappe.throw(_("Purchase Invoice without any outstanding amount cannot be held."))
self.validate_release_date()
def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
@@ -925,24 +959,3 @@ def get_list_context(context=None):
@erpnext.allow_regional
def make_regional_gl_entries(gl_entries, doc):
return gl_entries
@frappe.whitelist()
def change_release_date(name: str, release_date: str | None = None):
pi = frappe.get_lazy_doc("Purchase Invoice", name)
pi.check_permission()
pi.db_set("release_date", release_date)
@frappe.whitelist()
def unblock_invoice(name: str):
if frappe.db.exists("Purchase Invoice", name):
pi = frappe.get_lazy_doc("Purchase Invoice", name)
pi.unblock_invoice()
@frappe.whitelist()
def block_invoice(name: str, release_date: str, hold_comment: str | None = None):
if frappe.db.exists("Purchase Invoice", name):
pi = frappe.get_lazy_doc("Purchase Invoice", name)
pi.block_invoice(hold_comment, release_date)

View File

@@ -278,14 +278,166 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
def test_purchase_invoice_explicit_block(self):
pi = make_purchase_invoice()
pi.block_invoice()
release_date = add_days(nowdate(), 10)
pi.block_invoice(hold_comment="Waiting for the goods", release_date=release_date)
self.assertEqual(pi.on_hold, 1)
on_hold, hold_comment, saved_release_date = frappe.db.get_value(
"Purchase Invoice", pi.name, ["on_hold", "hold_comment", "release_date"]
)
self.assertEqual(on_hold, 1)
self.assertEqual(hold_comment, "Waiting for the goods")
self.assertEqual(getdate(saved_release_date), getdate(release_date))
pi.unblock_invoice()
self.assertEqual(pi.on_hold, 0)
on_hold, saved_release_date = frappe.db.get_value(
"Purchase Invoice", pi.name, ["on_hold", "release_date"]
)
self.assertEqual(on_hold, 0)
self.assertIsNone(saved_release_date)
def test_purchase_invoice_cannot_be_held_before_submission(self):
pi = make_purchase_invoice(do_not_save=True)
pi.on_hold = 1
self.assertRaises(frappe.ValidationError, pi.save)
pi.on_hold = 0
pi.save()
pi.submit()
pi.block_invoice()
self.assertEqual(frappe.db.get_value("Purchase Invoice", pi.name, "on_hold"), 1)
def test_return_purchase_invoice_cannot_be_held(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
pi = make_purchase_invoice()
return_pi = make_return_doc(pi.doctype, pi.name)
return_pi.on_hold = 1
self.assertRaisesRegex(frappe.ValidationError, "cannot be held", return_pi.save)
return_pi.on_hold = 0
return_pi.save()
return_pi.submit()
self.assertRaisesRegex(frappe.ValidationError, "cannot be held", return_pi.block_invoice)
def test_return_purchase_invoice_is_not_affected_by_hold_validations(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
pi = make_purchase_invoice()
# a return has a negative outstanding amount, which must not be mistaken
# for an invalid hold on a document that was never held
return_pi = make_return_doc(pi.doctype, pi.name)
return_pi.save()
return_pi.submit()
self.assertEqual(return_pi.docstatus, 1)
self.assertEqual(return_pi.on_hold, 0)
self.assertLess(return_pi.outstanding_amount, 0)
def test_settled_purchase_invoice_cannot_be_held(self):
pi = make_purchase_invoice()
pe = get_payment_entry("Purchase Invoice", dn=pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "1"
pe.reference_date = nowdate()
pe.save()
pe.submit()
pi.reload()
self.assertEqual(pi.outstanding_amount, 0)
self.assertRaises(frappe.ValidationError, pi.block_invoice)
self.assertEqual(frappe.db.get_value("Purchase Invoice", pi.name, "on_hold"), 0)
def test_release_date_of_held_invoice_must_be_in_future(self):
pi = make_purchase_invoice()
self.assertRaises(frappe.ValidationError, pi.block_invoice, "Hold", add_days(nowdate(), -1))
self.assertRaises(frappe.ValidationError, pi.block_invoice, "Hold", nowdate())
def test_rejected_hold_does_not_partially_update_invoice(self):
pi = make_purchase_invoice()
self.assertRaises(frappe.ValidationError, pi.block_invoice, "Hold", add_days(nowdate(), -1))
pi.reload()
self.assertEqual(pi.on_hold, 0)
self.assertIsNone(pi.release_date)
def test_change_release_date_of_held_invoice(self):
pi = make_purchase_invoice()
pi.block_invoice(hold_comment="Hold", release_date=add_days(nowdate(), 10))
new_release_date = add_days(nowdate(), 20)
pi.change_release_date(new_release_date)
self.assertEqual(
getdate(frappe.db.get_value("Purchase Invoice", pi.name, "release_date")),
getdate(new_release_date),
)
self.assertRaises(frappe.ValidationError, pi.change_release_date, add_days(nowdate(), -1))
def test_release_date_cannot_be_changed_on_an_invoice_that_is_not_held(self):
pi = make_purchase_invoice()
self.assertRaisesRegex(
frappe.ValidationError,
"Invoice is not blocked",
pi.change_release_date,
add_days(nowdate(), 10),
)
self.assertIsNone(frappe.db.get_value("Purchase Invoice", pi.name, "release_date"))
def test_hold_methods_are_whitelisted_document_methods(self):
import erpnext.accounts.doctype.purchase_invoice.purchase_invoice as purchase_invoice_module
pi = frappe.new_doc("Purchase Invoice")
for method in ("block_invoice", "unblock_invoice", "change_release_date"):
# raises if the method is not whitelisted for client side calls
pi.is_whitelisted(method)
self.assertFalse(
hasattr(purchase_invoice_module, method),
f"{method} should only be exposed as a document method",
)
def test_hold_methods_require_write_permission(self):
pi = make_purchase_invoice()
user = "test_pi_hold_permission@example.com"
if not frappe.db.exists("User", user):
frappe.get_doc(
{
"doctype": "User",
"email": user,
"first_name": "Test PI Hold",
"roles": [{"role": "Employee"}],
}
).insert(ignore_permissions=True)
frappe.set_user(user)
try:
self.assertRaises(frappe.PermissionError, pi.block_invoice)
self.assertRaises(frappe.PermissionError, pi.unblock_invoice)
self.assertRaises(frappe.PermissionError, pi.change_release_date, add_days(nowdate(), 10))
finally:
frappe.set_user("Administrator")
self.assertEqual(frappe.db.get_value("Purchase Invoice", pi.name, "on_hold"), 0)
def test_gl_entries_with_perpetual_inventory_against_pr(self):
pr = make_purchase_receipt(
company="_Test Company with perpetual inventory",

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: hello@frappe.io\n"
"POT-Creation-Date: 2026-08-02 10:09+0000\n"
"PO-Revision-Date: 2026-08-05 10:02\n"
"PO-Revision-Date: 2026-08-06 10:02\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Bosnian\n"
"MIME-Version: 1.0\n"
@@ -789,9 +789,9 @@ msgstr "<h4>Primjer Predloška Ugovora</h4>\n\n"
"-Važi do: {{ end_date }}\n"
"</pre>\n\n"
"<h4>Kako dobiti imena polja</h4>\n\n"
"<p>Nazivi polja koje možete koristiti u svom predlošku ugovora su polja u ugovoru za koje izradi predložak. Možete saznati polja bilo kojeg dokumenta putem Podešavanja &gt; Prilagodi prikaz obrasca i odabir vrste dokumenta (npr. Ugovor)</p>\n\n"
"<p>Nazivi polja koje možete koristiti u svom predlošku ugovora su polja u ugovoru za koje izradi predložak. Možete saznati polja bilo kojeg dokumenta putem Podešavanja &gt; Prilagodi prikaz obrasca i odabir tipa dokumenta (npr. Ugovor)</p>\n\n"
"<h4>Predložak</h4>\n\n"
"<p>Predložci se kompajliraju koristeći Jinja Templating Language. Da saznate više o Jinji, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">pročitajte ovu dokumentaciju.</a></p>"
"<p>Predložci se kompajliraju koristeći Jinja Templating Language. Da saznate više o Jinji, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">pročitaj ovu dokumentaciju.</a></p>"
#. Content of the 'Terms and Conditions Help' (HTML) field in DocType 'Terms
#. and Conditions'
@@ -2926,11 +2926,11 @@ msgstr "Dodaj Bilješku"
#: banking/src/components/features/BankReconciliation/RecordPaymentModalContent.tsx:879
msgid "Add a charge to the payment entry with the difference amount"
msgstr "Dodajte naplatu u unos plaćanja s iznosom razlike"
msgstr "Dodaj naplatu u unos plaćanja s iznosom razlike"
#: banking/src/components/features/BankReconciliation/RecordPaymentModalContent.tsx:863
msgid "Add a charge to the payment entry with the unallocated amount"
msgstr "Dodajte naplatu u unos plaćanja s nedodjeljnim iznosom"
msgstr "Dodaj naplatu u unos plaćanja s nedodjeljnim iznosom"
#: banking/src/components/features/BankReconciliation/BankEntryModalContent.tsx:776
msgid "Add a row with the difference amount"
@@ -2942,7 +2942,7 @@ msgstr "Dodaj sve račune na koje želite podijeliti transakciju."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:92
msgid "Add atleast one voucher to repost."
msgstr "Dodajte barem jedan verifikat za ponovno knjiženje."
msgstr "Dodaj barem jedan verifikat za ponovno knjiženje."
#: erpnext/www/book_appointment/index.html:42
msgid "Add details"
@@ -3405,7 +3405,7 @@ msgstr "Adresa & Kontakt"
#: erpnext/accounts/custom/address.py:35
msgid "Address needs to be linked to a Company. Please add a row for Company in the Links table."
msgstr "Adresa mora biti povezana s firmom. Dodajte red za firmu u tabeli Veze."
msgstr "Adresa mora biti povezana s firmom. Dodaj red za firmu u tabeli Veze."
#. Description of the 'Determine Address Tax Category from' (Select) field in
#. DocType 'Accounts Settings'
@@ -3966,7 +3966,7 @@ msgstr "Sve Prodajno Osoblje"
#. Description of a DocType
#: erpnext/setup/doctype/sales_person/sales_person.json
msgid "All Sales Transactions can be tagged against multiple Sales Persons so that you can set and monitor targets."
msgstr "Sve prodajne transakcije mogu se označiti naspram više prodajnih osoba kako biste mogli postaviti i nadzirati ciljeve."
msgstr "Sve prodajne transakcije mogu se odabrati naspram više prodajnih osoba kako biste mogli postaviti i nadzirati ciljeve."
#. Option for the 'Send To' (Select) field in DocType 'SMS Center'
#: erpnext/selling/doctype/sms_center/sms_center.json
@@ -4055,7 +4055,7 @@ msgstr "Sve odabrani artikli su već preneseni na ovu listu odabira"
#. in DocType 'CRM Settings'
#: erpnext/crm/doctype/crm_settings/crm_settings.json
msgid "All the Comments and Emails will be copied from one document to another newly created document(Lead -> Opportunity -> Quotation) throughout the CRM documents."
msgstr "Svi komentari i e-pošta kopirat će se iz jednog dokumenta u drugi novostvoreni dokument (Potencijalni Klijent -> Prilika-> Ponuda) kroz dokumente Prodajne Podrške."
msgstr "Svi komentari i e-pošta kopirat će se iz jednog dokumenta u drugi novoizrađeni dokument (Potencijalni Klijent -> Prilika-> Ponuda) kroz dokumente Prodajne Podrške."
#: erpnext/selling/page/point_of_sale/pos_past_order_summary.js:204
msgid "All the items have already been returned."
@@ -5598,7 +5598,7 @@ msgstr "Termin se može zakazati samo do {0} dana unaprijed."
#: erpnext/crm/doctype/appointment/appointment.py:79
msgid "Appointment cannot be scheduled for a past time."
msgstr "Termin se ne može zakazati za prošlu vrijeme."
msgstr "Termin se ne može zakazati za prošlo vrijeme."
#: erpnext/crm/doctype/appointment/appointment.py:98
msgid "Appointment cannot be scheduled on a holiday."
@@ -5664,11 +5664,11 @@ msgstr "Jeste li sigurni da želite izbrisati sve demo podatke?"
#: erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js:51
#: erpnext/stock/report/stock_ledger_variance/stock_ledger_variance.js:100
msgid "Are you sure you want to create Reposting Entries?"
msgstr "Jeste li sigurni da želite stvoriti ponovno knjiženje unosa?"
msgstr "Jeste li sigurni da želite izraditi ponovno knjiženje unosa?"
#: erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.js:66
msgid "Are you sure you want to create a Reposting Entry?"
msgstr "Jeste li sigurni da želite stvoriti ponovno knjiženje unosa?"
msgstr "Jeste li sigurni da želite izraditi ponovno knjiženje unosa?"
#: erpnext/public/js/bom_configurator/bom_configurator.bundle.js:499
msgid "Are you sure you want to delete this Item?"
@@ -6455,7 +6455,7 @@ msgstr "Red {0}: Serijski Broj je obavezan za Artikal {1}"
#: erpnext/stock/services/serial_batch_bundle_service.py:504
msgid "At row {0}: Serial and Batch Bundle {1} has already been created. Please remove the values from the serial no or batch no fields."
msgstr "U Redu {0}: Serijski i Šaržni Paket {1} je već stvoren. Uklonite vrijednosti iz polja za serijski ili šaržni broj."
msgstr "U Redu {0}: Serijski i Šaržni Paket {1} je već izrađen. Uklonite vrijednosti iz polja za serijski ili šaržni broj."
#: erpnext/manufacturing/doctype/bom_creator/bom_creator.py:123
msgid "At row {0}: set Parent Row No for item {1}"
@@ -6729,7 +6729,7 @@ msgstr "Automatska izrada Podizvođačkom Naloga"
#. Label of the auto_create_assets (Check) field in DocType 'Item'
#: erpnext/stock/doctype/item/item.json
msgid "Auto create assets on purchase"
msgstr "Automatski stvori sredstava pri nabavi"
msgstr "Automatski izradi sredstava pri nabavi"
#. Label of the auto_insert_price_list_rate_if_missing (Check) field in DocType
#. 'Stock Settings'
@@ -6796,7 +6796,7 @@ msgstr "Automatski Izradi Novi Šaržu"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Automatically add Taxes and Charges from Item Tax Template"
msgstr "Automatski dodajte PDV i Naknade iz Predloška za PDV na Artikal"
msgstr "Automatski dodaj PDV i Naknade iz Predloška za PDV na Artikal"
#. Label of the add_taxes_from_taxes_and_charges_template (Check) field in
#. DocType 'Accounts Settings'
@@ -7013,7 +7013,7 @@ msgstr "Prosječna Cjena"
#. Label of the avg_response_time (Duration) field in DocType 'Issue'
#: erpnext/support/doctype/issue/issue.json
msgid "Average Response Time"
msgstr "Prosječno Vreme Odziva"
msgstr "Prosječno Vreme Odgovora"
#. Description of the 'Lead Time in days' (Int) field in DocType 'Item'
#: erpnext/stock/doctype/item/item.json
@@ -7770,7 +7770,7 @@ msgstr "Bankovni Nacrt"
#: banking/src/components/features/BankReconciliation/BankEntryModalContent.tsx:98
msgid "Bank Entries Created"
msgstr "Bankovni Unosi Stvoreni"
msgstr "Bankovni Unosi Izrađeni"
#. Option for the 'Classify As' (Select) field in DocType 'Bank Transaction
#. Rule'
@@ -7792,7 +7792,7 @@ msgstr "Bankovni Unos"
#: banking/src/components/features/BankReconciliation/BankEntryModalContent.tsx:295
msgid "Bank Entry Created"
msgstr "Bankovni Unos Stvoren"
msgstr "Bankovni Unos Izrađen"
#. Label of the bank_entry_type (Select) field in DocType 'Bank Transaction
#. Rule'
@@ -8362,12 +8362,12 @@ msgstr "Šarža nije izrađena za artikal {0} jer nema Broj Šarže."
#. 'Item'
#: erpnext/stock/doctype/item/item.json
msgid "Batch number will be auto-created in format AAAA.00001 if not specified in transactions. Leave blank to always enter batch numbers manually."
msgstr "Broj šarže bit će automatski stvoren u formatu AAAA.00001 ako nije naveden u transakcijama. Ostavite prazno da biste uvijek ručno unosili brojeve šarže."
msgstr "Broj šarže bit će automatski izrađen u formatu AAAA.00001 ako nije naveden u transakcijama. Ostavite prazno da biste uvijek ručno unosili brojeve šarže."
#. Description of the 'Has Expiry Date' (Check) field in DocType 'Item'
#: erpnext/stock/doctype/item/item.json
msgid "Batch number will be created based on expiry date. Expiry dates can be set in the Batch master."
msgstr "Broj šarže bit će stvoren na temelju datuma isteka. Datumi isteka mogu se postaviti u Postavkama Šarže."
msgstr "Broj šarže bit će izrađen na temelju datuma isteka. Datumi isteka mogu se postaviti u Postavkama Šarže."
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py:384
msgid "Batch {0} and Warehouse"
@@ -9949,7 +9949,7 @@ msgstr "Nije moguće izraditi knjigovodstvene unose naspram onemogućenih račun
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py:146
msgid "Cannot create more Subcontracting Orders against the Purchase Order {0}."
msgstr "Ne može se stvoriti više Podugovornih Naloga na osnovu Naloga Nabave {0}."
msgstr "Ne može se izraditi više Podugovornih Naloga na osnovu Naloga Nabave {0}."
#: erpnext/controllers/sales_and_purchase_return.py:444
msgid "Cannot create return for consolidated invoice {0}."
@@ -10998,7 +10998,7 @@ msgstr "Zatvorite Predmet nakon (dana)"
#: erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js:69
msgid "Close Loan"
msgstr "Zatvori Zajam"
msgstr "Zatvori Kredit"
#. Label of the close_opportunity_after_days (Int) field in DocType 'CRM
#. Settings'
@@ -12182,7 +12182,7 @@ msgstr "Proizvedena Količina"
#: erpnext/manufacturing/doctype/job_card/job_card.py:1737
msgid "Completed Quantity ({0}), Pending Quantity ({1}) and Process Loss Quantity ({2}) must add up to the Qty to Manufacture ({3})."
msgstr "Izvršena Količina ({0}), Količina na Čekanju ({1}) i Količina Gubitka u Procesu ({2}) moraju se zbrajati do Količine za Proizvodnju ({3})."
msgstr "Završena Količina ({0}), Količina na Čekanju ({1}) i Količina Gubitka u Procesu ({2}) moraju se zbrajati do Količine za Proizvodnju ({3})."
#: erpnext/manufacturing/doctype/job_card/job_card.js:280
#: erpnext/public/js/shop_floor/shop_floor.js:825
@@ -14068,7 +14068,7 @@ msgstr "Stvarajednu grupisanu imovinu umjesto pojedinačnih kada se nabavlja na
#. 'Item'
#: erpnext/stock/doctype/item/item.json
msgid "Creates an Item Price automatically when the item is saved"
msgstr "Automatski stvori cjenu artikla kada se artikal spremi"
msgstr "Automatski izradi cjenu artikla kada se artikal spremi"
#: erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js:140
msgid "Creating Accounts..."
@@ -17662,7 +17662,7 @@ msgstr "Rastavljena Količina"
#: erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js:64
msgid "Disburse Loan"
msgstr "Isplati Zajam"
msgstr "Isplati Kredit"
#. Option for the 'Status' (Select) field in DocType 'Invoice Discounting'
#: erpnext/accounts/doctype/invoice_discounting/invoice_discounting.json
@@ -21632,7 +21632,7 @@ msgstr "Za individualnog Dobavljača"
#: erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py:379
msgid "For item <b>{0}</b>, only <b>{1}</b> assets have been created or linked to <b>{2}</b>. Please create or link <b>{3}</b> more assets with the respective document."
msgstr "Za artikal <b>{0}</b>, samo <b>{1}</b> imovina je stvorena ili povezana s <b>{2}</b>. Stvori ili poveži još <b>{3}</b> imovine s odgovarajućim dokumentom."
msgstr "Za artikal <b>{0}</b>, samo <b>{1}</b> imovina je izrađena ili povezana s <b>{2}</b>. Izradi ili poveži još <b>{3}</b> imovine s odgovarajućim dokumentom."
#: erpnext/controllers/status_updater.py:303
msgid "For item {0}, rate must be a positive number. To allow negative rates, enable {1} in {2}"
@@ -21646,7 +21646,7 @@ msgstr "Za stare serijske brojeve, nemojte preuzimati nabvnu cjenu iz serijskog
#: erpnext/manufacturing/doctype/bom/bom.py:400
msgid "For operation {0} at row {1}, please add raw materials or set a BOM against it."
msgstr "Za radnju {0} u redu {1}, molimo dodajte sirovine ili postavi Sastavnicu naspram nje."
msgstr "Za radnju {0} u redu {1}, molimo dodaj sirovine ili postavi Sastavnicu naspram nje."
#: erpnext/manufacturing/doctype/work_order/mapper.py:383
msgid "For operation {0}: Quantity ({1}) can not be greater than pending quantity ({2})"
@@ -23856,7 +23856,7 @@ msgstr "Ako je <b>Omogućeno</b> - Usaglašavanje se dešava na <b>Datum Knjiže
#: erpnext/accounts/doctype/loyalty_program/loyalty_program.js:34
msgid "If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)"
msgstr "Ako je automatska registracija označena, tada će klijenti biti automatski povezani sa dotičnim Programom Lojalnosti (prilikom spremanja)"
msgstr "Ako je automatska registracija odabrana, tada će klijenti biti automatski povezani sa dotičnim Programom Lojalnosti (prilikom spremanja)"
#. Description of the 'Cost Center' (Link) field in DocType 'Journal Entry
#. Account'
@@ -24118,7 +24118,7 @@ msgstr "Ako je omogućeno, sistem će dozvoliti korisnicima da uređuju sirovine
#. in DocType 'Buying Settings'
#: erpnext/buying/doctype/buying_settings/buying_settings.json
msgid "If enabled, the system will generate an accounting entry for materials rejected in the Purchase Receipt."
msgstr "Ako je omogućeno, sistem će stvoriti knjigovodstveni unos za odbijene materijale u Nabavnom Računu."
msgstr "Ako je omogućeno, sistem će izraditi knjigovodstveni unos za odbijene materijale u Nabavnom Računu."
#. Description of the 'Enable Item-wise Inventory Account' (Check) field in
#. DocType 'Company'
@@ -28000,7 +28000,7 @@ msgstr "Cjena Artikla se pojavljuje više puta na osnovu Cjenovnika, Dobavljača
#: erpnext/stock/doctype/item/item.py:186
msgid "Item Price created at rate {0}"
msgstr "Cjena Artikla stvorena po stopi {0}"
msgstr "Cjena Artikla izrađena po stopi {0}"
#: erpnext/stock/get_item_details.py:1160
msgid "Item Price updated for {0} in Price List {1}"
@@ -28341,7 +28341,7 @@ msgstr "Artikal Radnji"
#: erpnext/stock/doctype/stock_entry/stock_entry.py:676
msgid "Item rate has been updated to zero as Allow Zero Valuation Rate is checked for item {0}"
msgstr "Cjena Artikla je ažurirana na nulu jer je Dozvoli Nultu Stopu Vrednovanja označena za artikal {0}"
msgstr "Cjena Artikla je ažurirana na nulu jer je Dozvoli Nultu Stopu Vrednovanja odabrana za artikal {0}"
#: erpnext/stock/doctype/material_request/material_request.py:231
msgid "Item rates have been updated based on the selected Buying Price List {0}"
@@ -30955,7 +30955,7 @@ msgstr "Uporedi i Uskladi"
#: banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx:62
msgid "Match or Create"
msgstr "Uskladi ili Stvori"
msgstr "Uskladi ili Izradi"
#. Label of the transfer_match_days (Int) field in DocType 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -32253,7 +32253,7 @@ msgstr "Za datum {0} postoji više fiskalnih godina. Postavi poduzeće u Fiskaln
#: erpnext/stock/doctype/stock_entry/stock_entry.py:957
msgid "Multiple items cannot be marked as finished item"
msgstr "Više artikala se ne mogu označiti kao gotov proizvod"
msgstr "Više artikala se ne mogu odabrati kao gotov proizvod"
#: erpnext/setup/setup_wizard/data/industry_type.txt:33
msgid "Music"
@@ -32900,7 +32900,7 @@ msgstr "Nove fakture će se izraditi prema rasporedu čak i ako su trenutne fakt
#: erpnext/support/doctype/issue/issue.js:126
msgid "New issue created: {0}"
msgstr "Novi zahtjev stvoren: {0}"
msgstr "Novi zahtjev izrađen: {0}"
#: erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js:261
msgid "New release date should be in the future"
@@ -35664,7 +35664,7 @@ msgstr "Kasa Faktura nije podnešena"
#: erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py:130
msgid "POS Invoice isn't created by user {0}"
msgstr "Korisnik {0} nije stvorio Kasa Fakturu"
msgstr "Korisnik {0} nije izradio Kasa Fakturu"
#: erpnext/accounts/doctype/pos_invoice/pos_invoice.py:208
msgid "POS Invoice should have the field {0} checked."
@@ -37339,7 +37339,7 @@ msgstr "Platni Zahtjevi ne mogu se izraditi naspram: {0}"
#. in DocType 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Payment Requests made from Sales / Purchase Invoice will be put in Draft explicitly"
msgstr "Zahtjevi Plaćanja stvoren iz Prodajne / Nabavne Fakture bit će eksplicitno stavljeni u Nacrt"
msgstr "Zahtjevi Plaćanja izrađen iz Prodajne / Nabavne Fakture bit će eksplicitno stavljeni u Nacrt"
#. Label of the payment_schedule (Data) field in DocType 'Overdue Payment'
#. Label of the payment_schedule (Link) field in DocType 'Payment Reference'
@@ -47634,7 +47634,7 @@ msgstr "Red #{0}: Šarža {1} je već istekla."
#: erpnext/stock/doctype/stock_entry/stock_entry.py:417
msgid "Row #{0}: The job card item reference is missing. Kindly create the stock entry from the job card. If you have added the row manually then you won't be able to add job card item reference."
msgstr "Red #{0}: Nedostaje referenca artikla na radnoj kartici. Stvori unos zaliha iz radne kartice. Ako ste red dodali ručno, nećete moći dodati referencu artikla na radnu karticu."
msgstr "Red #{0}: Nedostaje referenca artikla na radnoj kartici. Izradi unos zaliha iz radne kartice. Ako ste red dodali ručno, nećete moći dodati referencu artikla na radnu karticu."
#: erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py:103
msgid "Row #{0}: The original Invoice {1} of return invoice {2} is not consolidated."
@@ -50129,7 +50129,7 @@ msgstr "Odabrani Početni Unos Kase bi trebao biti otvoren."
#: erpnext/accounts/doctype/sales_invoice/mapper.py:158
msgid "Selected Price List should have buying and selling fields checked."
msgstr "Odabrani Cjenovnik treba da ima označena polja za Nabavu i Prodaju."
msgstr "Odabrani Cjenovnik treba da ima odabrana polja za Nabavu i Prodaju."
#: erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py:123
msgid "Selected Print Format does not exist."
@@ -53118,7 +53118,7 @@ msgstr "Unos Zaliha {0} je izrađen"
#: erpnext/manufacturing/doctype/job_card/job_card.py:1785
msgid "Stock Entry {0} has been created"
msgstr "Unos Zaliha {0} je stvoren"
msgstr "Unos Zaliha {0} je izrađen"
#: erpnext/accounts/doctype/journal_entry/journal_entry.py:997
msgid "Stock Entry {0} is not submitted"
@@ -56619,7 +56619,7 @@ msgstr "Faktura nije u potpunosti dodijeljena jer postoji razlika od {0}."
#: erpnext/controllers/buying_controller.py:1263
msgid "The item {item} is not marked as {type_of} item. You can enable it as {type_of} item from its Item master."
msgstr "Artikal {item} nije označen kao {type_of} artikal. Možete ga omogućiti kao {type_of} Artikal u Postavkama Artikla."
msgstr "Artikal {item} nije odabran kao {type_of} artikal. Možete ga omogućiti kao {type_of} Artikal u Postavkama Artikla."
#: erpnext/stock/doctype/item/item.py:682
msgid "The items {0} and {1} are present in the following {2} :"
@@ -56627,7 +56627,7 @@ msgstr "Artikli {0} i {1} se nalaze u sljedećem {2} :"
#: erpnext/controllers/buying_controller.py:1256
msgid "The items {items} are not marked as {type_of} item. You can enable them as {type_of} item from their Item masters."
msgstr "Artikli {items} nisu označeni kao {type_of} artikli. Možete ih omogućiti kao {type_of} artikle u Postavkama Artikala."
msgstr "Artikli {items} nisu odabrani kao {type_of} artikli. Možete ih omogućiti kao {type_of} artikle u Postavkama Artikala."
#: erpnext/manufacturing/doctype/workstation/workstation.py:527
msgid "The job card {0} is in {1} state and you cannot complete it."
@@ -57098,7 +57098,7 @@ msgstr "Ovo omogućava izradu prodajnih naloga iz ponuda kojima je istekao rok v
#: erpnext/assets/doctype/asset/asset.py:438
msgid "This asset category is marked as non-depreciable. Please disable depreciation calculation or choose a different category."
msgstr "Ova kategorija imovine je označena kao neamortizujuća. Onemogući obračun amortizacije ili odaberi drugu kategoriju."
msgstr "Ova kategorija imovine je odabrana kao neamortizujuća. Onemogući obračun amortizacije ili odaberi drugu kategoriju."
#. Description of the 'Allow negative stock' (Check) field in DocType 'Stock
#. Settings'
@@ -57288,7 +57288,7 @@ msgstr "Ova radnja zahtijeva Kontrolu Kvalitete, ali nije konfiguriran predloža
#: erpnext/stock/doctype/delivery_note/delivery_note.js:509
msgid "This option can be checked to edit the 'Posting Date' and 'Posting Time' fields."
msgstr "Ova opcija se može označiti za uređivanje polja 'Datum Knjiženja' i 'Vrijeme Knjiženja'."
msgstr "Ova opcija se može odabrati za uređivanje polja 'Datum Knjiženja' i 'Vrijeme Knjiženja'."
#. Description of the 'Raise Material Request when stock reaches re-order
#. level' (Check) field in DocType 'Stock Settings'
@@ -59238,7 +59238,7 @@ msgstr "Transakcije naspram Poduzeća već postoje! Kontni Plan se može uvesti
#. 'Customer'
#: erpnext/selling/doctype/customer/customer.json
msgid "Transactions are blocked when the outstanding balance exceeds the credit limit. When Restrict Customer Over Billing is enabled, new invoices are also blocked when the customer's overdue amount exceeds the Overdue Limit."
msgstr "Transakcije se blokiraju kada preostali dug premaši kreditni limit. Kada je omogućena opcija Ograniči Prekomjerno Fakturisanja Klijenta, nove fakture se također blokiraju kada iznos dospjelih obaveza klijenta premaši granicu za dospjele obaveze."
msgstr "Transakcije se blokiraju kada preostali dug premaši kreditnu granicu. Kada je omogućena opcija Ograniči Prekomjerno Fakturisanja Klijenta, nove fakture se također blokiraju kada iznos dospjelih obaveza klijenta premaši granicu za dospjele obaveze."
#: banking/src/components/features/BankStatementImporter/CSV/StatementDetails.tsx:239
msgid "Transactions to be imported into the system"
@@ -61129,11 +61129,11 @@ msgstr "Stopa Vrednovanja artikla prema Prodajnoj Fakturi (samo za interne trans
#: erpnext/accounts/doctype/payment_entry/payment_entry.py:2010
#: erpnext/accounts/services/taxes.py:322
msgid "Valuation type charges can not be marked as Inclusive"
msgstr "Naknade za tip vrijednovanja ne mogu biti označene kao Inkluzivne"
msgstr "Naknade za tip vrijednovanja ne mogu biti odabrane kao Inkluzivne"
#: erpnext/public/js/controllers/accounts.js:228
msgid "Valuation type charges cannot be marked as Inclusive"
msgstr "Naknade tipa procjene vrijednosti ne mogu biti označene kao uključene."
msgstr "Naknade tipa procjene vrijednosti ne mogu biti odabrane kao uključene."
#: erpnext/stock/report/stock_ledger_variance/stock_ledger_variance.js:58
msgid "Value (G - D)"
@@ -62118,13 +62118,13 @@ msgstr "Upozori pri novim Zahtjevima za Ponudu"
#. in DocType 'Selling Settings'
#: erpnext/selling/doctype/selling_settings/selling_settings.json
msgid "Warn or stop if Item rate is changed in Delivery Notes and Sales Invoices generated from a Sales Order."
msgstr "Upozori ili zaustavi ako se cjena artikla promijeni u Otpremnicama i Prodajnim Fakturama stvorenih iz Prodajnog Naloga."
msgstr "Upozori ili zaustavi ako se cjena artikla promijeni u Otpremnicama i Prodajnim Fakturama izrađenih iz Prodajnog Naloga."
#. Description of the 'Maintain same rate throughout the purchase cycle'
#. (Check) field in DocType 'Buying Settings'
#: erpnext/buying/doctype/buying_settings/buying_settings.json
msgid "Warn or stop if Item rate is changed in Purchase Invoice or Purchase Receipt generated from a Purchase Order."
msgstr "Upozori ili zaustavi ako se cjena artikla promijeni u fakturi ili potvrdi o nabavi stvorenoj iz naloga nabave."
msgstr "Upozori ili zaustavi ako se cjena artikla promijeni u fakturi ili potvrdi o nabavi izrađenoj iz naloga nabave."
#: erpnext/projects/doctype/timesheet_detail/timesheet_detail.py:134
msgid "Warning - Row {0}: Billing Hours are more than Actual Hours"
@@ -64185,7 +64185,7 @@ msgstr "{0} mora biti negativan u povratnom dokumentu"
#: erpnext/accounts/doctype/sales_invoice/services/inter_company.py:60
msgid "{0} not allowed to transact with {1}. Please change the Company or add the Company in the 'Allowed To Transact With'-Section in the Customer record."
msgstr "{0} nije dozvoljeno obavljati transakcije sa {1}. Promijeni poduzeće ili dodaj poduzeće u sekciju 'Dozvoljena Transakcija s' u zapisu klijenata."
msgstr "{0} nije dozvoljeno obavljati transakcije sa {1}. Promijeni poduzeće ili dodaj poduzeće u odjeljak 'Dozvoljena Transakcija s' u zapisu klijenata."
#: erpnext/manufacturing/doctype/bom/services/costing.py:63
msgid "{0} not found for item {1}"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: hello@frappe.io\n"
"POT-Creation-Date: 2026-08-02 10:09+0000\n"
"PO-Revision-Date: 2026-08-05 10:02\n"
"PO-Revision-Date: 2026-08-06 10:02\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Persian\n"
"MIME-Version: 1.0\n"
@@ -39010,7 +39010,7 @@ msgstr "لطفاً یک یادداشت تحویل را انتخاب کنید"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:81
msgid "Please select a Holiday List to enable Appointment Scheduling."
msgstr ""
msgstr "لطفا برای فعال کردن زمان‌بندی قرار ملاقات، یک لیست تعطیلات انتخاب کنید."
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py:152
msgid "Please select a Subcontracting Purchase Order."
@@ -39096,7 +39096,7 @@ msgstr ""
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.py:1356
msgid "Please select a valid {0}"
msgstr ""
msgstr "لطفا یک {0} معتبر انتخاب کنید"
#: erpnext/selling/doctype/quotation/quotation.js:245
msgid "Please select a value for {0} quotation_to {1}"
@@ -44133,7 +44133,7 @@ msgstr ""
#: erpnext/stock/doctype/bin/bin.js:10
msgid "Recalculate Values"
msgstr ""
msgstr "محاسبه مجدد مقادیر"
#. Option for the 'Status' (Select) field in DocType 'Asset'
#. Option for the 'Purpose' (Select) field in DocType 'Asset Movement'
@@ -49365,7 +49365,7 @@ msgstr "زمانبند غیرفعال است. نمی‌توان حساب‌ها
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:232
msgid "Scheduler is inactive. Reposting will only run once background jobs are processed."
msgstr ""
msgstr "زمان‌بند غیرفعال است. ارسال مجدد فقط زمانی اجرا می‌شود که کارهای پس‌زمینه پردازش شوند."
#. Label of the schedules (Table) field in DocType 'Maintenance Schedule'
#: erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
@@ -49811,7 +49811,7 @@ msgstr "انتخاب آدرس تامین کننده"
#: erpnext/stock/doctype/material_request/material_request.js:449
msgid "Select Supplier for Items"
msgstr ""
msgstr "انتخاب تامین کننده برای آیتم‌ها"
#: erpnext/stock/doctype/batch/batch.js:150
msgid "Select Target Warehouse"
@@ -49865,7 +49865,7 @@ msgstr "یک تامین کننده انتخاب کنید"
#: erpnext/stock/doctype/material_request/mapper.py:230
#: erpnext/stock/doctype/material_request/material_request.js:553
msgid "Select a Supplier for Item {0}"
msgstr ""
msgstr "انتخاب یک تأمین‌کننده برای آیتم {0}"
#: banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx:49
msgid "Select a bank account to reconcile"
@@ -49910,7 +49910,7 @@ msgstr "از هر مجموعه یک آیتم را برای استفاده در
#: erpnext/stock/doctype/material_request/mapper.py:211
#: erpnext/stock/doctype/material_request/material_request.js:540
msgid "Select at least one Item"
msgstr ""
msgstr "حداقل یک آیتم را انتخاب کنید"
#: erpnext/stock/doctype/item/item.js:1256
msgid "Select at least one attribute value."
@@ -50249,7 +50249,7 @@ msgstr "ارسال با پیوست"
#: erpnext/accounts/doctype/payment_request/payment_request.js:51
#: erpnext/accounts/doctype/payment_request/payment_request.js:55
msgid "Sending Email"
msgstr ""
msgstr "ارسال ایمیل"
#. Option for the 'Detected Amount Format' (Select) field in DocType 'Bank
#. Statement Import Log'
@@ -51134,7 +51134,7 @@ msgstr "تنظیم تامین کننده"
#: erpnext/stock/doctype/material_request/material_request.js:456
msgid "Set Supplier for All Items"
msgstr ""
msgstr "تنظیم تأمین‌کننده برای همه آیتم‌ها"
#. Label of the set_target_warehouse (Link) field in DocType 'Sales Invoice'
#. Label of the set_warehouse (Link) field in DocType 'Purchase Order'
@@ -61276,7 +61276,7 @@ msgstr ""
#. Label of the verification_token (Data) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Verification Token"
msgstr ""
msgstr "توکن تأیید"
#: erpnext/www/book_appointment/verify/index.html:15
msgid "Verification failed please check the link"
@@ -62147,7 +62147,7 @@ msgstr ""
#: erpnext/templates/emails/appointment_confirmed.html:3
msgid "We look forward to meeting you"
msgstr ""
msgstr "مشتاق دیدار شما هستیم"
#: banking/src/pages/BankStatementImporter.tsx:169
msgid "We support uploading CSV, XLSX, XLS and PDF files. Please make sure the file contains the correct columns."

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: hello@frappe.io\n"
"POT-Creation-Date: 2026-08-02 10:09+0000\n"
"PO-Revision-Date: 2026-08-04 09:44\n"
"PO-Revision-Date: 2026-08-06 10:02\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Swedish\n"
"MIME-Version: 1.0\n"
@@ -18542,7 +18542,7 @@ msgstr "Påminnelse Typ"
#: erpnext/accounts/doctype/pos_profile/pos_profile.py:178
msgid "Duplicate Customer Group"
msgstr "Kopiera Kund Grupp"
msgstr "Duplicera Kund Grupp"
#: erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py:190
msgid "Duplicate DocType"
@@ -18554,11 +18554,11 @@ msgstr "Dubblett Post. Kontrollera Auktorisering Regel {0}"
#: erpnext/assets/doctype/asset/asset.py:418
msgid "Duplicate Finance Book"
msgstr "Kopiera Bokslut Register"
msgstr "Duplicera Bokslut Register"
#: erpnext/accounts/doctype/pos_profile/pos_profile.py:172
msgid "Duplicate Item Group"
msgstr "Kopiera Artikel Grupp"
msgstr "Duplicera Artikel Grupp"
#: erpnext/manufacturing/doctype/bom_creator/bom_creator.py:102
msgid "Duplicate Item Under Same Parent"
@@ -18576,7 +18576,7 @@ msgstr "Duplicera Kassa Fällt"
#: erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py:106
#: erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py:64
msgid "Duplicate POS Invoices found"
msgstr "Kopia av Kassa Fakturor hittad"
msgstr "Dubblett av Kassa Fakturor hittad"
#: erpnext/accounts/doctype/payment_request/payment_request.py:155
msgid "Duplicate Payment Schedule selected"
@@ -18584,7 +18584,7 @@ msgstr "Duplicerad Betalning Schema vald"
#: erpnext/projects/doctype/project/project.js:83
msgid "Duplicate Project with Tasks"
msgstr "Kopiera Projekt med Uppgifter"
msgstr "Duplicera Projekt med Uppgifter"
#: erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py:159
msgid "Duplicate Sales Invoices found"
@@ -18604,7 +18604,7 @@ msgstr "Kopia av Kund Grupp finns i Kund Grupp Tabell"
#: erpnext/stock/doctype/item_manufacturer/item_manufacturer.py:44
msgid "Duplicate entry against the item code {0} and manufacturer {1}"
msgstr "Kopiera post mot Artikel Kod {0} och Producent {1}"
msgstr "Duplicera post mot artikel kod {0} och producent {1}"
#: erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py:189
msgid "Duplicate entry: {0}{1}"
@@ -18612,19 +18612,19 @@ msgstr "Duplicerad post: {0}{1}"
#: erpnext/accounts/doctype/pos_profile/pos_profile.py:172
msgid "Duplicate item group found in the item group table"
msgstr "Kopiera Artikel Grupp hittad i Artikel Grupp Tabell"
msgstr "Dubblett av Artikel Grupp hittad i Artikel Grupp Tabell"
#: erpnext/accounts/doctype/dunning_type/dunning_type.py:133
msgid "Duplicate languages found on Dunning Letter Text. Keep only one of them."
msgstr "Det finns flera språk i påminnelse brev. Behåll endast ett språk."
msgstr "Det finns flera språk i Påminnelse Brev. Behåll endast ett språk."
#: erpnext/projects/doctype/project/project.js:186
msgid "Duplicate project has been created"
msgstr "Kopia av Projekt är skapad"
msgstr "Dubblett av Projekt är skapad"
#: erpnext/utilities/transaction_base.py:112
msgid "Duplicate row {0} with same {1}"
msgstr "Kopiera Rad {0} med samma {1}"
msgstr "Duplicera Rad {0} med samma {1}"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:110
msgid "Duplicate vouchers found. Remove the duplicate vouchers to continue to repost."
@@ -18632,7 +18632,7 @@ msgstr "Dubbletter av verifikat hittades. Ta bort dubbletter för att fortsätta
#: erpnext/accounts/doctype/pricing_rule/pricing_rule.py:157
msgid "Duplicate {0} found in the table"
msgstr "Kopia {0} hittades i Tabell"
msgstr "Dubblett {0} hittades i Tabell"
#. Label of the duration (Int) field in DocType 'Task'
#: erpnext/projects/doctype/task/task.json
@@ -47176,7 +47176,7 @@ msgstr "Rad # #{0}: Avskrivning Start Datum erfordras"
#: erpnext/accounts/doctype/payment_entry/payment_entry.py:336
msgid "Row #{0}: Duplicate entry in References {1} {2}"
msgstr "Rad # {0}: Duplikat Post i Referenser {1} {2}"
msgstr "Rad #{0}: Dubblett Post i Referenser {1} {2}"
#: erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py:113
msgid "Row #{0}: Either Party ID or Party Name is required"

View File

@@ -5545,6 +5545,66 @@ class TestPurchaseReceipt(ERPNextTestSuite):
self.assertEqual(frappe.parse_json(stock_queue), [[20, 0.0]])
def test_purchase_return_valuation_for_batchwise_valuation_batch(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
item_code = make_item(
"Test Purchase Return Batchwise Valn Item",
{
"is_stock_item": 1,
"has_batch_no": 1,
"batch_number_series": "BN-TPRBWV-.#####",
},
).name
batch_no = "BN-TPRBWV-00001"
batch = frappe.new_doc("Batch").update({"batch_id": batch_no, "item": item_code}).insert()
self.assertEqual(batch.use_batchwise_valuation, 1)
warehouse = "_Test Warehouse - _TC"
pr = make_purchase_receipt(
item_code=item_code,
qty=100,
rate=1000,
warehouse=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
)
make_purchase_receipt(
item_code=item_code,
qty=100,
rate=400,
warehouse=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
)
create_delivery_note(
item_code=item_code,
qty=100,
warehouse=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
)
return_pr = make_return_doc("Purchase Receipt", pr.name)
return_pr.submit()
sle = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_no": return_pr.name, "is_cancelled": 0},
["stock_value_difference", "qty_after_transaction", "stock_value", "serial_and_batch_bundle"],
as_dict=True,
)
self.assertEqual(flt(sle.qty_after_transaction), 0.0)
self.assertEqual(flt(sle.stock_value_difference, 2), -70000.0)
self.assertEqual(flt(sle.stock_value, 2), 0.0)
rate = frappe.db.get_value(
"Serial and Batch Entry", {"parent": sle.serial_and_batch_bundle}, "incoming_rate"
)
self.assertEqual(flt(rate, 2), 700.0)
def test_negative_stock_error_for_purchase_return(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry

View File

@@ -414,6 +414,13 @@ class SerialandBatchBundle(Document):
valuation_method = get_valuation_method(self.item_code, self.company)
# An outward return must go out at the batch's current average rate for a
# batchwise valuation batch. The original receipt rate is only correct while
# the batch still holds stock at that rate; once other receipts have changed
# the average, removing at the original rate strands a residue in the batch
# value (negative when returning the costlier receipt).
batchwise_avg_rates = self.get_batchwise_return_avg_rates()
stock_queue = []
non_batchwise_batches = []
if not self.has_serial_no and valuation_method == "FIFO":
@@ -447,6 +454,12 @@ class SerialandBatchBundle(Document):
batches = sorted(list(valuation_details["batches"].keys()))
valuation_rate = valuation_details["batches"].get(batches[cint(row.idx) - 1])
# a batch with an available balance goes out at its current average rate (a
# valid 0.0 included); the original receipt rate applies only when there is
# no balance to average
if not row.serial_no and row.batch_no in batchwise_avg_rates:
valuation_rate = batchwise_avg_rates[row.batch_no]
row.incoming_rate = flt(valuation_rate)
row.stock_value_difference = flt(row.qty) * flt(row.incoming_rate)
@@ -475,6 +488,43 @@ class SerialandBatchBundle(Document):
elif self.type_of_transaction == "Inward":
self.set_incoming_rate_for_inward_transaction(row, save, prev_sle=prev_sle)
def get_batchwise_return_avg_rates(self):
from erpnext.stock.utils import get_valuation_method
if self.type_of_transaction != "Outward" or self.has_serial_no:
return {}
batch_nos = [d.batch_no for d in self.entries if d.batch_no]
if not batch_nos:
return {}
if get_valuation_method(
self.item_code, self.company
) == "Moving Average" and frappe.db.get_single_value(
"Stock Settings", "do_not_use_batchwise_valuation"
):
return {}
batchwise_batches = frappe.get_all(
"Batch",
filters={"name": ("in", batch_nos), "use_batchwise_valuation": 1},
pluck="name",
)
if not batchwise_batches:
return {}
# scoped to batchwise batches only, so BatchNoValuation's non-batchwise
# machinery never runs for them
sle = self.get_sle_for_outward_transaction()
sle.batch_nos = {batch_no: sle.batch_nos[batch_no] for batch_no in batchwise_batches}
sle.batchwise_valuation_batches = batchwise_batches
sn_obj = BatchNoValuation(sle=sle, item_code=self.item_code, warehouse=self.warehouse)
return {
batch_no: abs(flt(sn_obj.batch_avg_rate.get(batch_no)))
for batch_no in batchwise_batches
if flt(sn_obj.available_qty.get(batch_no))
}
def validate_returned_serial_batch_no(self, return_against, row, original_inv_details):
if frappe.flags.through_repost_item_valuation and not frappe.in_test:
return

View File

@@ -988,6 +988,11 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
self.batchwise_valuation_batches = []
self.non_batchwise_valuation_batches = []
if batchwise_batches := self.sle.get("batchwise_valuation_batches"):
self.batchwise_valuation_batches = list(batchwise_batches)
self.non_batchwise_valuation_batches = list(set(self.batches) - set(batchwise_batches))
return
if get_valuation_method(
self.sle.item_code, self.sle.company
) == "Moving Average" and frappe.get_single_value("Stock Settings", "do_not_use_batchwise_valuation"):