Compare commits

..

12 Commits

Author SHA1 Message Date
Raffael Meyer
5dd6c0169b Merge branch 'version-16-hotfix' into l10n_version-16-hotfix 2026-08-06 20:02:37 +02:00
rohitwaghchaure
aa70d9bbc3 fix: purchase return of batchwise valuation batch valued at original receipt rate instead of batch avg rate (version-16-hotfix) (#57836)
* 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:44:56 +05:30
MochaMind
88f66af4ea fix: Bosnian translations 2026-08-06 15:31:41 +05:30
MochaMind
da0b874508 fix: Croatian translations 2026-08-06 15:31:35 +05:30
MochaMind
8b92317eac fix: Persian translations 2026-08-06 15:31:29 +05:30
MochaMind
d1e5fa6bb0 fix: Swedish translations 2026-08-06 15:31:20 +05:30
Mihir Kandoi
626e35135f fix(stock): drop call to confirm_if_drafts_exist missing on v16 (#57833) 2026-08-06 08:08:45 +00:00
Henil Maru
0e26f9b1db fix(sales-invoice): respect Customize Form hidden setting on Update Stock (#57819)
frm.toggle_display("update_stock", ...) unconditionally forced the
field visible based only on has_subcontracted, overwriting whatever
Customize Form had set on every refresh. OR it with the field's
original (property-setter-driven) hidden value instead.

Backport of #57818.
2026-08-05 17:58:58 +05:30
rohitwaghchaure
243266f5ef feat: stock validations in Period Closing Voucher and snapshot-seeded batch valuation (backport #57811) (#57816)
* feat: validate stock value and stock closing entry before period closing

(cherry picked from commit 20450bd4ec)

* fix: do not accept scoped stock closing entries as period closing prerequisite

(cherry picked from commit 359a347be2)

* feat: seed batch valuation from stock closing balance and freeze closed-period stock

(cherry picked from commit 49a127d59c)
2026-08-05 17:20:53 +05:30
mergify[bot]
af3184c8b4 fix(stock): handle multi-item opening balance in Stock Ledger report (backport #57591) (#57796)
* fix(stock): handle multi-item opening balance in Stock Ledger report (#57591)

* fix(stock): handle multi-item opening balance in Stock

* test(stock): add unit test for multi-item Stock Ledger report

---------

Co-authored-by: Afsal Syed <afsalsyed12@gmail.com>
(cherry picked from commit 0dbe410414)

# Conflicts:
#	erpnext/stock/report/stock_ledger/test_stock_ledger_report.py

* fix(stock): resolve stock ledger backport conflicts

---------

Co-authored-by: Sudharsanan Ashok <135326972+Sudharsanan11@users.noreply.github.com>
Co-authored-by: Sudharsanan11 <sudharsananashok1975@gmail.com>
2026-08-05 13:15:40 +05:30
Jatin3128
eeb3cd238e fix(subscription): don't reactivate a cancelled subscription (backport #57774)
* fix(subscription): don't reactivate a cancelled subscription

Backport of #57774 to version-16-hotfix.

set_subscription_status() unconditionally set status to Active once
there was no outstanding invoice, even if the subscription had been
intentionally cancelled. Paying off an invoice issued before
cancellation (directly, or via the Payment Entry -> refresh hook)
flipped a Cancelled subscription back to Active while cancelation_date
stayed set.

process()'s cancel_at_period_end check compared posting_date against
getdate(self.end_date), and getdate(None) returns today, so an empty
end_date was silently treated as "cancel now" on every scheduler run.
Combined with the reactivation bug, this let a cancelled subscription
toggle Cancelled -> Active on each run and generate another invoice at
the next period boundary.

Fixes #57761

* test: fix flaky test_update_bom_cost_in_all_boms via valuation reset

Backport of #56796 to version-16-hotfix.

reset_item_valuation_rate() only reconciled warehouses where the item
currently has positive stock (actual_qty > 0). get_valuation_rate()
averages Sum(stock_value)/Sum(actual_qty) across all of an item's
bins, so a negative balance left over in another warehouse by a prior
test can cancel out the reset qty and collapse the average to 0,
failing the assertion with 0.0 != 10.0.

This branch never got #56796 (it predates the frappe.get_all
refactor of this helper and still uses raw SQL), so applying the same
fix here: reconcile every warehouse with a non-zero balance, not just
positive ones.

* fix(subscription): don't let period rollover defeat cancel_at_period_end

process() can advance current_invoice_end to the next period (via
update_subscription_period(), when generating the current period's
invoice) before the cancel_at_period_end check further down runs. For
a subscription with no end_date, that check now compared posting_date
against the already-rolled-forward current_invoice_end, which is
always in the future, so cancel_at_period_end was silently never
honored.

Snapshot current_invoice_end before any rollover and use that in the
check instead, so it still targets the period that just ended.

Found via review on the version-15-hotfix backport (#57780).

---------

Co-authored-by: test <test@test.com>
2026-08-05 12:23:31 +05:30
mergify[bot]
adfa6768c9 fix: incorrect batch-wise valuation rate for entries with same posting datetime (backport #57794) (#57797)
fix: incorrect batch-wise valuation rate for entries with same posting datetime (#57794)

* fix: incorrect batch-wise valuation rate for entries with same posting datetime

The tie-breaker in get_batch_no_ledgers compared the bundle's creation
against the SLE's creation. These are different timelines - a bundle can
be created (drafted) much before its SLE (created at submission). For
entries sharing a posting datetime (backdated / amended vouchers), this
mis-ordered the entries against the ledger's replay order (SLE creation),
causing double counting or omission of batch qty / value and runaway
outgoing rates that no repost could heal.

Now the tie is broken using the creation of the bundle's own SLE (same
timeline on both sides). When the valuation runs through the bundle
before its SLE exists, the entry is by definition last in its timestamp
group, so all same-timestamp entries already in the ledger precede it.



* test: batch-wise valuation ordering for same posting datetime entries

Covers both tie-breaking branches of get_batch_no_ledgers:
- submission (pre-insertion) branch: same-timestamp inward at a different
  rate plus a multi-row outward voucher (same item and warehouse), at
  submission and after a backdated repost
- existing-SLE branch: a bundle created after its sibling's SLE, the
  ordering must follow the SLE creation and not the bundle creation

Both tests fail with the previous parent.creation < sle.creation
tie-breaker and pass with the fix.



---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 11:06:14 +05:30
21 changed files with 1685 additions and 409 deletions

View File

@@ -6,7 +6,7 @@ import frappe
from frappe.model.document import Document
from frappe.utils.user import is_website_user
__version__ = "16.31.0"
__version__ = "16.26.2"
def get_default_company(user=None):

View File

@@ -6,9 +6,10 @@ import copy
import frappe
from frappe import _
from frappe.query_builder.functions import Sum
from frappe.utils import add_days, flt, formatdate, getdate
from frappe.query_builder.functions import Max, Sum
from frappe.utils import add_days, flt, fmt_money, formatdate, get_link_to_form, getdate
from erpnext import is_perpetual_inventory_enabled
from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
make_closing_entries,
)
@@ -18,6 +19,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
from erpnext.accounts.general_ledger import check_freezing_date, is_immutable_ledger_enabled
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.stock.doctype.stock_closing_entry.stock_closing_entry import apply_unscoped_filters
from erpnext.stock.utils import get_stock_value_on
class PeriodClosingVoucher(AccountsController):
@@ -139,6 +142,121 @@ class PeriodClosingVoucher(AccountsController):
if account_currency != company_currency:
frappe.throw(_("Currency of the Closing Account must be {0}").format(company_currency))
def before_submit(self):
if not self.has_stock_transactions():
return
self.validate_stock_accounts_balance()
self.validate_stock_closing_entry()
def has_stock_transactions(self):
if not is_perpetual_inventory_enabled(self.company):
return False
return bool(
frappe.db.exists(
"Stock Ledger Entry",
{
"company": self.company,
"is_cancelled": 0,
"posting_date": ("<=", self.period_end_date),
},
)
)
def validate_stock_accounts_balance(self):
precision = frappe.get_precision("GL Entry", "debit")
account_balance = flt(self.get_stock_accounts_balance(), precision)
stock_value = flt(
get_stock_value_on(posting_date=self.period_end_date, company=self.company), precision
)
if account_balance == stock_value:
return
currency = frappe.get_cached_value("Company", self.company, "default_currency")
frappe.throw(
_(
"The closing balance {0} of the Stock Asset accounts does not match the closing value {1} of the Stock Balance report as on {2}. Resolve the difference using the Stock Ledger Variance report before closing the period."
).format(
frappe.bold(fmt_money(account_balance, currency=currency)),
frappe.bold(fmt_money(stock_value, currency=currency)),
frappe.bold(formatdate(self.period_end_date)),
),
title=_("Stock Value Mismatch"),
)
def get_stock_accounts_balance(self):
gle = frappe.qb.DocType("GL Entry")
account = frappe.qb.DocType("Account")
stock_accounts = (
frappe.qb.from_(account)
.select(account.name)
.where(
(account.account_type == "Stock")
& (account.company == self.company)
& (account.is_group == 0)
)
)
balance = (
frappe.qb.from_(gle)
.select(Sum(gle.debit - gle.credit))
.where(
(gle.company == self.company)
& (gle.is_cancelled == 0)
& (gle.posting_date <= self.period_end_date)
& gle.account.isin(stock_accounts)
)
).run()
return flt(balance[0][0]) if balance else 0.0
def validate_stock_closing_entry(self):
closing_entry = frappe.db.get_value(
"Stock Closing Entry",
apply_unscoped_filters(
{"company": self.company, "to_date": self.period_end_date, "docstatus": 1}
),
["name", "status", "modified"],
as_dict=True,
)
if not closing_entry:
frappe.throw(
_(
"Create a Stock Closing Entry for the entire company with To Date as {0} before submitting the Period Closing Voucher."
).format(frappe.bold(formatdate(self.period_end_date))),
title=_("Stock Closing Entry Required"),
)
if closing_entry.status != "Completed":
frappe.throw(
_(
"The Stock Closing Entry for {0} is not completed yet. Wait for it to complete before submitting the Period Closing Voucher."
).format(frappe.bold(formatdate(self.period_end_date))),
title=_("Stock Closing Entry In Progress"),
)
self.validate_stock_closing_entry_is_fresh(closing_entry)
def validate_stock_closing_entry_is_fresh(self, closing_entry):
sle = frappe.qb.DocType("Stock Ledger Entry")
last_change = (
frappe.qb.from_(sle)
.select(Max(sle.modified))
.where((sle.company == self.company) & (sle.posting_date <= self.period_end_date))
).run()
if last_change and last_change[0][0] and last_change[0][0] > closing_entry.modified:
frappe.throw(
_(
"Stock transactions were created or modified after the Stock Closing Entry {0} was generated. Regenerate it before submitting the Period Closing Voucher."
).format(get_link_to_form("Stock Closing Entry", closing_entry.name)),
title=_("Stock Closing Entry Outdated"),
)
def on_submit(self):
self.db_set("gle_processing_status", "In Progress")
if frappe.get_single_value("Accounts Settings", "use_legacy_controller_for_pcv"):

View File

@@ -3,7 +3,7 @@
import unittest
import frappe
from frappe.utils import today
from frappe.utils import flt, today
from erpnext.accounts.doctype.finance_book.test_finance_book import create_finance_book
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
@@ -307,6 +307,218 @@ class TestPeriodClosingVoucher(ERPNextTestSuite):
repost_doc.posting_date = today()
repost_doc.save()
def test_stock_validations_before_period_closing(self):
from unittest.mock import patch
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
create_custom_fields(
{
"Stock Closing Entry": [
{
"fieldname": "warehouse",
"label": "Warehouse",
"fieldtype": "Link",
"options": "Warehouse",
}
]
}
)
item = make_item("Test PCV Stock Item", {"is_stock_item": 1})
se = make_stock_entry(
item_code=item.name,
qty=10,
rate=100,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-03-15",
)
pcv = self.make_period_closing_voucher(posting_date="2021-03-31", submit=False)
self.assertRaisesRegex(frappe.ValidationError, "Create a Stock Closing Entry", pcv.submit)
sce = frappe.get_doc(
{
"doctype": "Stock Closing Entry",
"company": "Test PCV Company",
"from_date": pcv.period_start_date,
"to_date": pcv.period_end_date,
"warehouse": "Stores - TPC",
}
).insert()
with patch("erpnext.stock.doctype.stock_closing_entry.stock_closing_entry.enqueue"):
sce.submit()
sce.db_set("status", "Completed")
pcv.reload()
self.assertRaisesRegex(frappe.ValidationError, "Create a Stock Closing Entry", pcv.submit)
frappe.db.set_value("Stock Closing Entry", sce.name, {"warehouse": None, "status": "In Progress"})
pcv.reload()
self.assertRaisesRegex(frappe.ValidationError, "is not completed yet", pcv.submit)
sce.create_stock_closing_balance_entries()
sce.db_set("status", "Completed")
sle = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_no": se.name},
["name", "stock_value_difference"],
as_dict=1,
)
frappe.db.set_value(
"Stock Ledger Entry", sle.name, "stock_value_difference", sle.stock_value_difference + 100
)
pcv.reload()
self.assertRaisesRegex(frappe.ValidationError, "does not match", pcv.submit)
frappe.db.set_value(
"Stock Ledger Entry", sle.name, "stock_value_difference", sle.stock_value_difference
)
pcv.reload()
self.assertRaisesRegex(frappe.ValidationError, "Regenerate", pcv.submit)
self.rebuild_stock_closing_balance(sce)
pcv.reload()
pcv.submit()
self.assertEqual(pcv.docstatus, 1)
def test_batch_valuation_seeded_from_stock_closing_after_period_closing(self):
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import (
get_batch_from_bundle,
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
item = make_item(
"Test PCV Batch Item",
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TPCVB.####",
},
)
se1 = make_stock_entry(
item_code=item.name,
qty=10,
rate=100,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-03-15",
)
batch_no = get_batch_from_bundle(se1.items[0].serial_and_batch_bundle)
make_stock_entry(
item_code=item.name,
qty=10,
rate=200,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-06-15",
batch_no=batch_no,
)
pcv = self.make_period_closing_voucher(posting_date="2021-03-31", submit=False)
sce = self.make_completed_stock_closing_entry(pcv.period_start_date, pcv.period_end_date)
pcv.reload()
pcv.submit()
outward = make_stock_entry(
item_code=item.name,
qty=5,
from_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2022-04-01",
batch_no=batch_no,
)
stock_value_difference = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_no": outward.name, "is_cancelled": 0},
"stock_value_difference",
)
self.assertEqual(flt(stock_value_difference, 2), -750.0)
self.assertRaisesRegex(
frappe.ValidationError,
"frozen",
make_stock_entry,
item_code=item.name,
qty=1,
rate=100,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-05-01",
)
self.assertRaisesRegex(frappe.ValidationError, "frozen", se1.cancel)
self.assertRaisesRegex(frappe.ValidationError, "closed accounting period", sce.cancel)
def test_period_closing_blocks_stale_stock_closing_entry(self):
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
item = make_item("Test PCV Stock Item", {"is_stock_item": 1})
make_stock_entry(
item_code=item.name,
qty=10,
rate=100,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-03-15",
)
pcv = self.make_period_closing_voucher(posting_date="2021-03-31", submit=False)
sce = self.make_completed_stock_closing_entry(pcv.period_start_date, pcv.period_end_date)
make_stock_entry(
item_code=item.name,
qty=5,
rate=100,
to_warehouse="Stores - TPC",
company="Test PCV Company",
posting_date="2021-05-01",
)
pcv.reload()
self.assertRaisesRegex(frappe.ValidationError, "Regenerate", pcv.submit)
self.rebuild_stock_closing_balance(sce)
pcv.reload()
pcv.submit()
self.assertEqual(pcv.docstatus, 1)
def make_completed_stock_closing_entry(self, from_date, to_date):
from unittest.mock import patch
sce = frappe.get_doc(
{
"doctype": "Stock Closing Entry",
"company": "Test PCV Company",
"from_date": from_date,
"to_date": to_date,
}
).insert()
with patch("erpnext.stock.doctype.stock_closing_entry.stock_closing_entry.enqueue"):
sce.submit()
sce.create_stock_closing_balance_entries()
sce.db_set("status", "Completed")
return sce
def rebuild_stock_closing_balance(self, sce):
sce.remove_stock_closing()
sce.create_stock_closing_balance_entries()
sce.db_set("status", "Completed")
def make_period_closing_voucher(self, posting_date, submit=True):
surplus_account = create_account()
cost_center = create_cost_center("Test Cost Center 1")

View File

@@ -1180,7 +1180,16 @@ frappe.ui.form.on("Sales Invoice", {
}
frm.set_df_property("update_stock", "read_only", frm.doc.has_subcontracted);
frm.toggle_display("update_stock", !frm.doc.has_subcontracted);
// frm.set_df_property mutates a per-document copy, not the doctype's shared field
// metadata, so this always reflects the original (Customize Form) hidden value.
const hidden_by_customization = cint(
frappe.meta.get_docfield("Sales Invoice", "update_stock")?.hidden
);
frm.set_df_property(
"update_stock",
"hidden",
cint(frm.doc.has_subcontracted) || hidden_by_customization
);
},
});

View File

@@ -254,6 +254,9 @@ class Subscription(Document):
"""
Sets the status of the `Subscription`
"""
if self.status == "Cancelled":
return
if self.is_trialling():
self.status = "Trialing"
elif (
@@ -605,6 +608,11 @@ class Subscription(Document):
1. `process_for_active`
2. `process_for_past_due`
"""
# Snapshot before update_subscription_period() below can roll this forward,
# so the cancel_at_period_end check further down still targets the period
# that just ended, not the next one.
current_period_end = self.current_invoice_end
if not self.is_current_invoice_generated(
self.current_invoice_start, self.current_invoice_end
) and self.can_generate_new_invoice(posting_date):
@@ -625,8 +633,8 @@ class Subscription(Document):
self.update_subscription_period()
if self.cancel_at_period_end and (
getdate(posting_date) >= getdate(self.current_invoice_end)
or getdate(posting_date) >= getdate(self.end_date)
getdate(posting_date) >= getdate(current_period_end)
or (self.end_date and getdate(posting_date) >= getdate(self.end_date))
):
self.cancel_subscription()

View File

@@ -614,6 +614,32 @@ class TestSubscription(ERPNextTestSuite):
self.assertRaises(frappe.ValidationError, subscription.process, posting_date=add_days(start_date, 7))
def test_subscription_cancels_at_period_end_without_end_date(self):
# https://github.com/frappe/erpnext/issues/57761 -- generate_invoice() rolls
# current_invoice_end forward to the next period before this check runs, so
# with no end_date to fall back on, cancel_at_period_end must compare
# against the period that just ended, not the (already advanced) next one.
create_plan(
plan_name="_Test plan name 11",
cost=80,
currency="INR",
billing_interval="Day",
billing_interval_count=3,
)
subscription = create_subscription(
start_date=nowdate(),
cancel_at_period_end=1,
generate_invoice_at="End of the current subscription period",
plans=[{"plan": "_Test plan name 11", "qty": 1}],
)
self.assertEqual(len(subscription.invoices), 0)
period_end = subscription.current_invoice_end
subscription.process(posting_date=period_end)
self.assertEqual(subscription.status, "Cancelled")
self.assertEqual(len(subscription.invoices), 1)
def test_invoice_generated_when_scheduler_runs_one_day_late(self):
# The trigger date (period end) is long past, yet catch-up still bills the period
# on creation (Bug 1: the check is `>= trigger`, not `== trigger`).
@@ -774,6 +800,38 @@ class TestSubscription(ERPNextTestSuite):
subscription.reload()
self.assertEqual(subscription.status, "Active")
def test_cancelled_subscription_stays_cancelled_after_payment_and_reprocess(self):
# https://github.com/frappe/erpnext/issues/57761
subscription = create_subscription(
start_date=nowdate(),
generate_invoice_at="Beginning of the current subscription period",
submit_invoice=1,
cancel_at_period_end=1,
)
subscription.process(posting_date=nowdate())
invoice = subscription.get_current_invoice()
self.assertGreater(invoice.outstanding_amount, 0)
subscription.cancel_subscription()
self.assertEqual(subscription.status, "Cancelled")
cancelation_date = getdate(subscription.cancelation_date)
self.assertIsNotNone(cancelation_date)
payment_entry = get_payment_entry(invoice.doctype, invoice.name, bank_account="_Test Bank - _TC")
payment_entry.reference_no = "12345"
payment_entry.reference_date = nowdate()
payment_entry.submit()
subscription.reload()
self.assertEqual(subscription.status, "Cancelled")
self.assertEqual(getdate(subscription.cancelation_date), cancelation_date)
invoice_count = len(subscription.invoices)
subscription.process()
subscription.reload()
self.assertEqual(subscription.status, "Cancelled")
self.assertEqual(len(subscription.invoices), invoice_count)
def test_first_invoice_generated_on_create_for_prepaid(self):
subscription = create_subscription(
start_date=nowdate(),

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-03 09:00\n"
"PO-Revision-Date: 2026-08-06 10:01\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Persian\n"
"MIME-Version: 1.0\n"
@@ -6610,7 +6610,7 @@ msgstr ""
#. DocType 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Auto match and set the Party in Bank Transactions"
msgstr "مطابقت خودکار و تنظیم طرف در معاملات بانکی"
msgstr "مطابقت خودکار و تنظیم طرف در تراکنش‌های بانکی"
#. Label of the reorder_section (Section Break) field in DocType 'Item'
#: erpnext/stock/doctype/item/item.json
@@ -7781,7 +7781,7 @@ msgstr "تراکنش بانکی"
#: erpnext/accounts/doctype/bank/bank.json
#: erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.json
msgid "Bank Transaction Mapping"
msgstr "نگاشت معاملات بانکی"
msgstr "نگاشت تراکنش‌های بانکی"
#. Name of a DocType
#: erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.json
@@ -20481,7 +20481,7 @@ msgstr "نگاشت فیلد"
#. Transaction Mapping'
#: erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.json
msgid "Field in Bank Transaction"
msgstr "فیلد در معاملات بانکی"
msgstr "فیلد در تراکنش‌های بانکی"
#: erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py:95
msgid "Fieldname Conflict"
@@ -23790,7 +23790,7 @@ msgstr "اگر آیتم‌ها موجود هستند، مراحل انتقال
#. (Link) field in DocType 'Stock Settings'
#: erpnext/stock/doctype/stock_settings/stock_settings.json
msgid "If mentioned, the system will allow only the users with this Role to create or modify any stock transaction earlier than the latest stock transaction for a specific item and warehouse. If set as blank, it allows all users to create/edit back-dated transactions."
msgstr "در صورت ذکر شده، این سیستم فقط به کاربران دارای این نقش اجازه می‌دهد تا هر تراکنش موجودی را زودتر از آخرین تراکنش موجودی برای یک کالا و انبار خاص ایجاد یا اصلاح کنند. اگر به صورت خالی تنظیم شود، به همه کاربران اجازه می‌دهد تا تراکنش‌های قدیمی را ایجاد/ویرایش کنند."
msgstr "در صورت ذکر، سیستم فقط به کاربرانی که این نقش را دارند اجازه می‌دهد هرگونه تراکنش موجودی را قبل از آخرین تراکنش موجودی برای یک کالا و انبار خاص ایجاد یا اصلاح کنند. اگر خالی تنظیم شود، به همه کاربران اجازه می‌دهد تراکنش‌های تاریخ گذشته را ایجاد/ویرایش کنند."
#. Description of the 'To Package No.' (Int) field in DocType 'Packing Slip'
#: erpnext/stock/doctype/packing_slip/packing_slip.json
@@ -24575,7 +24575,7 @@ msgstr "شامل آیتم‌های غیر موجودی"
#: erpnext/accounts/doctype/bank_clearance/bank_clearance.json
#: erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js:45
msgid "Include POS Transactions"
msgstr "شامل معاملات POS"
msgstr "شامل تراکنش‌های POS"
#: erpnext/accounts/doctype/pos_invoice/pos_invoice.py:205
msgid "Include Payment"
@@ -33211,7 +33211,7 @@ msgstr "از طریق ایمیل اطلاع دهید"
#. Label of the reorder_email_notify (Check) field in DocType 'Stock Settings'
#: erpnext/stock/doctype/stock_settings/stock_settings.json
msgid "Notify by email on creation of automatic Material Request"
msgstr ""
msgstr "اطلاع رسانی از طریق ایمیل در مورد ایجاد درخواست خودکار مواد"
#. Description of the 'Notify Via Email' (Check) field in DocType 'Appointment
#. Booking Settings'
@@ -35187,7 +35187,7 @@ msgstr "تنظیمات POS"
#. Label of the pos_invoices (Table) field in DocType 'POS Closing Entry'
#: erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
msgid "POS Transactions"
msgstr "معاملات POS"
msgstr "تراکنش‌های POS"
#: erpnext/selling/page/point_of_sale/pos_controller.js:178
msgid "POS has been closed at {0}. Please refresh the page."
@@ -38419,7 +38419,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:153
msgid "Please select a Subcontracting Purchase Order."
@@ -38500,7 +38500,7 @@ msgstr "لطفاً یک سفارش خرید معتبر که برای پیمان
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.py:1355
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}"
@@ -42679,7 +42679,7 @@ msgstr "RFQ برای {0} مجاز نیست به دلیل رتبه کارت ام
#. Label of the auto_indent (Check) field in DocType 'Stock Settings'
#: erpnext/stock/doctype/stock_settings/stock_settings.json
msgid "Raise Material Request when stock reaches re-order level"
msgstr ""
msgstr "ثبت درخواست مواد زمانی که موجودی به سطح سفارش مجدد رسید"
#. Label of the complaint_raised_by (Data) field in DocType 'Warranty Claim'
#: erpnext/support/doctype/warranty_claim/warranty_claim.json
@@ -43312,7 +43312,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'
@@ -45060,7 +45060,7 @@ msgstr "انبار رزرو شده برای آیتم {item_code} در مواد
#: erpnext/stock/report/stock_projected_qty/stock_projected_qty.py:198
msgid "Reserved for POS Transactions"
msgstr "برای معاملات POS رزرو شده است"
msgstr "برای تراکنش‌های POS رزرو شده است"
#: erpnext/stock/report/stock_projected_qty/stock_projected_qty.py:177
msgid "Reserved for Production"
@@ -48420,7 +48420,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
@@ -48851,7 +48851,7 @@ msgstr "انتخاب آدرس تامین کننده"
#: erpnext/stock/doctype/material_request/material_request.js:448
msgid "Select Supplier for Items"
msgstr ""
msgstr "انتخاب تامین کننده برای آیتم‌ها"
#: erpnext/stock/doctype/batch/batch.js:150
msgid "Select Target Warehouse"
@@ -48905,7 +48905,7 @@ msgstr "یک تامین کننده انتخاب کنید"
#: erpnext/stock/doctype/material_request/material_request.js:552
#: erpnext/stock/doctype/material_request/material_request.py:699
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"
@@ -48946,7 +48946,7 @@ msgstr "از هر مجموعه یک آیتم را برای استفاده در
#: erpnext/stock/doctype/material_request/material_request.js:539
#: erpnext/stock/doctype/material_request/material_request.py:680
msgid "Select at least one Item"
msgstr ""
msgstr "حداقل یک آیتم را انتخاب کنید"
#: erpnext/stock/doctype/item/item.js:944
msgid "Select at least one attribute value."
@@ -49265,7 +49265,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'
@@ -50094,7 +50094,7 @@ msgstr "تنظیم تامین کننده"
#: erpnext/stock/doctype/material_request/material_request.js:455
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'
@@ -53005,7 +53005,7 @@ msgstr "پیش‌فاکتور خود را ارسال کنید"
#: erpnext/manufacturing/doctype/job_card/job_card.py:1524
msgid "Submitted Job Card cannot be processed."
msgstr "کارت شغلی ارسال‌شده قابل پردازش نیست."
msgstr "کارت کار ارسال‌شده قابل پردازش نیست."
#. Label of the subscription_section (Section Break) field in DocType 'Payment
#. Request'
@@ -56021,7 +56021,7 @@ msgstr "این گزینه برای ویرایش فیلدهای «تاریخ ار
#. level' (Check) field in DocType 'Stock Settings'
#: erpnext/stock/doctype/stock_settings/stock_settings.json
msgid "This option is useful if you want to ensure a constant supply of raw materials/products and avoid shortage. A Material Request will be raised automatically when stock reached the re-order level defined in the Item form."
msgstr ""
msgstr "این گزینه در صورتی مفید است که بخواهید از تأمین مداوم مواد اولیه/محصولات اطمینان حاصل کنید و از کمبود جلوگیری کنید. درخواست مواد به طور خودکار زمانی که موجودی به سطح سفارش مجدد تعریف شده در فرم کالا برسد، ایجاد می‌شود."
#: banking/src/components/features/BankReconciliation/IncorrectlyClearedEntries.tsx:180
msgid "This report shows all entries in the system where the <strong>clearance date is before the posting date</strong> which is incorrect."
@@ -60041,7 +60041,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"
@@ -60907,7 +60907,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."

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-03 09:00\n"
"PO-Revision-Date: 2026-08-06 10:01\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Croatian\n"
"MIME-Version: 1.0\n"
@@ -152,7 +152,7 @@ msgstr "% Završeno Metoda"
#: erpnext/projects/doctype/project/project.py:226
msgid "% Complete must be between 0 and 100"
msgstr ""
msgstr "% dovršenosti mora biti između 0 i 100"
#. Label of the percent_complete (Percent) field in DocType 'Project'
#: erpnext/projects/doctype/project/project.json
@@ -349,7 +349,7 @@ msgstr "'Ažuriraj Zalihe' ne može se provjeriti za prodaju osnovne Imovine"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:112
msgid "'Verification Link Expiry Duration' must be between 15 to 60 minutes."
msgstr ""
msgstr "'Trajanje Važenja Verifikacijske Poveznice' mora biti između 15 i 60 minuta."
#: erpnext/accounts/doctype/bank_account/bank_account.py:79
msgid "'{0}' account is already used by {1}. Use another account."
@@ -1118,7 +1118,7 @@ msgstr "Onemogućeni Paket Artikal ne može se odabrati u transakcijama."
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py:636
msgid "A draft reverse journal for {0} has been created: {1}"
msgstr ""
msgstr "Nacrt obrnutog naloga knjiženja za {0} je izrađen: {1}"
#: erpnext/stock/doctype/delivery_trip/delivery_trip.py:59
msgid "A driver must be set to submit."
@@ -1163,7 +1163,7 @@ msgstr "Kontrola Kvaliteta mora biti izvršena prije izdavanja Nabavnog Računa
#: erpnext/stock/doctype/material_request/material_request.js:476
msgid "A separate Purchase Order is created for each Supplier."
msgstr ""
msgstr "Za svakog Dobavljača izrađuje se zasebni Nalog Nabave."
#: erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py:96
msgid "A template with tax category {0} already exists. Only one template is allowed with each tax category"
@@ -1176,7 +1176,7 @@ msgstr "Distributer / trgovac / komisionar / podružnica / preprodavač treće s
#: erpnext/crm/doctype/appointment/appointment.py:70
msgid "A verified appointment cannot be moved back to 'Unverified' status."
msgstr ""
msgstr "Potvrđeni termin se ne može vratiti u status 'Neverificirano'."
#. Option for the 'Blood Group' (Select) field in DocType 'Employee'
#: erpnext/setup/doctype/employee/employee.json
@@ -2367,7 +2367,7 @@ msgstr "Radnja je Pokrenuta"
#. DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Action for Expired Unverified Appointments"
msgstr ""
msgstr "Radnja za Istekle Nepotvrđene Termine"
#. Label of the action_if_accumulated_monthly_budget_exceeded (Select) field in
#. DocType 'Budget'
@@ -2913,7 +2913,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 ""
msgstr "Dodaj barem jedan verifikat za ponovno knjiženje."
#: erpnext/www/book_appointment/index.html:42
msgid "Add details"
@@ -3430,7 +3430,7 @@ msgstr "Iznos Predujma"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:93
msgid "Advance Booking Days is mandatory for Appointment Scheduling."
msgstr ""
msgstr "Prethodna Rezervacija Dana je obavezna za Zakazivanje Termina."
#. Label of the advance_paid (Currency) field in DocType 'Sales Order'
#: erpnext/selling/doctype/sales_order/sales_order.json
@@ -3753,7 +3753,7 @@ msgstr "Dob ({0})"
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.js:102
#: erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:28
msgid "Age as on"
msgstr ""
msgstr "Dob na"
#. Label of the ageing_based_on (Select) field in DocType 'Process Statement Of
#. Accounts'
@@ -5107,7 +5107,7 @@ msgstr "Grupa Artikla je način za klasifikaciju Artikala na temelju tipa."
#: erpnext/crm/doctype/appointment/appointment.py:74
msgid "An appointment booked through the portal can only be opened via email verification."
msgstr ""
msgstr "Termin rezerviran putem portala može se otvoriti samo putem potvrde e-poštom."
#. Description of the 'Notify by email on creation of automatic Material
#. Request' (Check) field in DocType 'Stock Settings'
@@ -5505,7 +5505,7 @@ msgstr "Imenovanje"
#. Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Appointment Booking Portal Settings"
msgstr ""
msgstr "Postavke Portala za Zakazivanje Termina"
#. Name of a DocType
#. Label of a Workspace Sidebar Item
@@ -5525,7 +5525,7 @@ msgstr "Potvrda Termina"
#: erpnext/crm/doctype/appointment/appointment.py:189
msgid "Appointment Confirmed"
msgstr ""
msgstr "Termin Potvrđen"
#: erpnext/www/book_appointment/index.js:237
msgid "Appointment Created Successfully"
@@ -5547,7 +5547,7 @@ msgstr "Trajanje Termina (u minutama)"
#. 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Appointment Scheduling"
msgstr ""
msgstr "Zakazivanje Termina"
#: erpnext/www/book_appointment/index.py:24
msgid "Appointment Scheduling Disabled"
@@ -5559,7 +5559,7 @@ msgstr "Zakazivanje termina je onemogućeno za ovu stranicu"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:101
msgid "Appointment Scheduling needs to be enabled for Appointment Booking through portal."
msgstr ""
msgstr "Zakazivanje Termina mora biti omogućeno za Rezervaciju Termina putem portala."
#. Label of the appointment_with (Link) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
@@ -5568,31 +5568,31 @@ msgstr "Termin s"
#: erpnext/crm/doctype/appointment/appointment.py:86
msgid "Appointment can only be scheduled up to {0} day(s) in advance."
msgstr ""
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 ""
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."
msgstr ""
msgstr "Termin se ne može zakazati na praznik."
#: erpnext/www/book_appointment/verify/index.py:28
msgid "Appointment has been closed. Please book the appointment again."
msgstr ""
msgstr "Termin je zatvoren. Ponovo zakažete novi termin."
#: erpnext/www/book_appointment/verify/index.py:33
msgid "Appointment is already verified."
msgstr ""
msgstr "Termin je već potvrđen."
#: erpnext/crm/doctype/appointment/appointment.py:116
msgid "Appointment must be scheduled within the available slot timings."
msgstr ""
msgstr "Termin se mora zakazati unutar raspoloživih vremenskih utora."
#: erpnext/crm/doctype/appointment/appointment.py:66
msgid "Appointments created manually cannot have 'Unverified' status."
msgstr ""
msgstr "Ručno rezervirani termini ne mogu imati status 'Nepotvrđeno'."
#. Label of the approving_role (Link) field in DocType 'Authorization Rule'
#: erpnext/setup/doctype/authorization_rule/authorization_rule.json
@@ -8649,7 +8649,7 @@ msgstr "Spremnik"
#: erpnext/stock/doctype/bin/bin.js:16
msgid "Bin Values Recalculated"
msgstr ""
msgstr "Vrijednosti Spremnika Ponovo Izračunate"
#. Label of the bio (Text Editor) field in DocType 'Employee'
#: erpnext/setup/doctype/employee/employee.json
@@ -8784,7 +8784,7 @@ msgstr "Blokiraj Dostavljača"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Block a new Sales Invoice when the customer's overdue amount exceeds the Overdue Limit set on the customer."
msgstr ""
msgstr "Blokiraj novu Prodajnu Fakturu kada iznos dospjelog plaćanja klijenta premaši ograničenje dospjelog plaćanja postavljeno za klijenta."
#. Description of the 'Is Frozen' (Check) field in DocType 'Customer'
#: erpnext/selling/doctype/customer/customer.json
@@ -9868,7 +9868,7 @@ msgstr "Sastavnica se nemože deaktivirati ili otkazati jer je povezana sa drugi
#: erpnext/crm/doctype/opportunity/opportunity.py:282
msgid "Cannot declare as Lost because an active Quotation exists."
msgstr ""
msgstr "Ne može se proglasiti izgubljeno jer postoji aktivna Ponuda."
#: erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js:16
#: erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js:26
@@ -9977,7 +9977,7 @@ msgstr "Ne može se upućivati na broj reda veći ili jednak trenutnom broju red
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:96
msgid "Cannot repost more than {0} vouchers at once. Split them into multiple documents."
msgstr ""
msgstr "Nije moguće ponovo knjižiti više od {0} verifikata odjednom. Podijeli ih u više dokumenata."
#: erpnext/accounts/doctype/bank/bank.js:63
msgid "Cannot retrieve link token for update. Check Error Log for more information"
@@ -13863,7 +13863,7 @@ msgstr "Izrađeno Migracijom"
#. Label of the created_through_portal (Check) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Created through Portal"
msgstr ""
msgstr "Izrađeno putem Portala"
#: erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py:251
msgid "Created {0} scorecards for {1} between:"
@@ -16439,7 +16439,7 @@ msgstr "Obriši Potencijalne Klijente i Adrese"
#. in DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Delete Permanently"
msgstr ""
msgstr "Trajno Izbriši"
#. Label of the delete_transactions_status (Select) field in DocType
#. 'Transaction Deletion Record'
@@ -18421,7 +18421,7 @@ msgstr "Kopiraj red {0} sa istim {1}"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:110
msgid "Duplicate vouchers found. Remove the duplicate vouchers to continue to repost."
msgstr ""
msgstr "Pronađeni su duplikati verifikata. Ukloni duplikate verifikata da biste nastavili s ponovnim knjiženjem."
#: erpnext/accounts/doctype/pricing_rule/pricing_rule.py:157
msgid "Duplicate {0} found in the table"
@@ -18742,11 +18742,11 @@ msgstr "E-pošta poslana Dobavljaču {0}"
#. Label of the email_verified (Check) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Email Verified"
msgstr ""
msgstr "E-pošta Potvrđena"
#: erpnext/accounts/doctype/payment_request/payment_request.js:57
msgid "Email couldn't be sent."
msgstr ""
msgstr "E-pošta nije mogla biti poslana."
#: erpnext/setup/doctype/employee/employee.py:440
msgid "Email is required to create a user"
@@ -18994,7 +18994,7 @@ msgstr "Omogući Dozvoli Djelomičnu Rezervaciju u Postavkama Zaliha da rezervi
#. Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Enable Appointment Booking Through Portal"
msgstr ""
msgstr "Omogući Zakazivanje Termina Putem Portala"
#. Label of the enable_scheduling (Check) field in DocType 'Appointment Booking
#. Settings'
@@ -23386,7 +23386,7 @@ msgstr "Lista Praznika"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:89
msgid "Holiday List - {0} is not valid for current date."
msgstr ""
msgstr "Popis Praznika - {0} nije valjan za trenutni datum."
#. Label of the holiday_list_name (Data) field in DocType 'Holiday List'
#: erpnext/setup/doctype/holiday_list/holiday_list.json
@@ -24361,7 +24361,7 @@ msgstr "U Minutama"
#. DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "In Minutes (min: 15 mins, max: 60 mins)"
msgstr ""
msgstr "U minutama (min: 15 min, maks: 60 min)"
#: erpnext/accounts/report/accounts_payable/accounts_payable.js:149
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.js:181
@@ -28024,7 +28024,7 @@ msgstr "Artikal {0} nemože se dodati kao sam podsklop"
#: erpnext/stock/doctype/material_request/material_request.py:694
msgid "Item {0} cannot be ordered more than once"
msgstr ""
msgstr "Artikal {0} se ne može naručiti više od jednom"
#: erpnext/manufacturing/doctype/blanket_order/blanket_order.py:197
msgid "Item {0} cannot be ordered more than {1} against Blanket Order {2}."
@@ -30466,7 +30466,7 @@ msgstr "Označi kao Zatvoreno"
#. in DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Mark as Closed"
msgstr ""
msgstr "Odaberi kao Zatvoreno"
#. Description of the 'Is Internal Customer' (Check) field in DocType
#. 'Customer'
@@ -32423,7 +32423,7 @@ msgstr "Nova Prodajna Faktura"
#. Credit Limit'
#: erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
msgid "New Sales Invoices are blocked when the customer's overdue amount exceeds this. Requires 'Restrict Customer Over Billing' in Accounts Settings."
msgstr ""
msgstr "Nove prodajne fakture se blokiraju kada iznos dospjelog duga klijenta premaši ovaj iznos. Zahtijeva opciju 'Ograniči Prekomjerno Fakturisanje Klijenta' u Postavkama Knjiženja."
#. Label of the sales_order (Check) field in DocType 'Email Digest'
#: erpnext/setup/doctype/email_digest/email_digest.json
@@ -32680,7 +32680,7 @@ msgstr "Nema dostupnih dodatnih polja"
#: erpnext/crm/doctype/appointment/appointment.py:103
msgid "No availability of slots are found. Please add on Appointment Booking Settings."
msgstr ""
msgstr "Nije pronađeno nikakvo slobodno vrijeme termina. Dodaj ih u Postavkama Zakazivanja Termina."
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py:1367
msgid "No available quantity to reserve for item {0} in warehouse {1}"
@@ -34859,15 +34859,15 @@ msgstr "Dana Zakašnjenja"
#. Credit Limit'
#: erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
msgid "Overdue Limit"
msgstr ""
msgstr "Granica Dospijeća"
#: erpnext/selling/doctype/customer/customer.py:707
msgid "Overdue Limit Crossed"
msgstr ""
msgstr "Granica Dospijeća Prekoračena"
#: erpnext/selling/doctype/customer/customer.py:702
msgid "Overdue Limit crossed for customer {0}. Overdue amount {1} exceeds the allowed limit {2}."
msgstr ""
msgstr "Granica Dospijeća prekoračena je za {0}. Iznos dospijeća {1} prelazi dozvoljenu granicu {2}."
#. Name of a DocType
#: erpnext/accounts/doctype/overdue_payment/overdue_payment.json
@@ -35798,7 +35798,7 @@ msgstr "Djelimično Usaglašeno"
#. Option for the 'Status' (Select) field in DocType 'Repost Accounting Ledger'
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json
msgid "Partially Reposted"
msgstr ""
msgstr "Djelomično Ponovo Knjiženo"
#. Option for the 'Status' (Select) field in DocType 'Stock Reservation Entry'
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json
@@ -36562,7 +36562,7 @@ msgstr "Ograničenje Plaćanja"
#: erpnext/accounts/doctype/payment_request/payment_request.py:434
msgid "Payment Link couldn't be sent."
msgstr ""
msgstr "Poveznica za plaćanje nije mogla biti poslana."
#: erpnext/accounts/report/pos_register/pos_register.js:50
#: erpnext/accounts/report/pos_register/pos_register.py:126
@@ -37884,7 +37884,7 @@ msgstr "Dodaj Račun za Privremeno Otvaranje u Kontni Plan"
#: erpnext/crm/doctype/appointment/appointment.py:95
msgid "Please add a valid Holiday List on Appointment Booking Settings."
msgstr ""
msgstr "Dodaj valjani Popis Praznika u Postavke Zakazivanja Termina."
#: erpnext/accounts/doctype/bank_transaction_rule/bank_transaction_rule.py:119
msgid "Please add an account for the Bank Entry rule."
@@ -38269,7 +38269,7 @@ msgstr "Popuni Tabelu Prodajnih Naloga"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:57
msgid "Please fill up the Availability of Slots table to enable Appointment Scheduling."
msgstr ""
msgstr "Popuni tablicu Dostupnosti Termina kako biste omogućili Zakazivanje Termina."
#: erpnext/stock/doctype/shipment/shipment.js:277
msgid "Please first set Full Name, Email and Phone for the user"
@@ -38513,7 +38513,7 @@ msgstr "Odaberi Dostavnicu"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:81
msgid "Please select a Holiday List to enable Appointment Scheduling."
msgstr ""
msgstr "Odaberi Popis Praznika kako biste omogućili Zakazivanje Termina."
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py:153
msgid "Please select a Subcontracting Purchase Order."
@@ -38594,7 +38594,7 @@ msgstr "Odaberi važeći Nalog Nabave koji je konfigurisan za Podugovor."
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.py:1355
msgid "Please select a valid {0}"
msgstr ""
msgstr "Odaberi valjani {0}"
#: erpnext/selling/doctype/quotation/quotation.js:245
msgid "Please select a value for {0} quotation_to {1}"
@@ -42540,12 +42540,12 @@ msgstr "Količina ne može biti veća od {0} za artikal {1}"
#: erpnext/stock/doctype/material_request/material_request.py:704
msgid "Quantity for Item {0} must be greater than zero and cannot exceed {1}"
msgstr ""
msgstr "Količina za Artikal {0} mora biti veća od nule i ne može biti veća od {1}"
#: erpnext/stock/doctype/material_request/material_request.js:564
msgctxt "<b>${pending_qty}</b>"
msgid "Quantity for Item {0} must be greater than zero and cannot exceed {1}"
msgstr ""
msgstr "Količina za Artikal {0} mora biti veća od nule i ne može biti veća od {1}"
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js:564
msgid "Quantity is mandatory for the selected items."
@@ -43406,7 +43406,7 @@ msgstr "Ponovo izračunaj Stopu Vrednovanja"
#: erpnext/stock/doctype/bin/bin.js:10
msgid "Recalculate Values"
msgstr ""
msgstr "Preračunaj Vrijednosti"
#. Option for the 'Status' (Select) field in DocType 'Asset'
#. Option for the 'Purpose' (Select) field in DocType 'Asset Movement'
@@ -44608,7 +44608,7 @@ msgstr "Ponovno Knjiženje je započeto u pozadini"
#. Items'
#: erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json
msgid "Reposted"
msgstr ""
msgstr "Ponovno Knjiženo"
#. Label of the reposting_data_file (Attach) field in DocType 'Repost Item
#. Valuation'
@@ -44636,7 +44636,7 @@ msgstr "Referansa Ponovnog knjiženja"
#. 'Repost Accounting Ledger Items'
#: erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json
msgid "Reposting Status"
msgstr ""
msgstr "Status Ponovnog Knjiženja"
#. Label of the vouchers_based_on_item_and_warehouse_section (Section Break)
#. field in DocType 'Repost Item Valuation'
@@ -44650,11 +44650,11 @@ msgstr "Napred Ponovnog Knjiženja Kaučera"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:216
msgid "Reposting can be started only for submitted document."
msgstr ""
msgstr "Ponovno Knjiženje se može pokrenuti samo za podnešeni dokument."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:221
msgid "Reposting cannot be started when status is {0}."
msgstr ""
msgstr "Ponovno Knjiženje se ne može pokrenuti kada je status {0}."
#: erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py:227
#: erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py:338
@@ -44679,11 +44679,11 @@ msgstr "Ponovno Knjiženje u pozadini."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:211
msgid "Reposting is still in progress in background."
msgstr ""
msgstr "Ponovno knjiženje je još uvijek u tijeku u pozadini."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:315
msgid "Reposting {0} {1}"
msgstr ""
msgstr "Ponovno knjiženje {0} {1}"
#. Label of the represents_company (Link) field in DocType 'Purchase Invoice'
#. Label of the represents_company (Link) field in DocType 'Sales Invoice'
@@ -45356,7 +45356,7 @@ msgstr "Ograniči"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Restrict Customer Over Billing"
msgstr ""
msgstr "Ograničiti Prekomjerno Fakturisanje Klijenta"
#. Label of the restrict_based_on (Select) field in DocType 'Party Specific
#. Item'
@@ -45678,7 +45678,7 @@ msgstr "Obrnuta Signatura"
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py:628
msgid "Reverse {0} already available in draft status: {1}"
msgstr ""
msgstr "Obrnuto {0} već je dostupno u statusu nacrta: {1}"
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js:118
msgid "Reversing Journals..."
@@ -45807,7 +45807,7 @@ msgstr "Štap"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Role Allowed to Bypass Over Billing Restriction"
msgstr ""
msgstr "Uloga kojoj je dopušteno zaobilaženje Ograničenja Prekomjernog Fakturisanja"
#. Label of the role_allowed_to_over_deliver_receive (Link) field in DocType
#. 'Stock Settings'
@@ -48518,7 +48518,7 @@ msgstr "Raspoređivač je neaktivan. Nije moguće spojiti račune."
#: 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 "Zakazivač je neaktivan. Ponovno Knjiženje će se pokrenuti tek nakon što se obrade pozadinski zadaci."
#. Label of the schedules (Table) field in DocType 'Maintenance Schedule'
#: erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
@@ -48951,7 +48951,7 @@ msgstr "Odaberi Adresu Dobavljača"
#: erpnext/stock/doctype/material_request/material_request.js:448
msgid "Select Supplier for Items"
msgstr ""
msgstr "Odaberi Dobavljača za Artikle"
#: erpnext/stock/doctype/batch/batch.js:150
msgid "Select Target Warehouse"
@@ -49005,7 +49005,7 @@ msgstr "Odaberi Dobavljača"
#: erpnext/stock/doctype/material_request/material_request.js:552
#: erpnext/stock/doctype/material_request/material_request.py:699
msgid "Select a Supplier for Item {0}"
msgstr ""
msgstr "Odaberi Dobavljača za Artikal {0}"
#: banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx:49
msgid "Select a bank account to reconcile"
@@ -49046,7 +49046,7 @@ msgstr "Odaber artikal iz svakog skupa koja će se koristiti u Prodajnom Nalogu.
#: erpnext/stock/doctype/material_request/material_request.js:539
#: erpnext/stock/doctype/material_request/material_request.py:680
msgid "Select at least one Item"
msgstr ""
msgstr "Odaberi barem jedan Artikal"
#: erpnext/stock/doctype/item/item.js:944
msgid "Select at least one attribute value."
@@ -49365,7 +49365,7 @@ msgstr "Pošalji sa Prilogom"
#: erpnext/accounts/doctype/payment_request/payment_request.js:51
#: erpnext/accounts/doctype/payment_request/payment_request.js:55
msgid "Sending Email"
msgstr ""
msgstr "Slanje e-pošte u tijeku"
#. Option for the 'Detected Amount Format' (Select) field in DocType 'Bank
#. Statement Import Log'
@@ -50194,7 +50194,7 @@ msgstr "Postavi Dobavljača"
#: erpnext/stock/doctype/material_request/material_request.js:455
msgid "Set Supplier for All Items"
msgstr ""
msgstr "Postavi Dobavljača za Sve Artikle"
#. Label of the set_target_warehouse (Link) field in DocType 'Sales Invoice'
#. Label of the set_warehouse (Link) field in DocType 'Purchase Order'
@@ -52609,7 +52609,7 @@ msgstr "Zaliha nije dostupna za Artikal {0} u Skladištu {1}."
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py:1240
msgid "Stock not available to reserve for the Item {0} in Warehouse {1}."
msgstr ""
msgstr "Zaliha nije dostupna za rezervaciju za Artikal {0} u Skladištu {1}."
#: erpnext/selling/page/point_of_sale/pos_controller.js:826
msgid "Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2} {3}."
@@ -55286,7 +55286,7 @@ msgstr "Računa pod Obavezama ili Kapitalom, u kojoj će se knjižiti Rezultat"
#: erpnext/accounts/doctype/account/account.py:222
msgid "The account type of {0} cannot be changed from {1} because stock ledger entries exist against it."
msgstr ""
msgstr "Tip računa {0} ne može se promijeniti iz {1} jer postoje unosi u Registru Zaliha."
#: erpnext/accounts/doctype/payment_request/payment_request.py:1016
msgid "The allocated amount is greater than the outstanding amount of Payment Request {0}"
@@ -55444,7 +55444,7 @@ msgstr "Sljedeći redovi su duplikati:"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:130
msgid "The following vouchers are not submitted: {0}"
msgstr ""
msgstr "Sljedeći verifikati nisu podnešeni: {0}"
#: erpnext/stock/doctype/material_request/material_request.py:1062
msgid "The following {0} were created: {1}"
@@ -55956,7 +55956,7 @@ msgstr "Ovaj dokument je preko ograničenja za {0} {1} za artikal {4}. Da li pra
#: erpnext/templates/emails/appointment_confirmed.html:6
msgid "This email was sent from {0}"
msgstr ""
msgstr "Ova e-pošta je poslana od {0}"
#: erpnext/stock/doctype/delivery_note/delivery_note.js:496
msgid "This field is used to set the 'Customer'."
@@ -56102,7 +56102,7 @@ msgstr "Ovaj filter artikala je već primijenjen za {0}"
#: erpnext/templates/emails/confirm_appointment.html:4
msgid "This link is valid for {0} minutes"
msgstr ""
msgstr "Ova poveznica vrijedi {0} minuta"
#: erpnext/www/banking.py:35
msgid "This method is only meant for developer mode"
@@ -56223,7 +56223,7 @@ msgstr "Ova vrijednost će se koristiti kada se ne pronađe odgovarajući Zajedn
#: erpnext/www/book_appointment/verify/index.py:18
msgid "This verification link is invalid. Please book the appointment again."
msgstr ""
msgstr "Ova poveznica za verifikaciju je nevažeća. Ponovo zakaži termin."
#: banking/src/components/features/Settings/Preferences.tsx:86
msgid "This will automatically run transaction matching rules on unreconciled transactions every hour."
@@ -58030,7 +58030,7 @@ msgstr "Transakcije naspram Tvrtke već postoje! Kontni Plan se može uvesti sam
#. '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 ""
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"
@@ -58651,7 +58651,7 @@ msgstr "Poništi Dodjele"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:375
msgid "Unable to Repost Accounting Ledger"
msgstr ""
msgstr "Ponovo knjiži Knjigovodstveni Registar"
#: erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py:477
msgid "Unable to fetch DocType details. Please contact system administrator."
@@ -59594,7 +59594,7 @@ msgstr "Korisnicima sa ovom ulogom je dozvoljena prekomjerna Dostava/Primanje na
#. field in DocType 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Users with this role can still submit invoices for customers who have crossed their Overdue Limit."
msgstr ""
msgstr "Korisnici s ovom ulogom i dalje mogu podnositi fakture za klijente koji su prekoračili granicu dospjelosti."
#. Description of the 'Role to Notify on Depreciation Failure' (Link) field in
#. DocType 'Accounts Settings'
@@ -60141,12 +60141,12 @@ msgstr "Rizični Kapital"
#. 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Verification Link Expiry Duration"
msgstr ""
msgstr "Trajanje Vađenaj Verifikacijske Poveznice"
#. Label of the verification_token (Data) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Verification Token"
msgstr ""
msgstr "Verifikacijski Kod"
#: erpnext/www/book_appointment/verify/index.html:15
msgid "Verification failed please check the link"
@@ -60154,7 +60154,7 @@ msgstr "Verifikacija nije uspjela, provjeri vezu"
#: erpnext/www/book_appointment/verify/index.py:38
msgid "Verification link has expired."
msgstr ""
msgstr "Veza za provjeru je istekla."
#. Label of the verified_by (Data) field in DocType 'Quality Inspection'
#: erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -61012,7 +61012,7 @@ msgstr "Vidimo da je {0} napravljen protiv {1}. Ako želite da se ažuriraju pre
#: erpnext/templates/emails/appointment_confirmed.html:3
msgid "We look forward to meeting you"
msgstr ""
msgstr "Radujemo se susretu s vama"
#: 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."
@@ -62123,7 +62123,7 @@ msgstr "Vaše Ime (obavezno)"
#: erpnext/templates/emails/appointment_confirmed.html:2
msgid "Your email has been verified and your appointment has been confirmed for {0}"
msgstr ""
msgstr "Vaša e-pošta je potvrđena i vaš termin je potvrđen za {0}"
#: erpnext/www/book_appointment/verify/index.html:11
msgid "Your email has been verified and your appointment has been scheduled"
@@ -62948,7 +62948,7 @@ msgstr "Prikaz {0} trenutno nije podržan u Prilagođenom Financijskom Izvješć
#: erpnext/stock/doctype/material_request/material_request.py:732
msgid "{0} was set to today for items whose requested date has passed"
msgstr ""
msgstr "{0} je postavljen na danas za artikle čiji je traženi datum prošao"
#: erpnext/accounts/doctype/payment_term/payment_term.js:19
msgid "{0} will be given as discount."

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:43\n"
"PO-Revision-Date: 2026-08-06 10:01\n"
"Last-Translator: hello@frappe.io\n"
"Language-Team: Swedish\n"
"MIME-Version: 1.0\n"
@@ -152,7 +152,7 @@ msgstr "% Klart Sätt"
#: erpnext/projects/doctype/project/project.py:226
msgid "% Complete must be between 0 and 100"
msgstr ""
msgstr "% Färdig måste vara mellan 0 och 100"
#. Label of the percent_complete (Percent) field in DocType 'Project'
#: erpnext/projects/doctype/project/project.json
@@ -349,7 +349,7 @@ msgstr "\"Uppdatera Lager\" kan inte väljas för Fast Tillgång Försäljning"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:112
msgid "'Verification Link Expiry Duration' must be between 15 to 60 minutes."
msgstr ""
msgstr "'Verifiering Länk Utgång Tid' måste vara mellan 15 och 60 minuter."
#: erpnext/accounts/doctype/bank_account/bank_account.py:79
msgid "'{0}' account is already used by {1}. Use another account."
@@ -1125,7 +1125,7 @@ msgstr "Inaktiverad Artikel Paket kan inte väljas i transaktioner."
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py:636
msgid "A draft reverse journal for {0} has been created: {1}"
msgstr ""
msgstr "Utkast till omvänd journal för {0} har skapats: {1}"
#: erpnext/stock/doctype/delivery_trip/delivery_trip.py:59
msgid "A driver must be set to submit."
@@ -1170,7 +1170,7 @@ msgstr "Kvalitet kontroll måste genomföras innan Inköp Följesedel skapas fö
#: erpnext/stock/doctype/material_request/material_request.js:476
msgid "A separate Purchase Order is created for each Supplier."
msgstr ""
msgstr "Separat Inköp Order skapas för varje Leverantör."
#: erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py:96
msgid "A template with tax category {0} already exists. Only one template is allowed with each tax category"
@@ -1183,7 +1183,7 @@ msgstr "Tredje parts distributör / handlare / kommissionär / återförsäljare
#: erpnext/crm/doctype/appointment/appointment.py:70
msgid "A verified appointment cannot be moved back to 'Unverified' status."
msgstr ""
msgstr "Verifierad bokning kan inte flyttas tillbaka till \"Overifierad\" status."
#. Option for the 'Blood Group' (Select) field in DocType 'Employee'
#: erpnext/setup/doctype/employee/employee.json
@@ -2374,7 +2374,7 @@ msgstr "Åtgärd Initierad"
#. DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Action for Expired Unverified Appointments"
msgstr ""
msgstr "Åtgärd för Utgångna, Overifierade Bokningar"
#. Label of the action_if_accumulated_monthly_budget_exceeded (Select) field in
#. DocType 'Budget'
@@ -2920,7 +2920,7 @@ msgstr "Lägg till alla konton som du vill dela upp transaktion i."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:92
msgid "Add atleast one voucher to repost."
msgstr ""
msgstr "Lägg till minst ett verifikat för att bokföra om."
#: erpnext/www/book_appointment/index.html:42
msgid "Add details"
@@ -3437,7 +3437,7 @@ msgstr "Förskott Belopp"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:93
msgid "Advance Booking Days is mandatory for Appointment Scheduling."
msgstr ""
msgstr "Förhandsbokning erfordras för Tdsbokning Schemaläggning."
#. Label of the advance_paid (Currency) field in DocType 'Sales Order'
#: erpnext/selling/doctype/sales_order/sales_order.json
@@ -3760,7 +3760,7 @@ msgstr "Ålder ({0})"
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.js:102
#: erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:28
msgid "Age as on"
msgstr ""
msgstr "Ålder per"
#. Label of the ageing_based_on (Select) field in DocType 'Process Statement Of
#. Accounts'
@@ -5114,7 +5114,7 @@ msgstr "Artikel grupp är ett sätt att klassificera artiklar baserat på typer.
#: erpnext/crm/doctype/appointment/appointment.py:74
msgid "An appointment booked through the portal can only be opened via email verification."
msgstr ""
msgstr "Bokad tid via portal kan endast öppnas via e-post verifiering."
#. Description of the 'Notify by email on creation of automatic Material
#. Request' (Check) field in DocType 'Stock Settings'
@@ -5512,7 +5512,7 @@ msgstr "Möte"
#. Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Appointment Booking Portal Settings"
msgstr ""
msgstr "Tid Bokning Portal Inställningar"
#. Name of a DocType
#. Label of a Workspace Sidebar Item
@@ -5532,7 +5532,7 @@ msgstr "Tid Bokning Bekräftelse"
#: erpnext/crm/doctype/appointment/appointment.py:189
msgid "Appointment Confirmed"
msgstr ""
msgstr "Tidsbokning Bekräftad"
#: erpnext/www/book_appointment/index.js:237
msgid "Appointment Created Successfully"
@@ -5554,7 +5554,7 @@ msgstr "Tid Bokning Varar (Minuter)"
#. 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Appointment Scheduling"
msgstr ""
msgstr "Tidsbokning Schemaläggning"
#: erpnext/www/book_appointment/index.py:24
msgid "Appointment Scheduling Disabled"
@@ -5566,7 +5566,7 @@ msgstr "Tid Bokning är Inaktiverad för denna Webbplats"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:101
msgid "Appointment Scheduling needs to be enabled for Appointment Booking through portal."
msgstr ""
msgstr "Tidsbokning Schemaläggning måste vara aktiverad för Tidsbokning via portal."
#. Label of the appointment_with (Link) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
@@ -5575,31 +5575,31 @@ msgstr "Tid Bokning med"
#: erpnext/crm/doctype/appointment/appointment.py:86
msgid "Appointment can only be scheduled up to {0} day(s) in advance."
msgstr ""
msgstr "Tidsbokning kan endast schemaläggas upp till {0} dag(ar) i förväg."
#: erpnext/crm/doctype/appointment/appointment.py:79
msgid "Appointment cannot be scheduled for a past time."
msgstr ""
msgstr "Tidsbokning kan inte schemaläggas för förfluten tid."
#: erpnext/crm/doctype/appointment/appointment.py:98
msgid "Appointment cannot be scheduled on a holiday."
msgstr ""
msgstr "Tidsbokning kan inte schemaläggas på helgdag."
#: erpnext/www/book_appointment/verify/index.py:28
msgid "Appointment has been closed. Please book the appointment again."
msgstr ""
msgstr "Tidsbokning har stängts. Boka igen."
#: erpnext/www/book_appointment/verify/index.py:33
msgid "Appointment is already verified."
msgstr ""
msgstr "Tidsbokning är redan bekräftad."
#: erpnext/crm/doctype/appointment/appointment.py:116
msgid "Appointment must be scheduled within the available slot timings."
msgstr ""
msgstr "Tidsbokning måste schemaläggas inom tillgänglig tidsintervall."
#: erpnext/crm/doctype/appointment/appointment.py:66
msgid "Appointments created manually cannot have 'Unverified' status."
msgstr ""
msgstr "Tidsbokningar som skapas manuellt kan inte ha ”Overifierad” status."
#. Label of the approving_role (Link) field in DocType 'Authorization Rule'
#: erpnext/setup/doctype/authorization_rule/authorization_rule.json
@@ -8791,7 +8791,7 @@ msgstr "Spärra Leverantör"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Block a new Sales Invoice when the customer's overdue amount exceeds the Overdue Limit set on the customer."
msgstr ""
msgstr "Spärra ny Försäljning Faktura när kundens förfallna belopp överstiger förfallen gräns angiven för kund."
#. Description of the 'Is Frozen' (Check) field in DocType 'Customer'
#: erpnext/selling/doctype/customer/customer.json
@@ -9875,7 +9875,7 @@ msgstr "Kan inte inaktivera eller annullera Stycklista eftersom den är kopplat
#: erpnext/crm/doctype/opportunity/opportunity.py:282
msgid "Cannot declare as Lost because an active Quotation exists."
msgstr ""
msgstr "Kan inte ange som förlorad eftersom det finns aktiv Offert."
#: erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js:16
#: erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.js:26
@@ -9984,7 +9984,7 @@ msgstr "Kan inte hänvisa till rad nummer högre än eller lika med aktuell rad
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:96
msgid "Cannot repost more than {0} vouchers at once. Split them into multiple documents."
msgstr ""
msgstr "Kunde inte återbokföra fler än {0} verifikationer samtidigt. Dela upp dem i flera dokument."
#: erpnext/accounts/doctype/bank/bank.js:63
msgid "Cannot retrieve link token for update. Check Error Log for more information"
@@ -13870,7 +13870,7 @@ msgstr "Skapad av Migrering"
#. Label of the created_through_portal (Check) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Created through Portal"
msgstr ""
msgstr "Skapad via Portal"
#: erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py:251
msgid "Created {0} scorecards for {1} between:"
@@ -16446,7 +16446,7 @@ msgstr "Ta bort Prospekt och Adresser"
#. in DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Delete Permanently"
msgstr ""
msgstr "Ta bort Permanent"
#. Label of the delete_transactions_status (Select) field in DocType
#. 'Transaction Deletion Record'
@@ -18342,7 +18342,7 @@ msgstr "Påminnelse Typ"
#: erpnext/accounts/doctype/pos_profile/pos_profile.py:170
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"
@@ -18354,11 +18354,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:164
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"
@@ -18376,7 +18376,7 @@ msgstr "Duplicera Kassa Fällt"
#: erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py:104
#: 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:134
msgid "Duplicate Payment Schedule selected"
@@ -18384,7 +18384,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:157
msgid "Duplicate Sales Invoices found"
@@ -18404,7 +18404,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}"
@@ -18412,27 +18412,27 @@ msgstr "Duplicerad post: {0}{1}"
#: erpnext/accounts/doctype/pos_profile/pos_profile.py:164
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."
msgstr ""
msgstr "Dubbletter av verifikat hittades. Ta bort dubbletter för att fortsätta återbokföring."
#: 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
@@ -18749,11 +18749,11 @@ msgstr "E-post Skickad till Leverantör {0}"
#. Label of the email_verified (Check) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Email Verified"
msgstr ""
msgstr "E-post Verifierad"
#: erpnext/accounts/doctype/payment_request/payment_request.js:57
msgid "Email couldn't be sent."
msgstr ""
msgstr "E-post meddelande kunde inte skickas."
#: erpnext/setup/doctype/employee/employee.py:440
msgid "Email is required to create a user"
@@ -19001,7 +19001,7 @@ msgstr "Aktivera Tillåt Partiell Reservation i Lager Inställningar för att re
#. Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Enable Appointment Booking Through Portal"
msgstr ""
msgstr "Aktivera Tidsbokning via Portal"
#. Label of the enable_scheduling (Check) field in DocType 'Appointment Booking
#. Settings'
@@ -23392,7 +23392,7 @@ msgstr "Helg Lista"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:89
msgid "Holiday List - {0} is not valid for current date."
msgstr ""
msgstr "Helgdag Lista - {0} är inte giltig för aktuellt datum."
#. Label of the holiday_list_name (Data) field in DocType 'Holiday List'
#: erpnext/setup/doctype/holiday_list/holiday_list.json
@@ -24367,7 +24367,7 @@ msgstr "I Minuter"
#. DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "In Minutes (min: 15 mins, max: 60 mins)"
msgstr ""
msgstr "I Minuter (min: 15 min, max: 60 min)"
#: erpnext/accounts/report/accounts_payable/accounts_payable.js:149
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.js:181
@@ -28030,7 +28030,7 @@ msgstr "Artikel {0} kan inte läggas till som underenhet av sig själv"
#: erpnext/stock/doctype/material_request/material_request.py:694
msgid "Item {0} cannot be ordered more than once"
msgstr ""
msgstr "Artikel {0} kan inte skapas order för mer än en gång"
#: erpnext/manufacturing/doctype/blanket_order/blanket_order.py:197
msgid "Item {0} cannot be ordered more than {1} against Blanket Order {2}."
@@ -30472,7 +30472,7 @@ msgstr "Ange som Stängd "
#. in DocType 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Mark as Closed"
msgstr ""
msgstr "Ange som Stängd"
#. Description of the 'Is Internal Customer' (Check) field in DocType
#. 'Customer'
@@ -32429,7 +32429,7 @@ msgstr "Ny Försäljning Faktura"
#. Credit Limit'
#: erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
msgid "New Sales Invoices are blocked when the customer's overdue amount exceeds this. Requires 'Restrict Customer Over Billing' in Accounts Settings."
msgstr ""
msgstr "Nya Försäljning Fakturor spärras när kundens förfallna belopp överstiger detta belopp. Erfordrar att alternativ ”Begränsa Kund Överfakturering” är aktiverad i Bokföring Inställningar."
#. Label of the sales_order (Check) field in DocType 'Email Digest'
#: erpnext/setup/doctype/email_digest/email_digest.json
@@ -32686,7 +32686,7 @@ msgstr "Inga extra fält tillgängliga"
#: erpnext/crm/doctype/appointment/appointment.py:103
msgid "No availability of slots are found. Please add on Appointment Booking Settings."
msgstr ""
msgstr "Inga lediga tider hittades. Lägg till detta i Tidsbokning Inställningar."
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py:1367
msgid "No available quantity to reserve for item {0} in warehouse {1}"
@@ -34865,15 +34865,15 @@ msgstr "Försening Dagar"
#. Credit Limit'
#: erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
msgid "Overdue Limit"
msgstr ""
msgstr "Förfallen Gräns"
#: erpnext/selling/doctype/customer/customer.py:707
msgid "Overdue Limit Crossed"
msgstr ""
msgstr "Förfallen Gräns Överskriden"
#: erpnext/selling/doctype/customer/customer.py:702
msgid "Overdue Limit crossed for customer {0}. Overdue amount {1} exceeds the allowed limit {2}."
msgstr ""
msgstr "Förfallen Gräns överskriden för kund {0}. Förfallen belopp {1} överskrider tillåten gräns {2}."
#. Name of a DocType
#: erpnext/accounts/doctype/overdue_payment/overdue_payment.json
@@ -35804,7 +35804,7 @@ msgstr "Delvis Avstämd"
#. Option for the 'Status' (Select) field in DocType 'Repost Accounting Ledger'
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json
msgid "Partially Reposted"
msgstr ""
msgstr "Delvis Återbokförd"
#. Option for the 'Status' (Select) field in DocType 'Stock Reservation Entry'
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.json
@@ -36568,7 +36568,7 @@ msgstr "Betalning Gräns"
#: erpnext/accounts/doctype/payment_request/payment_request.py:434
msgid "Payment Link couldn't be sent."
msgstr ""
msgstr "Betalning Länk kunde inte skickas."
#: erpnext/accounts/report/pos_register/pos_register.js:50
#: erpnext/accounts/report/pos_register/pos_register.py:126
@@ -37890,7 +37890,7 @@ msgstr "Lägg till Tillfällig Öppning Konto i Kontoplan"
#: erpnext/crm/doctype/appointment/appointment.py:95
msgid "Please add a valid Holiday List on Appointment Booking Settings."
msgstr ""
msgstr "Lägg till giltig Helgdag Lista i Tidsbokning Inställningar."
#: erpnext/accounts/doctype/bank_transaction_rule/bank_transaction_rule.py:119
msgid "Please add an account for the Bank Entry rule."
@@ -38275,7 +38275,7 @@ msgstr "Fyll i Försäljning Order Tabell"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:57
msgid "Please fill up the Availability of Slots table to enable Appointment Scheduling."
msgstr ""
msgstr "Fyll i tabell ”Lediga Tider” för att aktivera Tidsbokning Schemaläggning."
#: erpnext/stock/doctype/shipment/shipment.js:277
msgid "Please first set Full Name, Email and Phone for the user"
@@ -38519,7 +38519,7 @@ msgstr "Välj Försäljning Följesedel"
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py:81
msgid "Please select a Holiday List to enable Appointment Scheduling."
msgstr ""
msgstr "Välj Helgdag Lista för att aktivera Tidsbokning Schemaläggning."
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py:153
msgid "Please select a Subcontracting Purchase Order."
@@ -38600,7 +38600,7 @@ msgstr "Välj giltig Inköp Order som är konfigurerad för Underleverantör."
#: erpnext/accounts/report/accounts_receivable/accounts_receivable.py:1355
msgid "Please select a valid {0}"
msgstr ""
msgstr "Välj giltig {0}"
#: erpnext/selling/doctype/quotation/quotation.js:245
msgid "Please select a value for {0} quotation_to {1}"
@@ -42546,12 +42546,12 @@ msgstr "Kvantitet kan inte vara högre än {0} för artikel {1}"
#: erpnext/stock/doctype/material_request/material_request.py:704
msgid "Quantity for Item {0} must be greater than zero and cannot exceed {1}"
msgstr ""
msgstr "Kvantitet för artikel {0} måste vara högre än noll och får inte överstiga {1}"
#: erpnext/stock/doctype/material_request/material_request.js:564
msgctxt "<b>${pending_qty}</b>"
msgid "Quantity for Item {0} must be greater than zero and cannot exceed {1}"
msgstr ""
msgstr "Kvantitet för artikel {0} måste vara högre än noll och får inte överstiga {1}"
#: erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js:564
msgid "Quantity is mandatory for the selected items."
@@ -43412,7 +43412,7 @@ msgstr "Räkna om Värdering Pris"
#: erpnext/stock/doctype/bin/bin.js:10
msgid "Recalculate Values"
msgstr ""
msgstr "Beräkna om Värden"
#. Option for the 'Status' (Select) field in DocType 'Asset'
#. Option for the 'Purpose' (Select) field in DocType 'Asset Movement'
@@ -44614,7 +44614,7 @@ msgstr "Bokföring startad i bakgrunden"
#. Items'
#: erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json
msgid "Reposted"
msgstr ""
msgstr "Återbokförd"
#. Label of the reposting_data_file (Attach) field in DocType 'Repost Item
#. Valuation'
@@ -44642,7 +44642,7 @@ msgstr "Ombokning Referens"
#. 'Repost Accounting Ledger Items'
#: erpnext/accounts/doctype/repost_accounting_ledger_items/repost_accounting_ledger_items.json
msgid "Reposting Status"
msgstr ""
msgstr "Återbokförd Status"
#. Label of the vouchers_based_on_item_and_warehouse_section (Section Break)
#. field in DocType 'Repost Item Valuation'
@@ -44656,11 +44656,11 @@ msgstr "Ombokning av Verifikat Framsteg"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:216
msgid "Reposting can be started only for submitted document."
msgstr ""
msgstr "Återbokföring kan endast påbörjas för godkända dokument."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:221
msgid "Reposting cannot be started when status is {0}."
msgstr ""
msgstr "Återbokföring kan inte påbörjas när status är {0}."
#: erpnext/stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py:227
#: erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py:338
@@ -44685,11 +44685,11 @@ msgstr "Ombokning i bakgrund."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:211
msgid "Reposting is still in progress in background."
msgstr ""
msgstr "Återbokföring pågår fortfarande i bakgrunden."
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:315
msgid "Reposting {0} {1}"
msgstr ""
msgstr "Återbokför {0} {1}"
#. Label of the represents_company (Link) field in DocType 'Purchase Invoice'
#. Label of the represents_company (Link) field in DocType 'Sales Invoice'
@@ -45362,7 +45362,7 @@ msgstr "Begränsa"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Restrict Customer Over Billing"
msgstr ""
msgstr "Begränsa Kund Överfakturering"
#. Label of the restrict_based_on (Select) field in DocType 'Party Specific
#. Item'
@@ -45684,7 +45684,7 @@ msgstr "Omvänd Signatur"
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py:628
msgid "Reverse {0} already available in draft status: {1}"
msgstr ""
msgstr "Omvänd {0} finns redan tillgänglig som utkast: {1}"
#: erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.js:118
msgid "Reversing Journals..."
@@ -45813,7 +45813,7 @@ msgstr "Stav"
#. 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Role Allowed to Bypass Over Billing Restriction"
msgstr ""
msgstr "Roll Tillåten att Kringgå Överfakturering Begränsning"
#. Label of the role_allowed_to_over_deliver_receive (Link) field in DocType
#. 'Stock Settings'
@@ -46320,7 +46320,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/selling/doctype/sales_order/sales_order.py:332
msgid "Row #{0}: Expected Delivery Date cannot be before Purchase Order Date"
@@ -48525,7 +48525,7 @@ msgstr "Schemaläggare är inaktiv. Kan inte slå samman konton."
#: 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 "Schemaläggare är inaktiv. Återbokföring kommer endast att köras när bakgrundsjobb är klara."
#. Label of the schedules (Table) field in DocType 'Maintenance Schedule'
#: erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
@@ -48958,7 +48958,7 @@ msgstr "Välj Leverantör Adress"
#: erpnext/stock/doctype/material_request/material_request.js:448
msgid "Select Supplier for Items"
msgstr ""
msgstr "Välj Leverantör för Artiklar"
#: erpnext/stock/doctype/batch/batch.js:150
msgid "Select Target Warehouse"
@@ -49012,7 +49012,7 @@ msgstr "Välj Leverantör"
#: erpnext/stock/doctype/material_request/material_request.js:552
#: erpnext/stock/doctype/material_request/material_request.py:699
msgid "Select a Supplier for Item {0}"
msgstr ""
msgstr "Välj Leverantör för Artikel {0}"
#: banking/src/components/features/BankReconciliation/MatchAndReconcile.tsx:49
msgid "Select a bank account to reconcile"
@@ -49053,7 +49053,7 @@ msgstr "Välj artikel från varje uppsättning som ska användas i Försäljning
#: erpnext/stock/doctype/material_request/material_request.js:539
#: erpnext/stock/doctype/material_request/material_request.py:680
msgid "Select at least one Item"
msgstr ""
msgstr "Välj minst en artikel"
#: erpnext/stock/doctype/item/item.js:944
msgid "Select at least one attribute value."
@@ -49372,7 +49372,7 @@ msgstr "Skicka med Bilaga"
#: erpnext/accounts/doctype/payment_request/payment_request.js:51
#: erpnext/accounts/doctype/payment_request/payment_request.js:55
msgid "Sending Email"
msgstr ""
msgstr "Skickar e-post"
#. Option for the 'Detected Amount Format' (Select) field in DocType 'Bank
#. Statement Import Log'
@@ -50201,7 +50201,7 @@ msgstr "Ange Leverantör"
#: erpnext/stock/doctype/material_request/material_request.js:455
msgid "Set Supplier for All Items"
msgstr ""
msgstr "Ange Leverantör för Alla Artiklar"
#. Label of the set_target_warehouse (Link) field in DocType 'Sales Invoice'
#. Label of the set_warehouse (Link) field in DocType 'Purchase Order'
@@ -52616,7 +52616,7 @@ msgstr "Lager ej tillgängligt för Artikel {0} i Lager {1}."
#: erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py:1240
msgid "Stock not available to reserve for the Item {0} in Warehouse {1}."
msgstr ""
msgstr "Lager är inte tillgängligt för reservation för artikel {0} i lager {1}."
#: erpnext/selling/page/point_of_sale/pos_controller.js:826
msgid "Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2} {3}."
@@ -55293,7 +55293,7 @@ msgstr "Konto under Skuld eller Eget Kapital, där Resultat Bokförs"
#: erpnext/accounts/doctype/account/account.py:222
msgid "The account type of {0} cannot be changed from {1} because stock ledger entries exist against it."
msgstr ""
msgstr "Konto typ {0} kan inte ändras från {1} eftersom det finns lager poster mot den."
#: erpnext/accounts/doctype/payment_request/payment_request.py:1016
msgid "The allocated amount is greater than the outstanding amount of Payment Request {0}"
@@ -55451,7 +55451,7 @@ msgstr "Följande rader är dubbletter:"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:130
msgid "The following vouchers are not submitted: {0}"
msgstr ""
msgstr "Följande verifikationer är inte godkända: {0}"
#: erpnext/stock/doctype/material_request/material_request.py:1062
msgid "The following {0} were created: {1}"
@@ -55963,7 +55963,7 @@ msgstr "Detta dokument är över gräns med {0} {1} för post {4}. Skapa annan {
#: erpnext/templates/emails/appointment_confirmed.html:6
msgid "This email was sent from {0}"
msgstr ""
msgstr "Detta e-postmeddelande skickades från {0}"
#: erpnext/stock/doctype/delivery_note/delivery_note.js:496
msgid "This field is used to set the 'Customer'."
@@ -56109,7 +56109,7 @@ msgstr "Detta artikel filter har redan tillämpats för {0}"
#: erpnext/templates/emails/confirm_appointment.html:4
msgid "This link is valid for {0} minutes"
msgstr ""
msgstr "Denna länk är giltig i {0} minuter"
#: erpnext/www/banking.py:35
msgid "This method is only meant for developer mode"
@@ -56230,7 +56230,7 @@ msgstr "Detta värde ska användas när ingen matchande Gemensam Kod för post h
#: erpnext/www/book_appointment/verify/index.py:18
msgid "This verification link is invalid. Please book the appointment again."
msgstr ""
msgstr "Denna verifiering länk är ogiltig. Boka ny tid."
#: banking/src/components/features/Settings/Preferences.tsx:86
msgid "This will automatically run transaction matching rules on unreconciled transactions every hour."
@@ -58037,7 +58037,7 @@ msgstr "Transaktioner mot bolag finns redan! Kontoplan kan endast importeras fö
#. '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 ""
msgstr "Transaktioner blockeras när det utestående saldo överskrider kredit gräns. När funktion ”Begränsa Kund Överfakturering” är aktiverad blockeras även nya fakturor när kundens förfallna belopp överskrider gräns för förfallna fordringar."
#: banking/src/components/features/BankStatementImporter/CSV/StatementDetails.tsx:239
msgid "Transactions to be imported into the system"
@@ -58658,7 +58658,7 @@ msgstr "Ångra Tilldelningar"
#: erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py:375
msgid "Unable to Repost Accounting Ledger"
msgstr ""
msgstr "Kunde inte Återbokföra Bokföring Register"
#: erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py:477
msgid "Unable to fetch DocType details. Please contact system administrator."
@@ -59601,7 +59601,7 @@ msgstr "Användare med denna roll tillåts att överleverera/ta emot ordrar öve
#. field in DocType 'Accounts Settings'
#: erpnext/accounts/doctype/accounts_settings/accounts_settings.json
msgid "Users with this role can still submit invoices for customers who have crossed their Overdue Limit."
msgstr ""
msgstr "Användare med denna roll kan fortfarande godkänna fakturor för kunder som överskridit överfakturering gräns."
#. Description of the 'Role to Notify on Depreciation Failure' (Link) field in
#. DocType 'Accounts Settings'
@@ -60148,12 +60148,12 @@ msgstr "Risk Kapital"
#. 'Appointment Booking Settings'
#: erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgid "Verification Link Expiry Duration"
msgstr ""
msgstr "Verifiering Länk Utgångstid"
#. Label of the verification_token (Data) field in DocType 'Appointment'
#: erpnext/crm/doctype/appointment/appointment.json
msgid "Verification Token"
msgstr ""
msgstr "Verifiering Kod"
#: erpnext/www/book_appointment/verify/index.html:15
msgid "Verification failed please check the link"
@@ -60161,7 +60161,7 @@ msgstr "Verifiering misslyckades, kontrollera länk"
#: erpnext/www/book_appointment/verify/index.py:38
msgid "Verification link has expired."
msgstr ""
msgstr "Verifiering Länk har upphört."
#. Label of the verified_by (Data) field in DocType 'Quality Inspection'
#: erpnext/stock/doctype/quality_inspection/quality_inspection.json
@@ -61019,7 +61019,7 @@ msgstr "Vi kan se att {0} görs mot {1}. Om du vill att {1} s utestående ska up
#: erpnext/templates/emails/appointment_confirmed.html:3
msgid "We look forward to meeting you"
msgstr ""
msgstr "Vi ser fram emot att träffa dig"
#: 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."
@@ -62130,7 +62130,7 @@ msgstr "Ditt Namn"
#: erpnext/templates/emails/appointment_confirmed.html:2
msgid "Your email has been verified and your appointment has been confirmed for {0}"
msgstr ""
msgstr "Din e-post adress har verifierats och bokad tid har bekräftats för {0}"
#: erpnext/www/book_appointment/verify/index.html:11
msgid "Your email has been verified and your appointment has been scheduled"
@@ -62955,7 +62955,7 @@ msgstr "{0} vy stöds för närvarande inte i Anpassad Bokslut Rapport."
#: erpnext/stock/doctype/material_request/material_request.py:732
msgid "{0} was set to today for items whose requested date has passed"
msgstr ""
msgstr "{0} angavs till idag för artiklar vars begärda datum har passerat"
#: erpnext/accounts/doctype/payment_term/payment_term.js:19
msgid "{0} will be given as discount."

View File

@@ -881,10 +881,15 @@ def reset_item_valuation_rate(item_code, warehouse_list=None, qty=None, rate=Non
warehouse_list = [warehouse_list]
if not warehouse_list:
# Reconcile every warehouse the item has a non-zero balance in -- including
# negative balances left by other tests. get_valuation_rate averages
# Sum(stock_value)/Sum(actual_qty) across all bins, so a leftover negative
# balance in one warehouse can cancel the reset qty elsewhere and make the
# average collapse to 0, which is a source of flaky BOM-cost failures.
warehouse_list = frappe.db.sql_list(
"""
select warehouse from `tabBin`
where item_code=%s and actual_qty > 0
where item_code=%s and actual_qty != 0
""",
item_code,
)

View File

@@ -159,6 +159,9 @@ class DeprecatedBatchNoValuation:
if self.sle.name:
query = query.where(sle.name != self.sle.name)
if getattr(self, "stock_closing_from_datetime", None):
query = query.where(sle.posting_datetime >= self.stock_closing_from_datetime)
return query.run(as_dict=True)
@deprecated(

View File

@@ -533,7 +533,7 @@ frappe.ui.form.on("Material Request", {
},
],
primary_action_label: __("Create"),
primary_action: async function (values) {
primary_action: function (values) {
const item_suppliers = (values.items || []).filter((row) => row.__checked);
if (!item_suppliers.length) {
frappe.throw(__("Select at least one Item"));
@@ -567,10 +567,6 @@ frappe.ui.form.on("Material Request", {
);
}
if (!(await erpnext.utils.confirm_if_drafts_exist(frm.doc, "Purchase Order"))) {
return;
}
frappe.call({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_orders_by_supplier",
args: { source_name: frm.doc.name, item_suppliers: item_suppliers },

View File

@@ -5611,6 +5611,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

@@ -4,7 +4,7 @@
import json
import frappe
from frappe.utils import flt, nowtime, today
from frappe.utils import add_days, add_to_date, flt, nowtime, today
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
@@ -1601,3 +1601,190 @@ class TestSerialandBatchBundleLogic(ERPNextTestSuite):
self.assertNotIn(bundles[1], bundle_wise_serial_nos)
self.assertEqual(bundle_wise_serial_nos[bundles[0]], [serial_no])
@ERPNextTestSuite.change_settings(
"Stock Settings", {"auto_create_serial_and_batch_bundle_for_outward": 1}
)
def test_batchwise_valuation_for_same_posting_datetime_entries(self):
# an inward at a different rate and multiple outward rows with the same
# item and warehouse share the same posting datetime, the tie-breaking
# must include the same-timestamp entries which are already part of the
# ledger and must not let the outward rows count each other
item_code = make_item(
"Test Batchwise Same Posting Datetime Item 1",
properties={
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TBSPD-ITEM1-.#####",
"valuation_method": "FIFO",
},
).name
warehouse = "_Test Warehouse - _TC"
receipt = make_stock_entry(
item_code=item_code,
qty=10,
rate=100,
target=warehouse,
posting_date=add_days(today(), -5),
posting_time="12:00:00",
)
batch_no = get_batch_from_bundle(receipt.items[0].serial_and_batch_bundle)
self.assertTrue(frappe.db.get_value("Batch", batch_no, "use_batchwise_valuation"))
# same posting datetime as the outward rows below, at a different rate
make_stock_entry(
item_code=item_code,
qty=20,
rate=250,
target=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
posting_date=add_days(today(), -3),
posting_time="12:00:00",
)
issue = make_stock_entry(
item_code=item_code,
qty=2,
source=warehouse,
posting_date=add_days(today(), -3),
posting_time="12:00:00",
do_not_save=True,
)
for qty in [3, 4]:
issue.append(
"items",
{
"item_code": item_code,
"s_warehouse": warehouse,
"qty": qty,
"conversion_factor": 1,
},
)
issue.save()
issue.submit()
# (10 * 100 + 20 * 250) / 30 = 200
self.assert_batchwise_outgoing_rate(item_code, outgoing_rate=200.0, balance_value=4200.0)
# backdated receipt reposts the same posting datetime cluster
make_stock_entry(
item_code=item_code,
qty=10,
rate=100,
target=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
posting_date=add_days(today(), -4),
posting_time="12:00:00",
)
# (20 * 100 + 20 * 250) / 40 = 175
self.assert_batchwise_outgoing_rate(item_code, outgoing_rate=175.0, balance_value=5425.0)
@ERPNextTestSuite.change_settings(
"Stock Settings", {"auto_create_serial_and_batch_bundle_for_outward": 1}
)
def test_batchwise_valuation_when_bundle_created_before_the_sle(self):
# a bundle can be created (drafted) much before / after its SLE, the
# tie-breaking for the same posting datetime entries must follow the
# SLE creation and not the bundle creation
item_code = make_item(
"Test Batchwise Same Posting Datetime Item 2",
properties={
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TBSPD-ITEM2-.#####",
"valuation_method": "FIFO",
},
).name
warehouse = "_Test Warehouse - _TC"
receipt = make_stock_entry(
item_code=item_code,
qty=10,
rate=100,
target=warehouse,
posting_date=add_days(today(), -5),
posting_time="12:00:00",
)
batch_no = get_batch_from_bundle(receipt.items[0].serial_and_batch_bundle)
# inward at a different rate, same posting datetime as the outward below
inward = make_stock_entry(
item_code=item_code,
qty=10,
rate=200,
target=warehouse,
batch_no=batch_no,
use_serial_batch_fields=1,
posting_date=add_days(today(), -3),
posting_time="12:00:00",
)
outward = make_stock_entry(
item_code=item_code,
qty=10,
source=warehouse,
posting_date=add_days(today(), -3),
posting_time="12:00:00",
)
# simulate the inward's bundle drafted after the outward's SLE, the
# bundle creation timeline no longer matches the SLE creation timeline
outward_sle_creation = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_no": outward.name, "is_cancelled": 0},
"creation",
)
frappe.db.set_value(
"Serial and Batch Bundle",
inward.items[0].serial_and_batch_bundle,
"creation",
add_to_date(outward_sle_creation, minutes=30),
update_modified=False,
)
repost = frappe.get_doc(
{
"doctype": "Repost Item Valuation",
"based_on": "Item and Warehouse",
"item_code": item_code,
"warehouse": warehouse,
"posting_date": add_days(today(), -6),
"posting_time": "00:00:00",
"allow_negative_stock": 1,
}
)
repost.submit()
# (10 * 100 + 10 * 200) / 20 = 150, the inward precedes the outward as
# per the SLE creation even though its bundle was created afterwards
self.assert_batchwise_outgoing_rate(item_code, outgoing_rate=150.0, balance_value=1500.0)
def assert_batchwise_outgoing_rate(self, item_code, outgoing_rate, balance_value):
sl_entries = frappe.get_all(
"Stock Ledger Entry",
filters={"item_code": item_code, "is_cancelled": 0},
fields=["actual_qty", "stock_value_difference", "stock_value"],
order_by="posting_datetime, creation",
)
for sle in sl_entries:
if sle.actual_qty > 0:
continue
self.assertEqual(flt(sle.stock_value_difference, 2), flt(sle.actual_qty * outgoing_rate, 2))
self.assertEqual(flt(sl_entries[-1].stock_value, 2), flt(balance_value, 2))

View File

@@ -10,9 +10,51 @@ from frappe.desk.form.load import get_attachments
from frappe.model.document import Document
from frappe.utils import add_days, get_date_str, get_link_to_form, nowtime, parse_json
from frappe.utils.background_jobs import enqueue
from frappe.utils.caching import request_cache
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
SCOPE_FIELDS = ("warehouse", "item_code", "item_group", "warehouse_type")
def apply_unscoped_filters(filters):
meta = frappe.get_meta("Stock Closing Entry")
for fieldname in SCOPE_FIELDS:
if meta.has_field(fieldname):
filters[fieldname] = ("is", "not set")
return filters
def get_closing_entry_for_closed_period(company):
closed_upto = frappe.db.get_value(
"Period Closing Voucher", {"docstatus": 1, "company": company}, [{"MAX": "period_end_date"}]
)
if not closed_upto:
return None
return _get_completed_closing_entry(company, str(closed_upto))
@request_cache
def _get_completed_closing_entry(company, closed_upto):
filters = apply_unscoped_filters(
{
"company": company,
"docstatus": 1,
"status": "Completed",
"to_date": ("<=", closed_upto),
}
)
return frappe.db.get_value(
"Stock Closing Entry",
filters,
["name", "to_date"],
order_by="to_date desc",
as_dict=True,
)
class StockClosingEntry(Document):
# begin: auto-generated types
@@ -68,7 +110,7 @@ class StockClosingEntry(Document):
)
)
for fieldname in ["warehouse", "item_code", "item_group", "warehouse_type"]:
for fieldname in SCOPE_FIELDS:
if self.get(fieldname):
query = query.where(table[fieldname] == self.get(fieldname))
@@ -86,14 +128,30 @@ class StockClosingEntry(Document):
self.enqueue_job()
def on_cancel(self):
self.validate_closed_period_lock()
self.set_status(save=True)
self.remove_stock_closing()
def validate_closed_period_lock(self):
pcv = frappe.db.get_value(
"Period Closing Voucher",
{"company": self.company, "docstatus": 1, "period_end_date": (">=", self.to_date)},
"name",
)
if pcv:
frappe.throw(
_(
"Stock Closing Entry {0} belongs to a closed accounting period. Cancel the Period Closing Voucher {1} first."
).format(self.name, get_link_to_form("Period Closing Voucher", pcv)),
title=_("Closed Period"),
)
def remove_stock_closing(self):
table = frappe.qb.DocType("Stock Closing Balance")
frappe.qb.from_(table).delete().where(table.stock_closing_entry == self.name).run()
@frappe.whitelist()
@frappe.whitelist(methods=["POST"])
def enqueue_job(self):
self.db_set("status", "In Progress")
enqueue(prepare_closing_stock_balance, name=self.name, queue="long", timeout=1500)
@@ -103,8 +161,9 @@ class StockClosingEntry(Document):
).format(self.name)
)
@frappe.whitelist()
@frappe.whitelist(methods=["POST"])
def regenerate_closing_balance(self):
self.validate_closed_period_lock()
self.remove_stock_closing()
self.enqueue_job()

View File

@@ -7,8 +7,10 @@ from collections import defaultdict
import frappe
from frappe import _
from frappe.query_builder.functions import Sum
from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import cint, flt, get_datetime
from pypika import Order
from pypika.analytics import RowNumber
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -53,14 +55,15 @@ def execute(filters=None):
data = []
conversion_factors = []
if opening_row:
data.append(opening_row)
opening_rows = opening_row if isinstance(opening_row, list) else ([opening_row] if opening_row else [])
for row in opening_rows:
data.append(row)
conversion_factors.append(0)
actual_qty = stock_value = 0
if opening_row:
actual_qty = opening_row.get("qty_after_transaction")
stock_value = opening_row.get("stock_value")
if opening_rows:
actual_qty = opening_rows[0].get("qty_after_transaction", 0)
stock_value = opening_rows[0].get("stock_value", 0)
available_serial_nos = {}
@@ -693,43 +696,120 @@ def get_opening_balance(filters, columns, sl_entries, inv_dimension_wise_value=N
if not (filters.item_code and filters.warehouse and filters.from_date):
return
from erpnext.stock.stock_ledger import get_previous_sle
item_codes = filters.item_code
if isinstance(item_codes, str):
item_codes = [item_codes]
project = None
if filters.get("project") and not frappe.get_all(
"Inventory Dimension", filters={"reference_document": "Project"}
):
project = filters.get("project")
warehouses = get_matching_warehouses(filters.warehouse)
if not warehouses:
return
last_entry = get_previous_sle(
{
"item_code": filters.item_code,
"warehouse_condition": get_warehouse_condition(filters.warehouse),
"posting_date": filters.from_date,
"posting_time": "00:00:00",
"project": project,
},
for_report=True,
sle_doctype = frappe.qb.DocType("Stock Ledger Entry")
sr_doctype = frappe.qb.DocType("Stock Reconciliation")
opening_reco_query = (
frappe.qb.from_(sle_doctype)
.inner_join(sr_doctype)
.on(sle_doctype.voucher_no == sr_doctype.name)
.select(sle_doctype.voucher_no)
.where(sle_doctype.docstatus < 2)
.where(sle_doctype.is_cancelled == 0)
.where(sle_doctype.item_code.isin(item_codes))
.where(sle_doctype.warehouse.isin(warehouses))
.where(sle_doctype.voucher_type == "Stock Reconciliation")
.where(sle_doctype.posting_date == filters.from_date)
.where(sr_doctype.purpose == "Opening Stock")
)
# check if any SLEs are actually Opening Stock Reconciliation
for sle in list(sl_entries):
if (
sle.get("voucher_type") == "Stock Reconciliation"
and sle.posting_date == filters.from_date
and frappe.db.get_value("Stock Reconciliation", sle.voucher_no, "purpose") == "Opening Stock"
):
last_entry = sle
sl_entries.remove(sle)
opening_reco_vouchers = set(opening_reco_query.run(pluck=True))
row = {
if opening_reco_vouchers:
sl_entries[:] = [sle for sle in sl_entries if sle.get("voucher_no") not in opening_reco_vouchers]
sle_cond = (sle_doctype.posting_date < filters.from_date) | (
(sle_doctype.posting_date == filters.from_date) & (sle_doctype.posting_time == "00:00:00")
)
if opening_reco_vouchers:
sle_cond = sle_cond | (
(sle_doctype.posting_date == filters.from_date)
& (sle_doctype.voucher_no.isin(list(opening_reco_vouchers)))
)
subq = (
frappe.qb.from_(sle_doctype)
.select(
sle_doctype.qty_after_transaction,
sle_doctype.stock_value,
RowNumber()
.over(sle_doctype.item_code, sle_doctype.warehouse)
.orderby(sle_doctype.posting_datetime, sle_doctype.creation, sle_doctype.name, order=Order.desc)
.as_("rn"),
)
.where(sle_doctype.docstatus < 2)
.where(sle_doctype.is_cancelled == 0)
.where(sle_doctype.item_code.isin(item_codes))
.where(sle_doctype.warehouse.isin(warehouses))
.where(sle_cond)
)
for field in ["voucher_no", "project", "company"]:
if filters.get(field):
subq = subq.where(sle_doctype[field] == filters.get(field))
inventory_dimension_fields = get_inventory_dimension_fields()
if inventory_dimension_fields:
for fieldname in inventory_dimension_fields:
if filters.get(fieldname):
subq = subq.where(sle_doctype[fieldname].isin(filters.get(fieldname)))
query = (
frappe.qb.from_(subq)
.select(
IfNull(Sum(subq.qty_after_transaction), 0.0).as_("total_qty"),
IfNull(Sum(subq.stock_value), 0.0).as_("total_stock_value"),
)
.where(subq.rn == 1)
)
res = query.run(as_dict=True)
total_qty = flt(res[0].total_qty) if res else 0.0
total_stock_value = flt(res[0].total_stock_value) if res else 0.0
valuation_rate = flt(total_stock_value / total_qty) if total_qty else 0.0
return {
"item_code": _("'Opening'"),
"qty_after_transaction": last_entry.get("qty_after_transaction", 0),
"valuation_rate": last_entry.get("valuation_rate", 0),
"stock_value": last_entry.get("stock_value", 0),
"qty_after_transaction": total_qty,
"valuation_rate": valuation_rate,
"stock_value": total_stock_value,
}
return row
def get_matching_warehouses(warehouses):
if not warehouses:
return []
if isinstance(warehouses, str):
warehouses = [warehouses]
warehouse_details = frappe.get_all(
"Warehouse",
filters={"name": ("in", warehouses)},
fields=["lft", "rgt"],
)
if not warehouse_details:
return warehouses
wh = frappe.qb.DocType("Warehouse")
cond = None
for d in warehouse_details:
c = (wh.lft >= d.lft) & (wh.rgt <= d.rgt)
cond = c if cond is None else (cond | c)
matching = (frappe.qb.from_(wh).select(wh.name).where(cond)).run(pluck=True)
return matching if matching else warehouses
def get_warehouse_condition(warehouses):
@@ -785,7 +865,15 @@ def get_opening_balance_for_inv_dimension(filters, inv_dimension_wise_value):
if not filters.item_code or not filters.warehouse or not filters.from_date:
return
if len(filters.get("item_code")) > 1 or len(filters.get("warehouse")) > 1:
item_codes = filters.get("item_code")
if isinstance(item_codes, str):
item_codes = [item_codes]
warehouses = filters.get("warehouse")
if isinstance(warehouses, str):
warehouses = [warehouses]
if len(item_codes) > 1 or len(warehouses) > 1:
return
sl_doctype = frappe.qb.DocType("Stock Ledger Entry")
@@ -805,17 +893,11 @@ def get_opening_balance_for_inv_dimension(filters, inv_dimension_wise_value):
)
)
if filters.get("item_code"):
if isinstance(filters.item_code, list | tuple):
query = query.where(sl_doctype.item_code.isin(filters.item_code))
else:
query = query.where(sl_doctype.item_code == filters.item_code)
if item_codes:
query = query.where(sl_doctype.item_code.isin(item_codes))
if filters.get("warehouse"):
if isinstance(filters.warehouse, list | tuple):
query = query.where(sl_doctype.warehouse.isin(filters.warehouse))
else:
query = query.where(sl_doctype.warehouse == filters.warehouse)
if warehouses:
query = query.where(sl_doctype.warehouse.isin(warehouses))
for key, value in inv_dimension_wise_value.items():
if isinstance(value, list | tuple):

View File

@@ -4,18 +4,333 @@
import frappe
from frappe.utils import add_days, today
from erpnext.maintenance.doctype.maintenance_schedule.test_maintenance_schedule import (
make_serial_item_with_serial,
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.report.stock_ledger.stock_ledger import execute
from erpnext.tests.utils import ERPNextTestSuite
WAREHOUSE = "Stores - _TC"
class TestStockLedgerReeport(ERPNextTestSuite):
def setUp(self) -> None:
make_serial_item_with_serial(self, "_Test Stock Report Serial Item")
self.filters = frappe._dict(
class TestStockLedgerReport(ERPNextTestSuite):
"""Correctness tests for the Stock Ledger report.
A shared `make_movements`/`run` pair keeps each test small without persisting
any data: movements are created per test and rolled back, while the report runs
read-only. Tests reuse bootstrap items and transact in `Stores - _TC`, which
starts clean (zero balance) for these items.
"""
def make_movements(self, item_code, movements):
for movement in movements:
make_stock_entry(item_code=item_code, **movement)
def run_report(self, item_code, from_date=None, to_date=None):
filters = frappe._dict(
company="_Test Company",
from_date=today(),
to_date=add_days(today(), 30),
item_code=["_Test Stock Report Serial Item"],
from_date=from_date or add_days(today(), -1),
to_date=to_date or today(),
item_code=[item_code],
warehouse=WAREHOUSE,
)
return list(execute(filters)[1])
def test_in_out_quantities_and_running_balance(self):
item = "_Test Item"
self.make_movements(
item,
[
{"qty": 10, "to_warehouse": WAREHOUSE, "basic_rate": 100},
{"qty": 4, "from_warehouse": WAREHOUSE},
],
)
rows = self.run_report(item)
receipt = next(row for row in rows if row.get("in_qty"))
issue = next(row for row in rows if row.get("out_qty"))
self.assertEqual(receipt["in_qty"], 10)
self.assertEqual(receipt["qty_after_transaction"], 10)
self.assertEqual(issue["out_qty"], -4)
self.assertEqual(issue["qty_after_transaction"], 6)
def test_opening_balance_reflects_movements_before_from_date(self):
item = "_Test Item"
self.make_movements(
item,
[
{
"qty": 10,
"to_warehouse": WAREHOUSE,
"basic_rate": 100,
"posting_date": add_days(today(), -10),
},
{"qty": 4, "from_warehouse": WAREHOUSE, "posting_date": today()},
],
)
rows = self.run_report(item, from_date=add_days(today(), -5), to_date=today())
# the receipt predates the range, so it surfaces as the opening balance
self.assertEqual(rows[0]["item_code"], "'Opening'")
self.assertEqual(rows[0]["qty_after_transaction"], 10)
# the in-range issue draws down from the opening balance
issue = next(row for row in rows if row.get("out_qty"))
self.assertEqual(issue["qty_after_transaction"], 6)
def test_filters_to_requested_item_only(self):
item_a = "_Test Item"
item_b = "_Test Item 2"
self.make_movements(item_a, [{"qty": 5, "to_warehouse": WAREHOUSE, "basic_rate": 100}])
self.make_movements(item_b, [{"qty": 7, "to_warehouse": WAREHOUSE, "basic_rate": 100}])
rows = self.run_report(item_a)
item_codes = {row["item_code"] for row in rows if row.get("voucher_no")}
self.assertEqual(item_codes, {item_a})
def test_multi_item_opening_balance_with_and_without_transactions(self):
item_a = "_Test Item"
item_b = "_Test Item 2"
self.make_movements(
item_a,
[
{
"qty": 10,
"to_warehouse": WAREHOUSE,
"basic_rate": 100,
"posting_date": add_days(today(), -10),
}
],
)
self.make_movements(
item_b,
[{"qty": 5, "to_warehouse": WAREHOUSE, "basic_rate": 50, "posting_date": add_days(today(), -10)}],
)
self.make_movements(
item_a,
[{"qty": 2, "from_warehouse": WAREHOUSE, "posting_date": today()}],
)
filters = frappe._dict(
company="_Test Company",
from_date=add_days(today(), -5),
to_date=today(),
item_code=[item_a, item_b],
warehouse=WAREHOUSE,
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
self.assertEqual(opening_rows[0]["qty_after_transaction"], 15)
def test_multi_warehouse_opening_balance_aggregation(self):
item = "_Test Item"
warehouse_1 = "Stores - _TC"
warehouse_2 = "Finished Goods - _TC"
self.make_movements(
item,
[
{
"qty": 10,
"to_warehouse": warehouse_1,
"basic_rate": 100,
"posting_date": add_days(today(), -10),
},
{
"qty": 20,
"to_warehouse": warehouse_2,
"basic_rate": 100,
"posting_date": add_days(today(), -10),
},
],
)
filters = frappe._dict(
company="_Test Company",
from_date=add_days(today(), -5),
to_date=today(),
item_code=[item],
warehouse=[warehouse_1, warehouse_2],
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
self.assertEqual(opening_rows[0]["qty_after_transaction"], 30)
def test_opening_stock_reconciliation_on_from_date_non_midnight_time(self):
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
item = "_Test Item"
from_date = today()
sr = create_stock_reconciliation(
item_code=item,
warehouse=WAREHOUSE,
qty=25,
rate=100,
posting_date=from_date,
posting_time="10:30:00",
purpose="Opening Stock",
do_not_submit=False,
)
filters = frappe._dict(
company="_Test Company",
from_date=from_date,
to_date=from_date,
item_code=[item],
warehouse=WAREHOUSE,
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
self.assertEqual(opening_rows[0]["qty_after_transaction"], 25)
# Ensure the Opening Stock Reconciliation is not duplicated in detail transaction rows
reco_rows = [row for row in rows if row.get("voucher_no") == sr.name]
self.assertEqual(len(reco_rows), 0)
def test_backdated_sle_independent_maxima_handling(self):
item = "_Test Item"
# Entry 1: Later posting date (2026-07-20), created first
self.make_movements(
item,
[
{
"qty": 10,
"to_warehouse": WAREHOUSE,
"basic_rate": 100,
"posting_date": add_days(today(), -10),
}
],
)
# Entry 2: Backdated posting date (2026-07-15), created LATER
self.make_movements(
item,
[
{
"qty": 5,
"to_warehouse": WAREHOUSE,
"basic_rate": 100,
"posting_date": add_days(today(), -15),
}
],
)
filters = frappe._dict(
company="_Test Company",
from_date=add_days(today(), -5),
to_date=today(),
item_code=[item],
warehouse=WAREHOUSE,
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
# Should correctly pick the latest posting date entry (15 Qty) despite backdated creation order
self.assertEqual(opening_rows[0]["qty_after_transaction"], 15)
def test_filtered_opening_balance_does_not_pick_excluded_creation_entry(self):
item = "_Test Item"
posting_date = add_days(today(), -10)
posting_time = "09:00:00"
included_entry = make_stock_entry(
item_code=item,
qty=10,
to_warehouse=WAREHOUSE,
basic_rate=100,
posting_date=posting_date,
posting_time=posting_time,
)
make_stock_entry(
item_code=item,
qty=50,
to_warehouse=WAREHOUSE,
basic_rate=100,
posting_date=posting_date,
posting_time=posting_time,
)
filters = frappe._dict(
company="_Test Company",
from_date=add_days(today(), -5),
to_date=today(),
item_code=[item],
warehouse=WAREHOUSE,
voucher_no=included_entry.name,
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
self.assertEqual(opening_rows[0]["qty_after_transaction"], 10)
def test_tied_creation_terminal_sle_is_not_summed_twice(self):
item = "_Test Item"
posting_date = add_days(today(), -10)
posting_time = "09:00:00"
stock_entry_1 = make_stock_entry(
item_code=item,
qty=10,
to_warehouse=WAREHOUSE,
basic_rate=100,
posting_date=posting_date,
posting_time=posting_time,
)
stock_entry_2 = make_stock_entry(
item_code=item,
qty=5,
to_warehouse=WAREHOUSE,
basic_rate=100,
posting_date=posting_date,
posting_time=posting_time,
)
sle_rows = frappe.get_all(
"Stock Ledger Entry",
filters={
"voucher_type": "Stock Entry",
"voucher_no": ("in", [stock_entry_1.name, stock_entry_2.name]),
"item_code": item,
"warehouse": WAREHOUSE,
"is_cancelled": 0,
},
fields=["name", "qty_after_transaction"],
order_by="name desc",
)
self.assertEqual(len(sle_rows), 2)
for sle in sle_rows:
frappe.db.set_value(
"Stock Ledger Entry",
sle.name,
"creation",
"2026-01-01 00:00:00.000000",
update_modified=False,
)
filters = frappe._dict(
company="_Test Company",
from_date=add_days(today(), -5),
to_date=today(),
item_code=[item],
warehouse=WAREHOUSE,
)
columns, rows = execute(filters)
opening_rows = [row for row in rows if row.get("item_code") == "'Opening'"]
self.assertEqual(len(opening_rows), 1)
self.assertEqual(opening_rows[0]["qty_after_transaction"], sle_rows[0].qty_after_transaction)
self.assertNotEqual(
opening_rows[0]["qty_after_transaction"],
sum(sle.qty_after_transaction for sle in sle_rows),
)

View File

@@ -820,13 +820,14 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
"Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "total_amount"
)
else:
entries = self.get_batch_stock_before_date()
self.stock_value_change = 0.0
self.batch_avg_rate = defaultdict(float)
self.available_qty = defaultdict(float)
self.stock_value_differece = defaultdict(float)
for ledger in entries:
self.seed_from_stock_closing_balance()
for ledger in self.get_batch_stock_before_date():
self.stock_value_differece[ledger.batch_no] += flt(ledger.incoming_rate)
self.available_qty[ledger.batch_no] += flt(ledger.qty)
@@ -834,6 +835,52 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
self.calculate_avg_rate_for_non_batchwise_valuation()
self.set_stock_value_difference()
def seed_from_stock_closing_balance(self):
self.stock_closing_from_datetime = None
closing_entry = self.get_closing_entry_for_seeding()
if not closing_entry:
return
from erpnext.stock.utils import get_combine_datetime
self.stock_closing_from_datetime = get_combine_datetime(
add_days(closing_entry.to_date, 1), "00:00:00"
)
for row in self.get_stock_closing_balance_entries(closing_entry.name):
self.stock_value_differece[row.batch_no] += flt(row.stock_value_difference)
self.available_qty[row.batch_no] += flt(row.actual_qty)
def get_closing_entry_for_seeding(self):
from erpnext.stock.doctype.stock_closing_entry.stock_closing_entry import (
get_closing_entry_for_closed_period,
)
if not self.batchwise_valuation_batches or not self.sle.posting_date:
return None
company = self.sle.company or frappe.get_cached_value("Warehouse", self.sle.warehouse, "company")
closing_entry = get_closing_entry_for_closed_period(company)
if not closing_entry or getdate(self.sle.posting_date) <= getdate(closing_entry.to_date):
return None
return closing_entry
def get_stock_closing_balance_entries(self, closing_entry):
table = frappe.qb.DocType("Stock Closing Balance")
return (
frappe.qb.from_(table)
.select(table.batch_no, table.actual_qty, table.stock_value_difference)
.where(
(table.stock_closing_entry == closing_entry)
& (table.item_code == self.sle.item_code)
& (table.warehouse == self.sle.warehouse)
& table.batch_no.isin(self.batchwise_valuation_batches)
& (table.inventory_dimension_key.isnull() | (table.inventory_dimension_key == ""))
)
).run(as_dict=True)
def get_batch_stock_before_date(self) -> list[dict]:
# Get batch wise stock value difference from Serial and Batch Bundle considering time condition
if not self.batchwise_valuation_batches:
@@ -841,14 +888,45 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
child = frappe.qb.DocType("Serial and Batch Entry")
sle_creation = self.sle.creation if self.sle.get("name") else None
if not self.sle.get("name") and self.sle.get("serial_and_batch_bundle"):
sle_creation = frappe.db.get_value(
"Stock Ledger Entry",
{"serial_and_batch_bundle": self.sle.serial_and_batch_bundle, "is_cancelled": 0},
"creation",
)
timestamp_condition = ""
if self.sle.posting_datetime:
timestamp_condition = child.posting_datetime < self.sle.posting_datetime
if self.sle.creation:
timestamp_condition |= (child.posting_datetime == self.sle.posting_datetime) & (
child.creation < self.sle.creation
sle_table = frappe.qb.DocType("Stock Ledger Entry")
if sle_creation:
# bundle creation and SLE creation are different timelines (a
# bundle can be created much before its SLE), so break the tie
# using the creation of the bundle's own SLE
tie_condition = ExistsCriterion(
frappe.qb.from_(sle_table)
.select(sle_table.name)
.where(
(sle_table.serial_and_batch_bundle == child.parent)
& (sle_table.is_cancelled == 0)
& (sle_table.creation < sle_creation)
)
)
else:
# the current entry is not yet in the ledger and will get the
# latest creation, so the same-timestamp entries which are
# already in the ledger precede it
tie_condition = ExistsCriterion(
frappe.qb.from_(sle_table)
.select(sle_table.name)
.where(
(sle_table.serial_and_batch_bundle == child.parent) & (sle_table.is_cancelled == 0)
)
)
timestamp_condition |= (child.posting_datetime == self.sle.posting_datetime) & tie_condition
query = (
frappe.qb.from_(child)
@@ -878,6 +956,9 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
if timestamp_condition:
query = query.where(timestamp_condition)
if self.stock_closing_from_datetime:
query = query.where(child.posting_datetime >= self.stock_closing_from_datetime)
return query.run(as_dict=True)
def prepare_batches(self):
@@ -890,6 +971,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"):

View File

@@ -56,6 +56,32 @@ class SerialNoExistsInFutureTransaction(frappe.ValidationError):
pass
def validate_stock_frozen_by_closing_entry(sl_entries):
from erpnext.stock.doctype.stock_closing_entry.stock_closing_entry import (
get_closing_entry_for_closed_period,
)
company = sl_entries[0].get("company")
if not company:
company = frappe.get_cached_value("Warehouse", sl_entries[0].get("warehouse"), "company")
closing_entry = get_closing_entry_for_closed_period(company)
if not closing_entry:
return
for sle in sl_entries:
if sle.get("posting_date") and getdate(sle.get("posting_date")) <= getdate(closing_entry.to_date):
frappe.throw(
_(
"Stock transactions dated on or before {0} are frozen because the period is closed and the Stock Closing Entry {1} has been generated. To make changes, cancel the Period Closing Voucher first."
).format(
frappe.bold(format_date(closing_entry.to_date)),
get_link_to_form("Stock Closing Entry", closing_entry.name),
),
title=_("Stock Frozen"),
)
def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
"""Create SL entries from SL entry dicts
@@ -70,6 +96,8 @@ def make_sl_entries(sl_entries, allow_negative_stock=False, via_landed_cost_vouc
from erpnext.controllers.stock_controller import future_sle_exists
if sl_entries:
validate_stock_frozen_by_closing_entry(sl_entries)
cancelled = sl_entries[0].get("is_cancelled")
if cancelled:
validate_cancellation(sl_entries)