Merge pull request #39764 from rohitwaghchaure/fixed-remove-file-from-disk-9515
fix: remove file from the disk after the completion of reposting
diff --git a/.github/workflows/patch_faux.yml b/.github/workflows/patch_faux.yml
new file mode 100644
index 0000000..93d88bd
--- /dev/null
+++ b/.github/workflows/patch_faux.yml
@@ -0,0 +1,22 @@
+# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
+
+name: Skipped Patch Test
+
+on:
+ pull_request:
+ paths:
+ - "**.js"
+ - "**.css"
+ - "**.md"
+ - "**.html"
+ - "**.csv"
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ name: Patch Test
+
+ steps:
+ - name: Pass skipped tests unconditionally
+ run: "echo Skipped"
diff --git a/.github/workflows/server-tests-mariadb-faux.yml b/.github/workflows/server-tests-mariadb-faux.yml
new file mode 100644
index 0000000..8334661
--- /dev/null
+++ b/.github/workflows/server-tests-mariadb-faux.yml
@@ -0,0 +1,24 @@
+# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
+
+name: Skipped Tests
+
+on:
+ pull_request:
+ paths:
+ - "**.js"
+ - "**.css"
+ - "**.md"
+ - "**.html"
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ container: [1, 2, 3, 4]
+
+ name: Python Unit Tests
+
+ steps:
+ - name: Pass skipped tests unconditionally
+ run: "echo Skipped"
diff --git a/.github/workflows/server-tests-mariadb.yml b/.github/workflows/server-tests-mariadb.yml
index ccdfc8c..1e5125e 100644
--- a/.github/workflows/server-tests-mariadb.yml
+++ b/.github/workflows/server-tests-mariadb.yml
@@ -31,6 +31,9 @@
test:
runs-on: ubuntu-latest
timeout-minutes: 60
+ env:
+ NODE_ENV: "production"
+ WITH_COVERAGE: ${{ github.event_name != 'pull_request' }}
strategy:
fail-fast: false
@@ -117,11 +120,11 @@
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
- name: Run Tests
- run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --with-coverage --total-builds 4 --build-number ${{ matrix.container }}'
+ run: 'cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --total-builds 4 --build-number ${{ matrix.container }}'
env:
TYPE: server
- CI_BUILD_ID: ${{ github.run_id }}
- ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
+ CAPTURE_COVERAGE: ${{ github.event_name != 'pull_request' }}
+
- name: Show bench output
if: ${{ always() }}
@@ -129,6 +132,7 @@
- name: Upload coverage data
uses: actions/upload-artifact@v3
+ if: github.event_name != 'pull_request'
with:
name: coverage-${{ matrix.container }}
path: /home/runner/frappe-bench/sites/coverage.xml
@@ -137,6 +141,7 @@
name: Coverage Wrap Up
needs: test
runs-on: ubuntu-latest
+ if: ${{ github.event_name != 'pull_request' }}
steps:
- name: Clone
uses: actions/checkout@v2
@@ -148,5 +153,6 @@
uses: codecov/codecov-action@v2
with:
name: MariaDB
+ token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true
diff --git a/README.md b/README.md
index 710187a..4f65ceb 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,7 @@
<p>ERP made simple</p>
</p>
-[![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml/badge.svg?branch=develop)](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml)
-[![UI](https://github.com/erpnext/erpnext_ui_tests/actions/workflows/ui-tests.yml/badge.svg?branch=develop&event=schedule)](https://github.com/erpnext/erpnext_ui_tests/actions/workflows/ui-tests.yml)
+[![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml/badge.svg?event=schedule)](https://github.com/frappe/erpnext/actions/workflows/server-tests-mariadb.yml)
[![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext)
[![codecov](https://codecov.io/gh/frappe/erpnext/branch/develop/graph/badge.svg?token=0TwvyUg3I5)](https://codecov.io/gh/frappe/erpnext)
[![docker pulls](https://img.shields.io/docker/pulls/frappe/erpnext-worker.svg)](https://hub.docker.com/r/frappe/erpnext-worker)
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 651599d..3f11798 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -118,6 +118,7 @@
self.validate_balance_must_be_debit_or_credit()
self.validate_account_currency()
self.validate_root_company_and_sync_account_to_children()
+ self.validate_receivable_payable_account_type()
def validate_parent_child_account_type(self):
if self.parent_account:
@@ -188,6 +189,24 @@
"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
)
+ def validate_receivable_payable_account_type(self):
+ doc_before_save = self.get_doc_before_save()
+ receivable_payable_types = ["Receivable", "Payable"]
+ if (
+ doc_before_save
+ and doc_before_save.account_type in receivable_payable_types
+ and doc_before_save.account_type != self.account_type
+ ):
+ # check for ledger entries
+ if frappe.db.get_all("GL Entry", filters={"account": self.name, "is_cancelled": 0}, limit=1):
+ msg = _(
+ "There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
+ ).format(
+ frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
+ )
+ frappe.msgprint(msg)
+ self.add_comment("Comment", msg)
+
def validate_root_details(self):
doc_before_save = self.get_doc_before_save()
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
index 2ec0b7f..56b22a6 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
@@ -36,16 +36,16 @@
}
},
"Fixed Assets": {
- "Capital Equipments": {
+ "Capital Equipment": {
"account_type": "Fixed Asset"
},
- "Electronic Equipments": {
+ "Electronic Equipment": {
"account_type": "Fixed Asset"
},
- "Furnitures and Fixtures": {
+ "Furniture and Fixtures": {
"account_type": "Fixed Asset"
},
- "Office Equipments": {
+ "Office Equipment": {
"account_type": "Fixed Asset"
},
"Plants and Machineries": {
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
index e30ad24..0699932 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
@@ -23,13 +23,13 @@
_("Tax Assets"): {"is_group": 1},
},
_("Fixed Assets"): {
- _("Capital Equipments"): {"account_type": "Fixed Asset"},
- _("Electronic Equipments"): {"account_type": "Fixed Asset"},
- _("Furnitures and Fixtures"): {"account_type": "Fixed Asset"},
- _("Office Equipments"): {"account_type": "Fixed Asset"},
+ _("Capital Equipment"): {"account_type": "Fixed Asset"},
+ _("Electronic Equipment"): {"account_type": "Fixed Asset"},
+ _("Furniture and Fixtures"): {"account_type": "Fixed Asset"},
+ _("Office Equipment"): {"account_type": "Fixed Asset"},
_("Plants and Machineries"): {"account_type": "Fixed Asset"},
_("Buildings"): {"account_type": "Fixed Asset"},
- _("Softwares"): {"account_type": "Fixed Asset"},
+ _("Software"): {"account_type": "Fixed Asset"},
_("Accumulated Depreciation"): {"account_type": "Accumulated Depreciation"},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
index 0e46f1e..ee4da73 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
@@ -36,13 +36,13 @@
"account_number": "1100-1600",
},
_("Fixed Assets"): {
- _("Capital Equipments"): {"account_type": "Fixed Asset", "account_number": "1710"},
- _("Electronic Equipments"): {"account_type": "Fixed Asset", "account_number": "1720"},
- _("Furnitures and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
- _("Office Equipments"): {"account_type": "Fixed Asset", "account_number": "1740"},
+ _("Capital Equipment"): {"account_type": "Fixed Asset", "account_number": "1710"},
+ _("Electronic Equipment"): {"account_type": "Fixed Asset", "account_number": "1720"},
+ _("Furniture and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
+ _("Office Equipment"): {"account_type": "Fixed Asset", "account_number": "1740"},
_("Plants and Machineries"): {"account_type": "Fixed Asset", "account_number": "1750"},
_("Buildings"): {"account_type": "Fixed Asset", "account_number": "1760"},
- _("Softwares"): {"account_type": "Fixed Asset", "account_number": "1770"},
+ _("Software"): {"account_type": "Fixed Asset", "account_number": "1770"},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation",
"account_number": "1780",
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 30eebef..7d0869b 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -6,6 +6,7 @@
import frappe
from frappe.test_runner import make_test_records
+from frappe.utils import nowdate
from erpnext.accounts.doctype.account.account import (
InvalidAccountMergeError,
@@ -119,7 +120,7 @@
InvalidAccountMergeError,
merge_account,
"Capital Stock - _TC",
- "Softwares - _TC",
+ "Software - _TC",
)
# Raise error as currency doesn't match
@@ -324,6 +325,19 @@
acc.account_currency = "USD"
self.assertRaises(frappe.ValidationError, acc.save)
+ def test_account_balance(self):
+ from erpnext.accounts.utils import get_balance_on
+
+ if not frappe.db.exists("Account", "Test Percent Account %5 - _TC"):
+ acc = frappe.new_doc("Account")
+ acc.account_name = "Test Percent Account %5"
+ acc.parent_account = "Tax Assets - _TC"
+ acc.company = "_Test Company"
+ acc.insert()
+
+ balance = get_balance_on(account="Test Percent Account %5 - _TC", date=nowdate())
+ self.assertEqual(balance, 0)
+
def _make_test_records(verbose=None):
from frappe.test_runner import make_test_objects
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index fd052d0..0e238e0 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -1,7 +1,6 @@
{
"actions": [],
"creation": "2013-06-24 15:49:57",
- "description": "Settings for Accounts",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
@@ -462,7 +461,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2023-11-20 09:37:47.650347",
+ "modified": "2024-01-30 14:04:26.553554",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py
index 4b99b19..df4bd56 100644
--- a/erpnext/accounts/doctype/bank_account/bank_account.py
+++ b/erpnext/accounts/doctype/bank_account/bank_account.py
@@ -9,6 +9,7 @@
load_address_and_contact,
)
from frappe.model.document import Document
+from frappe.utils import comma_and, get_link_to_form
class BankAccount(Document):
@@ -52,10 +53,21 @@
def validate(self):
self.validate_company()
self.validate_iban()
+ self.validate_account()
+
+ def validate_account(self):
+ if self.account:
+ if accounts := frappe.db.get_all("Bank Account", filters={"account": self.account}, as_list=1):
+ frappe.throw(
+ _("'{0}' account is already used by {1}. Use another account.").format(
+ frappe.bold(self.account),
+ frappe.bold(comma_and([get_link_to_form(self.doctype, x[0]) for x in accounts])),
+ )
+ )
def validate_company(self):
if self.is_company_account and not self.company:
- frappe.throw(_("Company is manadatory for company account"))
+ frappe.throw(_("Company is mandatory for company account"))
def validate_iban(self):
"""
diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
index 4b97619..8a505a8 100644
--- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
+++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py
@@ -5,7 +5,9 @@
import frappe
from frappe import _, msgprint
from frappe.model.document import Document
+from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, getdate
+from pypika import Order
import erpnext
@@ -179,39 +181,62 @@
pos_sales_invoices, pos_purchase_invoices = [], []
if include_pos_transactions:
- pos_sales_invoices = frappe.db.sql(
- """
- select
- "Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
- si.posting_date, si.customer as against_account, sip.clearance_date,
- account.account_currency, 0 as credit
- from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
- where
- sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
- and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s
- order by
- si.posting_date ASC, si.name DESC
- """,
- {"account": account, "from": from_date, "to": to_date},
- as_dict=1,
- )
+ si_payment = frappe.qb.DocType("Sales Invoice Payment")
+ si = frappe.qb.DocType("Sales Invoice")
+ acc = frappe.qb.DocType("Account")
- pos_purchase_invoices = frappe.db.sql(
- """
- select
- "Purchase Invoice" as payment_document, pi.name as payment_entry, pi.paid_amount as credit,
- pi.posting_date, pi.supplier as against_account, pi.clearance_date,
- account.account_currency, 0 as debit
- from `tabPurchase Invoice` pi, `tabAccount` account
- where
- pi.cash_bank_account=%(account)s and pi.docstatus=1 and account.name = pi.cash_bank_account
- and pi.posting_date >= %(from)s and pi.posting_date <= %(to)s
- order by
- pi.posting_date ASC, pi.name DESC
- """,
- {"account": account, "from": from_date, "to": to_date},
- as_dict=1,
- )
+ pos_sales_invoices = (
+ frappe.qb.from_(si_payment)
+ .inner_join(si)
+ .on(si_payment.parent == si.name)
+ .inner_join(acc)
+ .on(si_payment.account == acc.name)
+ .select(
+ ConstantColumn("Sales Invoice").as_("payment_document"),
+ si.name.as_("payment_entry"),
+ si_payment.reference_no.as_("cheque_number"),
+ si_payment.amount.as_("debit"),
+ si.posting_date,
+ si.customer.as_("against_account"),
+ si_payment.clearance_date,
+ acc.account_currency,
+ ConstantColumn(0).as_("credit"),
+ )
+ .where(
+ (si.docstatus == 1)
+ & (si_payment.account == account)
+ & (si.posting_date >= from_date)
+ & (si.posting_date <= to_date)
+ )
+ .orderby(si.posting_date)
+ .orderby(si.name, order=Order.desc)
+ ).run(as_dict=True)
+
+ pi = frappe.qb.DocType("Purchase Invoice")
+
+ pos_purchase_invoices = (
+ frappe.qb.from_(pi)
+ .inner_join(acc)
+ .on(pi.cash_bank_account == acc.name)
+ .select(
+ ConstantColumn("Purchase Invoice").as_("payment_document"),
+ pi.name.as_("payment_entry"),
+ pi.paid_amount.as_("credit"),
+ pi.posting_date,
+ pi.supplier.as_("against_account"),
+ pi.clearance_date,
+ acc.account_currency,
+ ConstantColumn(0).as_("debit"),
+ )
+ .where(
+ (pi.docstatus == 1)
+ & (pi.cash_bank_account == account)
+ & (pi.posting_date >= from_date)
+ & (pi.posting_date <= to_date)
+ )
+ .orderby(pi.posting_date)
+ .orderby(pi.name, order=Order.desc)
+ ).run(as_dict=True)
entries = (
list(payment_entries)
diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
index 0af2caf..4326c40 100644
--- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
+++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
@@ -48,11 +48,11 @@
def on_submit(self):
if not self.bank_guarantee_number:
- frappe.throw(_("Enter the Bank Guarantee Number before submittting."))
+ frappe.throw(_("Enter the Bank Guarantee Number before submitting."))
if not self.name_of_beneficiary:
- frappe.throw(_("Enter the name of the Beneficiary before submittting."))
+ frappe.throw(_("Enter the name of the Beneficiary before submitting."))
if not self.bank:
- frappe.throw(_("Enter the name of the bank or lending institution before submittting."))
+ frappe.throw(_("Enter the name of the bank or lending institution before submitting."))
@frappe.whitelist()
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
index 1a4747c..30e564c 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py
@@ -80,7 +80,8 @@
from frappe.utils.background_jobs import is_job_enqueued
from frappe.utils.scheduler import is_scheduler_inactive
- if is_scheduler_inactive() and not frappe.flags.in_test:
+ run_now = frappe.flags.in_test or frappe.conf.developer_mode
+ if is_scheduler_inactive() and not run_now:
frappe.throw(_("Scheduler is inactive. Cannot import data."), title=_("Scheduler Inactive"))
job_id = f"bank_statement_import::{self.name}"
@@ -97,7 +98,7 @@
google_sheets_url=self.google_sheets_url,
bank=self.bank,
template_options=self.template_options,
- now=frappe.conf.developer_mode or frappe.flags.in_test,
+ now=run_now,
)
return True
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index 7bb3f41..1fe3608 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -32,8 +32,16 @@
frappe.db.delete(dt)
clear_loan_transactions()
make_pos_profile()
- add_transactions()
- add_vouchers()
+
+ # generate and use a uniq hash identifier for 'Bank Account' and it's linked GL 'Account' to avoid validation error
+ uniq_identifier = frappe.generate_hash(length=10)
+ gl_account = create_gl_account("_Test Bank " + uniq_identifier)
+ bank_account = create_bank_account(
+ gl_account=gl_account, bank_account_name="Checking Account " + uniq_identifier
+ )
+
+ add_transactions(bank_account=bank_account)
+ add_vouchers(gl_account=gl_account)
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
def test_linked_payments(self):
@@ -219,7 +227,9 @@
frappe.db.delete("Loan Repayment")
-def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
+def create_bank_account(
+ bank_name="Citi Bank", gl_account="_Test Bank - _TC", bank_account_name="Checking Account"
+):
try:
frappe.get_doc(
{
@@ -231,21 +241,35 @@
pass
try:
- frappe.get_doc(
+ bank_account = frappe.get_doc(
{
"doctype": "Bank Account",
- "account_name": "Checking Account",
+ "account_name": bank_account_name,
"bank": bank_name,
- "account": account_name,
+ "account": gl_account,
}
).insert(ignore_if_duplicate=True)
except frappe.DuplicateEntryError:
pass
+ return bank_account.name
-def add_transactions():
- create_bank_account()
+def create_gl_account(gl_account_name="_Test Bank - _TC"):
+ gl_account = frappe.get_doc(
+ {
+ "doctype": "Account",
+ "company": "_Test Company",
+ "parent_account": "Current Assets - _TC",
+ "account_type": "Bank",
+ "is_group": 0,
+ "account_name": gl_account_name,
+ }
+ ).insert()
+ return gl_account.name
+
+
+def add_transactions(bank_account="_Test Bank - _TC"):
doc = frappe.get_doc(
{
"doctype": "Bank Transaction",
@@ -253,7 +277,7 @@
"date": "2018-10-23",
"deposit": 1200,
"currency": "INR",
- "bank_account": "Checking Account - Citi Bank",
+ "bank_account": bank_account,
}
).insert()
doc.submit()
@@ -265,7 +289,7 @@
"date": "2018-10-23",
"deposit": 1700,
"currency": "INR",
- "bank_account": "Checking Account - Citi Bank",
+ "bank_account": bank_account,
}
).insert()
doc.submit()
@@ -277,7 +301,7 @@
"date": "2018-10-26",
"withdrawal": 690,
"currency": "INR",
- "bank_account": "Checking Account - Citi Bank",
+ "bank_account": bank_account,
}
).insert()
doc.submit()
@@ -289,7 +313,7 @@
"date": "2018-10-27",
"deposit": 3900,
"currency": "INR",
- "bank_account": "Checking Account - Citi Bank",
+ "bank_account": bank_account,
}
).insert()
doc.submit()
@@ -301,13 +325,13 @@
"date": "2018-10-27",
"withdrawal": 109080,
"currency": "INR",
- "bank_account": "Checking Account - Citi Bank",
+ "bank_account": bank_account,
}
).insert()
doc.submit()
-def add_vouchers():
+def add_vouchers(gl_account="_Test Bank - _TC"):
try:
frappe.get_doc(
{
@@ -323,7 +347,7 @@
pi = make_purchase_invoice(supplier="Conrad Electronic", qty=1, rate=690)
- pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Conrad Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
@@ -342,14 +366,14 @@
pass
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1200)
- pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Herr G Oct 18"
pe.reference_date = "2018-10-24"
pe.insert()
pe.submit()
pi = make_purchase_invoice(supplier="Mr G", qty=1, rate=1700)
- pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Herr G Nov 18"
pe.reference_date = "2018-11-01"
pe.insert()
@@ -380,10 +404,10 @@
pass
pi = make_purchase_invoice(supplier="Poore Simon's", qty=1, rate=3900, is_paid=1, do_not_save=1)
- pi.cash_bank_account = "_Test Bank - _TC"
+ pi.cash_bank_account = gl_account
pi.insert()
pi.submit()
- pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account=gl_account)
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.paid_amount = 690
@@ -392,7 +416,7 @@
pe.submit()
si = create_sales_invoice(customer="Poore Simon's", qty=1, rate=3900)
- pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
+ pe = get_payment_entry("Sales Invoice", si.name, bank_account=gl_account)
pe.reference_no = "Poore Simon's Oct 18"
pe.reference_date = "2018-10-28"
pe.insert()
@@ -415,16 +439,12 @@
if not frappe.db.get_value(
"Mode of Payment Account", {"company": "_Test Company", "parent": "Cash"}
):
- mode_of_payment.append(
- "accounts", {"company": "_Test Company", "default_account": "_Test Bank - _TC"}
- )
+ mode_of_payment.append("accounts", {"company": "_Test Company", "default_account": gl_account})
mode_of_payment.save()
si = create_sales_invoice(customer="Fayva", qty=1, rate=109080, do_not_save=1)
si.is_pos = 1
- si.append(
- "payments", {"mode_of_payment": "Cash", "account": "_Test Bank - _TC", "amount": 109080}
- )
+ si.append("payments", {"mode_of_payment": "Cash", "account": gl_account, "amount": 109080})
si.insert()
si.submit()
diff --git a/erpnext/accounts/doctype/coupon_code/coupon_code.json b/erpnext/accounts/doctype/coupon_code/coupon_code.json
index 7dc5e9d..c6b1477 100644
--- a/erpnext/accounts/doctype/coupon_code/coupon_code.json
+++ b/erpnext/accounts/doctype/coupon_code/coupon_code.json
@@ -80,7 +80,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Up To"
},
{
"depends_on": "eval: doc.coupon_type == \"Promotional\"",
@@ -115,7 +115,7 @@
"read_only": 1
}
],
- "modified": "2019-10-19 14:48:14.602481",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
index bd2bfbd..21091eb 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
@@ -3,7 +3,7 @@
"allow_import": 1,
"autoname": "field:year",
"creation": "2013-01-22 16:50:25",
- "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
+ "description": "Represents a Financial Year. All accounting entries and other major transactions are tracked against the Fiscal Year.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -82,11 +82,12 @@
"icon": "fa fa-calendar",
"idx": 1,
"links": [],
- "modified": "2024-01-17 13:06:01.608953",
+ "modified": "2024-01-30 12:35:38.645968",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
- "owner": "Administrator",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
"permissions": [
{
"create": 1,
@@ -130,5 +131,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "name",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 777a5bb..def2838 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -13,16 +13,9 @@
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
-from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
- get_dimension_filter_map,
-)
from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
-from erpnext.exceptions import (
- InvalidAccountCurrency,
- InvalidAccountDimensionError,
- MandatoryAccountDimensionError,
-)
+from erpnext.exceptions import InvalidAccountCurrency
exclude_from_linked_with = True
@@ -98,7 +91,6 @@
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs()
- self.validate_allowed_dimensions()
validate_balance_type(self.account, adv_adj)
validate_frozen_account(self.account, adv_adj)
@@ -208,42 +200,6 @@
)
)
- def validate_allowed_dimensions(self):
- dimension_filter_map = get_dimension_filter_map()
- for key, value in dimension_filter_map.items():
- dimension = key[0]
- account = key[1]
-
- if self.account == account:
- if value["is_mandatory"] and not self.get(dimension):
- frappe.throw(
- _("{0} is mandatory for account {1}").format(
- frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)
- ),
- MandatoryAccountDimensionError,
- )
-
- if value["allow_or_restrict"] == "Allow":
- if self.get(dimension) and self.get(dimension) not in value["allowed_dimensions"]:
- frappe.throw(
- _("Invalid value {0} for {1} against account {2}").format(
- frappe.bold(self.get(dimension)),
- frappe.bold(frappe.unscrub(dimension)),
- frappe.bold(self.account),
- ),
- InvalidAccountDimensionError,
- )
- else:
- if self.get(dimension) and self.get(dimension) in value["allowed_dimensions"]:
- frappe.throw(
- _("Invalid value {0} for {1} against account {2}").format(
- frappe.bold(self.get(dimension)),
- frappe.bold(frappe.unscrub(dimension)),
- frappe.bold(self.account),
- ),
- InvalidAccountDimensionError,
- )
-
def check_pl_account(self):
if (
self.is_opening == "Yes"
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
index db4f7c4..c80bf62 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
@@ -154,7 +154,7 @@
}
});
},
- primary_action_label: __('Get Invocies')
+ primary_action_label: __('Get Invoices')
});
d.show();
},
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 40d552b..18cf4ed 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -150,6 +150,20 @@
if not self.title:
self.title = self.get_title()
+ def submit(self):
+ if len(self.accounts) > 100:
+ msgprint(_("The task has been enqueued as a background job."), alert=True)
+ self.queue_action("submit", timeout=4600)
+ else:
+ return self._submit()
+
+ def cancel(self):
+ if len(self.accounts) > 100:
+ msgprint(_("The task has been enqueued as a background job."), alert=True)
+ self.queue_action("cancel", timeout=4600)
+ else:
+ return self._cancel()
+
def on_submit(self):
self.validate_cheque_info()
self.check_credit_limit()
@@ -186,9 +200,12 @@
def update_advance_paid(self):
advance_paid = frappe._dict()
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
for d in self.get("accounts"):
if d.is_advance:
- if d.reference_type in frappe.get_hooks("advance_payment_doctypes"):
+ if d.reference_type in advance_payment_doctypes:
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
for voucher_type, order_list in advance_paid.items():
@@ -1152,7 +1169,9 @@
@frappe.whitelist()
-def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None):
+def get_default_bank_cash_account(
+ company, account_type=None, mode_of_payment=None, account=None, ignore_permissions=False
+):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
if mode_of_payment:
@@ -1190,7 +1209,7 @@
return frappe._dict(
{
"account": account,
- "balance": get_balance_on(account),
+ "balance": get_balance_on(account, ignore_account_permission=ignore_permissions),
"account_currency": account_details.account_currency,
"account_type": account_details.account_type,
}
diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json
index 14f2d80..488e8b2 100644
--- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json
+++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.json
@@ -1,173 +1,77 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:distribution_id",
- "beta": 0,
- "creation": "2013-01-10 16:34:05",
- "custom": 0,
- "description": "**Monthly Distribution** helps you distribute the Budget/Target across months if you have seasonality in your business.",
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "field:distribution_id",
+ "creation": "2013-01-10 16:34:05",
+ "description": "Helps you distribute the Budget/Target across months if you have seasonality in your business.",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "distribution_id",
+ "fiscal_year",
+ "percentages"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Name of the Monthly Distribution",
- "fieldname": "distribution_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Distribution Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "distribution_id",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "description": "Name of the Monthly Distribution",
+ "fieldname": "distribution_id",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Distribution Name",
+ "oldfieldname": "distribution_id",
+ "oldfieldtype": "Data",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "fiscal_year",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Fiscal Year",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "fiscal_year",
- "oldfieldtype": "Select",
- "options": "Fiscal Year",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "fiscal_year",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Fiscal Year",
+ "oldfieldname": "fiscal_year",
+ "oldfieldtype": "Select",
+ "options": "Fiscal Year",
+ "search_index": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "percentages",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Monthly Distribution Percentages",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "budget_distribution_details",
- "oldfieldtype": "Table",
- "options": "Monthly Distribution Percentage",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "percentages",
+ "fieldtype": "Table",
+ "label": "Monthly Distribution Percentages",
+ "oldfieldname": "budget_distribution_details",
+ "oldfieldtype": "Table",
+ "options": "Monthly Distribution Percentage"
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-bar-chart",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-11-21 14:54:35.998761",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Monthly Distribution",
- "name_case": "Title Case",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-bar-chart",
+ "idx": 1,
+ "links": [],
+ "modified": "2024-01-30 13:57:55.802744",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Monthly Distribution",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 2,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "permlevel": 2,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index f5f8f8a..acd9933 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -270,7 +270,7 @@
errors, "<a href='/app/List/Error Log' class='variant-click'>Error Log</a>"
),
indicator="red",
- title=_("Error Occured"),
+ title=_("Error Occurred"),
)
return names
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 2954d2f..62e2181 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -640,7 +640,7 @@
get_outstanding_invoices_or_orders: function(frm, get_outstanding_invoices, get_orders_to_be_billed) {
const today = frappe.datetime.get_today();
- const fields = [
+ let fields = [
{fieldtype:"Section Break", label: __("Posting Date")},
{fieldtype:"Date", label: __("From Date"),
fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)},
@@ -655,18 +655,29 @@
fieldname:"outstanding_amt_greater_than", default: 0},
{fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
- {fieldtype:"Section Break"},
- {fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
- "get_query": function() {
- return {
- "filters": {"company": frm.doc.company}
- }
+ ];
+
+ if (frm.dimension_filters) {
+ let column_break_insertion_point = Math.ceil((frm.dimension_filters.length)/2);
+
+ fields.push({fieldtype:"Section Break"});
+ frm.dimension_filters.map((elem, idx)=>{
+ fields.push({
+ fieldtype: "Link",
+ label: elem.document_type == "Cost Center" ? "Cost Center" : elem.label,
+ options: elem.document_type,
+ fieldname: elem.fieldname || elem.document_type
+ });
+ if(idx+1 == column_break_insertion_point) {
+ fields.push({fieldtype:"Column Break"});
}
- },
- {fieldtype:"Column Break"},
+ });
+ }
+
+ fields = fields.concat([
{fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
- ];
+ ]);
let btn_text = "";
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index 3a1e1ea..b1b8d5e 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -87,12 +87,14 @@
"status",
"custom_remarks",
"remarks",
+ "base_in_words",
"column_break_16",
"letter_head",
"print_heading",
"bank",
"bank_account_no",
"payment_order",
+ "in_words",
"subscription_section",
"auto_repeat",
"amended_from",
@@ -747,6 +749,20 @@
"hidden": 1,
"label": "Book Advance Payments in Separate Party Account",
"read_only": 1
+ },
+ {
+ "fieldname": "base_in_words",
+ "fieldtype": "Small Text",
+ "label": "In Words (Company Currency)",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "in_words",
+ "fieldtype": "Small Text",
+ "label": "In Words",
+ "print_hide": 1,
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index dbebbb0..c55c820 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -13,6 +13,7 @@
from pypika.functions import Coalesce, Sum
import erpnext
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
from erpnext.accounts.doctype.bank_account.bank_account import (
get_bank_account_details,
get_party_bank_account,
@@ -177,6 +178,7 @@
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
self.set_status()
+ self.set_total_in_words()
def on_submit(self):
if self.difference_amount:
@@ -189,7 +191,7 @@
def set_liability_account(self):
# Auto setting liability account should only be done during 'draft' status
- if self.docstatus > 0:
+ if self.docstatus > 0 or self.payment_type == "Internal Transfer":
return
if not frappe.db.get_value(
@@ -785,6 +787,21 @@
self.db_set("status", self.status, update_modified=True)
+ def set_total_in_words(self):
+ from frappe.utils import money_in_words
+
+ if self.payment_type in ("Pay", "Internal Transfer"):
+ base_amount = abs(self.base_paid_amount)
+ amount = abs(self.paid_amount)
+ currency = self.paid_from_account_currency
+ elif self.payment_type == "Receive":
+ base_amount = abs(self.base_received_amount)
+ amount = abs(self.received_amount)
+ currency = self.paid_to_account_currency
+
+ self.base_in_words = money_in_words(base_amount, self.company_currency)
+ self.in_words = money_in_words(amount, currency)
+
def set_tax_withholding(self):
if self.party_type != "Supplier":
return
@@ -925,7 +942,10 @@
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
- if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
+ if d.reference_doctype in advance_payment_doctypes:
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -1012,19 +1032,19 @@
)
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
-
- if self.payment_type == "Receive":
- self.difference_amount = base_party_amount - self.base_received_amount
- elif self.payment_type == "Pay":
- self.difference_amount = self.base_paid_amount - base_party_amount
- else:
- self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
-
- total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
included_taxes = self.get_included_taxes()
+ if self.payment_type == "Receive":
+ self.difference_amount = base_party_amount - self.base_received_amount + included_taxes
+ elif self.payment_type == "Pay":
+ self.difference_amount = self.base_paid_amount - base_party_amount - included_taxes
+ else:
+ self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) - included_taxes
+
+ total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
+
self.difference_amount = flt(
- self.difference_amount - total_deductions - included_taxes, self.precision("difference_amount")
+ self.difference_amount - total_deductions, self.precision("difference_amount")
)
def get_included_taxes(self):
@@ -1423,8 +1443,11 @@
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
for d in self.get("references"):
- if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
+ if d.allocated_amount and d.reference_doctype in advance_payment_doctypes:
frappe.get_doc(
d.reference_doctype, d.reference_name, for_update=True
).set_total_advance_paid()
@@ -1671,6 +1694,13 @@
condition += " and cost_center='%s'" % args.get("cost_center")
accounting_dimensions_filter.append(ple.cost_center == args.get("cost_center"))
+ # dynamic dimension filters
+ active_dimensions = get_dimensions()[0]
+ for dim in active_dimensions:
+ if args.get(dim.fieldname):
+ condition += " and {0}='{1}'".format(dim.fieldname, args.get(dim.fieldname))
+ accounting_dimensions_filter.append(ple[dim.fieldname] == args.get(dim.fieldname))
+
date_fields_dict = {
"posting_date": ["from_posting_date", "to_posting_date"],
"due_date": ["from_due_date", "to_due_date"],
@@ -1904,6 +1934,12 @@
if doc and hasattr(doc, "cost_center") and doc.cost_center:
condition = " and cost_center='%s'" % cost_center
+ # dynamic dimension filters
+ active_dimensions = get_dimensions()[0]
+ for dim in active_dimensions:
+ if filters.get(dim.fieldname):
+ condition += " and {0}='{1}'".format(dim.fieldname, filters.get(dim.fieldname))
+
if party_account_currency == company_currency:
grand_total_field = "base_grand_total"
rounded_total_field = "base_rounded_total"
@@ -2184,6 +2220,7 @@
party_type=None,
payment_type=None,
reference_date=None,
+ ignore_permissions=False,
):
doc = frappe.get_doc(dt, dn)
over_billing_allowance = frappe.db.get_single_value("Accounts Settings", "over_billing_allowance")
@@ -2206,14 +2243,14 @@
)
# bank or cash
- bank = get_bank_cash_account(doc, bank_account)
+ bank = get_bank_cash_account(doc, bank_account, ignore_permissions=ignore_permissions)
# if default bank or cash account is not set in company master and party has default company bank account, fetch it
if party_type in ["Customer", "Supplier"] and not bank:
party_bank_account = get_party_bank_account(party_type, doc.get(scrub(party_type)))
if party_bank_account:
account = frappe.db.get_value("Bank Account", party_bank_account, "account")
- bank = get_bank_cash_account(doc, account)
+ bank = get_bank_cash_account(doc, account, ignore_permissions=ignore_permissions)
paid_amount, received_amount = set_paid_amount_and_received_amount(
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc
@@ -2353,9 +2390,13 @@
pe.set(dimension, doc.get(dimension))
-def get_bank_cash_account(doc, bank_account):
+def get_bank_cash_account(doc, bank_account, ignore_permissions=False):
bank = get_default_bank_cash_account(
- doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"), account=bank_account
+ doc.company,
+ "Bank",
+ mode_of_payment=doc.get("mode_of_payment"),
+ account=bank_account,
+ ignore_permissions=ignore_permissions,
)
if not bank:
diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py
index 0dcb179..60f288e 100644
--- a/erpnext/accounts/doctype/payment_order/test_payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py
@@ -4,9 +4,13 @@
import unittest
import frappe
+from frappe.tests.utils import FrappeTestCase
from frappe.utils import getdate
-from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import create_bank_account
+from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import (
+ create_bank_account,
+ create_gl_account,
+)
from erpnext.accounts.doctype.payment_entry.payment_entry import (
get_payment_entry,
make_payment_order,
@@ -14,28 +18,32 @@
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-class TestPaymentOrder(unittest.TestCase):
+class TestPaymentOrder(FrappeTestCase):
def setUp(self):
- create_bank_account()
+ # generate and use a uniq hash identifier for 'Bank Account' and it's linked GL 'Account' to avoid validation error
+ uniq_identifier = frappe.generate_hash(length=10)
+ self.gl_account = create_gl_account("_Test Bank " + uniq_identifier)
+ self.bank_account = create_bank_account(
+ gl_account=self.gl_account, bank_account_name="Checking Account " + uniq_identifier
+ )
def tearDown(self):
- for bt in frappe.get_all("Payment Order"):
- doc = frappe.get_doc("Payment Order", bt.name)
- doc.cancel()
- doc.delete()
+ frappe.db.rollback()
def test_payment_order_creation_against_payment_entry(self):
purchase_invoice = make_purchase_invoice()
payment_entry = get_payment_entry(
- "Purchase Invoice", purchase_invoice.name, bank_account="_Test Bank - _TC"
+ "Purchase Invoice", purchase_invoice.name, bank_account=self.gl_account
)
payment_entry.reference_no = "_Test_Payment_Order"
payment_entry.reference_date = getdate()
- payment_entry.party_bank_account = "Checking Account - Citi Bank"
+ payment_entry.party_bank_account = self.bank_account
payment_entry.insert()
payment_entry.submit()
- doc = create_payment_order_against_payment_entry(payment_entry, "Payment Entry")
+ doc = create_payment_order_against_payment_entry(
+ payment_entry, "Payment Entry", self.bank_account
+ )
reference_doc = doc.get("references")[0]
self.assertEqual(reference_doc.reference_name, payment_entry.name)
self.assertEqual(reference_doc.reference_doctype, "Payment Entry")
@@ -43,13 +51,13 @@
self.assertEqual(reference_doc.amount, 250)
-def create_payment_order_against_payment_entry(ref_doc, order_type):
+def create_payment_order_against_payment_entry(ref_doc, order_type, bank_account):
payment_order = frappe.get_doc(
dict(
doctype="Payment Order",
company="_Test Company",
payment_order_type=order_type,
- company_bank_account="Checking Account - Citi Bank",
+ company_bank_account=bank_account,
)
)
doc = make_payment_order(ref_doc.name, payment_order)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index fc90c3d..99593de 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -95,6 +95,8 @@
this.frm.change_custom_button_type(__('Allocate'), null, 'default');
}
+ this.frm.trigger("set_query_for_dimension_filters");
+
// check for any running reconciliation jobs
if (this.frm.doc.receivable_payable_account) {
this.frm.call({
@@ -125,6 +127,25 @@
}
}
+ set_query_for_dimension_filters() {
+ frappe.call({
+ method: "erpnext.accounts.doctype.payment_reconciliation.payment_reconciliation.get_queries_for_dimension_filters",
+ args: {
+ company: this.frm.doc.company,
+ },
+ callback: (r) => {
+ if (!r.exc && r.message) {
+ r.message.forEach(x => {
+ this.frm.set_query(x.fieldname, () => {
+ return {
+ 'filters': x.filters
+ };
+ });
+ });
+ }
+ }
+ });
+ }
company() {
this.frm.set_value('party', '');
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
index ccb9e64..ff2aa6d 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
@@ -25,7 +25,9 @@
"invoice_limit",
"payment_limit",
"bank_cash_account",
+ "accounting_dimensions_section",
"cost_center",
+ "dimension_col_break",
"sec_break1",
"invoice_name",
"invoices",
@@ -39,6 +41,7 @@
{
"fieldname": "company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Company",
"options": "Company",
"reqd": 1
@@ -208,6 +211,18 @@
"fieldname": "payment_name",
"fieldtype": "Data",
"label": "Filter on Payment"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.invoices.length == 0",
+ "depends_on": "eval:doc.receivable_payable_account",
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions Filter"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
@@ -215,7 +230,7 @@
"is_virtual": 1,
"issingle": 1,
"links": [],
- "modified": "2023-11-17 17:33:55.701726",
+ "modified": "2024-01-18 11:56:20.234667",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index ed0921b..b2716c9 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -10,6 +10,7 @@
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
import erpnext
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import (
is_any_doc_running,
)
@@ -70,6 +71,7 @@
self.common_filter_conditions = []
self.accounting_dimension_filter_conditions = []
self.ple_posting_date_filter = []
+ self.dimensions = get_dimensions()[0]
def load_from_db(self):
# 'modified' attribute is required for `run_doc_method` to work properly.
@@ -172,6 +174,14 @@
if self.payment_name:
condition.update({"name": self.payment_name})
+ # pass dynamic dimension filter values to query builder
+ dimensions = {}
+ for x in self.dimensions:
+ dimension = x.fieldname
+ if self.get(dimension):
+ dimensions.update({dimension: self.get(dimension)})
+ condition.update({"accounting_dimensions": dimensions})
+
payment_entries = get_advance_payment_entries_for_regional(
self.party_type,
self.party,
@@ -185,66 +195,67 @@
return payment_entries
def get_jv_entries(self):
- condition = self.get_conditions()
+ je = qb.DocType("Journal Entry")
+ jea = qb.DocType("Journal Entry Account")
+ conditions = self.get_journal_filter_conditions()
+
+ # Dimension filters
+ for x in self.dimensions:
+ dimension = x.fieldname
+ if self.get(dimension):
+ conditions.append(jea[dimension] == self.get(dimension))
if self.payment_name:
- condition += f" and t1.name like '%%{self.payment_name}%%'"
+ conditions.append(je.name.like(f"%%{self.payment_name}%%"))
if self.get("cost_center"):
- condition += f" and t2.cost_center = '{self.cost_center}' "
+ conditions.append(jea.cost_center == self.cost_center)
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
else "debit_in_account_currency"
)
+ conditions.append(jea[dr_or_cr].gt(0))
- bank_account_condition = (
- "t2.against_account like %(bank_cash_account)s" if self.bank_cash_account else "1=1"
+ if self.bank_cash_account:
+ conditions.append(jea.against_account.like(f"%%{self.bank_cash_account}%%"))
+
+ journal_query = (
+ qb.from_(je)
+ .inner_join(jea)
+ .on(jea.parent == je.name)
+ .select(
+ ConstantColumn("Journal Entry").as_("reference_type"),
+ je.name.as_("reference_name"),
+ je.posting_date,
+ je.remark.as_("remarks"),
+ jea.name.as_("reference_row"),
+ jea[dr_or_cr].as_("amount"),
+ jea.is_advance,
+ jea.exchange_rate,
+ jea.account_currency.as_("currency"),
+ jea.cost_center.as_("cost_center"),
+ )
+ .where(
+ (je.docstatus == 1)
+ & (jea.party_type == self.party_type)
+ & (jea.party == self.party)
+ & (jea.account == self.receivable_payable_account)
+ & (
+ (jea.reference_type == "")
+ | (jea.reference_type.isnull())
+ | (jea.reference_type.isin(("Sales Order", "Purchase Order")))
+ )
+ )
+ .where(Criterion.all(conditions))
+ .orderby(je.posting_date)
)
- limit = f"limit {self.payment_limit}" if self.payment_limit else " "
+ if self.payment_limit:
+ journal_query = journal_query.limit(self.payment_limit)
- # nosemgrep
- journal_entries = frappe.db.sql(
- """
- select
- "Journal Entry" as reference_type, t1.name as reference_name,
- t1.posting_date, t1.remark as remarks, t2.name as reference_row,
- {dr_or_cr} as amount, t2.is_advance, t2.exchange_rate,
- t2.account_currency as currency, t2.cost_center as cost_center
- from
- `tabJournal Entry` t1, `tabJournal Entry Account` t2
- where
- t1.name = t2.parent and t1.docstatus = 1 and t2.docstatus = 1
- and t2.party_type = %(party_type)s and t2.party = %(party)s
- and t2.account = %(account)s and {dr_or_cr} > 0 {condition}
- and (t2.reference_type is null or t2.reference_type = '' or
- (t2.reference_type in ('Sales Order', 'Purchase Order')
- and t2.reference_name is not null and t2.reference_name != ''))
- and (CASE
- WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
- THEN 1=1
- ELSE {bank_account_condition}
- END)
- order by t1.posting_date
- {limit}
- """.format(
- **{
- "dr_or_cr": dr_or_cr,
- "bank_account_condition": bank_account_condition,
- "condition": condition,
- "limit": limit,
- }
- ),
- {
- "party_type": self.party_type,
- "party": self.party,
- "account": self.receivable_payable_account,
- "bank_cash_account": "%%%s%%" % self.bank_cash_account,
- },
- as_dict=1,
- )
+ journal_entries = journal_query.run(as_dict=True)
return list(journal_entries)
@@ -298,6 +309,7 @@
min_outstanding=-(self.minimum_payment_amount) if self.minimum_payment_amount else None,
max_outstanding=-(self.maximum_payment_amount) if self.maximum_payment_amount else None,
get_payments=True,
+ accounting_dimensions=self.accounting_dimension_filter_conditions,
)
for inv in return_outstanding:
@@ -447,8 +459,15 @@
row = self.append("allocation", {})
row.update(entry)
+ def update_dimension_values_in_allocated_entries(self, res):
+ for x in self.dimensions:
+ dimension = x.fieldname
+ if self.get(dimension):
+ res[dimension] = self.get(dimension)
+ return res
+
def get_allocated_entry(self, pay, inv, allocated_amount):
- return frappe._dict(
+ res = frappe._dict(
{
"reference_type": pay.get("reference_type"),
"reference_name": pay.get("reference_name"),
@@ -464,6 +483,9 @@
}
)
+ res = self.update_dimension_values_in_allocated_entries(res)
+ return res
+
def reconcile_allocations(self, skip_ref_details_update_for_pe=False):
adjust_allocations_for_taxes(self)
dr_or_cr = (
@@ -486,10 +508,10 @@
reconciled_entry.append(payment_details)
if entry_list:
- reconcile_against_document(entry_list, skip_ref_details_update_for_pe)
+ reconcile_against_document(entry_list, skip_ref_details_update_for_pe, self.dimensions)
if dr_or_cr_notes:
- reconcile_dr_cr_note(dr_or_cr_notes, self.company)
+ reconcile_dr_cr_note(dr_or_cr_notes, self.company, self.dimensions)
@frappe.whitelist()
def reconcile(self):
@@ -518,7 +540,7 @@
self.get_unreconciled_entries()
def get_payment_details(self, row, dr_or_cr):
- return frappe._dict(
+ payment_details = frappe._dict(
{
"voucher_type": row.get("reference_type"),
"voucher_no": row.get("reference_name"),
@@ -541,6 +563,12 @@
}
)
+ for x in self.dimensions:
+ if row.get(x.fieldname):
+ payment_details[x.fieldname] = row.get(x.fieldname)
+
+ return payment_details
+
def check_mandatory_to_fetch(self):
for fieldname in ["company", "party_type", "party", "receivable_payable_account"]:
if not self.get(fieldname):
@@ -648,6 +676,13 @@
if not invoices_to_reconcile:
frappe.throw(_("No records found in Allocation table"))
+ def build_dimensions_filter_conditions(self):
+ ple = qb.DocType("Payment Ledger Entry")
+ for x in self.dimensions:
+ dimension = x.fieldname
+ if self.get(dimension):
+ self.accounting_dimension_filter_conditions.append(ple[dimension] == self.get(dimension))
+
def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False):
self.common_filter_conditions.clear()
self.accounting_dimension_filter_conditions.clear()
@@ -671,40 +706,30 @@
if self.to_payment_date:
self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_payment_date))
- def get_conditions(self, get_payments=False):
- condition = " and company = '{0}' ".format(self.company)
+ self.build_dimensions_filter_conditions()
- if self.get("cost_center") and get_payments:
- condition = " and cost_center = '{0}' ".format(self.cost_center)
+ def get_journal_filter_conditions(self):
+ conditions = []
+ je = qb.DocType("Journal Entry")
+ jea = qb.DocType("Journal Entry Account")
+ conditions.append(je.company == self.company)
- condition += (
- " and posting_date >= {0}".format(frappe.db.escape(self.from_payment_date))
- if self.from_payment_date
- else ""
- )
- condition += (
- " and posting_date <= {0}".format(frappe.db.escape(self.to_payment_date))
- if self.to_payment_date
- else ""
- )
+ if self.from_payment_date:
+ conditions.append(je.posting_date.gte(self.from_payment_date))
+
+ if self.to_payment_date:
+ conditions.append(je.posting_date.lte(self.to_payment_date))
if self.minimum_payment_amount:
- condition += (
- " and unallocated_amount >= {0}".format(flt(self.minimum_payment_amount))
- if get_payments
- else " and total_debit >= {0}".format(flt(self.minimum_payment_amount))
- )
+ conditions.append(je.total_debit.gte(self.minimum_payment_amount))
+
if self.maximum_payment_amount:
- condition += (
- " and unallocated_amount <= {0}".format(flt(self.maximum_payment_amount))
- if get_payments
- else " and total_debit <= {0}".format(flt(self.maximum_payment_amount))
- )
+ conditions.append(je.total_debit.lte(self.maximum_payment_amount))
- return condition
+ return conditions
-def reconcile_dr_cr_note(dr_cr_notes, company):
+def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None):
for inv in dr_cr_notes:
voucher_type = "Credit Note" if inv.voucher_type == "Sales Invoice" else "Debit Note"
@@ -754,6 +779,15 @@
}
)
+ # Credit Note(JE) will inherit the same dimension values as payment
+ dimensions_dict = frappe._dict()
+ if active_dimensions:
+ for dim in active_dimensions:
+ dimensions_dict[dim.fieldname] = inv.get(dim.fieldname)
+
+ jv.accounts[0].update(dimensions_dict)
+ jv.accounts[1].update(dimensions_dict)
+
jv.flags.ignore_mandatory = True
jv.flags.ignore_exchange_rate = True
jv.remark = None
@@ -787,9 +821,27 @@
inv.against_voucher,
None,
inv.cost_center,
+ dimensions_dict,
)
@erpnext.allow_regional
def adjust_allocations_for_taxes(doc):
pass
+
+
+@frappe.whitelist()
+def get_queries_for_dimension_filters(company: str = None):
+ dimensions_with_filters = []
+ for d in get_dimensions()[0]:
+ filters = {}
+ meta = frappe.get_meta(d.document_type)
+ if meta.has_field("company") and company:
+ filters.update({"company": company})
+
+ if meta.is_tree:
+ filters.update({"is_group": 0})
+
+ dimensions_with_filters.append({"fieldname": d.fieldname, "filters": filters})
+
+ return dimensions_with_filters
diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
index 491c678..3f85b21 100644
--- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
@@ -24,7 +24,9 @@
"difference_account",
"exchange_rate",
"currency",
- "cost_center"
+ "accounting_dimensions_section",
+ "cost_center",
+ "dimension_col_break"
],
"fields": [
{
@@ -157,12 +159,21 @@
"fieldname": "gain_loss_posting_date",
"fieldtype": "Date",
"label": "Difference Posting Date"
+ },
+ {
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
}
],
"is_virtual": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-17 17:33:38.612615",
+ "modified": "2023-12-14 13:38:26.104150",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Allocation",
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js
index e913912..c85cd42 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request.js
@@ -25,6 +25,10 @@
})
frappe.ui.form.on("Payment Request", "refresh", function(frm) {
+ if(frm.doc.status == 'Failed'){
+ frm.set_intro(__("Failure: {0}", [frm.doc.failed_reason]), "red");
+ }
+
if(frm.doc.payment_request_type == 'Inward' && frm.doc.payment_channel !== "Phone" &&
!in_list(["Initiated", "Paid"], frm.doc.status) && !frm.doc.__islocal && frm.doc.docstatus==1){
frm.add_custom_button(__('Resend Payment Email'), function(){
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json
index 66b5c4b..f62b624 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.json
+++ b/erpnext/accounts/doctype/payment_request/payment_request.json
@@ -7,6 +7,7 @@
"field_order": [
"payment_request_type",
"transaction_date",
+ "failed_reason",
"column_break_2",
"naming_series",
"mode_of_payment",
@@ -389,13 +390,22 @@
"options": "Payment Request",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "failed_reason",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Reason for Failure",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2023-09-27 09:51:42.277638",
+ "modified": "2024-01-20 00:37:06.988919",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
@@ -433,4 +443,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 9772b94..a18104e 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -169,6 +169,13 @@
elif self.payment_channel == "Phone":
self.request_phone_payment()
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
+ if self.reference_doctype in advance_payment_doctypes:
+ # set advance payment status
+ ref_doc.set_total_advance_paid()
+
def request_phone_payment(self):
controller = _get_payment_gateway_controller(self.payment_gateway)
request_amount = self.get_request_amount()
@@ -207,6 +214,14 @@
self.check_if_payment_entry_exists()
self.set_as_cancelled()
+ ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
+ if self.reference_doctype in advance_payment_doctypes:
+ # set advance payment status
+ ref_doc.set_total_advance_paid()
+
def make_invoice(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
diff --git a/erpnext/accounts/doctype/payment_request/payment_request_list.js b/erpnext/accounts/doctype/payment_request/payment_request_list.js
index 85d729c..43f7856 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request_list.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request_list.js
@@ -16,6 +16,9 @@
else if(doc.status == "Paid") {
return [__("Paid"), "blue", "status,=,Paid"];
}
+ else if(doc.status == "Failed") {
+ return [__("Failed"), "red", "status,=,Failed"];
+ }
else if(doc.status == "Cancelled") {
return [__("Cancelled"), "red", "status,=,Cancelled"];
}
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index e542d3c..1a7eef6 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -11,7 +11,6 @@
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
SalesInvoice,
- get_bank_cash_account,
get_mode_of_payment_info,
update_multi_mode_option,
)
@@ -208,7 +207,6 @@
self.validate_stock_availablility()
self.validate_return_items_qty()
self.set_status()
- self.set_account_for_mode_of_payment()
self.validate_pos()
self.validate_payment_amount()
self.validate_loyalty_transaction()
@@ -371,7 +369,7 @@
if d.get("qty") > 0:
frappe.throw(
_(
- "Row #{}: You cannot add postive quantities in a return invoice. Please remove item {} to complete the return."
+ "Row #{}: You cannot add positive quantities in a return invoice. Please remove item {} to complete the return."
).format(d.idx, frappe.bold(d.item_code)),
title=_("Invalid Item"),
)
@@ -643,11 +641,6 @@
update_multi_mode_option(self, pos_profile)
self.paid_amount = 0
- def set_account_for_mode_of_payment(self):
- for pay in self.payments:
- if not pay.account:
- pay.account = get_bank_cash_account(pay.mode_of_payment, self.company).get("account")
-
@frappe.whitelist()
def create_payment_request(self):
for pay in self.payments:
@@ -793,7 +786,7 @@
invoices = json.loads(invoices)
if len(invoices) == 0:
- frappe.throw(_("Atleast one invoice has to be selected."))
+ frappe.throw(_("At least one invoice has to be selected."))
merge_log = frappe.new_doc("POS Invoice Merge Log")
merge_log.posting_date = getdate(nowdate())
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 200b82a..8fab290 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -93,7 +93,7 @@
inv.save()
- self.assertEqual(inv.net_total, 4298.25)
+ self.assertEqual(inv.net_total, 4298.24)
self.assertEqual(inv.grand_total, 4900.00)
def test_tax_calculation_with_multiple_items(self):
diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
index 5a281aa..ad2889d 100644
--- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
+++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
@@ -80,13 +80,16 @@
"target_warehouse",
"quality_inspection",
"serial_and_batch_bundle",
- "batch_no",
+ "use_serial_batch_fields",
"col_break5",
"allow_zero_valuation_rate",
- "serial_no",
"item_tax_rate",
"actual_batch_qty",
"actual_qty",
+ "section_break_tlhi",
+ "serial_no",
+ "column_break_ciit",
+ "batch_no",
"edit_references",
"sales_order",
"so_detail",
@@ -628,13 +631,13 @@
"options": "Quality Inspection"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"hidden": 1,
"label": "Batch No",
"options": "Batch",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "col_break5",
@@ -649,14 +652,14 @@
"print_hide": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"hidden": 1,
"in_list_view": 1,
"label": "Serial No",
"oldfieldname": "serial_no",
- "oldfieldtype": "Small Text",
- "read_only": 1
+ "oldfieldtype": "Small Text"
},
{
"fieldname": "item_tax_rate",
@@ -824,17 +827,33 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
"no_copy": 1,
"options": "Serial and Batch Bundle",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_tlhi",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_ciit",
+ "fieldtype": "Column Break"
}
],
"istable": 1,
"links": [],
- "modified": "2023-11-14 18:33:22.585715",
+ "modified": "2024-02-04 16:36:25.665743",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",
diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py
index e2a62f1..55a577b 100644
--- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py
+++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py
@@ -82,6 +82,7 @@
target_warehouse: DF.Link | None
total_weight: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
weight_per_unit: DF.Float
weight_uom: DF.Link | None
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
index 6af8a00..0ad9131 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py
@@ -351,7 +351,7 @@
inv.load_from_db()
consolidated_invoice = frappe.get_doc("Sales Invoice", inv.consolidated_invoice)
self.assertEqual(consolidated_invoice.status, "Return")
- self.assertEqual(consolidated_invoice.rounding_adjustment, -0.001)
+ self.assertEqual(consolidated_invoice.rounding_adjustment, -0.002)
finally:
frappe.set_user("Administrator")
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py
index 30f3e0c..c1add57 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py
@@ -132,7 +132,7 @@
if len(customer_groups) != len(set(customer_groups)):
frappe.throw(
- _("Duplicate customer group found in the cutomer group table"),
+ _("Duplicate customer group found in the customer group table"),
title=_("Duplicate Customer Group"),
)
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index e8e8044..61c01a4 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -339,7 +339,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Up To"
},
{
"fieldname": "col_break1",
@@ -608,7 +608,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
- "modified": "2023-02-14 04:53:34.887358",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index ca70490..300692f 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -193,7 +193,7 @@
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
- throw(_("Atleast one of the Selling or Buying must be selected"))
+ throw(_("At least one of the Selling or Buying must be selected"))
if not self.selling and self.applicable_for in [
"Customer",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index c03b18a..083c8fc 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -120,18 +120,6 @@
statement_dict = {}
ageing = ""
- err_journals = None
- if doc.report == "General Ledger" and doc.ignore_exchange_rate_revaluation_journals:
- err_journals = frappe.db.get_all(
- "Journal Entry",
- filters={
- "company": doc.company,
- "docstatus": 1,
- "voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
- },
- as_list=True,
- )
-
for entry in doc.customers:
if doc.include_ageing:
ageing = set_ageing(doc, entry)
@@ -144,8 +132,8 @@
)
filters = get_common_filters(doc)
- if err_journals:
- filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+ if doc.ignore_exchange_rate_revaluation_journals:
+ filters.update({"ignore_err": True})
if doc.report == "General Ledger":
filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
index 1d68b23..7fdfdcd 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.json
@@ -232,7 +232,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Up To"
},
{
"fieldname": "column_break_26",
@@ -278,7 +278,7 @@
}
],
"links": [],
- "modified": "2021-05-06 16:20:22.039078",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index f85fc87..a48f5ea 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1253,6 +1253,7 @@
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Status",
+ "no_copy": 1,
"options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nOverdue\nCancelled\nInternal Transfer",
"print_hide": 1
},
@@ -1612,7 +1613,7 @@
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2023-11-29 15:35:44.697496",
+ "modified": "2024-01-26 10:46:00.469053",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index c4e09b4..c68ff83 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -696,6 +696,7 @@
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty in bin depends upon updated ordered qty in PO
if self.update_stock == 1:
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
if self.is_old_subcontracting_flow:
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 992fbe6..5da6f8b 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1995,6 +1995,21 @@
self.assertEqual(pi.items[0].cost_center, "_Test Cost Center Buying - _TC")
+ def test_debit_note_with_account_mismatch(self):
+ new_creditors = create_account(
+ parent_account="Accounts Payable - _TC",
+ account_name="Creditors 2",
+ company="_Test Company",
+ account_type="Payable",
+ )
+ pi = make_purchase_invoice(qty=1, rate=1000)
+ dr_note = make_purchase_invoice(
+ qty=-1, rate=1000, is_return=1, return_against=pi.name, do_not_save=True
+ )
+ dr_note.credit_to = new_creditors
+
+ self.assertRaises(frappe.ValidationError, dr_note.save)
+
def test_debit_note_without_item(self):
pi = make_purchase_invoice(item_name="_Test Item", qty=10, do_not_submit=True)
pi.items[0].item_code = ""
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 9cf4e4f..3ee4214 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -62,15 +62,19 @@
"rm_supp_cost",
"warehouse_section",
"warehouse",
+ "add_serial_batch_bundle",
+ "serial_and_batch_bundle",
+ "use_serial_batch_fields",
+ "col_br_wh",
"from_warehouse",
"quality_inspection",
- "serial_and_batch_bundle",
- "serial_no",
- "col_br_wh",
"rejected_warehouse",
"rejected_serial_and_batch_bundle",
- "batch_no",
+ "section_break_rqbe",
+ "serial_no",
"rejected_serial_no",
+ "column_break_vbbb",
+ "batch_no",
"manufacture_details",
"manufacturer",
"column_break_13",
@@ -439,13 +443,11 @@
"print_hide": 1
},
{
- "depends_on": "eval:!doc.is_fixed_asset",
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
- "hidden": 1,
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
},
{
@@ -453,21 +455,18 @@
"fieldtype": "Column Break"
},
{
- "depends_on": "eval:!doc.is_fixed_asset",
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
"fieldname": "serial_no",
"fieldtype": "Text",
- "hidden": 1,
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
- "depends_on": "eval:!doc.is_fixed_asset",
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
"fieldname": "rejected_serial_no",
"fieldtype": "Text",
"label": "Rejected Serial No",
"no_copy": 1,
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "accounting",
@@ -890,7 +889,7 @@
"label": "Apply TDS"
},
{
- "depends_on": "eval:parent.update_stock == 1",
+ "depends_on": "eval:parent.update_stock == 1 && (doc.use_serial_batch_fields === 0 || doc.docstatus === 1)",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -900,7 +899,7 @@
"search_index": 1
},
{
- "depends_on": "eval:parent.update_stock == 1",
+ "depends_on": "eval:parent.update_stock == 1 && (doc.use_serial_batch_fields === 0 || doc.docstatus === 1)",
"fieldname": "rejected_serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Rejected Serial and Batch Bundle",
@@ -913,12 +912,33 @@
"fieldtype": "Link",
"label": "WIP Composite Asset",
"options": "Asset"
+ },
+ {
+ "depends_on": "eval:parent.update_stock === 1 && (doc.use_serial_batch_fields === 0 || doc.docstatus === 1)",
+ "fieldname": "add_serial_batch_bundle",
+ "fieldtype": "Button",
+ "label": "Add Serial / Batch No"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
+ "fieldname": "section_break_rqbe",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_vbbb",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-12-25 22:00:28.043555",
+ "modified": "2024-02-04 14:11:52.742228",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py
index e48d223..ccbc347 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py
@@ -88,6 +88,7 @@
stock_uom_rate: DF.Currency
total_weight: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency
warehouse: DF.Link | None
weight_per_unit: DF.Float
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
index c36efb8..2ff6a45 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
@@ -3,7 +3,7 @@
"allow_import": 1,
"allow_rename": 1,
"creation": "2013-01-10 16:34:08",
- "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
+ "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain a list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\", etc.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -77,7 +77,7 @@
"icon": "fa fa-money",
"idx": 1,
"links": [],
- "modified": "2022-05-16 16:15:29.059370",
+ "modified": "2024-01-30 13:08:09.537242",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges Template",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index cc19650..abc0694 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -421,7 +421,8 @@
self.calculate_taxes_and_totals()
def before_save(self):
- set_account_for_mode_of_payment(self)
+ self.set_account_for_mode_of_payment()
+ self.set_paid_amount()
def on_submit(self):
self.validate_pos_paid_amount()
@@ -446,6 +447,7 @@
# Updating stock ledger should always be called after updating prevdoc status,
# because updating reserved qty in bin depends upon updated delivered qty in SO
if self.update_stock == 1:
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
# this sequence because outstanding may get -ve
@@ -712,9 +714,6 @@
):
data.sales_invoice = sales_invoice
- def on_update(self):
- self.set_paid_amount()
-
def on_update_after_submit(self):
if hasattr(self, "repost_required"):
fields_to_check = [
@@ -745,6 +744,11 @@
self.paid_amount = paid_amount
self.base_paid_amount = base_paid_amount
+ def set_account_for_mode_of_payment(self):
+ for payment in self.payments:
+ if not payment.account:
+ payment.account = get_bank_cash_account(payment.mode_of_payment, self.company).get("account")
+
def validate_time_sheets_are_submitted(self):
for data in self.timesheets:
if data.time_sheet:
@@ -2113,12 +2117,6 @@
return make_return_doc("Sales Invoice", source_name, target_doc)
-def set_account_for_mode_of_payment(self):
- for data in self.payments:
- if not data.account:
- data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
-
-
def get_inter_company_details(doc, doctype):
if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"]:
parties = frappe.db.get_all(
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index cb4b2fc..8c3aede 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -323,7 +323,8 @@
si.insert()
# with inclusive tax
- self.assertEqual(si.items[0].net_amount, 3947.368421052631)
+ self.assertEqual(si.items[0].net_amount, 3947.37)
+ self.assertEqual(si.net_total, si.base_net_total)
self.assertEqual(si.net_total, 3947.37)
self.assertEqual(si.grand_total, 5000)
@@ -667,7 +668,7 @@
62.5,
625.0,
50,
- 499.97600115194473,
+ 499.98,
],
"_Test Item Home Desktop 200": [
190.66,
@@ -678,7 +679,7 @@
190.66,
953.3,
150,
- 749.9968530500239,
+ 750,
],
}
@@ -691,20 +692,21 @@
self.assertEqual(d.get(k), expected_values[d.item_code][i])
# check net total
- self.assertEqual(si.net_total, 1249.97)
+ self.assertEqual(si.base_net_total, si.net_total)
+ self.assertEqual(si.net_total, 1249.98)
self.assertEqual(si.total, 1578.3)
# check tax calculation
expected_values = {
"keys": ["tax_amount", "total"],
- "_Test Account Excise Duty - _TC": [140, 1389.97],
- "_Test Account Education Cess - _TC": [2.8, 1392.77],
- "_Test Account S&H Education Cess - _TC": [1.4, 1394.17],
- "_Test Account CST - _TC": [27.88, 1422.05],
- "_Test Account VAT - _TC": [156.25, 1578.30],
- "_Test Account Customs Duty - _TC": [125, 1703.30],
- "_Test Account Shipping Charges - _TC": [100, 1803.30],
- "_Test Account Discount - _TC": [-180.33, 1622.97],
+ "_Test Account Excise Duty - _TC": [140, 1389.98],
+ "_Test Account Education Cess - _TC": [2.8, 1392.78],
+ "_Test Account S&H Education Cess - _TC": [1.4, 1394.18],
+ "_Test Account CST - _TC": [27.88, 1422.06],
+ "_Test Account VAT - _TC": [156.25, 1578.31],
+ "_Test Account Customs Duty - _TC": [125, 1703.31],
+ "_Test Account Shipping Charges - _TC": [100, 1803.31],
+ "_Test Account Discount - _TC": [-180.33, 1622.98],
}
for d in si.get("taxes"):
@@ -740,7 +742,7 @@
"base_rate": 2500,
"base_amount": 25000,
"net_rate": 40,
- "net_amount": 399.9808009215558,
+ "net_amount": 399.98,
"base_net_rate": 2000,
"base_net_amount": 19999,
},
@@ -754,7 +756,7 @@
"base_rate": 7500,
"base_amount": 37500,
"net_rate": 118.01,
- "net_amount": 590.0531205155963,
+ "net_amount": 590.05,
"base_net_rate": 5900.5,
"base_net_amount": 29502.5,
},
@@ -792,8 +794,13 @@
self.assertEqual(si.base_grand_total, 60795)
self.assertEqual(si.grand_total, 1215.90)
- self.assertEqual(si.rounding_adjustment, 0.01)
- self.assertEqual(si.base_rounding_adjustment, 0.50)
+ # no rounding adjustment as the Smallest Currency Fraction Value of USD is 0.01
+ if frappe.db.get_value("Currency", "USD", "smallest_currency_fraction_value") < 0.01:
+ self.assertEqual(si.rounding_adjustment, 0.10)
+ self.assertEqual(si.base_rounding_adjustment, 5.0)
+ else:
+ self.assertEqual(si.rounding_adjustment, 0.0)
+ self.assertEqual(si.base_rounding_adjustment, 0.0)
def test_outstanding(self):
w = self.make()
@@ -1543,6 +1550,19 @@
self.assertEqual(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"), -1000)
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 2500)
+ def test_return_invoice_with_account_mismatch(self):
+ debtors2 = create_account(
+ parent_account="Accounts Receivable - _TC",
+ account_name="Debtors 2",
+ company="_Test Company",
+ account_type="Receivable",
+ )
+ si = create_sales_invoice(qty=1, rate=1000)
+ cr_note = create_sales_invoice(
+ qty=-1, rate=1000, is_return=1, return_against=si.name, debit_to=debtors2, do_not_save=True
+ )
+ self.assertRaises(frappe.ValidationError, cr_note.save)
+
def test_gle_made_when_asset_is_returned(self):
create_asset_data()
asset = create_asset(item_code="Macbook Pro")
@@ -2082,7 +2102,7 @@
def test_rounding_adjustment_2(self):
si = create_sales_invoice(rate=400, do_not_save=True)
- for rate in [400, 600, 100]:
+ for rate in [400.25, 600.30, 100.65]:
si.append(
"items",
{
@@ -2108,17 +2128,18 @@
)
si.save()
si.submit()
- self.assertEqual(si.net_total, 1271.19)
- self.assertEqual(si.grand_total, 1500)
- self.assertEqual(si.total_taxes_and_charges, 228.82)
- self.assertEqual(si.rounding_adjustment, -0.01)
+ self.assertEqual(si.net_total, si.base_net_total)
+ self.assertEqual(si.net_total, 1272.20)
+ self.assertEqual(si.grand_total, 1501.20)
+ self.assertEqual(si.total_taxes_and_charges, 229)
+ self.assertEqual(si.rounding_adjustment, -0.20)
expected_values = [
- ["_Test Account Service Tax - _TC", 0.0, 114.41],
- ["_Test Account VAT - _TC", 0.0, 114.41],
- [si.debit_to, 1500, 0.0],
- ["Round Off - _TC", 0.01, 0.01],
- ["Sales - _TC", 0.0, 1271.18],
+ ["_Test Account Service Tax - _TC", 0.0, 114.50],
+ ["_Test Account VAT - _TC", 0.0, 114.50],
+ [si.debit_to, 1501, 0.0],
+ ["Round Off - _TC", 0.20, 0.0],
+ ["Sales - _TC", 0.0, 1272.20],
]
gl_entries = frappe.db.sql(
@@ -2176,7 +2197,8 @@
si.save()
si.submit()
- self.assertEqual(si.net_total, 4007.16)
+ self.assertEqual(si.net_total, si.base_net_total)
+ self.assertEqual(si.net_total, 4007.15)
self.assertEqual(si.grand_total, 4488.02)
self.assertEqual(si.total_taxes_and_charges, 480.86)
self.assertEqual(si.rounding_adjustment, -0.02)
@@ -2188,7 +2210,7 @@
["_Test Account Service Tax - _TC", 0.0, 240.43],
["_Test Account VAT - _TC", 0.0, 240.43],
["Sales - _TC", 0.0, 4007.15],
- ["Round Off - _TC", 0.02, 0.01],
+ ["Round Off - _TC", 0.01, 0.0],
]
)
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index ec9e792..d06c786 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -83,14 +83,17 @@
"quality_inspection",
"pick_serial_and_batch",
"serial_and_batch_bundle",
- "batch_no",
- "incoming_rate",
+ "use_serial_batch_fields",
"col_break5",
"allow_zero_valuation_rate",
- "serial_no",
+ "incoming_rate",
"item_tax_rate",
"actual_batch_qty",
"actual_qty",
+ "section_break_eoec",
+ "serial_no",
+ "column_break_ytgd",
+ "batch_no",
"edit_references",
"sales_order",
"so_detail",
@@ -600,12 +603,11 @@
"options": "Quality Inspection"
},
{
+ "depends_on": "eval: doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
- "hidden": 1,
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
},
{
@@ -621,13 +623,12 @@
"print_hide": 1
},
{
+ "depends_on": "eval: doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
- "hidden": 1,
"label": "Serial No",
"oldfieldname": "serial_no",
- "oldfieldtype": "Small Text",
- "read_only": 1
+ "oldfieldtype": "Small Text"
},
{
"fieldname": "item_group",
@@ -891,6 +892,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.update_stock == 1 && (doc.use_serial_batch_fields === 0 || doc.docstatus === 1)",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -904,12 +906,27 @@
"fieldname": "pick_serial_and_batch",
"fieldtype": "Button",
"label": "Pick Serial / Batch No"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1 && parent.update_stock === 1",
+ "fieldname": "section_break_eoec",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_ytgd",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-12-29 13:03:14.121298",
+ "modified": "2024-02-04 11:52:16.106541",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
index 80f6774..c71d08e 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
@@ -86,6 +86,7 @@
target_warehouse: DF.Link | None
total_weight: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
weight_per_unit: DF.Float
weight_uom: DF.Link | None
diff --git a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
index 5ab46b7..bd59f65 100644
--- a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
+++ b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
@@ -8,6 +8,7 @@
"default",
"mode_of_payment",
"amount",
+ "reference_no",
"column_break_3",
"account",
"type",
@@ -75,11 +76,16 @@
"hidden": 1,
"label": "Default",
"read_only": 1
+ },
+ {
+ "fieldname": "reference_no",
+ "fieldtype": "Data",
+ "label": "Reference No"
}
],
"istable": 1,
"links": [],
- "modified": "2020-08-03 12:45:39.986598",
+ "modified": "2024-01-23 16:20:06.436979",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Payment",
@@ -87,5 +93,6 @@
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
index 57d0142..e460a01 100644
--- a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
+++ b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py
@@ -23,6 +23,7 @@
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
+ reference_no: DF.Data | None
type: DF.ReadOnly | None
# end: auto-generated types
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
index 408ecbf..736d283 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
@@ -3,7 +3,7 @@
"allow_import": 1,
"allow_rename": 1,
"creation": "2013-01-10 16:34:09",
- "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
+ "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain a list of tax heads and also other expense/income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -79,7 +79,7 @@
"icon": "fa fa-money",
"idx": 1,
"links": [],
- "modified": "2022-05-16 16:14:52.061672",
+ "modified": "2024-01-30 13:07:28.801104",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges Template",
diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index 97fd4d0..afa8bcb 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -51,7 +51,7 @@
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
- "options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
+ "options": "\nTrialing\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
"read_only": 1
},
{
@@ -267,7 +267,7 @@
"link_fieldname": "subscription"
}
],
- "modified": "2023-12-28 17:20:42.687789",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 6d27806..9f19366 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -78,9 +78,7 @@
purchase_tax_template: DF.Link | None
sales_tax_template: DF.Link | None
start_date: DF.Date | None
- status: DF.Literal[
- "", "Trialling", "Active", "Past Due Date", "Cancelled", "Unpaid", "Completed"
- ]
+ status: DF.Literal["", "Trialing", "Active", "Past Due Date", "Cancelled", "Unpaid", "Completed"]
submit_invoice: DF.Check
trial_period_end: DF.Date | None
trial_period_start: DF.Date | None
@@ -233,7 +231,7 @@
Sets the status of the `Subscription`
"""
if self.is_trialling():
- self.status = "Trialling"
+ self.status = "Trialing"
elif (
self.status == "Active" and self.end_date and getdate(posting_date) > getdate(self.end_date)
):
diff --git a/erpnext/accounts/doctype/subscription/subscription_list.js b/erpnext/accounts/doctype/subscription/subscription_list.js
index 6490ff3..ea48b53 100644
--- a/erpnext/accounts/doctype/subscription/subscription_list.js
+++ b/erpnext/accounts/doctype/subscription/subscription_list.js
@@ -1,7 +1,7 @@
frappe.listview_settings['Subscription'] = {
get_indicator: function(doc) {
- if(doc.status === 'Trialling') {
- return [__("Trialling"), "green"];
+ if(doc.status === 'Trialing') {
+ return [__("Trialing"), "green"];
} else if(doc.status === 'Active') {
return [__("Active"), "green"];
} else if(doc.status === 'Completed') {
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index a46642a..89be543 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -46,7 +46,7 @@
get_date_str(subscription.current_invoice_end),
)
self.assertEqual(subscription.invoices, [])
- self.assertEqual(subscription.status, "Trialling")
+ self.assertEqual(subscription.status, "Trialing")
def test_create_subscription_without_trial_with_correct_period(self):
subscription = create_subscription()
diff --git a/erpnext/accounts/form_tour/accounts_settings/accounts_settings.json b/erpnext/accounts/form_tour/accounts_settings/accounts_settings.json
index e2bf50d..b41012c 100644
--- a/erpnext/accounts/form_tour/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/form_tour/accounts_settings/accounts_settings.json
@@ -4,7 +4,7 @@
"doctype": "Form Tour",
"idx": 0,
"is_standard": 1,
- "modified": "2021-06-29 17:00:26.145996",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -82,7 +82,7 @@
"label": "Accounts Frozen Till Date",
"parent_field": "",
"position": "Right",
- "title": "Accounts Frozen Upto"
+ "title": "Accounts Frozen Up To"
},
{
"description": "Users with this Role are allowed to set frozen accounts and create/modify accounting entries against frozen accounts.",
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 1c8ac2f..2e82886 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -13,9 +13,13 @@
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
)
+from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
+ get_dimension_filter_map,
+)
from erpnext.accounts.doctype.accounting_period.accounting_period import ClosedAccountingPeriod
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
from erpnext.accounts.utils import create_payment_ledger_entry
+from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
def make_gl_entries(
@@ -355,6 +359,7 @@
process_debit_credit_difference(gl_map)
+ dimension_filter_map = get_dimension_filter_map()
if gl_map:
check_freezing_date(gl_map[0]["posting_date"], adv_adj)
is_opening = any(d.get("is_opening") == "Yes" for d in gl_map)
@@ -362,6 +367,7 @@
validate_against_pcv(is_opening, gl_map[0]["posting_date"], gl_map[0]["company"])
for entry in gl_map:
+ validate_allowed_dimensions(entry, dimension_filter_map)
make_entry(entry, adv_adj, update_outstanding, from_repost)
@@ -700,3 +706,39 @@
where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
(now(), frappe.session.user, voucher_type, voucher_no),
)
+
+
+def validate_allowed_dimensions(gl_entry, dimension_filter_map):
+ for key, value in dimension_filter_map.items():
+ dimension = key[0]
+ account = key[1]
+
+ if gl_entry.account == account:
+ if value["is_mandatory"] and not gl_entry.get(dimension):
+ frappe.throw(
+ _("{0} is mandatory for account {1}").format(
+ frappe.bold(frappe.unscrub(dimension)), frappe.bold(gl_entry.account)
+ ),
+ MandatoryAccountDimensionError,
+ )
+
+ if value["allow_or_restrict"] == "Allow":
+ if gl_entry.get(dimension) and gl_entry.get(dimension) not in value["allowed_dimensions"]:
+ frappe.throw(
+ _("Invalid value {0} for {1} against account {2}").format(
+ frappe.bold(gl_entry.get(dimension)),
+ frappe.bold(frappe.unscrub(dimension)),
+ frappe.bold(gl_entry.account),
+ ),
+ InvalidAccountDimensionError,
+ )
+ else:
+ if gl_entry.get(dimension) and gl_entry.get(dimension) in value["allowed_dimensions"]:
+ frappe.throw(
+ _("Invalid value {0} for {1} against account {2}").format(
+ frappe.bold(gl_entry.get(dimension)),
+ frappe.bold(frappe.unscrub(dimension)),
+ frappe.bold(gl_entry.account),
+ ),
+ InvalidAccountDimensionError,
+ )
diff --git a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.md b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.html
similarity index 64%
rename from erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.md
rename to erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.html
index c674ab6..0c4a462 100644
--- a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.md
+++ b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.html
@@ -1,3 +1,3 @@
-<h3>{{_("Fiscal Year")}}</h3>
+<h3>{{ _("Fiscal Year") }}</h3>
-<p>{{ _("New fiscal year created :- ") }} {{ doc.name }}</p>
\ No newline at end of file
+<p>{{ _("New fiscal year created :- ") }} {{ doc.name }}</p>
diff --git a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
index 4c7faf4..f605ad3 100644
--- a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
+++ b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.json
@@ -11,19 +11,21 @@
"event": "New",
"idx": 0,
"is_standard": 1,
- "message": "<h3>{{_(\"Fiscal Year\")}}</h3>\n\n<p>{{ _(\"New fiscal year created :- \") }} {{ doc.name }}</p>",
- "modified": "2018-04-25 14:30:38.588534",
+ "message_type": "HTML",
+ "modified": "2023-11-17 08:54:51.532104",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Notification for new fiscal year",
"owner": "Administrator",
"recipients": [
{
- "email_by_role": "Accounts User"
+ "receiver_by_role": "Accounts User"
},
{
- "email_by_role": "Accounts Manager"
+ "receiver_by_role": "Accounts Manager"
}
],
+ "send_system_notification": 0,
+ "send_to_all_assignees": 0,
"subject": "Notification for new fiscal year {{ doc.name }}"
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/report/account_balance/account_balance.js b/erpnext/accounts/report/account_balance/account_balance.js
index 5681be9..ab5dce8 100644
--- a/erpnext/accounts/report/account_balance/account_balance.js
+++ b/erpnext/accounts/report/account_balance/account_balance.js
@@ -39,7 +39,7 @@
{ "value": "Asset Received But Not Billed", "label": __("Asset Received But Not Billed") },
{ "value": "Bank", "label": __("Bank") },
{ "value": "Cash", "label": __("Cash") },
- { "value": "Chargeble", "label": __("Chargeble") },
+ { "value": "Chargeable", "label": __("Chargeable") },
{ "value": "Capital Work in Progress", "label": __("Capital Work in Progress") },
{ "value": "Cost of Goods Sold", "label": __("Cost of Goods Sold") },
{ "value": "Depreciation", "label": __("Depreciation") },
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index ed3b991..7d8d33c 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -10,10 +10,8 @@
<h2 class="text-center" style="margin-top:0">{%= __(report.report_name) %}</h2>
<h4 class="text-center">
- {% if (filters.customer_name) { %}
- {%= filters.customer_name %}
- {% } else { %}
- {%= filters.customer || filters.supplier %}
+ {% if (filters.party) { %}
+ {%= __(filters.party) %}
{% } %}
</h4>
<h6 class="text-center">
@@ -141,7 +139,7 @@
<th style="width: 24%">{%= __("Reference") %}</th>
{% } %}
{% if(!filters.show_future_payments) { %}
- <th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
+ <th style="width: 20%">{%= (filters.party) ? __("Remarks"): __("Party") %}</th>
{% } %}
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
{% if(!filters.show_future_payments) { %}
@@ -158,7 +156,7 @@
<th style="width: 10%">{%= __("Remaining Balance") %}</th>
{% } %}
{% } else { %}
- <th style="width: 40%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
+ <th style="width: 40%">{%= (filters.party) ? __("Remarks"): __("Party") %}</th>
<th style="width: 15%">{%= __("Total Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Total Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}</th>
@@ -187,7 +185,7 @@
{% if(!filters.show_future_payments) { %}
<td>
- {% if(!(filters.customer || filters.supplier)) { %}
+ {% if(!(filters.party)) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}
@@ -260,7 +258,7 @@
{% if(data[i]["party"]|| " ") { %}
{% if(!data[i]["is_total_row"]) { %}
<td>
- {% if(!(filters.customer || filters.supplier)) { %}
+ {% if(!(filters.party)) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 3a70afc..e3fa5e8 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -5,7 +5,7 @@
from collections import OrderedDict
import frappe
-from frappe import _, qb, scrub
+from frappe import _, qb, query_builder, scrub
from frappe.query_builder import Criterion
from frappe.query_builder.functions import Date, Substring, Sum
from frappe.utils import cint, cstr, flt, getdate, nowdate
@@ -576,6 +576,8 @@
def get_future_payments_from_payment_entry(self):
pe = frappe.qb.DocType("Payment Entry")
pe_ref = frappe.qb.DocType("Payment Entry Reference")
+ ifelse = query_builder.CustomFunction("IF", ["condition", "then", "else"])
+
return (
frappe.qb.from_(pe)
.inner_join(pe_ref)
@@ -587,6 +589,11 @@
(pe.posting_date).as_("future_date"),
(pe_ref.allocated_amount).as_("future_amount"),
(pe.reference_no).as_("future_ref"),
+ ifelse(
+ pe.payment_type == "Receive",
+ pe.source_exchange_rate * pe_ref.allocated_amount,
+ pe.target_exchange_rate * pe_ref.allocated_amount,
+ ).as_("future_amount_in_base_currency"),
)
.where(
(pe.docstatus < 2)
@@ -623,13 +630,24 @@
query = query.select(
Sum(jea.debit_in_account_currency - jea.credit_in_account_currency).as_("future_amount")
)
+ query = query.select(Sum(jea.debit - jea.credit).as_("future_amount_in_base_currency"))
else:
query = query.select(
Sum(jea.credit_in_account_currency - jea.debit_in_account_currency).as_("future_amount")
)
+ query = query.select(Sum(jea.credit - jea.debit).as_("future_amount_in_base_currency"))
else:
query = query.select(
- Sum(jea.debit if self.account_type == "Payable" else jea.credit).as_("future_amount")
+ Sum(jea.debit if self.account_type == "Payable" else jea.credit).as_(
+ "future_amount_in_base_currency"
+ )
+ )
+ query = query.select(
+ Sum(
+ jea.debit_in_account_currency
+ if self.account_type == "Payable"
+ else jea.credit_in_account_currency
+ ).as_("future_amount")
)
query = query.having(qb.Field("future_amount") > 0)
@@ -645,14 +663,19 @@
row.remaining_balance = row.outstanding
row.future_amount = 0.0
for future in self.future_payments.get((row.voucher_no, row.party), []):
- if row.remaining_balance > 0 and future.future_amount:
- if future.future_amount > row.outstanding:
+ if self.filters.in_party_currency:
+ future_amount_field = "future_amount"
+ else:
+ future_amount_field = "future_amount_in_base_currency"
+
+ if row.remaining_balance > 0 and future.get(future_amount_field):
+ if future.get(future_amount_field) > row.outstanding:
row.future_amount = row.outstanding
- future.future_amount = future.future_amount - row.outstanding
+ future[future_amount_field] = future.get(future_amount_field) - row.outstanding
row.remaining_balance = 0
else:
- row.future_amount += future.future_amount
- future.future_amount = 0
+ row.future_amount += future.get(future_amount_field)
+ future[future_amount_field] = 0
row.remaining_balance = row.outstanding - row.future_amount
row.setdefault("future_ref", []).append(
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index 976935b..6ff81be 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -772,3 +772,92 @@
# post sorting output should be [[Additional Debtors, ...], [Debtors, ...]]
report_output = sorted(report_output, key=lambda x: x[0])
self.assertEqual(expected_data, report_output)
+
+ def test_future_payments_on_foreign_currency(self):
+ self.customer2 = (
+ frappe.get_doc(
+ {
+ "doctype": "Customer",
+ "customer_name": "Jane Doe",
+ "type": "Individual",
+ "default_currency": "USD",
+ }
+ )
+ .insert()
+ .submit()
+ )
+
+ si = self.create_sales_invoice(do_not_submit=True)
+ si.posting_date = add_days(today(), -1)
+ si.customer = self.customer2
+ si.currency = "USD"
+ si.conversion_rate = 80
+ si.debit_to = self.debtors_usd
+ si.save().submit()
+
+ # full payment in USD
+ pe = get_payment_entry(si.doctype, si.name)
+ pe.posting_date = add_days(today(), 1)
+ pe.base_received_amount = 7500
+ pe.received_amount = 7500
+ pe.source_exchange_rate = 75
+ pe.save().submit()
+
+ filters = frappe._dict(
+ {
+ "company": self.company,
+ "report_date": today(),
+ "range1": 30,
+ "range2": 60,
+ "range3": 90,
+ "range4": 120,
+ "show_future_payments": True,
+ "in_party_currency": False,
+ }
+ )
+ report = execute(filters)[1]
+ self.assertEqual(len(report), 1)
+
+ expected_data = [8000.0, 8000.0, 500.0, 7500.0]
+ row = report[0]
+ self.assertEqual(
+ expected_data, [row.invoiced, row.outstanding, row.remaining_balance, row.future_amount]
+ )
+
+ filters.in_party_currency = True
+ report = execute(filters)[1]
+ self.assertEqual(len(report), 1)
+ expected_data = [100.0, 100.0, 0.0, 100.0]
+ row = report[0]
+ self.assertEqual(
+ expected_data, [row.invoiced, row.outstanding, row.remaining_balance, row.future_amount]
+ )
+
+ pe.cancel()
+ # partial payment in USD on a future date
+ pe = get_payment_entry(si.doctype, si.name)
+ pe.posting_date = add_days(today(), 1)
+ pe.base_received_amount = 6750
+ pe.received_amount = 6750
+ pe.source_exchange_rate = 75
+ pe.paid_amount = 90 # in USD
+ pe.references[0].allocated_amount = 90
+ pe.save().submit()
+
+ filters.in_party_currency = False
+ report = execute(filters)[1]
+ self.assertEqual(len(report), 1)
+ expected_data = [8000.0, 8000.0, 1250.0, 6750.0]
+ row = report[0]
+ self.assertEqual(
+ expected_data, [row.invoiced, row.outstanding, row.remaining_balance, row.future_amount]
+ )
+
+ filters.in_party_currency = True
+ report = execute(filters)[1]
+ self.assertEqual(len(report), 1)
+ expected_data = [100.0, 100.0, 10.0, 90.0]
+ row = report[0]
+ self.assertEqual(
+ expected_data, [row.invoiced, row.outstanding, row.remaining_balance, row.future_amount]
+ )
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.js b/erpnext/accounts/report/balance_sheet/balance_sheet.js
index b05e744..5525024 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.js
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.js
@@ -8,6 +8,20 @@
erpnext.utils.add_dimensions("Balance Sheet", 10);
+frappe.query_reports["Balance Sheet"]["filters"].push(
+ {
+ "fieldname": "selected_view",
+ "label": __("Select View"),
+ "fieldtype": "Select",
+ "options": [
+ { "value": "Report", "label": __("Report View") },
+ { "value": "Growth", "label": __("Growth View") }
+ ],
+ "default": "Report",
+ "reqd": 1
+ },
+);
+
frappe.query_reports["Balance Sheet"]["filters"].push({
fieldname: "accumulated_values",
label: __("Accumulated Values"),
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 79b5e4d..b7b9d34 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -203,8 +203,14 @@
"fieldname": "show_remarks",
"label": __("Show Remarks"),
"fieldtype": "Check"
+ },
+ {
+ "fieldname": "ignore_err",
+ "label": __("Ignore Exchange Rate Revaluation Journals"),
+ "fieldtype": "Check"
}
+
]
}
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 110ec75..cea3a7b 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -241,6 +241,19 @@
if filters.get("against_voucher_no"):
conditions.append("against_voucher=%(against_voucher_no)s")
+ if filters.get("ignore_err"):
+ err_journals = frappe.db.get_all(
+ "Journal Entry",
+ filters={
+ "company": filters.get("company"),
+ "docstatus": 1,
+ "voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
+ },
+ as_list=True,
+ )
+ if err_journals:
+ filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+
if filters.get("voucher_no_not_in"):
conditions.append("voucher_no not in %(voucher_no_not_in)s")
diff --git a/erpnext/accounts/report/general_ledger/test_general_ledger.py b/erpnext/accounts/report/general_ledger/test_general_ledger.py
index a8c362e..75f9430 100644
--- a/erpnext/accounts/report/general_ledger/test_general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/test_general_ledger.py
@@ -3,7 +3,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase
-from frappe.utils import today
+from frappe.utils import flt, today
from erpnext.accounts.report.general_ledger.general_ledger import execute
@@ -148,3 +148,105 @@
self.assertEqual(data[2]["credit"], 900)
self.assertEqual(data[3]["debit"], 100)
self.assertEqual(data[3]["credit"], 100)
+
+ def test_ignore_exchange_rate_journals_filter(self):
+ # create a new account with USD currency
+ account_name = "Test Debtors USD"
+ company = "_Test Company"
+ account = frappe.get_doc(
+ {
+ "account_name": account_name,
+ "is_group": 0,
+ "company": company,
+ "root_type": "Asset",
+ "report_type": "Balance Sheet",
+ "account_currency": "USD",
+ "parent_account": "Accounts Receivable - _TC",
+ "account_type": "Receivable",
+ "doctype": "Account",
+ }
+ )
+ account.insert(ignore_if_duplicate=True)
+ # create a JV to debit 1000 USD at 75 exchange rate
+ jv = frappe.new_doc("Journal Entry")
+ jv.posting_date = today()
+ jv.company = company
+ jv.multi_currency = 1
+ jv.cost_center = "_Test Cost Center - _TC"
+ jv.set(
+ "accounts",
+ [
+ {
+ "account": account.name,
+ "party_type": "Customer",
+ "party": "_Test Customer USD",
+ "debit_in_account_currency": 1000,
+ "credit_in_account_currency": 0,
+ "exchange_rate": 75,
+ "cost_center": "_Test Cost Center - _TC",
+ },
+ {
+ "account": "Cash - _TC",
+ "debit_in_account_currency": 0,
+ "credit_in_account_currency": 75000,
+ "cost_center": "_Test Cost Center - _TC",
+ },
+ ],
+ )
+ jv.save()
+ jv.submit()
+
+ revaluation = frappe.new_doc("Exchange Rate Revaluation")
+ revaluation.posting_date = today()
+ revaluation.company = company
+ accounts = revaluation.get_accounts_data()
+ revaluation.extend("accounts", accounts)
+ row = revaluation.accounts[0]
+ row.new_exchange_rate = 83
+ row.new_balance_in_base_currency = flt(
+ row.new_exchange_rate * flt(row.balance_in_account_currency)
+ )
+ row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
+ revaluation.set_total_gain_loss()
+ revaluation = revaluation.save().submit()
+
+ # post journal entry for Revaluation doc
+ frappe.db.set_value(
+ "Company", company, "unrealized_exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
+ )
+ revaluation_jv = revaluation.make_jv_for_revaluation()
+ revaluation_jv.cost_center = "_Test Cost Center - _TC"
+ for acc in revaluation_jv.get("accounts"):
+ acc.cost_center = "_Test Cost Center - _TC"
+ revaluation_jv.save()
+ revaluation_jv.submit()
+
+ # With ignore_err enabled
+ columns, data = execute(
+ frappe._dict(
+ {
+ "company": company,
+ "from_date": today(),
+ "to_date": today(),
+ "account": [account.name],
+ "group_by": "Group by Voucher (Consolidated)",
+ "ignore_err": True,
+ }
+ )
+ )
+ self.assertNotIn(revaluation_jv.name, set([x.voucher_no for x in data]))
+
+ # Without ignore_err enabled
+ columns, data = execute(
+ frappe._dict(
+ {
+ "company": company,
+ "from_date": today(),
+ "to_date": today(),
+ "account": [account.name],
+ "group_by": "Group by Voucher (Consolidated)",
+ "ignore_err": False,
+ }
+ )
+ )
+ self.assertIn(revaluation_jv.name, set([x.voucher_no for x in data]))
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
index e5898bf..a2f0fde 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
@@ -8,6 +8,21 @@
erpnext.utils.add_dimensions("Profit and Loss Statement", 10);
+frappe.query_reports["Profit and Loss Statement"]["filters"].push(
+ {
+ "fieldname": "selected_view",
+ "label": __("Select View"),
+ "fieldtype": "Select",
+ "options": [
+ { "value": "Report", "label": __("Report View") },
+ { "value": "Growth", "label": __("Growth View") },
+ { "value": "Margin", "label": __("Margin View") },
+ ],
+ "default": "Report",
+ "reqd": 1
+ },
+);
+
frappe.query_reports["Profit and Loss Statement"]["filters"].push({
fieldname: "accumulated_values",
label: __("Accumulated Values"),
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
index 4a80dd0..852cf15 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
@@ -354,9 +354,6 @@
if filters.get("to_date"):
query = query.where(gle.posting_date <= filters.get("to_date"))
- if bank_accounts:
- query = query.where(gle.against.notin(bank_accounts))
-
if filters.get("party"):
party = [filters.get("party")]
jv_condition = gle.against.isin(party) | (
@@ -368,7 +365,14 @@
(gle.voucher_type == "Journal Entry")
& ((gle.party_type == filters.get("party_type")) | (gle.party_type == ""))
)
- query = query.where((gle.account.isin(tds_accounts) & jv_condition) | gle.party.isin(party))
+
+ query.where((gle.account.isin(tds_accounts) & jv_condition) | gle.party.isin(party))
+ if bank_accounts:
+ query = query.where(
+ gle.against.notin(bank_accounts) & (gle.account.isin(tds_accounts) & jv_condition)
+ | gle.party.isin(party)
+ )
+
return query
diff --git a/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py
index b3f6737..af55ba6 100644
--- a/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py
@@ -5,9 +5,8 @@
from frappe.tests.utils import FrappeTestCase
from frappe.utils import today
-from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
-from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.tax_withholding_category.test_tax_withholding_category import (
create_tax_withholding_category,
@@ -17,7 +16,7 @@
from erpnext.accounts.utils import get_fiscal_year
-class TestTdsPayableMonthly(AccountsTestMixin, FrappeTestCase):
+class TestTaxWithholdingDetails(AccountsTestMixin, FrappeTestCase):
def setUp(self):
self.create_company()
self.clear_old_entries()
@@ -27,11 +26,15 @@
def test_tax_withholding_for_customers(self):
si = create_sales_invoice(rate=1000)
pe = create_tcs_payment_entry()
+ jv = create_tcs_journal_entry()
+
filters = frappe._dict(
company="_Test Company", party_type="Customer", from_date=today(), to_date=today()
)
result = execute(filters)[1]
expected_values = [
+ # Check for JV totals using back calculation logic
+ [jv.name, "TCS", 0.075, -10000.0, -7.5, -10000.0],
[pe.name, "TCS", 0.075, 2550, 0.53, 2550.53],
[si.name, "TCS", 0.075, 1000, 0.52, 1000.52],
]
@@ -41,12 +44,15 @@
for i in range(len(result)):
voucher = frappe._dict(result[i])
voucher_expected_values = expected_values[i]
- self.assertEqual(voucher.ref_no, voucher_expected_values[0])
- self.assertEqual(voucher.section_code, voucher_expected_values[1])
- self.assertEqual(voucher.rate, voucher_expected_values[2])
- self.assertEqual(voucher.base_total, voucher_expected_values[3])
- self.assertAlmostEqual(voucher.tax_amount, voucher_expected_values[4])
- self.assertAlmostEqual(voucher.grand_total, voucher_expected_values[5])
+ voucher_actual_values = (
+ voucher.ref_no,
+ voucher.section_code,
+ voucher.rate,
+ voucher.base_total,
+ voucher.tax_amount,
+ voucher.grand_total,
+ )
+ self.assertSequenceEqual(voucher_actual_values, voucher_expected_values)
def tearDown(self):
self.clear_old_entries()
@@ -109,3 +115,32 @@
)
payment_entry.submit()
return payment_entry
+
+
+def create_tcs_journal_entry():
+ jv = frappe.new_doc("Journal Entry")
+ jv.posting_date = today()
+ jv.company = "_Test Company"
+ jv.set(
+ "accounts",
+ [
+ {
+ "account": "Debtors - _TC",
+ "party_type": "Customer",
+ "party": "_Test Customer",
+ "credit_in_account_currency": 10000,
+ },
+ {
+ "account": "Debtors - _TC",
+ "party_type": "Customer",
+ "party": "_Test Customer",
+ "debit_in_account_currency": 9992.5,
+ },
+ {
+ "account": "TCS - _TC",
+ "debit_in_account_currency": 7.5,
+ },
+ ],
+ )
+ jv.insert()
+ return jv.submit()
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 2c4c762..5374ac1 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -78,8 +78,14 @@
"options": erpnext.get_presentation_currency_list()
},
{
- "fieldname": "with_period_closing_entry",
- "label": __("Period Closing Entry"),
+ "fieldname": "with_period_closing_entry_for_opening",
+ "label": __("With Period Closing Entry For Opening Balances"),
+ "fieldtype": "Check",
+ "default": 1
+ },
+ {
+ "fieldname": "with_period_closing_entry_for_current_period",
+ "label": __("Period Closing Entry For Current Period"),
"fieldtype": "Check",
"default": 1
},
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 8b7f0bb..2ff0eff 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -116,7 +116,7 @@
max_rgt,
filters,
gl_entries_by_account,
- ignore_closing_entries=not flt(filters.with_period_closing_entry),
+ ignore_closing_entries=not flt(filters.with_period_closing_entry_for_current_period),
ignore_opening_entries=True,
)
@@ -249,7 +249,7 @@
):
opening_balance = opening_balance.where(closing_balance.posting_date >= filters.year_start_date)
- if not flt(filters.with_period_closing_entry):
+ if not flt(filters.with_period_closing_entry_for_opening):
if doctype == "Account Closing Balance":
opening_balance = opening_balance.where(closing_balance.is_period_closing_voucher_entry == 0)
else:
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 19095bc..64bc39a 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -237,10 +237,9 @@
)
else:
- cond.append("""gle.cost_center = %s """ % (frappe.db.escape(cost_center, percent=False),))
+ cond.append("""gle.cost_center = %s """ % (frappe.db.escape(cost_center),))
if account:
-
if not (frappe.flags.ignore_account_permission or ignore_account_permission):
acc.check_permission("read")
@@ -259,7 +258,7 @@
if acc.account_currency == frappe.get_cached_value("Company", acc.company, "default_currency"):
in_account_currency = False
else:
- cond.append("""gle.account = %s """ % (frappe.db.escape(account, percent=False),))
+ cond.append("""gle.account = %s """ % (frappe.db.escape(account),))
if account_type:
accounts = frappe.db.get_all(
@@ -279,25 +278,29 @@
if party_type and party:
cond.append(
"""gle.party_type = %s and gle.party = %s """
- % (frappe.db.escape(party_type), frappe.db.escape(party, percent=False))
+ % (frappe.db.escape(party_type), frappe.db.escape(party))
)
if company:
- cond.append("""gle.company = %s """ % (frappe.db.escape(company, percent=False)))
+ cond.append("""gle.company = %s """ % (frappe.db.escape(company)))
if account or (party_type and party) or account_type:
-
+ precision = get_currency_precision()
if in_account_currency:
- select_field = "sum(debit_in_account_currency) - sum(credit_in_account_currency)"
+ select_field = (
+ "sum(round(debit_in_account_currency, %s)) - sum(round(credit_in_account_currency, %s))"
+ )
else:
- select_field = "sum(debit) - sum(credit)"
+ select_field = "sum(round(debit, %s)) - sum(round(credit, %s))"
+
bal = frappe.db.sql(
"""
SELECT {0}
FROM `tabGL Entry` gle
WHERE {1}""".format(
select_field, " and ".join(cond)
- )
+ ),
+ (precision, precision),
)[0][0]
# if bal is None, return 0
return flt(bal)
@@ -345,7 +348,7 @@
% (acc.lft, acc.rgt)
)
else:
- cond.append("""gle.account = %s """ % (frappe.db.escape(account, percent=False),))
+ cond.append("""gle.account = %s """ % (frappe.db.escape(account),))
entries = frappe.db.sql(
"""
@@ -453,7 +456,19 @@
return cc.name
-def reconcile_against_document(args, skip_ref_details_update_for_pe=False): # nosemgrep
+def _build_dimensions_dict_for_exc_gain_loss(
+ entry: dict | object = None, active_dimensions: list = None
+):
+ dimensions_dict = frappe._dict()
+ if entry and active_dimensions:
+ for dim in active_dimensions:
+ dimensions_dict[dim.fieldname] = entry.get(dim.fieldname)
+ return dimensions_dict
+
+
+def reconcile_against_document(
+ args, skip_ref_details_update_for_pe=False, active_dimensions=None
+): # nosemgrep
"""
Cancel PE or JV, Update against document, split if required and resubmit
"""
@@ -482,6 +497,8 @@
check_if_advance_entry_modified(entry)
validate_allocated_amount(entry)
+ dimensions_dict = _build_dimensions_dict_for_exc_gain_loss(entry, active_dimensions)
+
# update ref in advance entry
if voucher_type == "Journal Entry":
referenced_row = update_reference_in_journal_entry(entry, doc, do_not_save=False)
@@ -489,10 +506,14 @@
# amount and account in args
# referenced_row is used to deduplicate gain/loss journal
entry.update({"referenced_row": referenced_row})
- doc.make_exchange_gain_loss_journal([entry])
+ doc.make_exchange_gain_loss_journal([entry], dimensions_dict)
else:
referenced_row = update_reference_in_payment_entry(
- entry, doc, do_not_save=True, skip_ref_details_update_for_pe=skip_ref_details_update_for_pe
+ entry,
+ doc,
+ do_not_save=True,
+ skip_ref_details_update_for_pe=skip_ref_details_update_for_pe,
+ dimensions_dict=dimensions_dict,
)
doc.save(ignore_permissions=True)
@@ -600,7 +621,10 @@
jv_detail = journal_entry.get("accounts", {"name": d["voucher_detail_no"]})[0]
# Update Advance Paid in SO/PO since they might be getting unlinked
- if jv_detail.get("reference_type") in ("Sales Order", "Purchase Order"):
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
+ if jv_detail.get("reference_type") in advance_payment_doctypes:
frappe.get_doc(jv_detail.reference_type, jv_detail.reference_name).set_total_advance_paid()
if flt(d["unadjusted_amount"]) - flt(d["allocated_amount"]) != 0:
@@ -654,7 +678,7 @@
def update_reference_in_payment_entry(
- d, payment_entry, do_not_save=False, skip_ref_details_update_for_pe=False
+ d, payment_entry, do_not_save=False, skip_ref_details_update_for_pe=False, dimensions_dict=None
):
reference_details = {
"reference_doctype": d.against_voucher_type,
@@ -667,13 +691,17 @@
else payment_entry.get_exchange_rate(),
"exchange_gain_loss": d.difference_amount,
"account": d.account,
+ "dimensions": d.dimensions,
}
if d.voucher_detail_no:
existing_row = payment_entry.get("references", {"name": d["voucher_detail_no"]})[0]
# Update Advance Paid in SO/PO since they are getting unlinked
- if existing_row.get("reference_doctype") in ("Sales Order", "Purchase Order"):
+ advance_payment_doctypes = frappe.get_hooks(
+ "advance_payment_receivable_doctypes"
+ ) + frappe.get_hooks("advance_payment_payable_doctypes")
+ if existing_row.get("reference_doctype") in advance_payment_doctypes:
frappe.get_doc(
existing_row.reference_doctype, existing_row.reference_name
).set_total_advance_paid()
@@ -699,8 +727,9 @@
if not skip_ref_details_update_for_pe:
payment_entry.set_missing_ref_details()
payment_entry.set_amounts()
+
payment_entry.make_exchange_gain_loss_journal(
- frappe._dict({"difference_posting_date": d.difference_posting_date})
+ frappe._dict({"difference_posting_date": d.difference_posting_date}), dimensions_dict
)
if not do_not_save:
@@ -2042,6 +2071,7 @@
ref2_dn,
ref2_detail_no,
cost_center,
+ dimensions,
) -> str:
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.voucher_type = "Exchange Gain Or Loss"
@@ -2075,7 +2105,8 @@
dr_or_cr + "_in_account_currency": 0,
}
)
-
+ if dimensions:
+ journal_account.update(dimensions)
journal_entry.append("accounts", journal_account)
journal_account = frappe._dict(
@@ -2091,7 +2122,8 @@
reverse_dr_or_cr: abs(exc_gain_loss),
}
)
-
+ if dimensions:
+ journal_account.update(dimensions)
journal_entry.append("accounts", journal_account)
journal_entry.save()
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 02e7a9b..673fe54 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -571,16 +571,16 @@
indicator: 'red'
});
}
- var is_grouped_asset = frappe.db.get_value('Item', item.item_code, 'is_grouped_asset');
- var asset_quantity = is_grouped_asset ? item.qty : 1;
- var purchase_amount = flt(item.valuation_rate * asset_quantity, precision('gross_purchase_amount'));
+ frappe.db.get_value('Item', item.item_code, 'is_grouped_asset', (r) => {
+ var asset_quantity = r.is_grouped_asset ? item.qty : 1;
+ var purchase_amount = flt(item.valuation_rate * asset_quantity, precision('gross_purchase_amount'));
- frm.set_value('gross_purchase_amount', purchase_amount);
- frm.set_value('purchase_receipt_amount', purchase_amount);
- frm.set_value('asset_quantity', asset_quantity);
- frm.set_value('cost_center', item.cost_center || purchase_doc.cost_center);
- if(item.asset_location) { frm.set_value('location', item.asset_location); }
-
+ frm.set_value('gross_purchase_amount', purchase_amount);
+ frm.set_value('purchase_receipt_amount', purchase_amount);
+ frm.set_value('asset_quantity', asset_quantity);
+ frm.set_value('cost_center', item.cost_center || purchase_doc.cost_center);
+ if(item.asset_location) { frm.set_value('location', item.asset_location); }
+ });
},
set_depreciation_rate: function(frm, row) {
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 7357249..166e8c4 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -519,14 +519,11 @@
movement.cancel()
def cancel_capitalization(self):
- asset_capitalization = frappe.db.get_value(
- "Asset Capitalization",
- {"target_asset": self.name, "docstatus": 1, "entry_type": "Capitalization"},
- )
-
- if asset_capitalization:
- asset_capitalization = frappe.get_doc("Asset Capitalization", asset_capitalization)
- asset_capitalization.cancel()
+ if self.capitalized_in:
+ self.db_set("capitalized_in", None)
+ asset_capitalization = frappe.get_doc("Asset Capitalization", self.capitalized_in)
+ if asset_capitalization.docstatus == 1:
+ asset_capitalization.cancel()
def delete_depreciation_entries(self):
if self.calculate_depreciation:
@@ -1011,7 +1008,7 @@
assets = json.loads(assets)
if len(assets) == 0:
- frappe.throw(_("Atleast one asset has to be selected."))
+ frappe.throw(_("At least one asset has to be selected."))
asset_movement = frappe.new_doc("Asset Movement")
asset_movement.quantity = len(assets)
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index a93af94..df4593b 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -561,6 +561,8 @@
def reverse_depreciation_entry_made_after_disposal(asset, date):
for row in asset.get("finance_books"):
asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
+ if not asset_depr_schedule_doc:
+ continue
for schedule_idx, schedule in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")):
if schedule.schedule_date == date:
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index cad74df..c9ed806 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -126,6 +126,7 @@
self.create_target_asset()
def on_submit(self):
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
self.make_gl_entries()
self.update_target_asset()
@@ -146,6 +147,7 @@
def cancel_target_asset(self):
if self.entry_type == "Capitalization" and self.target_asset:
asset_doc = frappe.get_doc("Asset", self.target_asset)
+ frappe.db.set_value("Asset", self.target_asset, "capitalized_in", None)
if asset_doc.docstatus == 1:
asset_doc.cancel()
diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
index 26e1c3c..8eda441 100644
--- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
+++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.json
@@ -18,9 +18,12 @@
"amount",
"batch_and_serial_no_section",
"serial_and_batch_bundle",
+ "use_serial_batch_fields",
"column_break_13",
- "batch_no",
+ "section_break_bfqc",
"serial_no",
+ "column_break_mbuv",
+ "batch_no",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break"
@@ -39,13 +42,13 @@
"reqd": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"no_copy": 1,
"options": "Batch",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "section_break_6",
@@ -102,12 +105,12 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Serial No",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "item_code",
@@ -148,18 +151,34 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
"no_copy": 1,
"options": "Serial and Batch Bundle",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_bfqc",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_mbuv",
+ "fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-04-06 01:10:17.947952",
+ "modified": "2024-02-04 16:41:09.239762",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization Stock Item",
diff --git a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py
index 122cbb6..d2b075c 100644
--- a/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py
+++ b/erpnext/assets/doctype/asset_capitalization_stock_item/asset_capitalization_stock_item.py
@@ -27,6 +27,7 @@
serial_no: DF.SmallText | None
stock_qty: DF.Float
stock_uom: DF.Link
+ use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency
warehouse: DF.Link
# end: auto-generated types
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index 063fe99..780f61f 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -40,7 +40,7 @@
if getdate(task.next_due_date) < getdate(nowdate()):
task.maintenance_status = "Overdue"
if not task.assign_to and self.docstatus == 0:
- throw(_("Row #{}: Please asign task to a member.").format(task.idx))
+ throw(_("Row #{}: Please assign task to a member.").format(task.idx))
def on_update(self):
for task in self.get("asset_maintenance_tasks"):
diff --git a/erpnext/assets/onboarding_step/asset_category/asset_category.json b/erpnext/assets/onboarding_step/asset_category/asset_category.json
index 58f322e..a1b68ba 100644
--- a/erpnext/assets/onboarding_step/asset_category/asset_category.json
+++ b/erpnext/assets/onboarding_step/asset_category/asset_category.json
@@ -2,14 +2,14 @@
"action": "Show Form Tour",
"action_label": "Let's review existing Asset Category",
"creation": "2021-08-13 14:26:18.656303",
- "description": "# Asset Category\n\nAn Asset Category classifies different assets of a Company.\n\nYou can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipments\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n - Depreciation type and duration\n - Fixed asset account\n - Depreciation account\n",
+ "description": "# Asset Category\n\nAn Asset Category classifies different assets of a Company.\n\nYou can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipment\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n - Depreciation type and duration\n - Fixed asset account\n - Depreciation account\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2021-11-23 10:02:03.242127",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"name": "Asset Category",
"owner": "Administrator",
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index 45811a9..e689b05 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -202,7 +202,7 @@
"values": [flt(d.get("asset_value"), 2) for d in labels_values_map.values()],
},
{
- "name": _("Depreciatied Amount"),
+ "name": _("Depreciated Amount"),
"values": [flt(d.get("depreciated_amount"), 2) for d in labels_values_map.values()],
},
],
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index ddcbd55..d98a00f 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -1,7 +1,6 @@
{
"actions": [],
"creation": "2013-06-25 11:04:03",
- "description": "Settings for Buying Module",
"doctype": "DocType",
"document_type": "Other",
"engine": "InnoDB",
@@ -152,6 +151,7 @@
},
{
"default": "1",
+ "depends_on": "eval: frappe.boot.versions && frappe.boot.versions.payments",
"fieldname": "show_pay_button",
"fieldtype": "Check",
"label": "Show Pay Button in Purchase Order Portal"
@@ -214,7 +214,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2024-01-12 16:42:01.894346",
+ "modified": "2024-01-31 13:34:18.101256",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index f74df66..9da49a7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -134,6 +134,7 @@
"more_info_tab",
"tracking_section",
"status",
+ "advance_payment_status",
"column_break_75",
"per_billed",
"per_received",
@@ -1269,13 +1270,25 @@
"fieldtype": "Tab Break",
"label": "Connections",
"show_dashboard": 1
+ },
+ {
+ "fieldname": "advance_payment_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "in_standard_filter": 1,
+ "label": "Advance Payment Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "Not Initiated\nInitiated\nPartially Paid\nFully Paid",
+ "print_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2023-10-01 20:58:07.851037",
+ "modified": "2023-10-10 13:37:40.158761",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
@@ -1330,4 +1343,4 @@
"timeline_field": "supplier",
"title_field": "supplier_name",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index b830e7d..4d94868 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -215,6 +215,10 @@
self.validate_fg_item_for_subcontracting()
self.set_received_qty_for_drop_ship_items()
+
+ if not self.advance_payment_status:
+ self.advance_payment_status = "Not Initiated"
+
validate_inter_company_party(
self.doctype, self.supplier, self.company, self.inter_company_order_reference
)
@@ -453,6 +457,7 @@
self.update_ordered_qty()
self.update_reserved_qty_for_subcontract()
self.update_subcontracting_order_status()
+ self.update_blanket_order()
self.notify_update()
clear_doctype_notifications(self)
@@ -640,6 +645,7 @@
update_sco_status(sco, "Closed" if self.status == "Closed" else None)
+@frappe.request_cache
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor=1.0):
"""get last purchase rate for an item"""
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
index 6594746..d39d7f9 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
@@ -1,6 +1,6 @@
frappe.listview_settings['Purchase Order'] = {
add_fields: ["base_grand_total", "company", "currency", "supplier",
- "supplier_name", "per_received", "per_billed", "status"],
+ "supplier_name", "per_received", "per_billed", "status", "advance_payment_status"],
get_indicator: function (doc) {
if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
@@ -8,6 +8,8 @@
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.status === "Delivered") {
return [__("Delivered"), "green", "status,=,Closed"];
+ } else if (doc.advance_payment_status == "Initiated") {
+ return [__("To Pay"), "gray", "advance_payment_status,=,Initiated"];
} else if (flt(doc.per_received, 2) < 100 && doc.status !== "Closed") {
if (flt(doc.per_billed, 2) < 100) {
return [__("To Receive and Bill"), "orange",
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 9b382bb..a30de68 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -822,6 +822,30 @@
# To test if the PO does NOT have a Blanket Order
self.assertEqual(po_doc.items[0].blanket_order, None)
+ def test_blanket_order_on_po_close_and_open(self):
+ # Step - 1: Create Blanket Order
+ bo = make_blanket_order(blanket_order_type="Purchasing", quantity=10, rate=10)
+
+ # Step - 2: Create Purchase Order
+ po = create_purchase_order(
+ item_code="_Test Item", qty=5, against_blanket_order=1, against_blanket=bo.name
+ )
+
+ bo.load_from_db()
+ self.assertEqual(bo.items[0].ordered_qty, 5)
+
+ # Step - 3: Close Purchase Order
+ po.update_status("Closed")
+
+ bo.load_from_db()
+ self.assertEqual(bo.items[0].ordered_qty, 0)
+
+ # Step - 4: Re-Open Purchase Order
+ po.update_status("Re-open")
+
+ bo.load_from_db()
+ self.assertEqual(bo.items[0].ordered_qty, 5)
+
def test_payment_terms_are_fetched_when_creating_purchase_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
create_payment_terms_template,
@@ -1021,6 +1045,33 @@
self.assertTrue(frappe.db.get_value("Subcontracting Order", {"purchase_order": po.name}))
+ def test_purchase_order_advance_payment_status(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+ from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
+
+ po = create_purchase_order()
+ self.assertEqual(
+ frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Not Initiated"
+ )
+
+ pr = make_payment_request(dt=po.doctype, dn=po.name, submit_doc=True, return_doc=True)
+ self.assertEqual(frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Initiated")
+
+ pe = get_payment_entry(po.doctype, po.name).save().submit()
+ self.assertEqual(
+ frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Fully Paid"
+ )
+
+ pe.reload()
+ pe.cancel()
+ self.assertEqual(frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Initiated")
+
+ pr.reload()
+ pr.cancel()
+ self.assertEqual(
+ frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Not Initiated"
+ )
+
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
@@ -1121,6 +1172,7 @@
"schedule_date": add_days(nowdate(), 1),
"include_exploded_items": args.get("include_exploded_items", 1),
"against_blanket_order": args.against_blanket_order,
+ "against_blanket": args.against_blanket,
"material_request": args.material_request,
"material_request_item": args.material_request_item,
},
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 5a24cc2..e3e8def 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -545,7 +545,6 @@
"fieldname": "blanket_order",
"fieldtype": "Link",
"label": "Blanket Order",
- "no_copy": 1,
"options": "Blanket Order"
},
{
@@ -553,7 +552,6 @@
"fieldname": "blanket_order_rate",
"fieldtype": "Currency",
"label": "Blanket Order Rate",
- "no_copy": 1,
"print_hide": 1,
"read_only": 1
},
@@ -917,7 +915,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-24 13:24:41.298416",
+ "modified": "2024-02-05 11:23:24.859435",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js
index 91506c0..3bf4f2b 100644
--- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js
+++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js
@@ -54,7 +54,7 @@
"fieldtype": "MultiSelectList",
"width": "80",
get_data: function(txt) {
- let status = ["To Bill", "To Receive", "To Receive and Bill", "Completed"]
+ let status = ["To Pay", "To Bill", "To Receive", "To Receive and Bill", "Completed"]
let options = []
for (let option of status){
options.push({
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 0c554f2..e2b0ee5 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -7,6 +7,7 @@
import frappe
from frappe import _, bold, qb, throw
from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied
+from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Abs, Sum
from frappe.utils import (
@@ -21,12 +22,14 @@
get_link_to_form,
getdate,
nowdate,
+ parse_json,
today,
)
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
+ get_dimensions,
)
from erpnext.accounts.doctype.pricing_rule.utils import (
apply_pricing_rule_for_free_items,
@@ -199,6 +202,7 @@
self.validate_party()
self.validate_currency()
self.validate_party_account_currency()
+ self.validate_return_against_account()
if self.doctype in ["Purchase Invoice", "Sales Invoice"]:
if invalid_advances := [
@@ -347,6 +351,20 @@
for bundle in bundles:
frappe.delete_doc("Serial and Batch Bundle", bundle.name)
+ def validate_return_against_account(self):
+ if (
+ self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against
+ ):
+ cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to"
+ cr_dr_account_label = "Debit To" if self.doctype == "Sales Invoice" else "Credit To"
+ cr_dr_account = self.get(cr_dr_account_field)
+ if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account:
+ frappe.throw(
+ _("'{0}' account: '{1}' should match the Return Against Invoice").format(
+ frappe.bold(cr_dr_account_label), frappe.bold(cr_dr_account)
+ )
+ )
+
def validate_deferred_income_expense_account(self):
field_map = {
"Sales Invoice": "deferred_revenue_account",
@@ -675,7 +693,7 @@
if self.get("is_subcontracted"):
args["is_subcontracted"] = self.is_subcontracted
- ret = get_item_details(args, self, for_validate=True, overwrite_warehouse=False)
+ ret = get_item_details(args, self, for_validate=for_validate, overwrite_warehouse=False)
for fieldname, value in ret.items():
if item.meta.get_field(fieldname) and value is not None:
@@ -831,6 +849,37 @@
self.extend("taxes", get_taxes_and_charges(tax_master_doctype, self.get("taxes_and_charges")))
+ def append_taxes_from_item_tax_template(self):
+ if not frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template"):
+ return
+
+ for row in self.items:
+ item_tax_rate = row.get("item_tax_rate")
+ if not item_tax_rate:
+ continue
+
+ if isinstance(item_tax_rate, str):
+ item_tax_rate = parse_json(item_tax_rate)
+
+ for account_head, rate in item_tax_rate.items():
+ row = self.get_tax_row(account_head)
+
+ if not row:
+ self.append(
+ "taxes",
+ {
+ "charge_type": "On Net Total",
+ "account_head": account_head,
+ "rate": 0,
+ "description": account_head,
+ },
+ )
+
+ def get_tax_row(self, account_head):
+ for row in self.taxes:
+ if row.account_head == account_head:
+ return row
+
def set_other_charges(self):
self.set("taxes", [])
self.set_taxes()
@@ -1216,7 +1265,9 @@
return True
return False
- def make_exchange_gain_loss_journal(self, args: dict = None) -> None:
+ def make_exchange_gain_loss_journal(
+ self, args: dict = None, dimensions_dict: dict = None
+ ) -> None:
"""
Make Exchange Gain/Loss journal for Invoices and Payments
"""
@@ -1271,6 +1322,7 @@
self.name,
arg.get("referenced_row"),
arg.get("cost_center"),
+ dimensions_dict,
)
frappe.msgprint(
_("Exchange Gain/Loss amount has been booked through {0}").format(
@@ -1351,6 +1403,7 @@
self.name,
d.idx,
self.cost_center,
+ dimensions_dict,
)
frappe.msgprint(
_("Exchange Gain/Loss amount has been booked through {0}").format(
@@ -1415,7 +1468,13 @@
if lst:
from erpnext.accounts.utils import reconcile_against_document
- reconcile_against_document(lst)
+ # pass dimension values to utility method
+ active_dimensions = get_dimensions()[0]
+ for x in lst:
+ for dim in active_dimensions:
+ if self.get(dim.fieldname):
+ x.update({dim.fieldname: self.get(dim.fieldname)})
+ reconcile_against_document(lst, active_dimensions=active_dimensions)
def on_cancel(self):
from erpnext.accounts.doctype.bank_transaction.bank_transaction import (
@@ -1749,7 +1808,10 @@
def set_total_advance_paid(self):
ple = frappe.qb.DocType("Payment Ledger Entry")
- party = self.customer if self.doctype == "Sales Order" else self.supplier
+ if self.doctype in frappe.get_hooks("advance_payment_receivable_doctypes"):
+ party = self.customer
+ if self.doctype in frappe.get_hooks("advance_payment_payable_doctypes"):
+ party = self.supplier
advance = (
frappe.qb.from_(ple)
.select(ple.account_currency, Abs(Sum(ple.amount_in_account_currency)).as_("amount"))
@@ -1763,6 +1825,8 @@
.run(as_dict=True)
)
+ advance_paid, order_total = None, None
+
if advance:
advance = advance[0]
@@ -1791,7 +1855,38 @@
).format(formatted_advance_paid, self.name, formatted_order_total)
)
- frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid)
+ self.db_set("advance_paid", advance_paid)
+
+ self.set_advance_payment_status(advance_paid, order_total)
+
+ def set_advance_payment_status(
+ self, advance_paid: float | None = None, order_total: float | None = None
+ ):
+ new_status = None
+ # if money is paid set the paid states
+ if advance_paid:
+ new_status = "Partially Paid" if advance_paid < order_total else "Fully Paid"
+
+ if not new_status:
+ prs = frappe.db.count(
+ "Payment Request",
+ {
+ "reference_doctype": self.doctype,
+ "reference_name": self.name,
+ "docstatus": 1,
+ },
+ )
+ if self.doctype in frappe.get_hooks("advance_payment_receivable_doctypes"):
+ new_status = "Requested" if prs else "Not Requested"
+ if self.doctype in frappe.get_hooks("advance_payment_payable_doctypes"):
+ new_status = "Initiated" if prs else "Not Initiated"
+
+ if new_status == self.advance_payment_status:
+ return
+
+ self.db_set("advance_payment_status", new_status)
+ self.set_status(update=True)
+ self.notify_update()
@property
def company_abbr(self):
@@ -2684,47 +2779,37 @@
q = q.select((payment_entry.target_exchange_rate).as_("exchange_rate"))
if condition:
- if condition.get("name", None):
- q = q.where(payment_entry.name.like(f"%{condition.get('name')}%"))
+ # conditions should be built as an array and passed as Criterion
+ common_filter_conditions = []
- q = q.where(payment_entry.company == condition["company"])
- q = (
- q.where(payment_entry.posting_date >= condition["from_payment_date"])
- if condition.get("from_payment_date")
- else q
- )
- q = (
- q.where(payment_entry.posting_date <= condition["to_payment_date"])
- if condition.get("to_payment_date")
- else q
- )
+ common_filter_conditions.append(payment_entry.company == condition["company"])
+ if condition.get("name", None):
+ common_filter_conditions.append(payment_entry.name.like(f"%{condition.get('name')}%"))
+
+ if condition.get("from_payment_date"):
+ common_filter_conditions.append(payment_entry.posting_date.gte(condition["from_payment_date"]))
+
+ if condition.get("to_payment_date"):
+ common_filter_conditions.append(payment_entry.posting_date.lte(condition["to_payment_date"]))
+
if condition.get("get_payments") == True:
- q = (
- q.where(payment_entry.cost_center == condition["cost_center"])
- if condition.get("cost_center")
- else q
- )
- q = (
- q.where(payment_entry.unallocated_amount >= condition["minimum_payment_amount"])
- if condition.get("minimum_payment_amount")
- else q
- )
- q = (
- q.where(payment_entry.unallocated_amount <= condition["maximum_payment_amount"])
- if condition.get("maximum_payment_amount")
- else q
- )
- else:
- q = (
- q.where(payment_entry.total_debit >= condition["minimum_payment_amount"])
- if condition.get("minimum_payment_amount")
- else q
- )
- q = (
- q.where(payment_entry.total_debit <= condition["maximum_payment_amount"])
- if condition.get("maximum_payment_amount")
- else q
- )
+ if condition.get("cost_center"):
+ common_filter_conditions.append(payment_entry.cost_center == condition["cost_center"])
+
+ if condition.get("accounting_dimensions"):
+ for field, val in condition.get("accounting_dimensions").items():
+ common_filter_conditions.append(payment_entry[field] == val)
+
+ if condition.get("minimum_payment_amount"):
+ common_filter_conditions.append(
+ payment_entry.unallocated_amount.gte(condition["minimum_payment_amount"])
+ )
+
+ if condition.get("maximum_payment_amount"):
+ common_filter_conditions.append(
+ payment_entry.unallocated_amount.lte(condition["maximum_payment_amount"])
+ )
+ q = q.where(Criterion.all(common_filter_conditions))
q = q.orderby(payment_entry.posting_date)
q = q.limit(limit) if limit else q
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index e234eec..c46ef50 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -729,17 +729,24 @@
conditions, bin_conditions = [], []
filter_dict = get_doctype_wise_filters(filters)
- query = """select `tabWarehouse`.name,
+ warehouse_field = "name"
+ meta = frappe.get_meta("Warehouse")
+ if meta.get("show_title_field_in_link") and meta.get("title_field"):
+ searchfield = meta.get("title_field")
+ warehouse_field = meta.get("title_field")
+
+ query = """select `tabWarehouse`.`{warehouse_field}`,
CONCAT_WS(' : ', 'Actual Qty', ifnull(round(`tabBin`.actual_qty, 2), 0 )) actual_qty
from `tabWarehouse` left join `tabBin`
on `tabBin`.warehouse = `tabWarehouse`.name {bin_conditions}
where
`tabWarehouse`.`{key}` like {txt}
{fcond} {mcond}
- order by ifnull(`tabBin`.actual_qty, 0) desc
+ order by ifnull(`tabBin`.actual_qty, 0) desc, `tabWarehouse`.`{warehouse_field}` asc
limit
{page_len} offset {start}
""".format(
+ warehouse_field=warehouse_field,
bin_conditions=get_filters_cond(
doctype, filter_dict.get("Bin"), bin_conditions, ignore_permissions=True
),
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 6e50279..800e756 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -141,7 +141,7 @@
items_returned = True
if not items_returned:
- frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
+ frappe.throw(_("At least one item should be entered with negative quantity in return document"))
def validate_quantity(doc, args, ref, valid_items, already_returned_items):
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 8c43842..dc49023 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -599,7 +599,7 @@
if self.doctype in ["Sales Order", "Quotation"]:
for item in self.items:
item.gross_profit = flt(
- ((item.base_rate - item.valuation_rate) * item.stock_qty), self.precision("amount", item)
+ ((item.base_rate - flt(item.valuation_rate)) * item.stock_qty), self.precision("amount", item)
)
def set_customer_address(self):
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 297f8c2..e5f341f 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -54,6 +54,10 @@
"eval:self.per_delivered < 100 and self.per_billed >= 100 and self.docstatus == 1 and not self.skip_delivery_note",
],
[
+ "To Pay",
+ "eval:self.advance_payment_status == 'Requested' and self.docstatus == 1",
+ ],
+ [
"Completed",
"eval:(self.per_delivered >= 100 or self.skip_delivery_note) and self.per_billed >= 100 and self.docstatus == 1",
],
@@ -63,16 +67,20 @@
],
"Purchase Order": [
["Draft", None],
- [
- "To Receive and Bill",
- "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1",
- ],
["To Bill", "eval:self.per_received >= 100 and self.per_billed < 100 and self.docstatus == 1"],
[
"To Receive",
"eval:self.per_received < 100 and self.per_billed == 100 and self.docstatus == 1",
],
[
+ "To Receive and Bill",
+ "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1",
+ ],
+ [
+ "To Pay",
+ "eval:self.advance_payment_status == 'Initiated' and self.docstatus == 1",
+ ],
+ [
"Completed",
"eval:self.per_received >= 100 and self.per_billed == 100 and self.docstatus == 1",
],
@@ -91,7 +99,8 @@
],
"Purchase Receipt": [
["Draft", None],
- ["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
+ ["To Bill", "eval:self.per_billed == 0 and self.docstatus == 1"],
+ ["Partly Billed", "eval:self.per_billed > 0 and self.per_billed < 100 and self.docstatus == 1"],
["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 7c63518..74c835c 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -6,7 +6,7 @@
from typing import List, Tuple
import frappe
-from frappe import _
+from frappe import _, bold
from frappe.utils import cint, flt, get_link_to_form, getdate
import erpnext
@@ -21,6 +21,9 @@
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import (
get_evaluated_inventory_dimension,
)
+from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
+ get_type_of_transaction,
+)
from erpnext.stock.stock_ledger import get_items_to_be_repost
@@ -126,6 +129,81 @@
# remove extra whitespace and store one serial no on each line
row.serial_no = clean_serial_no_string(row.serial_no)
+ def make_bundle_using_old_serial_batch_fields(self):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ from erpnext.stock.serial_batch_bundle import SerialBatchCreation
+
+ # To handle test cases
+ if frappe.flags.in_test and frappe.flags.use_serial_and_batch_fields:
+ return
+
+ table_name = "items"
+ if self.doctype == "Asset Capitalization":
+ table_name = "stock_items"
+
+ for row in self.get(table_name):
+ if not row.serial_no and not row.batch_no and not row.get("rejected_serial_no"):
+ continue
+
+ if not row.use_serial_batch_fields and (
+ row.serial_no or row.batch_no or row.get("rejected_serial_no")
+ ):
+ frappe.throw(_("Please enable Use Old Serial / Batch Fields to make_bundle"))
+
+ if row.use_serial_batch_fields and (
+ not row.serial_and_batch_bundle and not row.get("rejected_serial_and_batch_bundle")
+ ):
+ if self.doctype == "Stock Reconciliation":
+ qty = row.qty
+ type_of_transaction = "Inward"
+ else:
+ qty = row.stock_qty
+ type_of_transaction = get_type_of_transaction(self, row)
+
+ sn_doc = SerialBatchCreation(
+ {
+ "item_code": row.item_code,
+ "warehouse": row.warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "voucher_detail_no": row.name,
+ "qty": qty,
+ "type_of_transaction": type_of_transaction,
+ "company": self.company,
+ "is_rejected": 1 if row.get("rejected_warehouse") else 0,
+ "serial_nos": get_serial_nos(row.serial_no) if row.serial_no else None,
+ "batches": frappe._dict({row.batch_no: qty}) if row.batch_no else None,
+ "batch_no": row.batch_no,
+ "use_serial_batch_fields": row.use_serial_batch_fields,
+ "do_not_submit": True,
+ }
+ ).make_serial_and_batch_bundle()
+
+ if sn_doc.is_rejected:
+ row.rejected_serial_and_batch_bundle = sn_doc.name
+ row.db_set(
+ {
+ "rejected_serial_and_batch_bundle": sn_doc.name,
+ "rejected_serial_no": "",
+ }
+ )
+ else:
+ row.serial_and_batch_bundle = sn_doc.name
+ row.db_set(
+ {
+ "serial_and_batch_bundle": sn_doc.name,
+ "serial_no": "",
+ "batch_no": "",
+ }
+ )
+
+ def set_use_serial_batch_fields(self):
+ if frappe.db.get_single_value("Stock Settings", "use_serial_batch_fields"):
+ for row in self.items:
+ row.use_serial_batch_fields = 1
+
def get_gl_entries(
self, warehouse_account=None, default_expense_account=None, default_cost_center=None
):
@@ -697,6 +775,9 @@
self.validate_in_transit_warehouses()
self.validate_multi_currency()
self.validate_packed_items()
+
+ if self.get("is_internal_supplier"):
+ self.validate_internal_transfer_qty()
else:
self.validate_internal_transfer_warehouse()
@@ -735,6 +816,116 @@
if self.doctype in ("Sales Invoice", "Delivery Note Item") and self.get("packed_items"):
frappe.throw(_("Packed Items cannot be transferred internally"))
+ def validate_internal_transfer_qty(self):
+ if self.doctype not in ["Purchase Invoice", "Purchase Receipt"]:
+ return
+
+ item_wise_transfer_qty = self.get_item_wise_inter_transfer_qty()
+ if not item_wise_transfer_qty:
+ return
+
+ item_wise_received_qty = self.get_item_wise_inter_received_qty()
+ precision = frappe.get_precision(self.doctype + " Item", "qty")
+
+ over_receipt_allowance = frappe.db.get_single_value(
+ "Stock Settings", "over_delivery_receipt_allowance"
+ )
+
+ parent_doctype = {
+ "Purchase Receipt": "Delivery Note",
+ "Purchase Invoice": "Sales Invoice",
+ }.get(self.doctype)
+
+ for key, transferred_qty in item_wise_transfer_qty.items():
+ recevied_qty = flt(item_wise_received_qty.get(key), precision)
+ if over_receipt_allowance:
+ transferred_qty = transferred_qty + flt(
+ transferred_qty * over_receipt_allowance / 100, precision
+ )
+
+ if recevied_qty > flt(transferred_qty, precision):
+ frappe.throw(
+ _("For Item {0} cannot be received more than {1} qty against the {2} {3}").format(
+ bold(key[1]),
+ bold(flt(transferred_qty, precision)),
+ bold(parent_doctype),
+ get_link_to_form(parent_doctype, self.get("inter_company_reference")),
+ )
+ )
+
+ def get_item_wise_inter_transfer_qty(self):
+ reference_field = "inter_company_reference"
+ if self.doctype == "Purchase Invoice":
+ reference_field = "inter_company_invoice_reference"
+
+ parent_doctype = {
+ "Purchase Receipt": "Delivery Note",
+ "Purchase Invoice": "Sales Invoice",
+ }.get(self.doctype)
+
+ child_doctype = parent_doctype + " Item"
+
+ parent_tab = frappe.qb.DocType(parent_doctype)
+ child_tab = frappe.qb.DocType(child_doctype)
+
+ query = (
+ frappe.qb.from_(parent_doctype)
+ .inner_join(child_tab)
+ .on(child_tab.parent == parent_tab.name)
+ .select(
+ child_tab.name,
+ child_tab.item_code,
+ child_tab.qty,
+ )
+ .where((parent_tab.name == self.get(reference_field)) & (parent_tab.docstatus == 1))
+ )
+
+ data = query.run(as_dict=True)
+ item_wise_transfer_qty = defaultdict(float)
+ for row in data:
+ item_wise_transfer_qty[(row.name, row.item_code)] += flt(row.qty)
+
+ return item_wise_transfer_qty
+
+ def get_item_wise_inter_received_qty(self):
+ child_doctype = self.doctype + " Item"
+
+ parent_tab = frappe.qb.DocType(self.doctype)
+ child_tab = frappe.qb.DocType(child_doctype)
+
+ query = (
+ frappe.qb.from_(self.doctype)
+ .inner_join(child_tab)
+ .on(child_tab.parent == parent_tab.name)
+ .select(
+ child_tab.item_code,
+ child_tab.qty,
+ )
+ .where(parent_tab.docstatus < 2)
+ )
+
+ if self.doctype == "Purchase Invoice":
+ query = query.select(
+ child_tab.sales_invoice_item.as_("name"),
+ )
+
+ query = query.where(
+ parent_tab.inter_company_invoice_reference == self.inter_company_invoice_reference
+ )
+ else:
+ query = query.select(
+ child_tab.delivery_note_item.as_("name"),
+ )
+
+ query = query.where(parent_tab.inter_company_reference == self.inter_company_reference)
+
+ data = query.run(as_dict=True)
+ item_wise_transfer_qty = defaultdict(float)
+ for row in data:
+ item_wise_transfer_qty[(row.name, row.item_code)] += flt(row.qty)
+
+ return item_wise_transfer_qty
+
def validate_putaway_capacity(self):
# if over receipt is attempted while 'apply putaway rule' is disabled
# and if rule was applied on the transaction, validate it.
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 9555902..17a2b07 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -260,18 +260,22 @@
return frappe.get_all(f"{doctype}", fields=fields, filters=filters)
def __get_consumed_items(self, doctype, receipt_items):
+ fields = [
+ "serial_no",
+ "rm_item_code",
+ "reference_name",
+ "batch_no",
+ "consumed_qty",
+ "main_item_code",
+ "parent as voucher_no",
+ ]
+
+ if self.subcontract_data.receipt_supplied_items_field != "Purchase Receipt Item Supplied":
+ fields.append("serial_and_batch_bundle")
+
return frappe.get_all(
self.subcontract_data.receipt_supplied_items_field,
- fields=[
- "serial_no",
- "rm_item_code",
- "reference_name",
- "serial_and_batch_bundle",
- "batch_no",
- "consumed_qty",
- "main_item_code",
- "parent as voucher_no",
- ],
+ fields=fields,
filters={"docstatus": 1, "reference_name": ("in", list(receipt_items)), "parenttype": doctype},
)
@@ -881,7 +885,9 @@
"posting_time": self.posting_time,
"qty": -1 * item.consumed_qty,
"voucher_detail_no": item.name,
- "serial_and_batch_bundle": item.serial_and_batch_bundle,
+ "serial_and_batch_bundle": item.get("serial_and_batch_bundle"),
+ "serial_no": item.get("serial_no"),
+ "batch_no": item.get("batch_no"),
}
)
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index f9f68a1..3d7a947 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -8,6 +8,7 @@
from frappe import _, scrub
from frappe.model.document import Document
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
+from frappe.utils.deprecations import deprecated
import erpnext
from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate
@@ -74,7 +75,7 @@
self.calculate_net_total()
self.calculate_tax_withholding_net_total()
self.calculate_taxes()
- self.manipulate_grand_total_for_inclusive_tax()
+ self.adjust_grand_total_for_inclusive_tax()
self.calculate_totals()
self._cleanup()
self.calculate_total_net_weight()
@@ -97,6 +98,7 @@
item_doc = frappe.get_cached_doc("Item", item.item_code)
args = {
"net_rate": item.net_rate or item.rate,
+ "base_net_rate": item.base_net_rate or item.base_rate,
"tax_category": self.doc.get("tax_category"),
"posting_date": self.doc.get("posting_date"),
"bill_date": self.doc.get("bill_date"),
@@ -279,7 +281,7 @@
):
amount = flt(item.amount) - total_inclusive_tax_amount_per_qty
- item.net_amount = flt(amount / (1 + cumulated_tax_fraction))
+ item.net_amount = flt(amount / (1 + cumulated_tax_fraction), item.precision("net_amount"))
item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate"))
item.discount_percentage = flt(item.discount_percentage, item.precision("discount_percentage"))
@@ -516,7 +518,12 @@
tax.base_tax_amount = round(tax.base_tax_amount, 0)
tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
+ @deprecated
def manipulate_grand_total_for_inclusive_tax(self):
+ # for backward compatablility - if in case used by an external application
+ return self.adjust_grand_total_for_inclusive_tax()
+
+ def adjust_grand_total_for_inclusive_tax(self):
# if fully inclusive taxes and diff
if self.doc.get("taxes") and any(cint(t.included_in_print_rate) for t in self.doc.get("taxes")):
last_tax = self.doc.get("taxes")[-1]
@@ -538,17 +545,21 @@
diff = flt(diff, self.doc.precision("rounding_adjustment"))
if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
- self.doc.rounding_adjustment = diff
+ self.doc.grand_total_diff = diff
+ else:
+ self.doc.grand_total_diff = 0
def calculate_totals(self):
if self.doc.get("taxes"):
- self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
+ self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(
+ self.doc.get("grand_total_diff")
+ )
else:
self.doc.grand_total = flt(self.doc.net_total)
if self.doc.get("taxes"):
self.doc.total_taxes_and_charges = flt(
- self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
+ self.doc.grand_total - self.doc.net_total - flt(self.doc.get("grand_total_diff")),
self.doc.precision("total_taxes_and_charges"),
)
else:
@@ -613,8 +624,8 @@
self.doc.grand_total, self.doc.currency, self.doc.precision("rounded_total")
)
- # if print_in_rate is set, we would have already calculated rounding adjustment
- self.doc.rounding_adjustment += flt(
+ # rounding adjustment should always be the difference vetween grand and rounded total
+ self.doc.rounding_adjustment = flt(
self.doc.rounded_total - self.doc.grand_total, self.doc.precision("rounding_adjustment")
)
@@ -832,7 +843,6 @@
self.calculate_paid_amount()
def calculate_paid_amount(self):
-
paid_amount = base_paid_amount = 0.0
if self.doc.is_pos:
diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py
index 97d3c5c..fad216d 100644
--- a/erpnext/controllers/tests/test_accounts_controller.py
+++ b/erpnext/controllers/tests/test_accounts_controller.py
@@ -56,6 +56,7 @@
20 series - Sales Invoice against Journals
30 series - Sales Invoice against Credit Notes
40 series - Company default Cost center is unset
+ 50 series - Dimension inheritence
"""
def setUp(self):
@@ -1255,3 +1256,214 @@
)
frappe.db.set_value("Company", self.company, "cost_center", cc)
+
+ def setup_dimensions(self):
+ # create dimension
+ from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
+ create_dimension,
+ )
+
+ create_dimension()
+ # make it non-mandatory
+ loc = frappe.get_doc("Accounting Dimension", "Location")
+ for x in loc.dimension_defaults:
+ x.mandatory_for_bs = False
+ x.mandatory_for_pl = False
+ loc.save()
+
+ def test_50_dimensions_filter(self):
+ """
+ Test workings of dimension filters
+ """
+ self.setup_dimensions()
+ rate_in_account_currency = 1
+
+ # Invoices
+ si1 = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True)
+ si1.department = "Management"
+ si1.save().submit()
+
+ si2 = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True)
+ si2.department = "Operations"
+ si2.save().submit()
+
+ # Payments
+ cr_note1 = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True)
+ cr_note1.department = "Management"
+ cr_note1.is_return = 1
+ cr_note1.save().submit()
+
+ cr_note2 = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True)
+ cr_note2.department = "Legal"
+ cr_note2.is_return = 1
+ cr_note2.save().submit()
+
+ pe1 = get_payment_entry(si1.doctype, si1.name)
+ pe1.references = []
+ pe1.department = "Research & Development"
+ pe1.save().submit()
+
+ pe2 = get_payment_entry(si1.doctype, si1.name)
+ pe2.references = []
+ pe2.department = "Management"
+ pe2.save().submit()
+
+ je1 = self.create_journal_entry(
+ acc1=self.debit_usd,
+ acc1_exc_rate=75,
+ acc2=self.cash,
+ acc1_amount=-1,
+ acc2_amount=-75,
+ acc2_exc_rate=1,
+ )
+ je1.accounts[0].party_type = "Customer"
+ je1.accounts[0].party = self.customer
+ je1.accounts[0].department = "Management"
+ je1.save().submit()
+
+ # assert dimension filter's result
+ pr = self.create_payment_reconciliation()
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 2)
+ self.assertEqual(len(pr.payments), 5)
+
+ pr.department = "Legal"
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 0)
+ self.assertEqual(len(pr.payments), 1)
+
+ pr.department = "Management"
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 1)
+ self.assertEqual(len(pr.payments), 3)
+
+ pr.department = "Research & Development"
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 0)
+ self.assertEqual(len(pr.payments), 1)
+
+ def test_51_cr_note_should_inherit_dimension(self):
+ self.setup_dimensions()
+ rate_in_account_currency = 1
+
+ # Invoice
+ si = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True)
+ si.department = "Management"
+ si.save().submit()
+
+ # Payment
+ cr_note = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True)
+ cr_note.department = "Management"
+ cr_note.is_return = 1
+ cr_note.save().submit()
+
+ pr = self.create_payment_reconciliation()
+ pr.department = "Management"
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 1)
+ self.assertEqual(len(pr.payments), 1)
+ invoices = [x.as_dict() for x in pr.invoices]
+ payments = [x.as_dict() for x in pr.payments]
+ pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
+ pr.reconcile()
+ self.assertEqual(len(pr.invoices), 0)
+ self.assertEqual(len(pr.payments), 0)
+
+ # There should be 2 journals, JE(Cr Note) and JE(Exchange Gain/Loss)
+ exc_je_for_si = self.get_journals_for(si.doctype, si.name)
+ exc_je_for_cr_note = self.get_journals_for(cr_note.doctype, cr_note.name)
+ self.assertNotEqual(exc_je_for_si, [])
+ self.assertEqual(len(exc_je_for_si), 2)
+ self.assertEqual(len(exc_je_for_cr_note), 2)
+ self.assertEqual(exc_je_for_si, exc_je_for_cr_note)
+
+ for x in exc_je_for_si + exc_je_for_cr_note:
+ with self.subTest(x=x):
+ self.assertEqual(
+ [cr_note.department, cr_note.department],
+ frappe.db.get_all("Journal Entry Account", filters={"parent": x.parent}, pluck="department"),
+ )
+
+ def test_52_dimension_inhertiance_exc_gain_loss(self):
+ # Sales Invoice in Foreign Currency
+ self.setup_dimensions()
+ rate = 80
+ rate_in_account_currency = 1
+ dpt = "Research & Development"
+
+ si = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_save=True)
+ si.department = dpt
+ si.save().submit()
+
+ pe = self.create_payment_entry(amount=1, source_exc_rate=82).save()
+ pe.department = dpt
+ pe = pe.save().submit()
+
+ pr = self.create_payment_reconciliation()
+ pr.department = dpt
+ pr.get_unreconciled_entries()
+ self.assertEqual(len(pr.invoices), 1)
+ self.assertEqual(len(pr.payments), 1)
+ invoices = [x.as_dict() for x in pr.invoices]
+ payments = [x.as_dict() for x in pr.payments]
+ pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
+ pr.reconcile()
+ self.assertEqual(len(pr.invoices), 0)
+ self.assertEqual(len(pr.payments), 0)
+
+ # Exc Gain/Loss journals should inherit dimension from parent
+ journals = self.get_journals_for(si.doctype, si.name)
+ self.assertEqual(
+ [dpt, dpt],
+ frappe.db.get_all(
+ "Journal Entry Account",
+ filters={"parent": ("in", [x.parent for x in journals])},
+ pluck="department",
+ ),
+ )
+
+ def test_53_dimension_inheritance_on_advance(self):
+ self.setup_dimensions()
+ dpt = "Research & Development"
+
+ adv = self.create_payment_entry(amount=1, source_exc_rate=85)
+ adv.department = dpt
+ adv.save().submit()
+ adv.reload()
+
+ # Sales Invoices in different exchange rates
+ si = self.create_sales_invoice(qty=1, conversion_rate=82, rate=1, do_not_submit=True)
+ si.department = dpt
+ advances = si.get_advance_entries()
+ self.assertEqual(len(advances), 1)
+ self.assertEqual(advances[0].reference_name, adv.name)
+ si.append(
+ "advances",
+ {
+ "doctype": "Sales Invoice Advance",
+ "reference_type": advances[0].reference_type,
+ "reference_name": advances[0].reference_name,
+ "reference_row": advances[0].reference_row,
+ "advance_amount": 1,
+ "allocated_amount": 1,
+ "ref_exchange_rate": advances[0].exchange_rate,
+ "remarks": advances[0].remarks,
+ },
+ )
+ si = si.save().submit()
+
+ # Outstanding in both currencies should be '0'
+ adv.reload()
+ self.assertEqual(si.outstanding_amount, 0)
+ self.assert_ledger_outstanding(si.doctype, si.name, 0.0, 0.0)
+
+ # Exc Gain/Loss journals should inherit dimension from parent
+ journals = self.get_journals_for(si.doctype, si.name)
+ self.assertEqual(
+ [dpt, dpt],
+ frappe.db.get_all(
+ "Journal Entry Account",
+ filters={"parent": ("in", [x.parent for x in journals])},
+ pluck="department",
+ ),
+ )
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
index ba1fae9..8cba24a 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py
@@ -155,7 +155,7 @@
except RecursionError:
self.log(
_(
- "Error occured while parsing Chart of Accounts: Please make sure that no two accounts have the same name"
+ "Error occurred while parsing Chart of Accounts: Please make sure that no two accounts have the same name"
)
)
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 6efb893..14b7656 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -481,7 +481,8 @@
communication_doctypes = ["Customer", "Supplier"]
-advance_payment_doctypes = ["Sales Order", "Purchase Order"]
+advance_payment_receivable_doctypes = ["Sales Order"]
+advance_payment_payable_doctypes = ["Purchase Order"]
invoice_doctypes = ["Sales Invoice", "Purchase Invoice"]
@@ -538,6 +539,8 @@
"Account Closing Balance",
"Supplier Quotation",
"Supplier Quotation Item",
+ "Payment Reconciliation",
+ "Payment Reconciliation Allocation",
]
get_matching_queries = (
diff --git a/erpnext/locale/main.pot b/erpnext/locale/main.pot
index adfa7ee..3409014 100644
--- a/erpnext/locale/main.pot
+++ b/erpnext/locale/main.pot
@@ -7,8 +7,8 @@
msgstr ""
"Project-Id-Version: ERPNext VERSION\n"
"Report-Msgid-Bugs-To: info@erpnext.com\n"
-"POT-Creation-Date: 2024-01-12 13:34+0053\n"
-"PO-Revision-Date: 2024-01-12 13:34+0053\n"
+"POT-Creation-Date: 2024-01-29 18:13+0053\n"
+"PO-Revision-Date: 2024-01-29 18:13+0053\n"
"Last-Translator: info@erpnext.com\n"
"Language-Team: info@erpnext.com\n"
"MIME-Version: 1.0\n"
@@ -30,7 +30,7 @@
msgid " Address"
msgstr ""
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:597
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:612
msgid " Amount"
msgstr ""
@@ -40,7 +40,7 @@
msgid " Is Child Table"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:181
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:186
#: accounts/report/tds_computation_summary/tds_computation_summary.py:107
#: selling/report/sales_analytics/sales_analytics.py:66
msgid " Name"
@@ -50,7 +50,7 @@
msgid " Qty"
msgstr ""
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:588
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:603
msgid " Rate"
msgstr ""
@@ -144,7 +144,7 @@
"\n"
"An Asset Category classifies different assets of a Company.\n"
"\n"
-"You can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipments\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n"
+"You can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipment\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n"
" - Depreciation type and duration\n"
" - Fixed asset account\n"
" - Depreciation account\n"
@@ -640,7 +640,7 @@
msgstr ""
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:280
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:325
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:332
msgid "% Of Grand Total"
msgstr ""
@@ -725,11 +725,11 @@
msgid "% of materials delivered against this Sales Order"
msgstr ""
-#: controllers/accounts_controller.py:1830
+#: controllers/accounts_controller.py:1899
msgid "'Account' in the Accounting section of Customer {0}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:260
+#: selling/doctype/sales_order/sales_order.py:263
msgid "'Allow Multiple Sales Orders Against a Customer's Purchase Order'"
msgstr ""
@@ -745,11 +745,11 @@
msgid "'Days Since Last Order' must be greater than or equal to zero"
msgstr ""
-#: controllers/accounts_controller.py:1835
+#: controllers/accounts_controller.py:1904
msgid "'Default {0} Account' in Company {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1162
+#: accounts/doctype/journal_entry/journal_entry.py:1048
msgid "'Entries' cannot be empty"
msgstr ""
@@ -1347,11 +1347,11 @@
msgid "A - C"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:207
+#: manufacturing/doctype/bom/bom.py:209
msgid "A BOM with name {0} already exists for item {1}."
msgstr ""
-#: selling/doctype/customer/customer.py:296
+#: selling/doctype/customer/customer.py:297
msgid "A Customer Group exists with same name please change the Customer name or rename the Customer Group"
msgstr ""
@@ -1367,7 +1367,7 @@
msgid "A Packing Slip can only be created for Draft Delivery Note."
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:508
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:530
msgid "A Reconciliation Job {0} is running for the same filters. Cannot reconcile now"
msgstr ""
@@ -1379,6 +1379,14 @@
"Sales Order at the heart of your sales and purchase transactions. Sales Orders are linked in Delivery Note, Sales Invoices, Material Request, and Maintenance transactions. Through Sales Order, you can track fulfillment of the overall deal towards the customer."
msgstr ""
+#: setup/doctype/company/company.py:937
+msgid "A Transaction Deletion Job is triggered for {0}"
+msgstr ""
+
+#: setup/doctype/company/company.py:914
+msgid "A Transaction Deletion Job: {0} is already running for {1}"
+msgstr ""
+
#. Description of the 'Send To Primary Contact' (Check) field in DocType
#. 'Process Statement Of Accounts'
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -1600,11 +1608,11 @@
msgid "Abbreviation"
msgstr ""
-#: setup/doctype/company/company.py:163
+#: setup/doctype/company/company.py:164
msgid "Abbreviation already used for another company"
msgstr ""
-#: setup/doctype/company/company.py:158
+#: setup/doctype/company/company.py:159
msgid "Abbreviation is mandatory"
msgstr ""
@@ -1694,7 +1702,7 @@
msgid "Accepted Qty in Stock UOM"
msgstr ""
-#: public/js/controllers/transaction.js:2094
+#: public/js/controllers/transaction.js:2124
msgid "Accepted Quantity"
msgstr ""
@@ -1764,11 +1772,11 @@
#: accounts/report/budget_variance_report/budget_variance_report.py:83
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.py:291
#: accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py:205
-#: accounts/report/financial_statements.py:633
+#: accounts/report/financial_statements.py:621
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.js:30
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.py:193
#: accounts/report/general_ledger/general_ledger.js:38
-#: accounts/report/general_ledger/general_ledger.py:562
+#: accounts/report/general_ledger/general_ledger.py:565
#: accounts/report/payment_ledger/payment_ledger.js:31
#: accounts/report/payment_ledger/payment_ledger.py:145
#: accounts/report/trial_balance/trial_balance.py:415
@@ -2076,8 +2084,8 @@
msgid "Account Manager"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:864
-#: controllers/accounts_controller.py:1839
+#: accounts/doctype/sales_invoice/sales_invoice.py:867
+#: controllers/accounts_controller.py:1908
msgid "Account Missing"
msgstr ""
@@ -2236,7 +2244,7 @@
msgid "Account is not set for the dashboard chart {0}"
msgstr ""
-#: assets/doctype/asset/asset.py:669
+#: assets/doctype/asset/asset.py:677
msgid "Account not Found"
msgstr ""
@@ -2265,7 +2273,7 @@
msgid "Account {0} added multiple times"
msgstr ""
-#: setup/doctype/company/company.py:186
+#: setup/doctype/company/company.py:187
msgid "Account {0} does not belong to company: {1}"
msgstr ""
@@ -2305,7 +2313,7 @@
msgid "Account {0} is frozen"
msgstr ""
-#: controllers/accounts_controller.py:998
+#: controllers/accounts_controller.py:1032
msgid "Account {0} is invalid. Account Currency must be {1}"
msgstr ""
@@ -2325,11 +2333,11 @@
msgid "Account {0}: You can not assign itself as parent account"
msgstr ""
-#: accounts/general_ledger.py:404
+#: accounts/general_ledger.py:403
msgid "Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:226
+#: accounts/doctype/journal_entry/journal_entry.py:243
msgid "Account: {0} can only be updated via Stock Transactions"
msgstr ""
@@ -2337,11 +2345,11 @@
msgid "Account: {0} does not exist"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:2075
+#: accounts/doctype/payment_entry/payment_entry.py:2098
msgid "Account: {0} is not permitted under Payment Entry"
msgstr ""
-#: controllers/accounts_controller.py:2522
+#: controllers/accounts_controller.py:2591
msgid "Account: {0} with currency: {1} can not be selected"
msgstr ""
@@ -2647,6 +2655,13 @@
msgid "Accounting Dimensions"
msgstr ""
+#. Label of a Section Break field in DocType 'Payment Reconciliation
+#. Allocation'
+#: accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json
+msgctxt "Payment Reconciliation Allocation"
+msgid "Accounting Dimensions"
+msgstr ""
+
#. Label of a Section Break field in DocType 'Payment Request'
#: accounts/doctype/payment_request/payment_request.json
msgctxt "Payment Request"
@@ -2797,6 +2812,12 @@
msgid "Accounting Dimensions "
msgstr ""
+#. Label of a Section Break field in DocType 'Payment Reconciliation'
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.json
+msgctxt "Payment Reconciliation"
+msgid "Accounting Dimensions Filter"
+msgstr ""
+
#. Label of a Table field in DocType 'Journal Entry'
#: accounts/doctype/journal_entry/journal_entry.json
msgctxt "Journal Entry"
@@ -2817,37 +2838,37 @@
msgid "Accounting Entries are reposted."
msgstr ""
-#: assets/doctype/asset/asset.py:703 assets/doctype/asset/asset.py:720
+#: assets/doctype/asset/asset.py:709 assets/doctype/asset/asset.py:724
#: assets/doctype/asset_capitalization/asset_capitalization.py:572
msgid "Accounting Entry for Asset"
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:740
+#: stock/doctype/purchase_receipt/purchase_receipt.py:738
msgid "Accounting Entry for Service"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:910
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:932
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:950
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:969
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:990
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1013
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1148
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1294
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1314
-#: controllers/stock_controller.py:170 controllers/stock_controller.py:187
-#: stock/doctype/purchase_receipt/purchase_receipt.py:842
-#: stock/doctype/stock_entry/stock_entry.py:1466
-#: stock/doctype/stock_entry/stock_entry.py:1482
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:906
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:926
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:942
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:959
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:978
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:999
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1126
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1266
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1284
+#: controllers/stock_controller.py:168 controllers/stock_controller.py:183
+#: stock/doctype/purchase_receipt/purchase_receipt.py:839
+#: stock/doctype/stock_entry/stock_entry.py:1464
+#: stock/doctype/stock_entry/stock_entry.py:1478
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py:519
msgid "Accounting Entry for Stock"
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:660
+#: stock/doctype/purchase_receipt/purchase_receipt.py:658
msgid "Accounting Entry for {0}"
msgstr ""
-#: controllers/accounts_controller.py:1881
+#: controllers/accounts_controller.py:1950
msgid "Accounting Entry for {0}: {1} can only be made in currency: {2}"
msgstr ""
@@ -2894,7 +2915,7 @@
msgid "Accounting entries for this invoice needs to be reposted. Please click on 'Repost' button to update."
msgstr ""
-#: setup/doctype/company/company.py:316
+#: setup/doctype/company/company.py:317
msgid "Accounts"
msgstr ""
@@ -3011,6 +3032,7 @@
#: accounts/doctype/dunning_type/dunning_type.json
#: accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.json
#: accounts/doctype/finance_book/finance_book.json
+#: accounts/doctype/fiscal_year/fiscal_year.json
#: accounts/doctype/gl_entry/gl_entry.json
#: accounts/doctype/item_tax_template/item_tax_template.json
#: accounts/doctype/journal_entry/journal_entry.json
@@ -3068,18 +3090,18 @@
msgid "Accounts Manager"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:329
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:343
msgid "Accounts Missing Error"
msgstr ""
#. Name of a report
-#. Label of a Card Break in the Accounting Workspace
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
+#. Label of a shortcut in the Payables Workspace
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:85
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:117
#: accounts/report/accounts_payable/accounts_payable.json
#: accounts/report/accounts_payable_summary/accounts_payable_summary.js:122
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
#: buying/doctype/supplier/supplier.js:90
msgid "Accounts Payable"
msgstr ""
@@ -3092,22 +3114,23 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#: accounts/report/accounts_payable/accounts_payable.js:175
#: accounts/report/accounts_payable_summary/accounts_payable_summary.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
msgid "Accounts Payable Summary"
msgstr ""
#. Name of a report
-#. Label of a Card Break in the Accounting Workspace
-#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
+#. Label of a shortcut in the Receivables Workspace
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:12
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:12
#: accounts/report/accounts_receivable/accounts_receivable.json
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:150
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
#: selling/doctype/customer/customer.js:155
msgid "Accounts Receivable"
msgstr ""
@@ -3139,10 +3162,10 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#: accounts/report/accounts_receivable/accounts_receivable.js:208
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
msgid "Accounts Receivable Summary"
msgstr ""
@@ -3267,7 +3290,7 @@
msgid "Accounts User"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1267
+#: accounts/doctype/journal_entry/journal_entry.py:1153
msgid "Accounts table cannot be blank."
msgstr ""
@@ -3326,9 +3349,9 @@
msgid "Accumulated Monthly"
msgstr ""
-#: accounts/report/balance_sheet/balance_sheet.js:13
+#: accounts/report/balance_sheet/balance_sheet.js:27
#: accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.js:13
-#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:13
+#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:28
msgid "Accumulated Values"
msgstr ""
@@ -3828,8 +3851,8 @@
msgid "Actual qty in stock"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1212
-#: public/js/controllers/accounts.js:175
+#: accounts/doctype/payment_entry/payment_entry.js:1223
+#: public/js/controllers/accounts.js:176
msgid "Actual type tax cannot be included in Item rate in row {0}"
msgstr ""
@@ -3839,7 +3862,7 @@
#: public/js/bom_configurator/bom_configurator.bundle.js:291
#: public/js/utils/crm_activities.js:168
#: public/js/utils/serial_no_batch_selector.js:17
-#: public/js/utils/serial_no_batch_selector.js:176
+#: public/js/utils/serial_no_batch_selector.js:180
msgid "Add"
msgstr ""
@@ -3884,7 +3907,7 @@
msgstr ""
#: public/js/bom_configurator/bom_configurator.bundle.js:224
-#: selling/doctype/sales_order/sales_order.js:213
+#: selling/doctype/sales_order/sales_order.js:207
#: stock/dashboard/item_dashboard.js:205
msgid "Add Item"
msgstr ""
@@ -3950,6 +3973,12 @@
msgid "Add Sales Partners"
msgstr ""
+#. Label of a Button field in DocType 'Purchase Invoice Item'
+#: accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+msgctxt "Purchase Invoice Item"
+msgid "Add Serial / Batch No"
+msgstr ""
+
#. Label of a Button field in DocType 'Purchase Receipt Item'
#: stock/doctype/purchase_receipt_item/purchase_receipt_item.json
msgctxt "Purchase Receipt Item"
@@ -4663,9 +4692,9 @@
msgid "Address & Contacts"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Name of a report
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: selling/report/address_and_contacts/address_and_contacts.json
msgid "Address And Contacts"
msgstr ""
@@ -4859,7 +4888,7 @@
msgid "Adjustment Against"
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:583
+#: stock/doctype/purchase_receipt/purchase_receipt.py:581
msgid "Adjustment based on Purchase Invoice rate"
msgstr ""
@@ -4876,7 +4905,7 @@
#: accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json
#: accounts/doctype/pos_opening_entry/pos_opening_entry.json
#: accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json
-#: portal/doctype/homepage/homepage.json stock/reorder_item.py:264
+#: stock/reorder_item.py:303
msgid "Administrator"
msgstr ""
@@ -4908,12 +4937,24 @@
msgid "Advance Paid"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order_list.js:45
-#: selling/doctype/sales_order/sales_order_list.js:59
+#: buying/doctype/purchase_order/purchase_order_list.js:47
+#: selling/doctype/sales_order/sales_order_list.js:61
msgid "Advance Payment"
msgstr ""
-#: controllers/accounts_controller.py:211
+#. Label of a Select field in DocType 'Purchase Order'
+#: buying/doctype/purchase_order/purchase_order.json
+msgctxt "Purchase Order"
+msgid "Advance Payment Status"
+msgstr ""
+
+#. Label of a Select field in DocType 'Sales Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "Advance Payment Status"
+msgstr ""
+
+#: controllers/accounts_controller.py:214
msgid "Advance Payments"
msgstr ""
@@ -4969,11 +5010,11 @@
msgid "Advance amount"
msgstr ""
-#: controllers/taxes_and_totals.py:733
+#: controllers/taxes_and_totals.py:743
msgid "Advance amount cannot be greater than {0} {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:725
+#: accounts/doctype/journal_entry/journal_entry.py:741
msgid "Advance paid against {0} {1} cannot be greater than Grand Total {2}"
msgstr ""
@@ -5022,7 +5063,6 @@
msgstr ""
#. Label of a Text field in DocType 'GL Entry'
-#. Label of a Dynamic Link field in DocType 'GL Entry'
#: accounts/doctype/gl_entry/gl_entry.json
msgctxt "GL Entry"
msgid "Against"
@@ -5030,7 +5070,7 @@
#: accounts/report/bank_clearance_summary/bank_clearance_summary.py:39
#: accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py:94
-#: accounts/report/general_ledger/general_ledger.py:628
+#: accounts/report/general_ledger/general_ledger.py:631
msgid "Against Account"
msgstr ""
@@ -5041,7 +5081,6 @@
msgstr ""
#. Label of a Text field in DocType 'Journal Entry Account'
-#. Label of a Dynamic Link field in DocType 'Journal Entry Account'
#: accounts/doctype/journal_entry_account/journal_entry_account.json
msgctxt "Journal Entry Account"
msgid "Against Account"
@@ -5065,11 +5104,11 @@
msgid "Against Blanket Order"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:942
+#: accounts/doctype/sales_invoice/sales_invoice.py:945
msgid "Against Customer Order {0} dated {1}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:973
+#: selling/doctype/sales_order/sales_order.js:967
msgid "Against Default Supplier"
msgstr ""
@@ -5127,8 +5166,8 @@
msgid "Against Income Account"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:593
-#: accounts/doctype/payment_entry/payment_entry.py:667
+#: accounts/doctype/journal_entry/journal_entry.py:609
+#: accounts/doctype/payment_entry/payment_entry.py:669
msgid "Against Journal Entry {0} does not have any unmatched {1} entry"
msgstr ""
@@ -5170,19 +5209,7 @@
msgid "Against Supplier Invoice {0} dated {1}"
msgstr ""
-#. Label of a Link field in DocType 'GL Entry'
-#: accounts/doctype/gl_entry/gl_entry.json
-msgctxt "GL Entry"
-msgid "Against Type"
-msgstr ""
-
-#. Label of a Link field in DocType 'Journal Entry Account'
-#: accounts/doctype/journal_entry_account/journal_entry_account.json
-msgctxt "Journal Entry Account"
-msgid "Against Type"
-msgstr ""
-
-#: accounts/report/general_ledger/general_ledger.py:647
+#: accounts/report/general_ledger/general_ledger.py:650
msgid "Against Voucher"
msgstr ""
@@ -5204,7 +5231,7 @@
msgid "Against Voucher No"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:645
+#: accounts/report/general_ledger/general_ledger.py:648
#: accounts/report/payment_ledger/payment_ledger.py:176
msgid "Against Voucher Type"
msgstr ""
@@ -5229,7 +5256,7 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:151
-#: accounts/report/accounts_receivable/accounts_receivable.py:1111
+#: accounts/report/accounts_receivable/accounts_receivable.py:1134
msgid "Age (Days)"
msgstr ""
@@ -5374,7 +5401,7 @@
#: accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js:148
#: accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js:168
#: accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py:166
-#: accounts/utils.py:1296 public/js/setup_wizard.js:163
+#: accounts/utils.py:1324 public/js/setup_wizard.js:163
msgid "All Accounts"
msgstr ""
@@ -5414,7 +5441,7 @@
msgid "All Activities HTML"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:266
+#: manufacturing/doctype/bom/bom.py:268
msgid "All BOMs"
msgstr ""
@@ -5448,14 +5475,14 @@
#: patches/v11_0/update_department_lft_rgt.py:9
#: patches/v11_0/update_department_lft_rgt.py:11
#: patches/v11_0/update_department_lft_rgt.py:17
-#: setup/doctype/company/company.py:309 setup/doctype/company/company.py:312
-#: setup/doctype/company/company.py:317 setup/doctype/company/company.py:323
-#: setup/doctype/company/company.py:329 setup/doctype/company/company.py:335
-#: setup/doctype/company/company.py:341 setup/doctype/company/company.py:347
-#: setup/doctype/company/company.py:353 setup/doctype/company/company.py:359
-#: setup/doctype/company/company.py:365 setup/doctype/company/company.py:371
-#: setup/doctype/company/company.py:377 setup/doctype/company/company.py:383
-#: setup/doctype/company/company.py:389
+#: setup/doctype/company/company.py:310 setup/doctype/company/company.py:313
+#: setup/doctype/company/company.py:318 setup/doctype/company/company.py:324
+#: setup/doctype/company/company.py:330 setup/doctype/company/company.py:336
+#: setup/doctype/company/company.py:342 setup/doctype/company/company.py:348
+#: setup/doctype/company/company.py:354 setup/doctype/company/company.py:360
+#: setup/doctype/company/company.py:366 setup/doctype/company/company.py:372
+#: setup/doctype/company/company.py:378 setup/doctype/company/company.py:384
+#: setup/doctype/company/company.py:390
msgid "All Departments"
msgstr ""
@@ -5523,7 +5550,7 @@
msgid "All Territories"
msgstr ""
-#: setup/doctype/company/company.py:258 setup/doctype/company/company.py:274
+#: setup/doctype/company/company.py:259 setup/doctype/company/company.py:275
msgid "All Warehouses"
msgstr ""
@@ -5538,15 +5565,15 @@
msgid "All communications including and above this shall be moved into the new Issue"
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:1173
+#: stock/doctype/purchase_receipt/purchase_receipt.py:1170
msgid "All items have already been Invoiced/Returned"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2195
+#: stock/doctype/stock_entry/stock_entry.py:2191
msgid "All items have already been transferred for this Work Order."
msgstr ""
-#: public/js/controllers/transaction.js:2180
+#: public/js/controllers/transaction.js:2210
msgid "All items in this document already have a linked Quality Inspection."
msgstr ""
@@ -5583,7 +5610,7 @@
msgid "Allocate Advances Automatically (FIFO)"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:668
+#: accounts/doctype/payment_entry/payment_entry.js:679
msgid "Allocate Payment Amount"
msgstr ""
@@ -5671,15 +5698,15 @@
msgid "Allocated amount"
msgstr ""
-#: accounts/utils.py:593
+#: accounts/utils.py:614
msgid "Allocated amount cannot be greater than unadjusted amount"
msgstr ""
-#: accounts/utils.py:591
+#: accounts/utils.py:612
msgid "Allocated amount cannot be negative"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:237
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:258
msgid "Allocation"
msgstr ""
@@ -6600,7 +6627,7 @@
msgid "Amended From"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:539
+#: accounts/doctype/journal_entry/journal_entry.js:529
#: accounts/doctype/pos_closing_entry/closing_voucher_details.html:41
#: accounts/doctype/pos_closing_entry/closing_voucher_details.html:67
#: accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html:10
@@ -6608,7 +6635,7 @@
#: accounts/report/billed_items_to_be_received/billed_items_to_be_received.py:80
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:43
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:270
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:315
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:322
#: accounts/report/payment_ledger/payment_ledger.py:194
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:43
#: accounts/report/share_balance/share_balance.py:61
@@ -7141,19 +7168,19 @@
msgid "Amount in customer's currency"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1099
+#: accounts/doctype/payment_entry/payment_entry.py:1119
msgid "Amount {0} {1} against {2} {3}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1107
+#: accounts/doctype/payment_entry/payment_entry.py:1127
msgid "Amount {0} {1} deducted against {2}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1075
+#: accounts/doctype/payment_entry/payment_entry.py:1095
msgid "Amount {0} {1} transferred from {2} to {3}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1082
+#: accounts/doctype/payment_entry/payment_entry.py:1102
msgid "Amount {0} {1} {2} {3}"
msgstr ""
@@ -7171,12 +7198,12 @@
msgid "An error has occurred during {0}. Check {1} for more details"
msgstr ""
-#: stock/reorder_item.py:248
-msgid "An error occured for certain Items while creating Material Requests based on Re-order level. Please rectify these issues :"
+#: public/js/controllers/buying.js:297 public/js/utils/sales_common.js:364
+msgid "An error occurred during the update process"
msgstr ""
-#: public/js/controllers/buying.js:297 public/js/utils/sales_common.js:355
-msgid "An error occurred during the update process"
+#: stock/reorder_item.py:287
+msgid "An error occurred for certain Items while creating Material Requests based on Re-order level. Please rectify these issues :"
msgstr ""
#: accounts/doctype/budget/budget.py:232
@@ -8045,21 +8072,21 @@
msgid "Asset Depreciation Schedule for Asset {0} and Finance Book {1} is not using shift based depreciation"
msgstr ""
-#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:883
-#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:929
+#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:898
+#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:944
#: assets/doctype/asset_shift_allocation/asset_shift_allocation.py:83
msgid "Asset Depreciation Schedule not found for Asset {0} and Finance Book {1}"
msgstr ""
-#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:92
+#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:94
msgid "Asset Depreciation Schedule {0} for Asset {1} already exists."
msgstr ""
-#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:86
+#: assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py:88
msgid "Asset Depreciation Schedule {0} for Asset {1} and Finance Book {2} already exists."
msgstr ""
-#: assets/doctype/asset/asset.py:144 assets/doctype/asset/asset.py:180
+#: assets/doctype/asset/asset.py:144 assets/doctype/asset/asset.py:181
msgid "Asset Depreciation Schedules created:<br>{0}<br><br>Please check, edit if needed, and submit the Asset."
msgstr ""
@@ -8169,7 +8196,7 @@
msgid "Asset Movement Item"
msgstr ""
-#: assets/doctype/asset/asset.py:897
+#: assets/doctype/asset/asset.py:901
msgid "Asset Movement record {0} created"
msgstr ""
@@ -8355,35 +8382,35 @@
msgid "Asset Value Analytics"
msgstr ""
-#: assets/doctype/asset/asset.py:171
+#: assets/doctype/asset/asset.py:172
msgid "Asset cancelled"
msgstr ""
-#: assets/doctype/asset/asset.py:505
+#: assets/doctype/asset/asset.py:506
msgid "Asset cannot be cancelled, as it is already {0}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:689
+#: assets/doctype/asset_capitalization/asset_capitalization.py:687
msgid "Asset capitalized after Asset Capitalization {0} was submitted"
msgstr ""
-#: assets/doctype/asset/asset.py:193
+#: assets/doctype/asset/asset.py:194
msgid "Asset created"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:635
+#: assets/doctype/asset_capitalization/asset_capitalization.py:633
msgid "Asset created after Asset Capitalization {0} was submitted"
msgstr ""
-#: assets/doctype/asset/asset.py:1150
+#: assets/doctype/asset/asset.py:1156
msgid "Asset created after being split from Asset {0}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:697
+#: assets/doctype/asset_capitalization/asset_capitalization.py:695
msgid "Asset decapitalized after Asset Capitalization {0} was submitted"
msgstr ""
-#: assets/doctype/asset/asset.py:196
+#: assets/doctype/asset/asset.py:197
msgid "Asset deleted"
msgstr ""
@@ -8403,11 +8430,11 @@
msgid "Asset restored"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:705
+#: assets/doctype/asset_capitalization/asset_capitalization.py:703
msgid "Asset restored after Asset Capitalization {0} was cancelled"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1323
+#: accounts/doctype/sales_invoice/sales_invoice.py:1320
msgid "Asset returned"
msgstr ""
@@ -8419,7 +8446,7 @@
msgid "Asset scrapped via Journal Entry {0}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1357
+#: accounts/doctype/sales_invoice/sales_invoice.py:1354
msgid "Asset sold"
msgstr ""
@@ -8431,7 +8458,7 @@
msgid "Asset transferred to Location {0}"
msgstr ""
-#: assets/doctype/asset/asset.py:1074
+#: assets/doctype/asset/asset.py:1080
msgid "Asset updated after being split into Asset {0}"
msgstr ""
@@ -8451,7 +8478,7 @@
msgid "Asset {0} cannot be scrapped, as it is already {1}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:228
+#: assets/doctype/asset_capitalization/asset_capitalization.py:237
msgid "Asset {0} does not belong to Item {1}"
msgstr ""
@@ -8467,16 +8494,16 @@
msgid "Asset {0} does not belongs to the location {1}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:761
-#: assets/doctype/asset_capitalization/asset_capitalization.py:861
+#: assets/doctype/asset_capitalization/asset_capitalization.py:759
+#: assets/doctype/asset_capitalization/asset_capitalization.py:859
msgid "Asset {0} does not exist"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:641
+#: assets/doctype/asset_capitalization/asset_capitalization.py:639
msgid "Asset {0} has been created. Please set the depreciation details if any and submit it."
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:663
+#: assets/doctype/asset_capitalization/asset_capitalization.py:661
msgid "Asset {0} has been updated. Please set the depreciation details if any and submit it."
msgstr ""
@@ -8573,8 +8600,20 @@
msgid "Assignment Conditions"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:407
-#: accounts/doctype/sales_invoice/sales_invoice.py:508
+#: assets/doctype/asset/asset.py:1011
+msgid "At least one asset has to be selected."
+msgstr ""
+
+#: accounts/doctype/pos_invoice/pos_invoice.py:789
+msgid "At least one invoice has to be selected."
+msgstr ""
+
+#: controllers/sales_and_purchase_return.py:144
+msgid "At least one item should be entered with negative quantity in return document"
+msgstr ""
+
+#: accounts/doctype/pos_invoice/pos_invoice.py:405
+#: accounts/doctype/sales_invoice/sales_invoice.py:509
msgid "At least one mode of payment is required for POS invoice."
msgstr ""
@@ -8582,45 +8621,33 @@
msgid "At least one of the Applicable Modules should be selected"
msgstr ""
+#: accounts/doctype/pricing_rule/pricing_rule.py:196
+msgid "At least one of the Selling or Buying must be selected"
+msgstr ""
+
+#: stock/doctype/stock_entry/stock_entry.py:643
+msgid "At least one warehouse is mandatory"
+msgstr ""
+
#: manufacturing/doctype/routing/routing.py:50
msgid "At row #{0}: the sequence id {1} cannot be less than previous row sequence id {2}"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:579
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:582
msgid "At row {0}: Batch No is mandatory for Item {1}"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:571
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:574
msgid "At row {0}: Serial No is mandatory for Item {1}"
msgstr ""
-#: assets/doctype/asset/asset.py:1007
-msgid "Atleast one asset has to be selected."
-msgstr ""
-
-#: accounts/doctype/pos_invoice/pos_invoice.py:796
-msgid "Atleast one invoice has to be selected."
-msgstr ""
-
-#: controllers/sales_and_purchase_return.py:144
-msgid "Atleast one item should be entered with negative quantity in return document"
-msgstr ""
-
-#: accounts/doctype/pricing_rule/pricing_rule.py:196
-msgid "Atleast one of the Selling or Buying must be selected"
-msgstr ""
-
-#: stock/doctype/stock_entry/stock_entry.py:643
-msgid "Atleast one warehouse is mandatory"
-msgstr ""
-
#. Description of the 'File to Rename' (Attach) field in DocType 'Rename Tool'
#: utilities/doctype/rename_tool/rename_tool.json
msgctxt "Rename Tool"
msgid "Attach .csv file with two columns, one for the old name and one for the new name"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:199
+#: public/js/utils/serial_no_batch_selector.js:246
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:66
msgid "Attach CSV File"
msgstr ""
@@ -8817,7 +8844,7 @@
msgid "Auto Email Report"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:244
+#: public/js/utils/serial_no_batch_selector.js:316
msgid "Auto Fetch"
msgstr ""
@@ -8833,7 +8860,7 @@
msgid "Auto Material Request"
msgstr ""
-#: stock/reorder_item.py:240
+#: stock/reorder_item.py:242
msgid "Auto Material Requests Generated"
msgstr ""
@@ -8991,7 +9018,7 @@
msgid "Auto re-order"
msgstr ""
-#: public/js/controllers/buying.js:295 public/js/utils/sales_common.js:353
+#: public/js/controllers/buying.js:295 public/js/utils/sales_common.js:362
msgid "Auto repeat document updated"
msgstr ""
@@ -9167,7 +9194,7 @@
msgid "Available Stock for Packing Items"
msgstr ""
-#: assets/doctype/asset/asset.py:269
+#: assets/doctype/asset/asset.py:270
msgid "Available for use date is required"
msgstr ""
@@ -9185,7 +9212,7 @@
msgid "Available-for-use Date"
msgstr ""
-#: assets/doctype/asset/asset.py:354
+#: assets/doctype/asset/asset.py:355
msgid "Available-for-use Date should be after purchase date"
msgstr ""
@@ -9279,7 +9306,7 @@
#: manufacturing/report/bom_stock_calculated/bom_stock_calculated.js:9
#: manufacturing/report/bom_stock_report/bom_stock_report.js:5
#: manufacturing/report/work_order_stock_report/work_order_stock_report.py:109
-#: selling/doctype/sales_order/sales_order.js:816
+#: selling/doctype/sales_order/sales_order.js:810
#: stock/doctype/material_request/material_request.js:243
#: stock/doctype/stock_entry/stock_entry.js:545
#: stock/report/bom_search/bom_search.py:38
@@ -9352,7 +9379,7 @@
msgid "BOM 1"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1346
+#: manufacturing/doctype/bom/bom.py:1348
msgid "BOM 1 {0} and BOM 2 {1} should not be same"
msgstr ""
@@ -9642,19 +9669,19 @@
msgid "BOM recursion: {0} cannot be child of {1}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:629
+#: manufacturing/doctype/bom/bom.py:631
msgid "BOM recursion: {1} cannot be parent or child of {0}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1221
+#: manufacturing/doctype/bom/bom.py:1223
msgid "BOM {0} does not belong to Item {1}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1203
+#: manufacturing/doctype/bom/bom.py:1205
msgid "BOM {0} must be active"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1206
+#: manufacturing/doctype/bom/bom.py:1208
msgid "BOM {0} must be submitted"
msgstr ""
@@ -9713,7 +9740,7 @@
msgid "Balance (Dr - Cr)"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:581
+#: accounts/report/general_ledger/general_ledger.py:584
msgid "Balance ({0})"
msgstr ""
@@ -9744,10 +9771,10 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/balance_sheet/balance_sheet.json
-#: accounts/workspace/accounting/accounting.json
-#: public/js/financial_statements.js:79
+#: accounts/workspace/financial_reports/financial_reports.json
+#: public/js/financial_statements.js:131
msgid "Balance Sheet"
msgstr ""
@@ -10190,7 +10217,7 @@
msgid "Bank Transaction {0} added as Payment Entry"
msgstr ""
-#: accounts/doctype/bank_transaction/bank_transaction.py:106
+#: accounts/doctype/bank_transaction/bank_transaction.py:124
msgid "Bank Transaction {0} is already fully reconciled"
msgstr ""
@@ -10235,7 +10262,7 @@
msgid "Banking"
msgstr ""
-#: public/js/utils/barcode_scanner.js:258
+#: public/js/utils/barcode_scanner.js:273
msgid "Barcode"
msgstr ""
@@ -10362,7 +10389,7 @@
msgid "Base Tax Withholding Net Total"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:236
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:241
msgid "Base Total"
msgstr ""
@@ -10543,9 +10570,9 @@
#: manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.js:88
#: manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py:117
-#: public/js/controllers/transaction.js:2120
-#: public/js/utils/barcode_scanner.js:236
-#: public/js/utils/serial_no_batch_selector.js:295
+#: public/js/controllers/transaction.js:2150
+#: public/js/utils/barcode_scanner.js:251
+#: public/js/utils/serial_no_batch_selector.js:367
#: stock/report/batch_wise_balance_history/batch_wise_balance_history.js:59
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.js:80
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.py:156
@@ -10673,11 +10700,15 @@
msgid "Batch No"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:582
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:585
msgid "Batch No is mandatory"
msgstr ""
-#: stock/utils.py:596
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:2118
+msgid "Batch No {0} does not exists"
+msgstr ""
+
+#: stock/utils.py:643
msgid "Batch No {0} is linked with Item {1} which has serial no. Please scan serial no instead."
msgstr ""
@@ -10688,12 +10719,12 @@
msgstr ""
#: public/js/utils/serial_no_batch_selector.js:15
-#: public/js/utils/serial_no_batch_selector.js:174
+#: public/js/utils/serial_no_batch_selector.js:178
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:48
msgid "Batch Nos"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1087
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1113
msgid "Batch Nos are created successfully"
msgstr ""
@@ -10761,12 +10792,12 @@
msgid "Batch {0} and Warehouse"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2349
+#: stock/doctype/stock_entry/stock_entry.py:2345
#: stock/doctype/stock_ledger_entry/stock_ledger_entry.py:272
msgid "Batch {0} of Item {1} has expired."
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2351
+#: stock/doctype/stock_entry/stock_entry.py:2347
msgid "Batch {0} of Item {1} is disabled."
msgstr ""
@@ -10802,7 +10833,11 @@
msgid "Beginning of the current subscription period"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1038
+#: accounts/doctype/subscription/subscription.py:341
+msgid "Below Subscription Plans are of different currency to the party default billing currency/Company currency: {0}"
+msgstr ""
+
+#: accounts/report/accounts_receivable/accounts_receivable.py:1061
#: accounts/report/purchase_register/purchase_register.py:214
msgid "Bill Date"
msgstr ""
@@ -10819,7 +10854,7 @@
msgid "Bill Date"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1037
+#: accounts/report/accounts_receivable/accounts_receivable.py:1060
#: accounts/report/purchase_register/purchase_register.py:213
msgid "Bill No"
msgstr ""
@@ -10844,7 +10879,7 @@
#. Title of an Onboarding Step
#. Label of a Card Break in the Manufacturing Workspace
-#: manufacturing/doctype/bom/bom.py:1087
+#: manufacturing/doctype/bom/bom.py:1089
#: manufacturing/onboarding_step/create_bom/create_bom.json
#: manufacturing/workspace/manufacturing/manufacturing.json
#: stock/doctype/material_request/material_request.js:99
@@ -11093,7 +11128,7 @@
msgid "Billing Interval Count cannot be less than 1"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:353
+#: accounts/doctype/subscription/subscription.py:383
msgid "Billing Interval in Subscription Plan must be Month to follow calendar months"
msgstr ""
@@ -11324,7 +11359,7 @@
msgid "Bom No"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:227
+#: accounts/doctype/payment_entry/payment_entry.py:229
msgid "Book Advance Payments as Liability option is chosen. Paid From account changed from {0} to {1}."
msgstr ""
@@ -11392,7 +11427,7 @@
msgid "Booking stock value across multiple accounts will make it harder to track stock and account value."
msgstr ""
-#: accounts/general_ledger.py:686
+#: accounts/general_ledger.py:685
msgid "Books have been closed till the period ending on {0}"
msgstr ""
@@ -11403,7 +11438,7 @@
msgid "Both"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:329
+#: accounts/doctype/subscription/subscription.py:359
msgid "Both Trial Period Start Date and Trial Period End Date must be set"
msgstr ""
@@ -11874,10 +11909,6 @@
msgid "By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a <a href='https://docs.erpnext.com/docs/user/manual/en/setting-up/settings/naming-series' target='_blank'>Naming Series</a> choose the 'Naming Series' option."
msgstr ""
-#: templates/pages/home.html:59
-msgid "By {0}"
-msgstr ""
-
#. Label of a Check field in DocType 'Customer Credit Limit'
#: selling/doctype/customer_credit_limit/customer_credit_limit.json
msgctxt "Customer Credit Limit"
@@ -12258,13 +12289,13 @@
msgid "Can not filter based on Voucher No, if grouped by Voucher"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1340
-#: accounts/doctype/payment_entry/payment_entry.py:2206
+#: accounts/doctype/journal_entry/journal_entry.py:1226
+#: accounts/doctype/payment_entry/payment_entry.py:2229
msgid "Can only make payment against unbilled {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1188
-#: controllers/accounts_controller.py:2431 public/js/controllers/accounts.js:90
+#: accounts/doctype/payment_entry/payment_entry.js:1199
+#: controllers/accounts_controller.py:2500 public/js/controllers/accounts.js:90
msgid "Can refer row only if the charge type is 'On Previous Row Amount' or 'Previous Row Total'"
msgstr ""
@@ -12591,11 +12622,6 @@
msgid "Cancelled"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry_list.js:7
-msgctxt "docstatus,=,2"
-msgid "Cancelled"
-msgstr ""
-
#: stock/doctype/delivery_trip/delivery_trip.js:76
#: stock/doctype/delivery_trip/delivery_trip.py:189
msgid "Cannot Calculate Arrival Time as Driver Address is Missing."
@@ -12622,7 +12648,7 @@
msgid "Cannot amend {0} {1}, please create a new one instead."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:240
+#: accounts/doctype/journal_entry/journal_entry.py:257
msgid "Cannot apply TDS against multiple parties in one entry"
msgstr ""
@@ -12638,7 +12664,7 @@
msgid "Cannot cancel because submitted Stock Entry {0} exists"
msgstr ""
-#: stock/stock_ledger.py:187
+#: stock/stock_ledger.py:196
msgid "Cannot cancel the transaction. Reposting of item valuation on submission is not completed yet."
msgstr ""
@@ -12670,7 +12696,7 @@
msgid "Cannot change Variant properties after stock transaction. You will have to make a new Item to do this."
msgstr ""
-#: setup/doctype/company/company.py:208
+#: setup/doctype/company/company.py:209
msgid "Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency."
msgstr ""
@@ -12694,7 +12720,7 @@
msgid "Cannot covert to Group because Account Type is selected."
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:917
+#: stock/doctype/purchase_receipt/purchase_receipt.py:914
msgid "Cannot create Stock Reservation Entries for future dated Purchase Receipts."
msgstr ""
@@ -12702,7 +12728,7 @@
msgid "Cannot create a Delivery Trip from Draft documents."
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:1562
+#: selling/doctype/sales_order/sales_order.py:1576
#: stock/doctype/pick_list/pick_list.py:104
msgid "Cannot create a pick list for Sales Order {0} because it has reserved stock. Please unreserve the stock in order to create a pick list."
msgstr ""
@@ -12711,7 +12737,7 @@
msgid "Cannot create accounting entries against disabled accounts: {0}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:947
+#: manufacturing/doctype/bom/bom.py:949
msgid "Cannot deactivate or cancel BOM as it is linked with other BOMs"
msgstr ""
@@ -12728,8 +12754,8 @@
msgid "Cannot delete Serial No {0}, as it is used in stock transactions"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:635
-#: selling/doctype/sales_order/sales_order.py:658
+#: selling/doctype/sales_order/sales_order.py:638
+#: selling/doctype/sales_order/sales_order.py:661
msgid "Cannot ensure delivery by Serial No as Item {0} is added with and without Ensure Delivery by Serial No."
msgstr ""
@@ -12737,11 +12763,11 @@
msgid "Cannot find Item with this Barcode"
msgstr ""
-#: controllers/accounts_controller.py:2964
+#: controllers/accounts_controller.py:3023
msgid "Cannot find {} for item {}. Please set the same in Item Master or Stock Settings."
msgstr ""
-#: controllers/accounts_controller.py:1741
+#: controllers/accounts_controller.py:1774
msgid "Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings"
msgstr ""
@@ -12757,12 +12783,12 @@
msgid "Cannot produce more than {0} items for {1}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:292
+#: accounts/doctype/payment_entry/payment_entry.py:294
msgid "Cannot receive from customer against negative outstanding"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1198
-#: controllers/accounts_controller.py:2446
+#: accounts/doctype/payment_entry/payment_entry.js:1209
+#: controllers/accounts_controller.py:2515
#: public/js/controllers/accounts.js:100
msgid "Cannot refer row number greater than or equal to current row number for this Charge type"
msgstr ""
@@ -12775,15 +12801,15 @@
msgid "Cannot retrieve link token. Check Error Log for more information"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1192
-#: accounts/doctype/payment_entry/payment_entry.js:1363
-#: accounts/doctype/payment_entry/payment_entry.py:1569
-#: controllers/accounts_controller.py:2436 public/js/controllers/accounts.js:94
-#: public/js/controllers/taxes_and_totals.js:451
+#: accounts/doctype/payment_entry/payment_entry.js:1203
+#: accounts/doctype/payment_entry/payment_entry.js:1374
+#: accounts/doctype/payment_entry/payment_entry.py:1579
+#: controllers/accounts_controller.py:2505 public/js/controllers/accounts.js:94
+#: public/js/controllers/taxes_and_totals.js:453
msgid "Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"
msgstr ""
-#: selling/doctype/quotation/quotation.py:265
+#: selling/doctype/quotation/quotation.py:266
msgid "Cannot set as Lost as Sales Order is made."
msgstr ""
@@ -12795,11 +12821,11 @@
msgid "Cannot set multiple Item Defaults for a company."
msgstr ""
-#: controllers/accounts_controller.py:3114
+#: controllers/accounts_controller.py:3173
msgid "Cannot set quantity less than delivered quantity"
msgstr ""
-#: controllers/accounts_controller.py:3119
+#: controllers/accounts_controller.py:3178
msgid "Cannot set quantity less than received quantity"
msgstr ""
@@ -12807,7 +12833,7 @@
msgid "Cannot set the field <b>{0}</b> for copying in variants"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:865
+#: accounts/doctype/payment_entry/payment_entry.js:876
msgid "Cannot {0} {1} {2} without any negative outstanding invoice"
msgstr ""
@@ -12849,7 +12875,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:26
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:39
-msgid "Capital Equipments"
+msgid "Capital Equipment"
msgstr ""
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:103
@@ -12913,13 +12939,6 @@
msgid "Capitalized In"
msgstr ""
-#. Option for the 'Section Based On' (Select) field in DocType 'Homepage
-#. Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Cards"
-msgstr ""
-
#. Label of a Data field in DocType 'Shipment'
#: stock/doctype/shipment/shipment.json
msgctxt "Shipment"
@@ -12977,13 +12996,13 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/cash_flow/cash_flow.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Cash Flow"
msgstr ""
-#: public/js/financial_statements.js:89
+#: public/js/financial_statements.js:141
msgid "Cash Flow Statement"
msgstr ""
@@ -13088,7 +13107,7 @@
msgid "Category-wise Asset Value"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:309
+#: buying/doctype/purchase_order/purchase_order.py:313
#: buying/doctype/request_for_quotation/request_for_quotation.py:99
msgid "Caution"
msgstr ""
@@ -13169,7 +13188,7 @@
msgid "Change in Stock Value"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:882
+#: accounts/doctype/sales_invoice/sales_invoice.py:885
msgid "Change the account type to Receivable or select a different account."
msgstr ""
@@ -13200,21 +13219,21 @@
msgid "Channel Partner"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1624
-#: controllers/accounts_controller.py:2499
+#: accounts/doctype/payment_entry/payment_entry.py:1634
+#: controllers/accounts_controller.py:2568
msgid "Charge of type 'Actual' in row {0} cannot be included in Item Rate or Paid Amount"
msgstr ""
+#: accounts/report/account_balance/account_balance.js:42
+msgid "Chargeable"
+msgstr ""
+
#. Option for the 'Account Type' (Select) field in DocType 'Account'
#: accounts/doctype/account/account.json
msgctxt "Account"
msgid "Chargeable"
msgstr ""
-#: accounts/report/account_balance/account_balance.js:42
-msgid "Chargeble"
-msgstr ""
-
#. Label of a Currency field in DocType 'Bank Guarantee'
#: accounts/doctype/bank_guarantee/bank_guarantee.json
msgctxt "Bank Guarantee"
@@ -13426,7 +13445,7 @@
msgid "Cheque Width"
msgstr ""
-#: public/js/controllers/transaction.js:2031
+#: public/js/controllers/transaction.js:2061
msgid "Cheque/Reference Date"
msgstr ""
@@ -13618,15 +13637,15 @@
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:292
-#: buying/doctype/purchase_order/purchase_order_list.js:28
+#: buying/doctype/purchase_order/purchase_order_list.js:30
#: crm/doctype/opportunity/opportunity.js:108
#: manufacturing/doctype/production_plan/production_plan.js:101
#: manufacturing/doctype/work_order/work_order.js:559
#: quality_management/doctype/quality_meeting/quality_meeting_list.js:8
-#: selling/doctype/sales_order/sales_order.js:527
-#: selling/doctype/sales_order/sales_order.js:547
-#: selling/doctype/sales_order/sales_order_list.js:43
-#: stock/doctype/delivery_note/delivery_note.js:218
+#: selling/doctype/sales_order/sales_order.js:521
+#: selling/doctype/sales_order/sales_order.js:541
+#: selling/doctype/sales_order/sales_order_list.js:45
+#: stock/doctype/delivery_note/delivery_note.js:209
#: stock/doctype/purchase_receipt/purchase_receipt.js:222
#: subcontracting/doctype/subcontracting_order/subcontracting_order.js:108
#: support/doctype/issue/issue.js:17
@@ -13770,7 +13789,7 @@
msgid "Closed Work Order can not be stopped or Re-opened"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:417
+#: selling/doctype/sales_order/sales_order.py:420
msgid "Closed order cannot be cancelled. Unclose to cancel."
msgstr ""
@@ -14138,7 +14157,7 @@
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.js:40
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:227
#: accounts/report/item_wise_sales_register/item_wise_sales_register.js:28
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:265
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:272
#: accounts/report/payment_ledger/payment_ledger.js:9
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js:8
#: accounts/report/pos_register/pos_register.js:9
@@ -14181,7 +14200,7 @@
#: manufacturing/report/work_order_summary/work_order_summary.js:8
#: projects/report/project_summary/project_summary.js:9
#: projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py:44
-#: public/js/financial_statements.js:100 public/js/purchase_trends_filters.js:8
+#: public/js/financial_statements.js:153 public/js/purchase_trends_filters.js:8
#: public/js/sales_trends_filters.js:55
#: regional/report/electronic_invoice_register/electronic_invoice_register.js:28
#: regional/report/irs_1099/irs_1099.js:8
@@ -14227,7 +14246,7 @@
#: stock/report/reserved_stock/reserved_stock.py:191
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.js:9
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.py:73
-#: stock/report/serial_no_ledger/serial_no_ledger.py:38
+#: stock/report/serial_no_ledger/serial_no_ledger.py:37
#: stock/report/stock_ageing/stock_ageing.js:8
#: stock/report/stock_analytics/stock_analytics.js:42
#: stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.js:8
@@ -14508,12 +14527,6 @@
msgid "Company"
msgstr ""
-#. Label of a Link field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Company"
-msgstr ""
-
#. Label of a Link field in DocType 'Import Supplier Invoice'
#: regional/doctype/import_supplier_invoice/import_supplier_invoice.json
msgctxt "Import Supplier Invoice"
@@ -15148,19 +15161,14 @@
msgid "Company Description"
msgstr ""
-#. Description of the 'Description' (Text) field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Company Description for website homepage"
-msgstr ""
-
#. Label of a Section Break field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
msgid "Company Details"
msgstr ""
-#. Option for the 'Prefered Contact Email' (Select) field in DocType 'Employee'
+#. Option for the 'Preferred Contact Email' (Select) field in DocType
+#. 'Employee'
#. Label of a Data field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
@@ -15221,12 +15229,6 @@
msgid "Company Shipping Address"
msgstr ""
-#. Description of the 'Tag Line' (Data) field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Company Tagline for website homepage"
-msgstr ""
-
#. Label of a Data field in DocType 'Sales Invoice'
#: accounts/doctype/sales_invoice/sales_invoice.json
msgctxt "Sales Invoice"
@@ -15237,7 +15239,7 @@
msgid "Company and Posting Date is mandatory"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2232
+#: accounts/doctype/sales_invoice/sales_invoice.py:2203
msgid "Company currencies of both the companies should match for Inter Company Transactions."
msgstr ""
@@ -15247,18 +15249,18 @@
msgstr ""
#: accounts/doctype/bank_account/bank_account.py:58
-msgid "Company is manadatory for company account"
+msgid "Company is mandatory for company account"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:383
+#: accounts/doctype/subscription/subscription.py:413
msgid "Company is mandatory was generating invoice. Please set default company in Global Defaults."
msgstr ""
-#: setup/doctype/company/company.js:153
+#: setup/doctype/company/company.js:161
msgid "Company name not same"
msgstr ""
-#: assets/doctype/asset/asset.py:205
+#: assets/doctype/asset/asset.py:206
msgid "Company of asset {0} and purchase document {1} doesn't matches."
msgstr ""
@@ -15305,7 +15307,7 @@
msgid "Company {} does not exist yet. Taxes setup aborted."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:451
+#: accounts/doctype/pos_invoice/pos_invoice.py:449
msgid "Company {} does not match with POS Profile Company {}"
msgstr ""
@@ -15338,7 +15340,7 @@
msgid "Competitor Name"
msgstr ""
-#: public/js/utils/sales_common.js:408
+#: public/js/utils/sales_common.js:417
msgid "Competitors"
msgstr ""
@@ -15376,7 +15378,7 @@
#: accounts/doctype/subscription/subscription_list.js:8
#: assets/doctype/asset_repair/asset_repair_list.js:7
-#: buying/doctype/purchase_order/purchase_order_list.js:22
+#: buying/doctype/purchase_order/purchase_order_list.js:24
#: manufacturing/doctype/bom_creator/bom_creator_list.js:9
#: manufacturing/report/job_card_summary/job_card_summary.py:93
#: manufacturing/report/work_order_summary/work_order_summary.py:151
@@ -15386,7 +15388,7 @@
#: setup/doctype/transaction_deletion_record/transaction_deletion_record_list.js:9
#: stock/doctype/delivery_note/delivery_note_list.js:14
#: stock/doctype/material_request/material_request_list.js:13
-#: stock/doctype/purchase_receipt/purchase_receipt_list.js:14
+#: stock/doctype/purchase_receipt/purchase_receipt_list.js:16
msgid "Completed"
msgstr ""
@@ -15980,9 +15982,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Consolidated Financial Statement"
msgstr ""
@@ -16028,7 +16030,7 @@
msgid "Consumed Amount"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:309
+#: assets/doctype/asset_capitalization/asset_capitalization.py:318
msgid "Consumed Asset Items is mandatory for Decapitalization"
msgstr ""
@@ -16099,7 +16101,7 @@
msgid "Consumed Stock Items"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:312
+#: assets/doctype/asset_capitalization/asset_capitalization.py:321
msgid "Consumed Stock Items or Consumed Asset Items is mandatory for Capitalization"
msgstr ""
@@ -16628,12 +16630,6 @@
msgid "Contacts"
msgstr ""
-#. Label of a Text field in DocType 'Homepage Section Card'
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgctxt "Homepage Section Card"
-msgid "Content"
-msgstr ""
-
#. Label of a Data field in DocType 'Issue'
#: support/doctype/issue/issue.json
msgctxt "Issue"
@@ -16641,7 +16637,7 @@
msgstr ""
#: erpnext_integrations/doctype/plaid_settings/plaid_settings.js:136
-#: public/js/controllers/transaction.js:2044
+#: public/js/controllers/transaction.js:2074
#: selling/doctype/quotation/quotation.js:344
msgid "Continue"
msgstr ""
@@ -16887,7 +16883,7 @@
msgid "Conversion factor for default Unit of Measure must be 1 in row {0}"
msgstr ""
-#: controllers/accounts_controller.py:2315
+#: controllers/accounts_controller.py:2384
msgid "Conversion rate cannot be 0 or 1"
msgstr ""
@@ -17002,17 +16998,16 @@
#. Name of a DocType
#: accounts/doctype/cost_center/cost_center.json
-#: accounts/doctype/payment_entry/payment_entry.js:659
#: accounts/report/accounts_payable/accounts_payable.js:28
#: accounts/report/accounts_payable_summary/accounts_payable_summary.js:62
#: accounts/report/accounts_receivable/accounts_receivable.js:30
-#: accounts/report/accounts_receivable/accounts_receivable.py:1024
+#: accounts/report/accounts_receivable/accounts_receivable.py:1047
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:62
#: accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.js:42
#: accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py:181
#: accounts/report/general_ledger/general_ledger.js:152
-#: accounts/report/general_ledger/general_ledger.py:640
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:293
+#: accounts/report/general_ledger/general_ledger.py:643
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:300
#: accounts/report/purchase_register/purchase_register.js:46
#: accounts/report/sales_payment_summary/sales_payment_summary.py:29
#: accounts/report/sales_register/sales_register.js:52
@@ -17022,7 +17017,7 @@
#: assets/report/fixed_asset_register/fixed_asset_register.py:461
#: buying/report/procurement_tracker/procurement_tracker.js:16
#: buying/report/procurement_tracker/procurement_tracker.py:32
-#: public/js/financial_statements.js:184
+#: public/js/financial_statements.js:237
msgid "Cost Center"
msgstr ""
@@ -17087,6 +17082,12 @@
msgid "Cost Center"
msgstr ""
+#. Label of a shortcut in the Receivables Workspace
+#: accounts/workspace/receivables/receivables.json
+msgctxt "Cost Center"
+msgid "Cost Center"
+msgstr ""
+
#. Label of a Link field in DocType 'Cost Center Allocation Percentage'
#: accounts/doctype/cost_center_allocation_percentage/cost_center_allocation_percentage.json
msgctxt "Cost Center Allocation Percentage"
@@ -17392,7 +17393,7 @@
msgid "Cost Center Allocation Percentages"
msgstr ""
-#: public/js/utils/sales_common.js:374
+#: public/js/utils/sales_common.js:383
msgid "Cost Center For Item with Item Code {0} has been Changed to {1}"
msgstr ""
@@ -17421,8 +17422,8 @@
msgid "Cost Center is a part of Cost Center Allocation, hence cannot be converted to a group"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1261
-#: stock/doctype/purchase_receipt/purchase_receipt.py:790
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1235
+#: stock/doctype/purchase_receipt/purchase_receipt.py:788
msgid "Cost Center is required in row {0} in Taxes table for type {1}"
msgstr ""
@@ -17442,15 +17443,15 @@
msgid "Cost Center {0} cannot be used for allocation as it is used as main cost center in other allocation record."
msgstr ""
-#: assets/doctype/asset/asset.py:245
+#: assets/doctype/asset/asset.py:246
msgid "Cost Center {} doesn't belong to Company {}"
msgstr ""
-#: assets/doctype/asset/asset.py:252
+#: assets/doctype/asset/asset.py:253
msgid "Cost Center {} is a group cost center and group cost centers cannot be used in transactions"
msgstr ""
-#: accounts/report/financial_statements.py:624
+#: accounts/report/financial_statements.py:612
msgid "Cost Center: {0} does not exist"
msgstr ""
@@ -17589,7 +17590,7 @@
msgid "Could Not Delete Demo Data"
msgstr ""
-#: selling/doctype/quotation/quotation.py:546
+#: selling/doctype/quotation/quotation.py:551
msgid "Could not auto create Customer due to the following missing mandatory field(s):"
msgstr ""
@@ -17612,7 +17613,7 @@
msgstr ""
#: accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py:128
-#: accounts/report/financial_statements.py:248
+#: accounts/report/financial_statements.py:236
msgid "Could not retrieve information for {0}."
msgstr ""
@@ -17624,7 +17625,7 @@
msgid "Could not solve weighted score function. Make sure the formula is valid."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1027
+#: accounts/doctype/sales_invoice/sales_invoice.py:1030
msgid "Could not update stock, invoice contains drop shipping item."
msgstr ""
@@ -17766,7 +17767,7 @@
#: accounts/doctype/account/account_tree.js:80
#: accounts/doctype/bank_clearance/bank_clearance.py:79
-#: accounts/doctype/journal_entry/journal_entry.js:308
+#: accounts/doctype/journal_entry/journal_entry.js:298
msgid "Cr"
msgstr ""
@@ -17836,39 +17837,39 @@
#: public/js/communication.js:24 public/js/communication.js:30
#: public/js/controllers/transaction.js:300
#: public/js/controllers/transaction.js:301
-#: public/js/controllers/transaction.js:2158
+#: public/js/controllers/transaction.js:2188
#: selling/doctype/customer/customer.js:165
#: selling/doctype/quotation/quotation.js:119
#: selling/doctype/quotation/quotation.js:129
-#: selling/doctype/sales_order/sales_order.js:554
+#: selling/doctype/sales_order/sales_order.js:548
+#: selling/doctype/sales_order/sales_order.js:559
+#: selling/doctype/sales_order/sales_order.js:560
#: selling/doctype/sales_order/sales_order.js:565
-#: selling/doctype/sales_order/sales_order.js:566
+#: selling/doctype/sales_order/sales_order.js:570
#: selling/doctype/sales_order/sales_order.js:571
#: selling/doctype/sales_order/sales_order.js:576
-#: selling/doctype/sales_order/sales_order.js:577
+#: selling/doctype/sales_order/sales_order.js:581
#: selling/doctype/sales_order/sales_order.js:582
#: selling/doctype/sales_order/sales_order.js:587
-#: selling/doctype/sales_order/sales_order.js:588
-#: selling/doctype/sales_order/sales_order.js:593
+#: selling/doctype/sales_order/sales_order.js:599
#: selling/doctype/sales_order/sales_order.js:605
-#: selling/doctype/sales_order/sales_order.js:611
-#: selling/doctype/sales_order/sales_order.js:612
-#: selling/doctype/sales_order/sales_order.js:614
-#: selling/doctype/sales_order/sales_order.js:745
-#: selling/doctype/sales_order/sales_order.js:853
-#: stock/doctype/delivery_note/delivery_note.js:98
-#: stock/doctype/delivery_note/delivery_note.js:99
-#: stock/doctype/delivery_note/delivery_note.js:113
+#: selling/doctype/sales_order/sales_order.js:606
+#: selling/doctype/sales_order/sales_order.js:608
+#: selling/doctype/sales_order/sales_order.js:739
+#: selling/doctype/sales_order/sales_order.js:847
+#: stock/doctype/delivery_note/delivery_note.js:89
+#: stock/doctype/delivery_note/delivery_note.js:90
+#: stock/doctype/delivery_note/delivery_note.js:104
+#: stock/doctype/delivery_note/delivery_note.js:167
+#: stock/doctype/delivery_note/delivery_note.js:172
#: stock/doctype/delivery_note/delivery_note.js:176
#: stock/doctype/delivery_note/delivery_note.js:181
-#: stock/doctype/delivery_note/delivery_note.js:185
#: stock/doctype/delivery_note/delivery_note.js:190
-#: stock/doctype/delivery_note/delivery_note.js:199
-#: stock/doctype/delivery_note/delivery_note.js:205
-#: stock/doctype/delivery_note/delivery_note.js:232
+#: stock/doctype/delivery_note/delivery_note.js:196
+#: stock/doctype/delivery_note/delivery_note.js:223
#: stock/doctype/item/item.js:105 stock/doctype/item/item.js:108
#: stock/doctype/item/item.js:112 stock/doctype/item/item.js:449
-#: stock/doctype/item/item.js:665
+#: stock/doctype/item/item.js:651
#: stock/doctype/material_request/material_request.js:114
#: stock/doctype/material_request/material_request.js:120
#: stock/doctype/material_request/material_request.js:123
@@ -17988,7 +17989,7 @@
msgid "Create Missing Party"
msgstr ""
-#: manufacturing/doctype/bom_creator/bom_creator.js:139
+#: manufacturing/doctype/bom_creator/bom_creator.js:150
msgid "Create Multi-level BOM"
msgstr ""
@@ -18086,6 +18087,10 @@
msgid "Create Sample Retention Stock Entry"
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:220
+msgid "Create Serial Nos"
+msgstr ""
+
#: stock/dashboard/item_dashboard.js:271
#: stock/doctype/material_request/material_request.js:376
msgid "Create Stock Entry"
@@ -18123,7 +18128,7 @@
msgid "Create Users"
msgstr ""
-#: stock/doctype/item/item.js:661
+#: stock/doctype/item/item.js:647
msgid "Create Variant"
msgstr ""
@@ -18234,7 +18239,7 @@
msgid "Create an Item"
msgstr ""
-#: stock/stock_ledger.py:1595
+#: stock/stock_ledger.py:1684
msgid "Create an incoming stock transaction for the Item."
msgstr ""
@@ -18299,7 +18304,7 @@
msgid "Creating Company and Importing Chart of Accounts"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:918
+#: selling/doctype/sales_order/sales_order.js:912
msgid "Creating Delivery Note ..."
msgstr ""
@@ -18311,7 +18316,7 @@
msgid "Creating Packing Slip ..."
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:1032
+#: selling/doctype/sales_order/sales_order.js:1026
msgid "Creating Purchase Order ..."
msgstr ""
@@ -18397,15 +18402,15 @@
msgid "Credit"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:598
+#: accounts/report/general_ledger/general_ledger.py:601
msgid "Credit (Transaction)"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:575
+#: accounts/report/general_ledger/general_ledger.py:578
msgid "Credit ({0})"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:546
+#: accounts/doctype/journal_entry/journal_entry.js:536
msgid "Credit Account"
msgstr ""
@@ -18507,7 +18512,7 @@
msgid "Credit Limit"
msgstr ""
-#: selling/doctype/customer/customer.py:545
+#: selling/doctype/customer/customer.py:546
msgid "Credit Limit Crossed"
msgstr ""
@@ -18548,10 +18553,10 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:173
-#: accounts/report/accounts_receivable/accounts_receivable.py:1047
+#: accounts/report/accounts_receivable/accounts_receivable.py:1070
#: controllers/sales_and_purchase_return.py:328
#: setup/setup_wizard/operations/install_fixtures.py:256
-#: stock/doctype/delivery_note/delivery_note.js:93
+#: stock/doctype/delivery_note/delivery_note.js:84
msgid "Credit Note"
msgstr ""
@@ -18610,16 +18615,16 @@
msgid "Credit in Company Currency"
msgstr ""
-#: selling/doctype/customer/customer.py:511
-#: selling/doctype/customer/customer.py:565
+#: selling/doctype/customer/customer.py:512
+#: selling/doctype/customer/customer.py:566
msgid "Credit limit has been crossed for customer {0} ({1}/{2})"
msgstr ""
-#: selling/doctype/customer/customer.py:327
+#: selling/doctype/customer/customer.py:328
msgid "Credit limit is already defined for the Company {0}"
msgstr ""
-#: selling/doctype/customer/customer.py:564
+#: selling/doctype/customer/customer.py:565
msgid "Credit limit reached for customer {0}"
msgstr ""
@@ -18696,17 +18701,17 @@
#: accounts/doctype/account/account_tree.js:121
#: accounts/report/account_balance/account_balance.py:28
-#: accounts/report/accounts_receivable/accounts_receivable.py:1056
+#: accounts/report/accounts_receivable/accounts_receivable.py:1079
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:208
#: accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py:104
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.js:94
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.py:298
#: accounts/report/customer_ledger_summary/customer_ledger_summary.py:147
#: accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py:212
-#: accounts/report/financial_statements.py:643
+#: accounts/report/financial_statements.py:631
#: accounts/report/general_ledger/general_ledger.js:146
#: accounts/report/gross_profit/gross_profit.py:363
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:629
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:644
#: accounts/report/payment_ledger/payment_ledger.py:213
#: accounts/report/profitability_analysis/profitability_analysis.py:175
#: accounts/report/purchase_register/purchase_register.py:229
@@ -18716,7 +18721,7 @@
#: accounts/report/trial_balance_for_party/trial_balance_for_party.py:228
#: buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py:218
#: manufacturing/doctype/bom_creator/bom_creator.js:77
-#: public/js/financial_statements.js:178 public/js/utils/unreconcile.js:63
+#: public/js/financial_statements.js:231 public/js/utils/unreconcile.js:63
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:121
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:72
#: selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py:85
@@ -19012,8 +19017,8 @@
msgid "Currency can not be changed after making entries using some other currency"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1346
-#: accounts/doctype/payment_entry/payment_entry.py:1413 accounts/utils.py:2062
+#: accounts/doctype/payment_entry/payment_entry.py:1360
+#: accounts/doctype/payment_entry/payment_entry.py:1422 accounts/utils.py:2091
msgid "Currency for {0} must be {1}"
msgstr ""
@@ -19021,7 +19026,7 @@
msgid "Currency of the Closing Account must be {0}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:573
+#: manufacturing/doctype/bom/bom.py:575
msgid "Currency of the price list {0} must be {1} or {2}"
msgstr ""
@@ -19212,14 +19217,6 @@
msgid "Custom"
msgstr ""
-#. Option for the 'Section Based On' (Select) field in DocType 'Homepage
-#. Section'
-#. Label of a Section Break field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Custom HTML"
-msgstr ""
-
#. Label of a Check field in DocType 'Payment Entry'
#: accounts/doctype/payment_entry/payment_entry.json
msgctxt "Payment Entry"
@@ -19240,7 +19237,7 @@
#: accounts/report/gross_profit/gross_profit.py:321
#: accounts/report/inactive_sales_items/inactive_sales_items.py:37
#: accounts/report/item_wise_sales_register/item_wise_sales_register.js:22
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:214
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:221
#: accounts/report/pos_register/pos_register.js:45
#: accounts/report/pos_register/pos_register.py:123
#: accounts/report/pos_register/pos_register.py:186
@@ -19276,7 +19273,7 @@
#: selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py:64
#: setup/doctype/customer_group/customer_group.json
#: setup/doctype/territory/territory.json
-#: stock/doctype/delivery_note/delivery_note.js:368
+#: stock/doctype/delivery_note/delivery_note.js:359
#: stock/doctype/stock_entry/stock_entry.js:300
#: stock/report/delayed_item_report/delayed_item_report.js:37
#: stock/report/delayed_item_report/delayed_item_report.py:117
@@ -19333,13 +19330,13 @@
msgid "Customer"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#. Label of a Link in the CRM Workspace
#. Label of a shortcut in the CRM Workspace
#. Label of a Link in the Selling Workspace
#. Label of a Link in the Home Workspace
#. Label of a shortcut in the Home Workspace
-#: accounts/workspace/accounting/accounting.json crm/workspace/crm/crm.json
+#: accounts/workspace/receivables/receivables.json crm/workspace/crm/crm.json
#: selling/workspace/selling/selling.json setup/workspace/home/home.json
msgctxt "Customer"
msgid "Customer"
@@ -19653,7 +19650,7 @@
msgid "Customer Code"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1004
+#: accounts/report/accounts_receivable/accounts_receivable.py:1027
msgid "Customer Contact"
msgstr ""
@@ -19676,10 +19673,10 @@
msgid "Customer Contact Email"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Name of a report
#. Label of a Link in the Selling Workspace
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: selling/report/customer_credit_balance/customer_credit_balance.json
#: selling/workspace/selling/selling.json
msgid "Customer Credit Balance"
@@ -19734,13 +19731,13 @@
#. Name of a DocType
#: accounts/report/accounts_receivable/accounts_receivable.js:118
-#: accounts/report/accounts_receivable/accounts_receivable.py:1074
+#: accounts/report/accounts_receivable/accounts_receivable.py:1097
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:99
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:188
#: accounts/report/customer_ledger_summary/customer_ledger_summary.js:56
#: accounts/report/customer_ledger_summary/customer_ledger_summary.py:166
#: accounts/report/gross_profit/gross_profit.py:328
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:201
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:208
#: accounts/report/sales_register/sales_register.js:27
#: accounts/report/sales_register/sales_register.py:200
#: public/js/sales_trends_filters.js:26
@@ -19912,7 +19909,7 @@
msgid "Customer Group Name"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1174
+#: accounts/report/accounts_receivable/accounts_receivable.py:1197
msgid "Customer Group: {0} does not exist"
msgstr ""
@@ -19933,7 +19930,7 @@
msgid "Customer Items"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1065
+#: accounts/report/accounts_receivable/accounts_receivable.py:1088
msgid "Customer LPO"
msgstr ""
@@ -19942,9 +19939,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/customer_ledger_summary/customer_ledger_summary.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Customer Ledger Summary"
msgstr ""
@@ -19954,11 +19951,11 @@
msgid "Customer Mobile No"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1011
+#: accounts/report/accounts_receivable/accounts_receivable.py:1034
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:160
#: accounts/report/customer_ledger_summary/customer_ledger_summary.js:92
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:34
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:220
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:227
#: accounts/report/sales_register/sales_register.py:191
#: selling/report/customer_credit_balance/customer_credit_balance.py:74
#: selling/report/inactive_customers/inactive_customers.py:79
@@ -20155,7 +20152,7 @@
msgid "Customer Provided"
msgstr ""
-#: setup/doctype/company/company.py:358
+#: setup/doctype/company/company.py:359
msgid "Customer Service"
msgstr ""
@@ -20206,8 +20203,8 @@
msgid "Customer required for 'Customerwise Discount'"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:983
-#: selling/doctype/sales_order/sales_order.py:332
+#: accounts/doctype/sales_invoice/sales_invoice.py:986
+#: selling/doctype/sales_order/sales_order.py:335
#: stock/doctype/delivery_note/delivery_note.py:354
msgid "Customer {0} does not belong to project {1}"
msgstr ""
@@ -20328,10 +20325,6 @@
msgid "Customerwise Discount"
msgstr ""
-#: portal/doctype/homepage/homepage.js:9
-msgid "Customize Homepage Sections"
-msgstr ""
-
#. Name of a DocType
#: stock/doctype/customs_tariff_number/customs_tariff_number.json
msgid "Customs Tariff Number"
@@ -20504,7 +20497,7 @@
msgid "Data exported from Tally that consists of the Chart of Accounts, Customers, Suppliers, Addresses, Items and UOMs"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:552
+#: accounts/doctype/journal_entry/journal_entry.js:542
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html:36
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:150
#: accounts/report/account_balance/account_balance.js:16
@@ -20772,7 +20765,7 @@
msgid "Date of Joining"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:262
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:267
msgid "Date of Transaction"
msgstr ""
@@ -20910,7 +20903,7 @@
msgid "Dear"
msgstr ""
-#: stock/reorder_item.py:246
+#: stock/reorder_item.py:285
msgid "Dear System Manager,"
msgstr ""
@@ -20937,15 +20930,15 @@
msgid "Debit"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:591
+#: accounts/report/general_ledger/general_ledger.py:594
msgid "Debit (Transaction)"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:569
+#: accounts/report/general_ledger/general_ledger.py:572
msgid "Debit ({0})"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:540
+#: accounts/doctype/journal_entry/journal_entry.js:530
msgid "Debit Account"
msgstr ""
@@ -20980,7 +20973,7 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:175
-#: accounts/report/accounts_receivable/accounts_receivable.py:1050
+#: accounts/report/accounts_receivable/accounts_receivable.py:1073
#: controllers/sales_and_purchase_return.py:332
#: setup/setup_wizard/operations/install_fixtures.py:257
#: stock/doctype/purchase_receipt/purchase_receipt.js:73
@@ -21022,11 +21015,11 @@
msgid "Debit To"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:864
+#: accounts/doctype/sales_invoice/sales_invoice.py:867
msgid "Debit To is required"
msgstr ""
-#: accounts/general_ledger.py:466
+#: accounts/general_ledger.py:465
msgid "Debit and Credit not equal for {0} #{1}. Difference is {2}."
msgstr ""
@@ -21066,7 +21059,7 @@
msgid "Decapitalized"
msgstr ""
-#: public/js/utils/sales_common.js:435
+#: public/js/utils/sales_common.js:444
msgid "Declare Lost"
msgstr ""
@@ -21106,12 +21099,6 @@
msgid "Default"
msgstr ""
-#. Option for the 'Hero Section Based On' (Select) field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Default"
-msgstr ""
-
#. Label of a Check field in DocType 'POS Payment Method'
#: accounts/doctype/pos_payment_method/pos_payment_method.json
msgctxt "POS Payment Method"
@@ -21208,7 +21195,7 @@
msgid "Default BOM for {0} not found"
msgstr ""
-#: controllers/accounts_controller.py:3157
+#: controllers/accounts_controller.py:3216
msgid "Default BOM not found for FG Item {0}"
msgstr ""
@@ -21885,7 +21872,7 @@
msgid "Deferred Revenue and Expense"
msgstr ""
-#: accounts/deferred_revenue.py:577
+#: accounts/deferred_revenue.py:569
msgid "Deferred accounting failed for some invoices:"
msgstr ""
@@ -21942,7 +21929,7 @@
msgid "Delayed Tasks Summary"
msgstr ""
-#: setup/doctype/company/company.js:171
+#: setup/doctype/company/company.js:176
msgid "Delete"
msgstr ""
@@ -21966,7 +21953,7 @@
msgid "Delete Transactions"
msgstr ""
-#: setup/doctype/company/company.js:171
+#: setup/doctype/company/company.js:176
msgid "Delete all the Transactions for this Company"
msgstr ""
@@ -22028,9 +22015,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
msgid "Delivered Items To Be Billed"
msgstr ""
@@ -22130,10 +22117,10 @@
#: accounts/doctype/sales_invoice/sales_invoice.js:281
#: accounts/doctype/sales_invoice/sales_invoice_list.js:27
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:20
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:279
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:286
#: accounts/report/sales_register/sales_register.py:243
-#: selling/doctype/sales_order/sales_order.js:565
-#: selling/doctype/sales_order/sales_order_list.js:55
+#: selling/doctype/sales_order/sales_order.js:559
+#: selling/doctype/sales_order/sales_order_list.js:57
#: stock/doctype/delivery_note/delivery_note.json
#: stock/doctype/delivery_trip/delivery_trip.js:51
#: stock/doctype/pick_list/pick_list.js:102
@@ -22253,7 +22240,7 @@
msgid "Delivery Note Trends"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1145
+#: accounts/doctype/sales_invoice/sales_invoice.py:1148
msgid "Delivery Note {0} is not submitted"
msgstr ""
@@ -22261,7 +22248,7 @@
msgid "Delivery Note(s) created for the Pick List"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1069
+#: accounts/report/accounts_receivable/accounts_receivable.py:1092
#: stock/doctype/delivery_trip/delivery_trip.js:67
msgid "Delivery Notes"
msgstr ""
@@ -22309,7 +22296,7 @@
msgstr ""
#. Name of a DocType
-#: stock/doctype/delivery_note/delivery_note.js:189
+#: stock/doctype/delivery_note/delivery_note.js:180
#: stock/doctype/delivery_trip/delivery_trip.json
msgid "Delivery Trip"
msgstr ""
@@ -22341,7 +22328,7 @@
msgid "Delivery to"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:348
+#: selling/doctype/sales_order/sales_order.py:351
msgid "Delivery warehouse required for stock item {0}"
msgstr ""
@@ -22494,15 +22481,12 @@
msgid "Depreciate based on shifts"
msgstr ""
+#: assets/report/fixed_asset_register/fixed_asset_register.py:205
#: assets/report/fixed_asset_register/fixed_asset_register.py:393
#: assets/report/fixed_asset_register/fixed_asset_register.py:454
msgid "Depreciated Amount"
msgstr ""
-#: assets/report/fixed_asset_register/fixed_asset_register.py:205
-msgid "Depreciatied Amount"
-msgstr ""
-
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:56
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:81
#: accounts/report/account_balance/account_balance.js:45
@@ -22625,15 +22609,15 @@
msgid "Depreciation Posting Date should not be equal to Available for Use Date."
msgstr ""
-#: assets/doctype/asset/asset.py:490
+#: assets/doctype/asset/asset.py:491
msgid "Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}"
msgstr ""
-#: assets/doctype/asset/asset.py:459
+#: assets/doctype/asset/asset.py:460
msgid "Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date"
msgstr ""
-#: assets/doctype/asset/asset.py:450
+#: assets/doctype/asset/asset.py:451
msgid "Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date"
msgstr ""
@@ -22668,21 +22652,21 @@
msgid "Depreciation Schedule View"
msgstr ""
-#: assets/doctype/asset/asset.py:346
+#: assets/doctype/asset/asset.py:347
msgid "Depreciation cannot be calculated for fully depreciated assets"
msgstr ""
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:71
#: accounts/report/gross_profit/gross_profit.py:245
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:175
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:185
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:192
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:71
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py:207
#: manufacturing/report/bom_stock_calculated/bom_stock_calculated.py:58
#: manufacturing/report/bom_stock_report/bom_stock_report.py:26
#: manufacturing/report/work_order_stock_report/work_order_stock_report.py:112
#: public/js/bank_reconciliation_tool/data_table_manager.js:56
-#: public/js/controllers/transaction.js:2108
+#: public/js/controllers/transaction.js:2138
#: selling/doctype/quotation/quotation.js:279
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:41
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:35
@@ -22799,12 +22783,6 @@
msgid "Description"
msgstr ""
-#. Label of a Text field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Description"
-msgstr ""
-
#. Label of a Long Text field in DocType 'Incoterm'
#: setup/doctype/incoterm/incoterm.json
msgctxt "Incoterm"
@@ -23266,7 +23244,7 @@
msgid "Desk User"
msgstr ""
-#: public/js/utils/sales_common.js:414
+#: public/js/utils/sales_common.js:423
msgid "Detailed Reason"
msgstr ""
@@ -23385,7 +23363,7 @@
msgid "Difference (Dr - Cr)"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:266
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:287
msgid "Difference Account"
msgstr ""
@@ -23418,11 +23396,11 @@
msgid "Difference Account must be a Asset/Liability type account, since this Stock Entry is an Opening Entry"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:713
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:714
msgid "Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:280
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:301
msgid "Difference Amount"
msgstr ""
@@ -23463,7 +23441,7 @@
msgid "Difference Amount (Company Currency)"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:183
+#: accounts/doctype/payment_entry/payment_entry.py:185
msgid "Difference Amount must be zero"
msgstr ""
@@ -23486,7 +23464,7 @@
msgid "Difference Value"
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:375
+#: stock/doctype/delivery_note/delivery_note.js:366
msgid "Different 'Source Warehouse' and 'Target Warehouse' can be set for each row."
msgstr ""
@@ -23506,7 +23484,7 @@
msgid "Dimension Details"
msgstr ""
-#: accounts/report/budget_variance_report/budget_variance_report.js:98
+#: accounts/report/budget_variance_report/budget_variance_report.js:94
msgid "Dimension Filter"
msgstr ""
@@ -23829,15 +23807,15 @@
msgid "Disabled Account Selected"
msgstr ""
-#: stock/utils.py:407
+#: stock/utils.py:454
msgid "Disabled Warehouse {0} cannot be used for this transaction."
msgstr ""
-#: controllers/accounts_controller.py:547
+#: controllers/accounts_controller.py:550
msgid "Disabled pricing rules since this {} is an internal transfer"
msgstr ""
-#: controllers/accounts_controller.py:561
+#: controllers/accounts_controller.py:564
msgid "Disabled tax included prices since this {} is an internal transfer"
msgstr ""
@@ -24140,7 +24118,7 @@
msgid "Discount must be less than 100"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:2509
+#: accounts/doctype/payment_entry/payment_entry.py:2532
msgid "Discount of {} applied as per Payment Term"
msgstr ""
@@ -24226,7 +24204,7 @@
msgid "Dislikes"
msgstr ""
-#: setup/doctype/company/company.py:352
+#: setup/doctype/company/company.py:353
msgid "Dispatch"
msgstr ""
@@ -24627,7 +24605,7 @@
msgid "Download Backups"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:190
+#: public/js/utils/serial_no_batch_selector.js:237
msgid "Download CSV Template"
msgstr ""
@@ -24705,7 +24683,7 @@
#: accounts/doctype/account/account_tree.js:80
#: accounts/doctype/bank_clearance/bank_clearance.py:79
-#: accounts/doctype/journal_entry/journal_entry.js:308
+#: accounts/doctype/journal_entry/journal_entry.js:298
msgid "Dr"
msgstr ""
@@ -24924,11 +24902,6 @@
msgid "Draft"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry_list.js:5
-msgctxt "docstatus,=,0"
-msgid "Draft"
-msgstr ""
-
#. Name of a DocType
#: setup/doctype/driver/driver.json
msgid "Driver"
@@ -25103,13 +25076,21 @@
msgid "Due Date cannot be before Posting / Supplier Invoice Date"
msgstr ""
-#: controllers/accounts_controller.py:573
+#: controllers/accounts_controller.py:576
msgid "Due Date is mandatory"
msgstr ""
#. Name of a DocType
+#. Label of a Card Break in the Receivables Workspace
#: accounts/doctype/dunning/dunning.json
#: accounts/doctype/sales_invoice/sales_invoice.js:155
+#: accounts/workspace/receivables/receivables.json
+msgid "Dunning"
+msgstr ""
+
+#. Label of a Link in the Receivables Workspace
+#: accounts/workspace/receivables/receivables.json
+msgctxt "Dunning"
msgid "Dunning"
msgstr ""
@@ -25172,7 +25153,9 @@
msgstr ""
#. Label of a Data field in DocType 'Dunning Type'
+#. Label of a Link in the Receivables Workspace
#: accounts/doctype/dunning_type/dunning_type.json
+#: accounts/workspace/receivables/receivables.json
msgctxt "Dunning Type"
msgid "Dunning Type"
msgstr ""
@@ -25193,7 +25176,7 @@
msgid "Duplicate Entry. Please check Authorization Rule {0}"
msgstr ""
-#: assets/doctype/asset/asset.py:300
+#: assets/doctype/asset/asset.py:301
msgid "Duplicate Finance Book"
msgstr ""
@@ -25211,7 +25194,7 @@
msgstr ""
#: accounts/doctype/pos_profile/pos_profile.py:135
-msgid "Duplicate customer group found in the cutomer group table"
+msgid "Duplicate customer group found in the customer group table"
msgstr ""
#: stock/doctype/item_manufacturer/item_manufacturer.py:44
@@ -25341,7 +25324,7 @@
msgid "Edit Full Form"
msgstr ""
-#: controllers/item_variant.py:154
+#: controllers/item_variant.py:158
msgid "Edit Not Allowed"
msgstr ""
@@ -25349,7 +25332,7 @@
msgid "Edit Note"
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:379
+#: stock/doctype/delivery_note/delivery_note.js:370
msgid "Edit Posting Date and Time"
msgstr ""
@@ -25477,7 +25460,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:27
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:40
-msgid "Electronic Equipments"
+msgid "Electronic Equipment"
msgstr ""
#. Name of a report
@@ -26153,7 +26136,7 @@
#: accounts/report/payment_ledger/payment_ledger.js:24
#: assets/report/fixed_asset_register/fixed_asset_register.js:75
#: projects/report/project_summary/project_summary.py:74
-#: public/js/financial_statements.js:138 public/js/setup_wizard.js:42
+#: public/js/financial_statements.js:191 public/js/setup_wizard.js:42
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js:24
#: templates/pages/projects.html:47
msgid "End Date"
@@ -26255,11 +26238,11 @@
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.js:56
#: accounts/report/financial_ratios/financial_ratios.js:25
#: assets/report/fixed_asset_register/fixed_asset_register.js:90
-#: public/js/financial_statements.js:153
+#: public/js/financial_statements.js:206
msgid "End Year"
msgstr ""
-#: accounts/report/financial_statements.py:137
+#: accounts/report/financial_statements.py:125
msgid "End Year cannot be before Start Year"
msgstr ""
@@ -26305,6 +26288,10 @@
msgid "Enter First and Last name of Employee, based on Which Full Name will be updated. IN transactions, it will be Full Name which will be fetched."
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:208
+msgid "Enter Serial Nos"
+msgstr ""
+
#: stock/doctype/material_request/material_request.js:313
msgid "Enter Supplier"
msgstr ""
@@ -26333,7 +26320,7 @@
msgid "Enter amount to be redeemed."
msgstr ""
-#: stock/doctype/item/item.js:818
+#: stock/doctype/item/item.js:804
msgid "Enter an Item Code, the name will be auto-filled the same as Item Code on clicking inside the Item Name field."
msgstr ""
@@ -26345,7 +26332,7 @@
msgid "Enter customer's phone number"
msgstr ""
-#: assets/doctype/asset/asset.py:344
+#: assets/doctype/asset/asset.py:345
msgid "Enter depreciation details"
msgstr ""
@@ -26353,6 +26340,10 @@
msgid "Enter discount percentage."
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:211
+msgid "Enter each serial no in a new line"
+msgstr ""
+
#. Description of the 'Campaign' (Link) field in DocType 'Opportunity'
#: crm/doctype/opportunity/opportunity.json
msgctxt "Opportunity"
@@ -26360,7 +26351,7 @@
msgstr ""
#: accounts/doctype/bank_guarantee/bank_guarantee.py:51
-msgid "Enter the Bank Guarantee Number before submittting."
+msgid "Enter the Bank Guarantee Number before submitting."
msgstr ""
#: manufacturing/doctype/routing/routing.js:82
@@ -26371,14 +26362,14 @@
msgstr ""
#: accounts/doctype/bank_guarantee/bank_guarantee.py:53
-msgid "Enter the name of the Beneficiary before submittting."
+msgid "Enter the name of the Beneficiary before submitting."
msgstr ""
#: accounts/doctype/bank_guarantee/bank_guarantee.py:55
-msgid "Enter the name of the bank or lending institution before submittting."
+msgid "Enter the name of the bank or lending institution before submitting."
msgstr ""
-#: stock/doctype/item/item.js:838
+#: stock/doctype/item/item.js:824
msgid "Enter the opening stock units."
msgstr ""
@@ -26405,7 +26396,7 @@
msgid "Entity"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:200
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:205
#: accounts/report/tds_computation_summary/tds_computation_summary.py:123
msgid "Entity Type"
msgstr ""
@@ -26456,7 +26447,7 @@
msgid "Equity/Liability Account"
msgstr ""
-#: accounts/doctype/payment_request/payment_request.py:395
+#: accounts/doctype/payment_request/payment_request.py:410
#: manufacturing/doctype/job_card/job_card.py:773
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:197
msgid "Error"
@@ -26529,7 +26520,7 @@
msgstr ""
#: accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py:273
-msgid "Error Occured"
+msgid "Error Occurred"
msgstr ""
#: telephony/doctype/call_log/call_log.py:195
@@ -26541,14 +26532,14 @@
msgstr ""
#: erpnext_integrations/doctype/tally_migration/tally_migration.py:157
-msgid "Error occured while parsing Chart of Accounts: Please make sure that no two accounts have the same name"
+msgid "Error occurred while parsing Chart of Accounts: Please make sure that no two accounts have the same name"
msgstr ""
#: assets/doctype/asset/depreciation.py:406
msgid "Error while posting depreciation entries"
msgstr ""
-#: accounts/deferred_revenue.py:575
+#: accounts/deferred_revenue.py:567
msgid "Error while processing deferred accounting for {0}"
msgstr ""
@@ -26556,7 +26547,7 @@
msgid "Error while reposting item valuation"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:709
+#: accounts/doctype/payment_entry/payment_entry.js:720
msgid "Error: {0} is mandatory field"
msgstr ""
@@ -26625,7 +26616,7 @@
msgid "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions, then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item, leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings."
msgstr ""
-#: stock/stock_ledger.py:1887
+#: stock/stock_ledger.py:1976
msgid "Example: Serial No {0} reserved in {1}."
msgstr ""
@@ -26663,7 +26654,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:73
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:97
-#: setup/doctype/company/company.py:516
+#: setup/doctype/company/company.py:517
msgid "Exchange Gain/Loss"
msgstr ""
@@ -26685,8 +26676,8 @@
msgid "Exchange Gain/Loss"
msgstr ""
-#: controllers/accounts_controller.py:1279
-#: controllers/accounts_controller.py:1359
+#: controllers/accounts_controller.py:1313
+#: controllers/accounts_controller.py:1394
msgid "Exchange Gain/Loss amount has been booked through {0}"
msgstr ""
@@ -26979,7 +26970,7 @@
msgid "Expected Delivery Date"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:313
+#: selling/doctype/sales_order/sales_order.py:316
msgid "Expected Delivery Date should be after Sales Order Date"
msgstr ""
@@ -27101,7 +27092,7 @@
msgid "Expense"
msgstr ""
-#: controllers/stock_controller.py:367
+#: controllers/stock_controller.py:359
msgid "Expense / Difference account ({0}) must be a 'Profit or Loss' account"
msgstr ""
@@ -27188,7 +27179,7 @@
msgid "Expense Account"
msgstr ""
-#: controllers/stock_controller.py:347
+#: controllers/stock_controller.py:339
msgid "Expense Account Missing"
msgstr ""
@@ -27594,7 +27585,7 @@
msgid "Failed to setup defaults"
msgstr ""
-#: setup/doctype/company/company.py:698
+#: setup/doctype/company/company.py:699
msgid "Failed to setup defaults for country {0}. Please contact support."
msgstr ""
@@ -27675,7 +27666,7 @@
msgid "Fees"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:260
+#: public/js/utils/serial_no_batch_selector.js:332
msgid "Fetch Based On"
msgstr ""
@@ -27725,7 +27716,7 @@
msgstr ""
#: accounts/doctype/dunning/dunning.js:131
-#: public/js/controllers/transaction.js:1082
+#: public/js/controllers/transaction.js:1083
msgid "Fetching exchange rates ..."
msgstr ""
@@ -27804,7 +27795,7 @@
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.js:17
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.js:17
-#: public/js/financial_statements.js:114
+#: public/js/financial_statements.js:167
msgid "Filter Based On"
msgstr ""
@@ -27840,7 +27831,7 @@
msgid "Filter on Payment"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:685
+#: accounts/doctype/payment_entry/payment_entry.js:696
#: public/js/bank_reconciliation_tool/dialog_manager.js:192
msgid "Filters"
msgstr ""
@@ -27907,7 +27898,7 @@
#: accounts/report/supplier_ledger_summary/supplier_ledger_summary.js:32
#: accounts/report/trial_balance/trial_balance.js:70
#: assets/report/fixed_asset_register/fixed_asset_register.js:49
-#: public/js/financial_statements.js:108
+#: public/js/financial_statements.js:161
msgid "Finance Book"
msgstr ""
@@ -28025,12 +28016,17 @@
msgid "Financial Ratios"
msgstr ""
+#. Name of a Workspace
+#: accounts/workspace/financial_reports/financial_reports.json
+msgid "Financial Reports"
+msgstr ""
+
#. Title of an Onboarding Step
-#. Label of a Card Break in the Accounting Workspace
+#. Label of a Card Break in the Financial Reports Workspace
#: accounts/doctype/account/account_tree.js:158
#: accounts/onboarding_step/financial_statements/financial_statements.json
-#: accounts/workspace/accounting/accounting.json
-#: public/js/financial_statements.js:77
+#: accounts/workspace/financial_reports/financial_reports.json
+#: public/js/financial_statements.js:129
msgid "Financial Statements"
msgstr ""
@@ -28111,15 +28107,15 @@
msgid "Finished Good Item Quantity"
msgstr ""
-#: controllers/accounts_controller.py:3145
+#: controllers/accounts_controller.py:3204
msgid "Finished Good Item is not specified for service item {0}"
msgstr ""
-#: controllers/accounts_controller.py:3160
+#: controllers/accounts_controller.py:3219
msgid "Finished Good Item {0} Qty can not be zero"
msgstr ""
-#: controllers/accounts_controller.py:3154
+#: controllers/accounts_controller.py:3213
msgid "Finished Good Item {0} must be a sub-contracted item"
msgstr ""
@@ -28163,7 +28159,7 @@
msgid "Finished Good {0} must be a sub-contracted item."
msgstr ""
-#: setup/doctype/company/company.py:261
+#: setup/doctype/company/company.py:262
msgid "Finished Goods"
msgstr ""
@@ -28443,7 +28439,7 @@
msgid "Following Material Requests have been raised automatically based on Item's re-order level"
msgstr ""
-#: selling/doctype/customer/customer.py:739
+#: selling/doctype/customer/customer.py:740
msgid "Following fields are mandatory to create address:"
msgstr ""
@@ -28459,7 +28455,7 @@
msgid "For"
msgstr ""
-#: public/js/utils/sales_common.js:265
+#: public/js/utils/sales_common.js:274
msgid "For 'Product Bundle' items, Warehouse, Serial No and Batch No will be considered from the 'Packing List' table. If Warehouse and Batch No are same for all packing items for any 'Product Bundle' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table."
msgstr ""
@@ -28479,6 +28475,10 @@
msgid "For Default Supplier (Optional)"
msgstr ""
+#: controllers/stock_controller.py:770
+msgid "For Item {0} cannot be received more than {1} qty against the {2} {3}"
+msgstr ""
+
#. Label of a Link field in DocType 'Job Card'
#: manufacturing/doctype/job_card/job_card.json
msgctxt "Job Card"
@@ -28525,7 +28525,7 @@
msgstr ""
#: manufacturing/doctype/production_plan/production_plan.js:331
-#: selling/doctype/sales_order/sales_order.js:814
+#: selling/doctype/sales_order/sales_order.js:808
#: stock/doctype/material_request/material_request.js:247
msgid "For Warehouse"
msgstr ""
@@ -28540,15 +28540,15 @@
msgid "For Warehouse is required before Submit"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:112
+#: public/js/utils/serial_no_batch_selector.js:116
msgid "For Work Order"
msgstr ""
-#: controllers/status_updater.py:229
+#: controllers/status_updater.py:238
msgid "For an item {0}, quantity must be negative number"
msgstr ""
-#: controllers/status_updater.py:226
+#: controllers/status_updater.py:235
msgid "For an item {0}, quantity must be positive number"
msgstr ""
@@ -28578,7 +28578,7 @@
msgid "For individual supplier"
msgstr ""
-#: controllers/status_updater.py:234
+#: controllers/status_updater.py:243
msgid "For item {0}, rate must be a positive number. To Allow negative rates, enable {1} in {2}"
msgstr ""
@@ -28587,7 +28587,7 @@
msgstr ""
#: manufacturing/doctype/work_order/work_order.py:1523
-msgid "For operation {0}: Quantity ({1}) can not be greter than pending quantity({2})"
+msgid "For operation {0}: Quantity ({1}) can not be greater than pending quantity({2})"
msgstr ""
#: stock/doctype/stock_entry/stock_entry.py:1302
@@ -28600,8 +28600,8 @@
msgid "For reference"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1218
-#: public/js/controllers/accounts.js:181
+#: accounts/doctype/payment_entry/payment_entry.js:1229
+#: public/js/controllers/accounts.js:182
msgid "For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included"
msgstr ""
@@ -29041,7 +29041,7 @@
msgid "From Date and To Date are Mandatory"
msgstr ""
-#: accounts/report/financial_statements.py:142
+#: accounts/report/financial_statements.py:130
msgid "From Date and To Date are mandatory"
msgstr ""
@@ -29530,9 +29530,23 @@
msgid "Fully Depreciated"
msgstr ""
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Purchase
+#. Order'
+#: buying/doctype/purchase_order/purchase_order.json
+msgctxt "Purchase Order"
+msgid "Fully Paid"
+msgstr ""
+
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Sales
+#. Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "Fully Paid"
+msgstr ""
+
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:28
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:41
-msgid "Furnitures and Fixtures"
+msgid "Furniture and Fixtures"
msgstr ""
#: accounts/doctype/account/account_tree.js:111
@@ -29548,13 +29562,13 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:185
-#: accounts/report/accounts_receivable/accounts_receivable.py:1061
+#: accounts/report/accounts_receivable/accounts_receivable.py:1084
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:180
msgid "Future Payment Amount"
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:184
-#: accounts/report/accounts_receivable/accounts_receivable.py:1060
+#: accounts/report/accounts_receivable/accounts_receivable.py:1083
msgid "Future Payment Ref"
msgstr ""
@@ -29574,7 +29588,7 @@
#. Name of a DocType
#: accounts/doctype/gl_entry/gl_entry.json
-#: accounts/report/general_ledger/general_ledger.py:554
+#: accounts/report/general_ledger/general_ledger.py:557
msgid "GL Entry"
msgstr ""
@@ -29635,7 +29649,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:74
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:98
-#: setup/doctype/company/company.py:524
+#: setup/doctype/company/company.py:525
msgid "Gain/Loss on Asset Disposal"
msgstr ""
@@ -29673,13 +29687,13 @@
#. Description of a report in the Onboarding Step 'Financial Statements'
#. Name of a report
-#. Label of a Card Break in the Accounting Workspace
-#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/doctype/account/account.js:95
#: accounts/onboarding_step/financial_statements/financial_statements.json
#: accounts/report/general_ledger/general_ledger.json
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "General Ledger"
msgstr ""
@@ -29804,11 +29818,8 @@
msgid "Get Finished Goods for Manufacture"
msgstr ""
-#: accounts/doctype/invoice_discounting/invoice_discounting.js:157
-msgid "Get Invocies"
-msgstr ""
-
#: accounts/doctype/invoice_discounting/invoice_discounting.js:55
+#: accounts/doctype/invoice_discounting/invoice_discounting.js:157
msgid "Get Invoices"
msgstr ""
@@ -29854,9 +29865,9 @@
#: maintenance/doctype/maintenance_visit/maintenance_visit.js:132
#: public/js/controllers/buying.js:267
#: selling/doctype/quotation/quotation.js:160
-#: selling/doctype/sales_order/sales_order.js:129
-#: selling/doctype/sales_order/sales_order.js:649
-#: stock/doctype/delivery_note/delivery_note.js:169
+#: selling/doctype/sales_order/sales_order.js:132
+#: selling/doctype/sales_order/sales_order.js:643
+#: stock/doctype/delivery_note/delivery_note.js:160
#: stock/doctype/material_request/material_request.js:100
#: stock/doctype/material_request/material_request.js:162
#: stock/doctype/purchase_receipt/purchase_receipt.js:130
@@ -30090,7 +30101,7 @@
msgid "Goods"
msgstr ""
-#: setup/doctype/company/company.py:262
+#: setup/doctype/company/company.py:263
#: stock/doctype/stock_entry/stock_entry_list.js:14
msgid "Goods In Transit"
msgstr ""
@@ -30099,7 +30110,7 @@
msgid "Goods Transferred"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1622
+#: stock/doctype/stock_entry/stock_entry.py:1618
msgid "Goods are already received against the outward entry {0}"
msgstr ""
@@ -30123,7 +30134,7 @@
#: accounts/report/pos_register/pos_register.py:207
#: accounts/report/purchase_register/purchase_register.py:275
#: accounts/report/sales_register/sales_register.py:303
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:248
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:253
#: templates/includes/order/order_taxes.html:105 templates/pages/rfq.html:58
msgid "Grand Total"
msgstr ""
@@ -30410,10 +30421,10 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/gross_profit/gross_profit.json
#: accounts/report/gross_profit/gross_profit.py:287
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Gross Profit"
msgstr ""
@@ -30454,11 +30465,11 @@
msgid "Gross Purchase Amount"
msgstr ""
-#: assets/doctype/asset/asset.py:316
+#: assets/doctype/asset/asset.py:317
msgid "Gross Purchase Amount is mandatory"
msgstr ""
-#: assets/doctype/asset/asset.py:361
+#: assets/doctype/asset/asset.py:362
msgid "Gross Purchase Amount should be <b>equal</b> to purchase amount of one single Asset."
msgstr ""
@@ -30583,7 +30594,7 @@
msgid "Group by Voucher (Consolidated)"
msgstr ""
-#: stock/utils.py:401
+#: stock/utils.py:448
msgid "Group node warehouse is not allowed to select for transactions"
msgstr ""
@@ -30645,6 +30656,11 @@
msgid "Groups"
msgstr ""
+#: accounts/report/balance_sheet/balance_sheet.js:18
+#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:18
+msgid "Growth View"
+msgstr ""
+
#: stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py:245
#: stock/report/stock_ledger_variance/stock_ledger_variance.py:169
msgid "H - F"
@@ -30690,7 +30706,7 @@
#: accounts/report/budget_variance_report/budget_variance_report.js:66
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.js:69
#: manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.js:60
-#: public/js/financial_statements.js:166
+#: public/js/financial_statements.js:219
#: public/js/purchase_trends_filters.js:21 public/js/sales_trends_filters.js:13
#: selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.js:35
#: selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.js:35
@@ -30915,7 +30931,7 @@
msgid "Here are the error logs for the aforementioned failed depreciation entries: {0}"
msgstr ""
-#: stock/stock_ledger.py:1580
+#: stock/stock_ledger.py:1669
msgid "Here are the options to proceed:"
msgstr ""
@@ -30940,24 +30956,6 @@
msgid "Here, your weekly offs are pre-populated based on the previous selections. You can add more rows to also add public and national holidays individually."
msgstr ""
-#. Label of a Attach Image field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Hero Image"
-msgstr ""
-
-#. Label of a Section Break field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Hero Section"
-msgstr ""
-
-#. Label of a Select field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Hero Section Based On"
-msgstr ""
-
#: stock/doctype/repost_item_valuation/repost_item_valuation.py:391
msgid "Hi,"
msgstr ""
@@ -31021,7 +31019,7 @@
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:288
-#: selling/doctype/sales_order/sales_order.js:545
+#: selling/doctype/sales_order/sales_order.js:539
msgid "Hold"
msgstr ""
@@ -31105,34 +31103,6 @@
msgid "Home"
msgstr ""
-#. Name of a DocType
-#: portal/doctype/homepage/homepage.json
-msgid "Homepage"
-msgstr ""
-
-#. Name of a DocType
-#: portal/doctype/homepage_section/homepage_section.json
-msgid "Homepage Section"
-msgstr ""
-
-#. Option for the 'Hero Section Based On' (Select) field in DocType 'Homepage'
-#. Label of a Link field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Homepage Section"
-msgstr ""
-
-#. Name of a DocType
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgid "Homepage Section Card"
-msgstr ""
-
-#. Label of a Link field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Homepage Slideshow"
-msgstr ""
-
#. Label of a Currency field in DocType 'BOM Operation'
#: manufacturing/doctype/bom_operation/bom_operation.json
msgctxt "BOM Operation"
@@ -31197,7 +31167,7 @@
msgid "Hrs"
msgstr ""
-#: setup/doctype/company/company.py:364
+#: setup/doctype/company/company.py:365
msgid "Human Resources"
msgstr ""
@@ -31468,7 +31438,7 @@
msgid "If more than one package of the same type (for print)"
msgstr ""
-#: stock/stock_ledger.py:1590
+#: stock/stock_ledger.py:1679
msgid "If not, you can Cancel / Submit this entry"
msgstr ""
@@ -31496,7 +31466,7 @@
msgid "If the account is frozen, entries are allowed to restricted users."
msgstr ""
-#: stock/stock_ledger.py:1583
+#: stock/stock_ledger.py:1672
msgid "If the item is transacting as a Zero Valuation Rate item in this entry, please enable 'Allow Zero Valuation Rate' in the {0} Item table."
msgstr ""
@@ -31546,7 +31516,7 @@
msgid "If this is unchecked, direct GL entries will be created to book deferred revenue or expense"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:636
+#: accounts/doctype/payment_entry/payment_entry.py:638
msgid "If this is undesirable please cancel the corresponding Payment Entry."
msgstr ""
@@ -31572,7 +31542,7 @@
msgid "If ticked, the BOM cost will be automatically updated based on Valuation Rate / Price List Rate / last purchase rate of raw materials."
msgstr ""
-#: stock/doctype/item/item.js:828
+#: stock/doctype/item/item.js:814
msgid "If you are maintaining stock of this Item in your Inventory, ERPNext will make a stock ledger entry for each transaction of this item."
msgstr ""
@@ -31656,7 +31626,7 @@
msgid "Ignore Exchange Rate Revaluation Journals"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:806
+#: selling/doctype/sales_order/sales_order.js:800
msgid "Ignore Existing Ordered Qty"
msgstr ""
@@ -31814,12 +31784,6 @@
msgid "Image"
msgstr ""
-#. Label of a Attach Image field in DocType 'Homepage Section Card'
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgctxt "Homepage Section Card"
-msgid "Image"
-msgstr ""
-
#. Label of a Attach Image field in DocType 'Item'
#: stock/doctype/item/item.json
msgctxt "Item"
@@ -32144,6 +32108,11 @@
msgid "Import Type"
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:197
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:77
+msgid "Import Using CSV file"
+msgstr ""
+
#. Label of a HTML field in DocType 'Bank Statement Import'
#: accounts/doctype/bank_statement_import/bank_statement_import.json
msgctxt "Bank Statement Import"
@@ -32369,6 +32338,12 @@
msgid "In Words"
msgstr ""
+#. Label of a Small Text field in DocType 'Payment Entry'
+#: accounts/doctype/payment_entry/payment_entry.json
+msgctxt "Payment Entry"
+msgid "In Words"
+msgstr ""
+
#. Label of a Data field in DocType 'Purchase Invoice'
#: accounts/doctype/purchase_invoice/purchase_invoice.json
msgctxt "Purchase Invoice"
@@ -32429,6 +32404,12 @@
msgid "In Words (Company Currency)"
msgstr ""
+#. Label of a Small Text field in DocType 'Payment Entry'
+#: accounts/doctype/payment_entry/payment_entry.json
+msgctxt "Payment Entry"
+msgid "In Words (Company Currency)"
+msgstr ""
+
#. Label of a Data field in DocType 'Purchase Invoice'
#: accounts/doctype/purchase_invoice/purchase_invoice.json
msgctxt "Purchase Invoice"
@@ -32541,7 +32522,7 @@
msgid "In the case of 'Use Multi-Level BOM' in a work order, if the user wishes to add sub-assembly costs to Finished Goods items without using a job card as well the scrap items, then this option needs to be enable."
msgstr ""
-#: stock/doctype/item/item.js:853
+#: stock/doctype/item/item.js:839
msgid "In this section, you can define Company-wide transaction-related defaults for this Item. Eg. Default Warehouse, Default Price List, Supplier, etc."
msgstr ""
@@ -32602,7 +32583,7 @@
msgid "Include Default FB Assets"
msgstr ""
-#: accounts/report/balance_sheet/balance_sheet.js:20
+#: accounts/report/balance_sheet/balance_sheet.js:34
#: accounts/report/cash_flow/cash_flow.js:20
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.js:107
#: accounts/report/general_ledger/general_ledger.js:183
@@ -32618,7 +32599,7 @@
msgid "Include Expired"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:804
+#: selling/doctype/sales_order/sales_order.js:798
msgid "Include Exploded Items"
msgstr ""
@@ -32771,6 +32752,7 @@
#: accounts/report/account_balance/account_balance.js:28
#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.py:172
#: accounts/report/profitability_analysis/profitability_analysis.py:182
+#: public/js/financial_statements.js:35
msgid "Income"
msgstr ""
@@ -32794,7 +32776,8 @@
msgstr ""
#: accounts/report/account_balance/account_balance.js:51
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:286
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.js:65
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:293
msgid "Income Account"
msgstr ""
@@ -32916,11 +32899,11 @@
msgid "Incorrect Balance Qty After Transaction"
msgstr ""
-#: controllers/subcontracting_controller.py:706
+#: controllers/subcontracting_controller.py:710
msgid "Incorrect Batch Consumed"
msgstr ""
-#: assets/doctype/asset/asset.py:277
+#: assets/doctype/asset/asset.py:278
#: assets/doctype/asset_value_adjustment/asset_value_adjustment.py:74
msgid "Incorrect Date"
msgstr ""
@@ -32934,7 +32917,7 @@
msgid "Incorrect Movement Purpose"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:293
+#: accounts/doctype/payment_entry/payment_entry.py:295
msgid "Incorrect Payment Type"
msgstr ""
@@ -32943,7 +32926,7 @@
msgid "Incorrect Serial No Valuation"
msgstr ""
-#: controllers/subcontracting_controller.py:719
+#: controllers/subcontracting_controller.py:723
msgid "Incorrect Serial Number Consumed"
msgstr ""
@@ -33051,7 +33034,7 @@
msgid "Increment cannot be 0"
msgstr ""
-#: controllers/item_variant.py:110
+#: controllers/item_variant.py:114
msgid "Increment for Attribute {0} cannot be 0"
msgstr ""
@@ -33177,6 +33160,13 @@
msgid "Initiated"
msgstr ""
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Purchase
+#. Order'
+#: buying/doctype/purchase_order/purchase_order.json
+msgctxt "Purchase Order"
+msgid "Initiated"
+msgstr ""
+
#. Option for the 'Import Type' (Select) field in DocType 'Bank Statement
#. Import'
#: accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -33195,11 +33185,11 @@
msgid "Inspected By"
msgstr ""
-#: controllers/stock_controller.py:678
+#: controllers/stock_controller.py:666
msgid "Inspection Rejected"
msgstr ""
-#: controllers/stock_controller.py:648 controllers/stock_controller.py:650
+#: controllers/stock_controller.py:636 controllers/stock_controller.py:638
msgid "Inspection Required"
msgstr ""
@@ -33221,7 +33211,7 @@
msgid "Inspection Required before Purchase"
msgstr ""
-#: controllers/stock_controller.py:665
+#: controllers/stock_controller.py:653
msgid "Inspection Submission"
msgstr ""
@@ -33243,7 +33233,7 @@
#. Name of a DocType
#: selling/doctype/installation_note/installation_note.json
-#: stock/doctype/delivery_note/delivery_note.js:180
+#: stock/doctype/delivery_note/delivery_note.js:171
msgid "Installation Note"
msgstr ""
@@ -33325,19 +33315,19 @@
msgid "Insufficient Capacity"
msgstr ""
-#: controllers/accounts_controller.py:3071
-#: controllers/accounts_controller.py:3095
+#: controllers/accounts_controller.py:3130
+#: controllers/accounts_controller.py:3154
msgid "Insufficient Permissions"
msgstr ""
#: stock/doctype/pick_list/pick_list.py:705
#: stock/doctype/stock_entry/stock_entry.py:776
-#: stock/serial_batch_bundle.py:880 stock/stock_ledger.py:1264
-#: stock/stock_ledger.py:1751
+#: stock/serial_batch_bundle.py:880 stock/stock_ledger.py:1369
+#: stock/stock_ledger.py:1840
msgid "Insufficient Stock"
msgstr ""
-#: stock/stock_ledger.py:1766
+#: stock/stock_ledger.py:1855
msgid "Insufficient Stock for Batch"
msgstr ""
@@ -33478,7 +33468,7 @@
msgid "Interest"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:2316
+#: accounts/doctype/payment_entry/payment_entry.py:2339
msgid "Interest and/or dunning fee"
msgstr ""
@@ -33502,15 +33492,15 @@
msgid "Internal Customer"
msgstr ""
-#: selling/doctype/customer/customer.py:217
+#: selling/doctype/customer/customer.py:218
msgid "Internal Customer for company {0} already exists"
msgstr ""
-#: controllers/accounts_controller.py:530
+#: controllers/accounts_controller.py:533
msgid "Internal Sale or Delivery Reference missing."
msgstr ""
-#: controllers/accounts_controller.py:532
+#: controllers/accounts_controller.py:535
msgid "Internal Sales Reference Missing"
msgstr ""
@@ -33524,7 +33514,7 @@
msgid "Internal Supplier for company {0} already exists"
msgstr ""
-#: stock/doctype/delivery_note/delivery_note_dashboard.py:25
+#: stock/doctype/delivery_note/delivery_note_dashboard.py:27
#: stock/doctype/material_request/material_request_dashboard.py:19
msgid "Internal Transfer"
msgstr ""
@@ -33559,7 +33549,7 @@
msgid "Internal Transfer"
msgstr ""
-#: controllers/accounts_controller.py:541
+#: controllers/accounts_controller.py:544
msgid "Internal Transfer Reference Missing"
msgstr ""
@@ -33573,7 +33563,7 @@
msgid "Internal Work History"
msgstr ""
-#: controllers/stock_controller.py:744
+#: controllers/stock_controller.py:735
msgid "Internal transfers can only be done in company's default currency"
msgstr ""
@@ -33610,20 +33600,20 @@
#: accounts/doctype/purchase_invoice/purchase_invoice.py:369
#: accounts/doctype/purchase_invoice/purchase_invoice.py:377
-#: accounts/doctype/sales_invoice/sales_invoice.py:873
-#: accounts/doctype/sales_invoice/sales_invoice.py:883
+#: accounts/doctype/sales_invoice/sales_invoice.py:876
+#: accounts/doctype/sales_invoice/sales_invoice.py:886
#: assets/doctype/asset_category/asset_category.py:68
#: assets/doctype/asset_category/asset_category.py:96
-#: controllers/accounts_controller.py:2462
-#: controllers/accounts_controller.py:2468
+#: controllers/accounts_controller.py:2531
+#: controllers/accounts_controller.py:2537
msgid "Invalid Account"
msgstr ""
-#: controllers/item_variant.py:125
+#: controllers/item_variant.py:129
msgid "Invalid Attribute"
msgstr ""
-#: controllers/accounts_controller.py:377
+#: controllers/accounts_controller.py:380
msgid "Invalid Auto Repeat Date"
msgstr ""
@@ -33631,7 +33621,7 @@
msgid "Invalid Barcode. There is no Item attached to this barcode."
msgstr ""
-#: public/js/controllers/transaction.js:2330
+#: public/js/controllers/transaction.js:2360
msgid "Invalid Blanket Order for the selected Customer and Item"
msgstr ""
@@ -33639,12 +33629,12 @@
msgid "Invalid Child Procedure"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2000
+#: accounts/doctype/sales_invoice/sales_invoice.py:1977
msgid "Invalid Company for Inter Company Transaction."
msgstr ""
-#: assets/doctype/asset/asset.py:248 assets/doctype/asset/asset.py:255
-#: controllers/accounts_controller.py:2483
+#: assets/doctype/asset/asset.py:249 assets/doctype/asset/asset.py:256
+#: controllers/accounts_controller.py:2552
msgid "Invalid Cost Center"
msgstr ""
@@ -33652,7 +33642,7 @@
msgid "Invalid Credentials"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:315
+#: selling/doctype/sales_order/sales_order.py:318
msgid "Invalid Delivery Date"
msgstr ""
@@ -33669,7 +33659,7 @@
msgid "Invalid Formula"
msgstr ""
-#: assets/doctype/asset/asset.py:366
+#: assets/doctype/asset/asset.py:367
msgid "Invalid Gross Purchase Amount"
msgstr ""
@@ -33677,7 +33667,7 @@
msgid "Invalid Group By"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:376
+#: accounts/doctype/pos_invoice/pos_invoice.py:374
msgid "Invalid Item"
msgstr ""
@@ -33686,7 +33676,7 @@
msgstr ""
#: accounts/doctype/pos_closing_entry/pos_closing_entry.py:59
-#: accounts/general_ledger.py:678
+#: accounts/general_ledger.py:677
msgid "Invalid Opening Entry"
msgstr ""
@@ -33714,24 +33704,24 @@
msgid "Invalid Priority"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:989
+#: manufacturing/doctype/bom/bom.py:991
msgid "Invalid Process Loss Configuration"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:597
+#: accounts/doctype/payment_entry/payment_entry.py:599
msgid "Invalid Purchase Invoice"
msgstr ""
-#: controllers/accounts_controller.py:3110
+#: controllers/accounts_controller.py:3169
msgid "Invalid Qty"
msgstr ""
-#: controllers/accounts_controller.py:987
+#: controllers/accounts_controller.py:1021
msgid "Invalid Quantity"
msgstr ""
-#: assets/doctype/asset/asset.py:410 assets/doctype/asset/asset.py:416
-#: assets/doctype/asset/asset.py:443
+#: assets/doctype/asset/asset.py:411 assets/doctype/asset/asset.py:417
+#: assets/doctype/asset/asset.py:444
msgid "Invalid Schedule"
msgstr ""
@@ -33743,7 +33733,7 @@
msgid "Invalid URL"
msgstr ""
-#: controllers/item_variant.py:144
+#: controllers/item_variant.py:148
msgid "Invalid Value"
msgstr ""
@@ -33756,7 +33746,7 @@
msgid "Invalid condition expression"
msgstr ""
-#: selling/doctype/quotation/quotation.py:252
+#: selling/doctype/quotation/quotation.py:253
msgid "Invalid lost reason {0}, please create a new lost reason"
msgstr ""
@@ -33783,7 +33773,7 @@
msgid "Invalid {0}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1998
+#: accounts/doctype/sales_invoice/sales_invoice.py:1975
msgid "Invalid {0} for Inter Company Transaction."
msgstr ""
@@ -33824,7 +33814,7 @@
msgstr ""
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:177
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:187
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:194
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py:100
msgid "Invoice"
msgstr ""
@@ -33872,7 +33862,7 @@
msgid "Invoice Discounting"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1042
+#: accounts/report/accounts_receivable/accounts_receivable.py:1065
msgid "Invoice Grand Total"
msgstr ""
@@ -33999,7 +33989,7 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:168
-#: accounts/report/accounts_receivable/accounts_receivable.py:1044
+#: accounts/report/accounts_receivable/accounts_receivable.py:1067
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:168
#: accounts/report/customer_ledger_summary/customer_ledger_summary.py:104
msgid "Invoiced Amount"
@@ -34009,7 +33999,7 @@
msgid "Invoiced Qty"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2051
+#: accounts/doctype/sales_invoice/sales_invoice.py:2028
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:62
msgid "Invoices"
msgstr ""
@@ -34051,6 +34041,13 @@
msgid "Invoices and Payments have been Fetched and Allocated"
msgstr ""
+#. Label of a Card Break in the Payables Workspace
+#. Label of a Card Break in the Receivables Workspace
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
+msgid "Invoicing"
+msgstr ""
+
#. Label of a Section Break field in DocType 'Accounts Settings'
#: accounts/doctype/accounts_settings/accounts_settings.json
msgctxt "Accounts Settings"
@@ -34810,6 +34807,12 @@
msgid "Is Stock Item"
msgstr ""
+#. Label of a Check field in DocType 'Sales Order Item'
+#: selling/doctype/sales_order_item/sales_order_item.json
+msgctxt "Sales Order Item"
+msgid "Is Stock Item"
+msgstr ""
+
#. Label of a Check field in DocType 'Purchase Invoice'
#: accounts/doctype/purchase_invoice/purchase_invoice.json
msgctxt "Purchase Invoice"
@@ -35044,7 +35047,7 @@
msgid "It can take upto few hours for accurate stock values to be visible after merging items."
msgstr ""
-#: public/js/controllers/transaction.js:1809
+#: public/js/controllers/transaction.js:1839
msgid "It is needed to fetch Item Details."
msgstr ""
@@ -35060,7 +35063,7 @@
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.js:50
#: buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js:33
#: buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py:206
-#: controllers/taxes_and_totals.py:1009
+#: controllers/taxes_and_totals.py:1018
#: manufacturing/report/bom_stock_calculated/bom_stock_calculated.py:51
#: manufacturing/report/bom_stock_report/bom_stock_report.py:25
#: manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.js:67
@@ -35071,7 +35074,7 @@
#: public/js/purchase_trends_filters.js:48
#: public/js/purchase_trends_filters.js:65 public/js/sales_trends_filters.js:23
#: public/js/sales_trends_filters.js:41 public/js/stock_analytics.js:61
-#: selling/doctype/sales_order/sales_order.js:983
+#: selling/doctype/sales_order/sales_order.js:977
#: selling/report/customer_wise_item_price/customer_wise_item_price.js:15
#: selling/report/item_wise_sales_history/item_wise_sales_history.js:37
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js:63
@@ -35305,7 +35308,7 @@
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:36
#: accounts/report/gross_profit/gross_profit.py:224
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:150
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:160
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:167
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:36
#: buying/report/purchase_order_analysis/purchase_order_analysis.py:193
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py:200
@@ -35321,12 +35324,12 @@
#: manufacturing/report/quality_inspection_summary/quality_inspection_summary.py:86
#: manufacturing/report/work_order_stock_report/work_order_stock_report.py:119
#: projects/doctype/timesheet/timesheet.js:187
-#: public/js/controllers/transaction.js:2082 public/js/utils.js:459
+#: public/js/controllers/transaction.js:2112 public/js/utils.js:459
#: public/js/utils.js:606 selling/doctype/quotation/quotation.js:268
-#: selling/doctype/sales_order/sales_order.js:297
-#: selling/doctype/sales_order/sales_order.js:398
-#: selling/doctype/sales_order/sales_order.js:688
-#: selling/doctype/sales_order/sales_order.js:812
+#: selling/doctype/sales_order/sales_order.js:291
+#: selling/doctype/sales_order/sales_order.js:392
+#: selling/doctype/sales_order/sales_order.js:682
+#: selling/doctype/sales_order/sales_order.js:806
#: selling/report/customer_wise_item_price/customer_wise_item_price.py:29
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:27
#: selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py:19
@@ -35831,7 +35834,7 @@
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.js:28
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:164
#: accounts/report/item_wise_sales_register/item_wise_sales_register.js:53
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:174
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:181
#: accounts/report/purchase_register/purchase_register.js:58
#: accounts/report/sales_register/sales_register.js:70
#: public/js/purchase_trends_filters.js:49 public/js/sales_trends_filters.js:24
@@ -36041,6 +36044,12 @@
msgid "Item Group"
msgstr ""
+#. Label of a Link field in DocType 'Stock Reconciliation Item'
+#: stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
+msgctxt "Stock Reconciliation Item"
+msgid "Item Group"
+msgstr ""
+
#. Label of a Link field in DocType 'Supplier Quotation Item'
#: buying/doctype/supplier_quotation_item/supplier_quotation_item.json
msgctxt "Supplier Quotation Item"
@@ -36140,7 +36149,7 @@
#: accounts/report/gross_profit/gross_profit.py:231
#: accounts/report/inactive_sales_items/inactive_sales_items.py:33
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:156
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:166
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:173
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:70
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py:206
#: maintenance/doctype/maintenance_schedule/maintenance_schedule.js:95
@@ -36152,7 +36161,7 @@
#: manufacturing/report/production_planning_report/production_planning_report.py:356
#: manufacturing/report/quality_inspection_summary/quality_inspection_summary.py:92
#: manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.py:128
-#: public/js/controllers/transaction.js:2088
+#: public/js/controllers/transaction.js:2118
#: selling/report/customer_wise_item_price/customer_wise_item_price.py:35
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:33
#: selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py:25
@@ -36793,8 +36802,8 @@
msgid "Item UOM"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:343
-#: accounts/doctype/pos_invoice/pos_invoice.py:350
+#: accounts/doctype/pos_invoice/pos_invoice.py:341
+#: accounts/doctype/pos_invoice/pos_invoice.py:348
msgid "Item Unavailable"
msgstr ""
@@ -36827,7 +36836,7 @@
msgid "Item Variant Settings"
msgstr ""
-#: stock/doctype/item/item.js:681
+#: stock/doctype/item/item.js:667
msgid "Item Variant {0} already exists with same attributes"
msgstr ""
@@ -36922,7 +36931,7 @@
msgid "Item and Warranty Details"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2329
+#: stock/doctype/stock_entry/stock_entry.py:2325
msgid "Item for row {0} does not match Material Request"
msgstr ""
@@ -36939,7 +36948,7 @@
msgstr ""
#: buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py:42
-#: selling/doctype/sales_order/sales_order.js:990
+#: selling/doctype/sales_order/sales_order.js:984
msgid "Item name"
msgstr ""
@@ -36949,7 +36958,7 @@
msgid "Item operation"
msgstr ""
-#: controllers/accounts_controller.py:3137
+#: controllers/accounts_controller.py:3196
msgid "Item qty can not be updated as raw materials are already processed."
msgstr ""
@@ -36963,7 +36972,7 @@
msgid "Item to be manufactured or repacked"
msgstr ""
-#: stock/utils.py:517
+#: stock/utils.py:564
msgid "Item valuation reposting in progress. Report might show incorrect item valuation."
msgstr ""
@@ -36979,11 +36988,11 @@
msgid "Item {0} cannot be ordered more than {1} against Blanket Order {2}."
msgstr ""
-#: assets/doctype/asset/asset.py:230 stock/doctype/item/item.py:603
+#: assets/doctype/asset/asset.py:231 stock/doctype/item/item.py:603
msgid "Item {0} does not exist"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:558
+#: manufacturing/doctype/bom/bom.py:560
msgid "Item {0} does not exist in the system or has expired"
msgstr ""
@@ -36995,19 +37004,19 @@
msgid "Item {0} has already been returned"
msgstr ""
-#: assets/doctype/asset/asset.py:232
+#: assets/doctype/asset/asset.py:233
msgid "Item {0} has been disabled"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:642
-msgid "Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No"
+#: selling/doctype/sales_order/sales_order.py:645
+msgid "Item {0} has no Serial No. Only serialized items can have delivery based on Serial No"
msgstr ""
#: stock/doctype/item/item.py:1102
msgid "Item {0} has reached its end of life on {1}"
msgstr ""
-#: stock/stock_ledger.py:102
+#: stock/stock_ledger.py:111
msgid "Item {0} ignored since it is not a stock item"
msgstr ""
@@ -37031,11 +37040,11 @@
msgid "Item {0} is not a stock Item"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1542
+#: stock/doctype/stock_entry/stock_entry.py:1538
msgid "Item {0} is not active or end of life has been reached"
msgstr ""
-#: assets/doctype/asset/asset.py:234
+#: assets/doctype/asset/asset.py:235
msgid "Item {0} must be a Fixed Asset Item"
msgstr ""
@@ -37047,7 +37056,7 @@
msgid "Item {0} must be a Sub-contracted Item"
msgstr ""
-#: assets/doctype/asset/asset.py:236
+#: assets/doctype/asset/asset.py:237
msgid "Item {0} must be a non-stock item"
msgstr ""
@@ -37059,7 +37068,7 @@
msgid "Item {0} not found."
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:338
+#: buying/doctype/purchase_order/purchase_order.py:342
msgid "Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item)."
msgstr ""
@@ -37067,7 +37076,7 @@
msgid "Item {0}: {1} qty produced. "
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:1071
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:1131
msgid "Item {} does not exist."
msgstr ""
@@ -37089,9 +37098,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
msgid "Item-wise Purchase Register"
msgstr ""
@@ -37103,18 +37112,18 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#: accounts/report/item_wise_sales_register/item_wise_sales_register.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
msgid "Item-wise Sales Register"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:309
+#: manufacturing/doctype/bom/bom.py:311
msgid "Item: {0} does not exist in the system"
msgstr ""
#: public/js/utils.js:442 setup/doctype/item_group/item_group.js:70
-#: stock/doctype/delivery_note/delivery_note.js:373
+#: stock/doctype/delivery_note/delivery_note.js:364
#: templates/generators/bom.html:38 templates/pages/rfq.html:37
msgid "Items"
msgstr ""
@@ -37287,7 +37296,7 @@
msgstr ""
#: manufacturing/doctype/production_plan/production_plan.py:1462
-#: selling/doctype/sales_order/sales_order.js:1024
+#: selling/doctype/sales_order/sales_order.js:1018
msgid "Items Required"
msgstr ""
@@ -37303,11 +37312,11 @@
msgid "Items and Pricing"
msgstr ""
-#: controllers/accounts_controller.py:3357
+#: controllers/accounts_controller.py:3416
msgid "Items cannot be updated as Subcontracting Order is created against the Purchase Order {0}."
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:830
+#: selling/doctype/sales_order/sales_order.js:824
msgid "Items for Raw Material Request"
msgstr ""
@@ -37330,7 +37339,7 @@
msgid "Items to Order and Receive"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:258
+#: selling/doctype/sales_order/sales_order.js:252
msgid "Items to Reserve"
msgstr ""
@@ -37515,7 +37524,7 @@
msgid "Journal Entries"
msgstr ""
-#: accounts/utils.py:838
+#: accounts/utils.py:866
msgid "Journal Entries {0} are un-linked"
msgstr ""
@@ -37549,8 +37558,13 @@
#. Option for the 'Entry Type' (Select) field in DocType 'Journal Entry'
#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
+#. Label of a shortcut in the Payables Workspace
+#. Label of a shortcut in the Receivables Workspace
#: accounts/doctype/journal_entry/journal_entry.json
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
msgctxt "Journal Entry"
msgid "Journal Entry"
msgstr ""
@@ -37603,7 +37617,7 @@
msgid "Journal Entry Type"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:455
+#: accounts/doctype/journal_entry/journal_entry.py:471
msgid "Journal Entry for Asset scrapping cannot be cancelled. Please restore the Asset."
msgstr ""
@@ -37613,11 +37627,11 @@
msgid "Journal Entry for Scrap"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:215
+#: accounts/doctype/journal_entry/journal_entry.py:232
msgid "Journal Entry type should be set as Depreciation Entry for asset depreciation"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:581
+#: accounts/doctype/journal_entry/journal_entry.py:597
msgid "Journal Entry {0} does not have account {1} or already matched against other voucher"
msgstr ""
@@ -38157,6 +38171,11 @@
msgid "Ledger Merge Accounts"
msgstr ""
+#. Label of a Card Break in the Financial Reports Workspace
+#: accounts/workspace/financial_reports/financial_reports.json
+msgid "Ledgers"
+msgstr ""
+
#. Option for the 'Status' (Select) field in DocType 'Driver'
#: setup/doctype/driver/driver.json
msgctxt "Driver"
@@ -38181,7 +38200,7 @@
msgid "Left Index"
msgstr ""
-#: setup/doctype/company/company.py:388
+#: setup/doctype/company/company.py:389
msgid "Legal"
msgstr ""
@@ -38576,7 +38595,7 @@
msgid "Likes"
msgstr ""
-#: controllers/status_updater.py:353
+#: controllers/status_updater.py:362
msgid "Limit Crossed"
msgstr ""
@@ -38895,7 +38914,7 @@
msgstr ""
#: crm/report/lost_opportunity/lost_opportunity.py:49
-#: public/js/utils/sales_common.js:401
+#: public/js/utils/sales_common.js:410
msgid "Lost Reasons"
msgstr ""
@@ -39245,8 +39264,8 @@
msgid "Machine operator errors"
msgstr ""
-#: setup/doctype/company/company.py:562 setup/doctype/company/company.py:577
-#: setup/doctype/company/company.py:578 setup/doctype/company/company.py:579
+#: setup/doctype/company/company.py:563 setup/doctype/company/company.py:578
+#: setup/doctype/company/company.py:579 setup/doctype/company/company.py:580
msgid "Main"
msgstr ""
@@ -39379,7 +39398,7 @@
#: accounts/doctype/sales_invoice/sales_invoice.js:162
#: maintenance/doctype/maintenance_schedule/maintenance_schedule.json
#: maintenance/doctype/maintenance_visit/maintenance_visit.js:78
-#: selling/doctype/sales_order/sales_order.js:588
+#: selling/doctype/sales_order/sales_order.js:582
msgid "Maintenance Schedule"
msgstr ""
@@ -39524,7 +39543,7 @@
#. Name of a DocType
#: maintenance/doctype/maintenance_schedule/maintenance_schedule.js:83
#: maintenance/doctype/maintenance_visit/maintenance_visit.json
-#: selling/doctype/sales_order/sales_order.js:587
+#: selling/doctype/sales_order/sales_order.js:581
#: support/doctype/warranty_claim/warranty_claim.js:50
msgid "Maintenance Visit"
msgstr ""
@@ -39563,12 +39582,6 @@
msgid "Make"
msgstr ""
-#. Label of a Data field in DocType 'Vehicle'
-#: setup/doctype/vehicle/vehicle.json
-msgctxt "Vehicle"
-msgid "Make"
-msgstr ""
-
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:56
msgid "Make "
msgstr ""
@@ -39664,7 +39677,7 @@
msgid "Manage your orders"
msgstr ""
-#: setup/doctype/company/company.py:370
+#: setup/doctype/company/company.py:371
msgid "Management"
msgstr ""
@@ -39672,11 +39685,11 @@
#: accounts/doctype/promotional_scheme/promotional_scheme.py:141
#: buying/doctype/supplier_quotation/supplier_quotation.js:60
#: manufacturing/doctype/bom/bom.js:71 manufacturing/doctype/bom/bom.js:482
-#: manufacturing/doctype/bom/bom.py:243
+#: manufacturing/doctype/bom/bom.py:245
#: manufacturing/doctype/bom_update_log/bom_update_log.py:73
-#: public/js/controllers/accounts.js:248
-#: public/js/controllers/transaction.js:2454 public/js/utils/party.js:273
-#: stock/doctype/delivery_note/delivery_note.js:147
+#: public/js/controllers/accounts.js:249
+#: public/js/controllers/transaction.js:2484 public/js/utils/party.js:273
+#: stock/doctype/delivery_note/delivery_note.js:138
#: stock/doctype/purchase_receipt/purchase_receipt.js:113
#: stock/doctype/purchase_receipt/purchase_receipt.js:198
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js:81
@@ -39705,7 +39718,7 @@
msgid "Mandatory Depends On"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1566
+#: accounts/doctype/sales_invoice/sales_invoice.py:1549
msgid "Mandatory Field"
msgstr ""
@@ -39721,7 +39734,7 @@
msgid "Mandatory For Profit and Loss Account"
msgstr ""
-#: selling/doctype/quotation/quotation.py:551
+#: selling/doctype/quotation/quotation.py:556
msgid "Mandatory Missing"
msgstr ""
@@ -39967,6 +39980,12 @@
msgid "Manufacturer"
msgstr ""
+#. Label of a Data field in DocType 'Vehicle'
+#: setup/doctype/vehicle/vehicle.json
+msgctxt "Vehicle"
+msgid "Manufacturer"
+msgstr ""
+
#: manufacturing/report/bom_stock_calculated/bom_stock_calculated.py:70
msgid "Manufacturer Part Number"
msgstr ""
@@ -40069,7 +40088,7 @@
msgid "Manufacturing Manager"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1693
+#: stock/doctype/stock_entry/stock_entry.py:1689
msgid "Manufacturing Quantity is mandatory"
msgstr ""
@@ -40277,6 +40296,10 @@
msgid "Margin Type"
msgstr ""
+#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:19
+msgid "Margin View"
+msgstr ""
+
#. Label of a Select field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
@@ -40318,7 +40341,7 @@
msgid "Market Segment"
msgstr ""
-#: setup/doctype/company/company.py:322
+#: setup/doctype/company/company.py:323
msgid "Marketing"
msgstr ""
@@ -40440,7 +40463,7 @@
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py:186
#: manufacturing/doctype/job_card/job_card.js:57
#: manufacturing/doctype/production_plan/production_plan.js:113
-#: selling/doctype/sales_order/sales_order.js:576
+#: selling/doctype/sales_order/sales_order.js:570
#: selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py:36
#: stock/doctype/material_request/material_request.json
#: stock/doctype/material_request/material_request.py:365
@@ -40670,7 +40693,7 @@
msgid "Material Request Type"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:1507
+#: selling/doctype/sales_order/sales_order.py:1521
msgid "Material Request not created, as quantity for Raw Materials already available."
msgstr ""
@@ -40685,11 +40708,11 @@
msgid "Material Request used to make this Stock Entry"
msgstr ""
-#: controllers/subcontracting_controller.py:968
+#: controllers/subcontracting_controller.py:974
msgid "Material Request {0} is cancelled or stopped"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:845
+#: selling/doctype/sales_order/sales_order.js:839
msgid "Material Request {0} submitted."
msgstr ""
@@ -40827,7 +40850,7 @@
msgid "Materials Required (Exploded)"
msgstr ""
-#: controllers/subcontracting_controller.py:1158
+#: controllers/subcontracting_controller.py:1164
msgid "Materials are already received against the {0} {1}"
msgstr ""
@@ -40934,11 +40957,11 @@
msgid "Maximum Payment Amount"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2846
+#: stock/doctype/stock_entry/stock_entry.py:2842
msgid "Maximum Samples - {0} can be retained for Batch {1} and Item {2}."
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2837
+#: stock/doctype/stock_entry/stock_entry.py:2833
msgid "Maximum Samples - {0} have already been retained for Batch {1} and Item {2} in Batch {3}."
msgstr ""
@@ -41002,7 +41025,7 @@
msgid "Meeting"
msgstr ""
-#: stock/stock_ledger.py:1596
+#: stock/stock_ledger.py:1685
msgid "Mention Valuation Rate in the Item master."
msgstr ""
@@ -41305,28 +41328,28 @@
msgid "Mismatch"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:1072
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:1132
msgid "Missing"
msgstr ""
#: accounts/doctype/pos_opening_entry/pos_opening_entry.py:69
#: accounts/doctype/pos_profile/pos_profile.py:166
#: accounts/doctype/purchase_invoice/purchase_invoice.py:548
-#: accounts/doctype/sales_invoice/sales_invoice.py:2067
-#: accounts/doctype/sales_invoice/sales_invoice.py:2631
+#: accounts/doctype/sales_invoice/sales_invoice.py:2044
+#: accounts/doctype/sales_invoice/sales_invoice.py:2602
#: assets/doctype/asset_category/asset_category.py:115
msgid "Missing Account"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1410
+#: accounts/doctype/sales_invoice/sales_invoice.py:1403
msgid "Missing Asset"
msgstr ""
-#: accounts/doctype/gl_entry/gl_entry.py:179 assets/doctype/asset/asset.py:264
+#: accounts/doctype/gl_entry/gl_entry.py:179 assets/doctype/asset/asset.py:265
msgid "Missing Cost Center"
msgstr ""
-#: assets/doctype/asset/asset.py:308
+#: assets/doctype/asset/asset.py:309
msgid "Missing Finance Book"
msgstr ""
@@ -41350,7 +41373,7 @@
msgid "Missing Serial No Bundle"
msgstr ""
-#: selling/doctype/customer/customer.py:742
+#: selling/doctype/customer/customer.py:743
msgid "Missing Values Required"
msgstr ""
@@ -41362,7 +41385,7 @@
msgid "Missing email template for dispatch. Please set one in Delivery Settings."
msgstr ""
-#: manufacturing/doctype/bom/bom.py:955
+#: manufacturing/doctype/bom/bom.py:957
#: manufacturing/doctype/work_order/work_order.py:979
msgid "Missing value"
msgstr ""
@@ -41508,7 +41531,7 @@
msgstr ""
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:213
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:236
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:243
#: accounts/report/purchase_register/purchase_register.py:201
#: accounts/report/sales_register/sales_register.py:222
msgid "Mode Of Payment"
@@ -41762,7 +41785,7 @@
#: buying/report/purchase_analytics/purchase_analytics.js:62
#: manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.js:58
#: manufacturing/report/production_analytics/production_analytics.js:35
-#: public/js/financial_statements.js:164
+#: public/js/financial_statements.js:217
#: public/js/purchase_trends_filters.js:19 public/js/sales_trends_filters.js:11
#: public/js/stock_analytics.js:53
#: selling/report/sales_analytics/sales_analytics.js:62
@@ -42066,10 +42089,6 @@
msgid "More columns found than expected. Please compare the uploaded file with standard template"
msgstr ""
-#: templates/includes/macros.html:57 templates/pages/home.html:40
-msgid "More details"
-msgstr ""
-
#: stock/doctype/batch/batch.js:111 stock/doctype/batch/batch_dashboard.py:10
msgid "Move"
msgstr ""
@@ -42078,7 +42097,7 @@
msgid "Move Item"
msgstr ""
-#: templates/includes/macros.html:201
+#: templates/includes/macros.html:169
msgid "Move to Cart"
msgstr ""
@@ -42124,7 +42143,7 @@
msgid "Multi-level BOM Creator"
msgstr ""
-#: selling/doctype/customer/customer.py:368
+#: selling/doctype/customer/customer.py:369
msgid "Multiple Loyalty Programs found for Customer {}. Please select manually."
msgstr ""
@@ -42147,7 +42166,7 @@
msgid "Multiple Warehouse Accounts"
msgstr ""
-#: controllers/accounts_controller.py:865
+#: controllers/accounts_controller.py:899
msgid "Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year"
msgstr ""
@@ -42189,7 +42208,7 @@
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py:357
#: crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py:29
#: manufacturing/doctype/bom_creator/bom_creator.js:45
-#: public/js/utils/serial_no_batch_selector.js:332
+#: public/js/utils/serial_no_batch_selector.js:404
#: selling/doctype/quotation/quotation.js:261
msgid "Name"
msgstr ""
@@ -42427,11 +42446,11 @@
msgid "Needs Analysis"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:376
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:377
msgid "Negative Quantity is not allowed"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:380
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:381
msgid "Negative Valuation Rate is not allowed"
msgstr ""
@@ -42915,7 +42934,7 @@
msgid "Net Weight UOM"
msgstr ""
-#: controllers/accounts_controller.py:1179
+#: controllers/accounts_controller.py:1210
msgid "Net total calculation precision loss"
msgstr ""
@@ -43085,7 +43104,7 @@
msgid "New Workplace"
msgstr ""
-#: selling/doctype/customer/customer.py:337
+#: selling/doctype/customer/customer.py:338
msgid "New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}"
msgstr ""
@@ -43256,7 +43275,7 @@
msgid "No Answer"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2175
+#: accounts/doctype/sales_invoice/sales_invoice.py:2146
msgid "No Customer found for Inter Company Transactions which represents company {0}"
msgstr ""
@@ -43281,29 +43300,29 @@
msgid "No Item with Serial No {0}"
msgstr ""
-#: controllers/subcontracting_controller.py:1078
+#: controllers/subcontracting_controller.py:1084
msgid "No Items selected for transfer."
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:674
+#: selling/doctype/sales_order/sales_order.js:668
msgid "No Items with Bill of Materials to Manufacture"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:788
+#: selling/doctype/sales_order/sales_order.js:782
msgid "No Items with Bill of Materials."
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:192
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:213
msgid "No Outstanding Invoices found for this party"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:528
+#: accounts/doctype/pos_invoice/pos_invoice.py:526
msgid "No POS Profile found. Please create a New POS Profile first"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1534
-#: accounts/doctype/journal_entry/journal_entry.py:1600
-#: accounts/doctype/journal_entry/journal_entry.py:1623
+#: accounts/doctype/journal_entry/journal_entry.py:1420
+#: accounts/doctype/journal_entry/journal_entry.py:1486
+#: accounts/doctype/journal_entry/journal_entry.py:1509
#: stock/doctype/item/item.py:1332
msgid "No Permission"
msgstr ""
@@ -43314,7 +43333,7 @@
msgstr ""
#: accounts/doctype/purchase_invoice/purchase_invoice.py:333
-#: accounts/doctype/sales_invoice/sales_invoice.py:946
+#: accounts/doctype/sales_invoice/sales_invoice.py:949
msgid "No Remarks"
msgstr ""
@@ -43322,7 +43341,7 @@
msgid "No Stock Available Currently"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2159
+#: accounts/doctype/sales_invoice/sales_invoice.py:2130
msgid "No Supplier found for Inter Company Transactions which represents company {0}"
msgstr ""
@@ -43334,11 +43353,11 @@
msgid "No Terms"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:190
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:211
msgid "No Unreconciled Invoices and Payments found for this party and account"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:194
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:215
msgid "No Unreconciled Payments found for this party"
msgstr ""
@@ -43346,12 +43365,12 @@
msgid "No Work Orders were created"
msgstr ""
-#: stock/doctype/purchase_receipt/purchase_receipt.py:729
+#: stock/doctype/purchase_receipt/purchase_receipt.py:727
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py:606
msgid "No accounting entries for the following warehouses"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:648
+#: selling/doctype/sales_order/sales_order.py:651
msgid "No active BOM found for item {0}. Delivery by Serial No cannot be ensured"
msgstr ""
@@ -43387,11 +43406,11 @@
msgid "No employee was scheduled for call popup"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1053
+#: accounts/doctype/payment_entry/payment_entry.js:1064
msgid "No gain or loss in the exchange rate"
msgstr ""
-#: controllers/subcontracting_controller.py:999
+#: controllers/subcontracting_controller.py:1005
msgid "No item available for transfer."
msgstr ""
@@ -43487,7 +43506,7 @@
msgid "No outstanding invoices require exchange rate revaluation"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1784
+#: accounts/doctype/payment_entry/payment_entry.py:1801
msgid "No outstanding {0} found for the {1} {2} which qualify the filters you have specified."
msgstr ""
@@ -43509,38 +43528,38 @@
msgid "No record found"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:649
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:677
msgid "No records found in Allocation table"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:551
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:579
msgid "No records found in the Invoices table"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:554
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:582
msgid "No records found in the Payments table"
msgstr ""
-#. Description of the 'Stock Frozen Upto' (Date) field in DocType 'Stock
+#. Description of the 'Stock Frozen Up To' (Date) field in DocType 'Stock
#. Settings'
#: stock/doctype/stock_settings/stock_settings.json
msgctxt "Stock Settings"
msgid "No stock transactions can be created or modified before this date."
msgstr ""
-#: controllers/accounts_controller.py:2366
+#: controllers/accounts_controller.py:2435
msgid "No updates pending for reposting"
msgstr ""
-#: templates/includes/macros.html:323 templates/includes/macros.html:356
+#: templates/includes/macros.html:291 templates/includes/macros.html:324
msgid "No values"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:328
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:342
msgid "No {0} Accounts found for this company."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2226
+#: accounts/doctype/sales_invoice/sales_invoice.py:2197
msgid "No {0} found for Inter Company Transactions."
msgstr ""
@@ -43580,7 +43599,7 @@
msgid "Non Profit"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1303
+#: manufacturing/doctype/bom/bom.py:1305
msgid "Non stock items"
msgstr ""
@@ -43591,7 +43610,7 @@
msgid "None"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:314
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:315
msgid "None of the items have any change in quantity or value."
msgstr ""
@@ -43603,8 +43622,8 @@
msgstr ""
#: accounts/doctype/mode_of_payment/mode_of_payment.py:66
-#: accounts/doctype/pos_invoice/pos_invoice.py:256
-#: accounts/doctype/sales_invoice/sales_invoice.py:524
+#: accounts/doctype/pos_invoice/pos_invoice.py:254
+#: accounts/doctype/sales_invoice/sales_invoice.py:525
#: assets/doctype/asset/asset.js:530 assets/doctype/asset/asset.js:547
#: controllers/buying_controller.py:206
#: selling/doctype/product_bundle/product_bundle.py:71
@@ -43641,12 +43660,26 @@
msgid "Not Delivered"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:740
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Purchase
+#. Order'
+#: buying/doctype/purchase_order/purchase_order.json
+msgctxt "Purchase Order"
+msgid "Not Initiated"
+msgstr ""
+
+#: buying/doctype/purchase_order/purchase_order.py:744
#: templates/pages/material_request_info.py:21 templates/pages/order.py:32
#: templates/pages/rfq.py:48
msgid "Not Permitted"
msgstr ""
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Sales
+#. Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "Not Requested"
+msgstr ""
+
#: selling/report/lost_quotations/lost_quotations.py:86
#: support/report/issue_analytics/issue_analytics.py:208
#: support/report/issue_summary/issue_summary.py:198
@@ -43695,24 +43728,24 @@
msgid "Not allowed to update stock transactions older than {0}"
msgstr ""
-#: accounts/doctype/gl_entry/gl_entry.py:445
-msgid "Not authorized to edit frozen Account {0}"
+#: setup/doctype/authorization_control/authorization_control.py:57
+msgid "Not authorized since {0} exceeds limits"
msgstr ""
-#: setup/doctype/authorization_control/authorization_control.py:57
-msgid "Not authroized since {0} exceeds limits"
+#: accounts/doctype/gl_entry/gl_entry.py:445
+msgid "Not authorized to edit frozen Account {0}"
msgstr ""
#: templates/includes/products_as_grid.html:20
msgid "Not in stock"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:663
+#: buying/doctype/purchase_order/purchase_order.py:667
#: manufacturing/doctype/work_order/work_order.py:1256
#: manufacturing/doctype/work_order/work_order.py:1390
#: manufacturing/doctype/work_order/work_order.py:1440
-#: selling/doctype/sales_order/sales_order.py:741
-#: selling/doctype/sales_order/sales_order.py:1490
+#: selling/doctype/sales_order/sales_order.py:755
+#: selling/doctype/sales_order/sales_order.py:1504
msgid "Not permitted"
msgstr ""
@@ -43720,10 +43753,10 @@
#: manufacturing/doctype/bom_update_log/bom_update_log.py:100
#: manufacturing/doctype/production_plan/production_plan.py:1607
#: public/js/controllers/buying.js:440 selling/doctype/customer/customer.py:125
-#: selling/doctype/sales_order/sales_order.js:963
+#: selling/doctype/sales_order/sales_order.js:957
#: stock/doctype/item/item.js:426 stock/doctype/item/item.py:539
#: stock/doctype/stock_entry/stock_entry.py:1288
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:731
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:732
msgid "Note"
msgstr ""
@@ -43764,7 +43797,7 @@
msgid "Note: Item {0} added multiple times"
msgstr ""
-#: controllers/accounts_controller.py:447
+#: controllers/accounts_controller.py:450
msgid "Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"
msgstr ""
@@ -43776,7 +43809,7 @@
msgid "Note: To merge the items, create a separate Stock Reconciliation for the old item {0}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:943
+#: accounts/doctype/journal_entry/journal_entry.py:895
msgid "Note: {0}"
msgstr ""
@@ -43947,12 +43980,6 @@
msgid "Notify customer and agent via email on the day of the appointment."
msgstr ""
-#. Label of a Select field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Number of Columns"
-msgstr ""
-
#. Label of a Int field in DocType 'Appointment Booking Settings'
#: crm/doctype/appointment_booking_settings/appointment_booking_settings.json
msgctxt "Appointment Booking Settings"
@@ -43991,13 +44018,6 @@
msgid "Number of Order"
msgstr ""
-#. Description of the 'Number of Columns' (Select) field in DocType 'Homepage
-#. Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Number of columns for this section. 3 cards will be shown per row if you select 3 columns."
-msgstr ""
-
#. Description of the 'Grace Period' (Int) field in DocType 'Subscription
#. Settings'
#: accounts/doctype/subscription_settings/subscription_settings.json
@@ -44111,7 +44131,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:29
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:42
-msgid "Office Equipments"
+msgid "Office Equipment"
msgstr ""
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:62
@@ -44648,7 +44668,7 @@
msgid "Opening Accumulated Depreciation"
msgstr ""
-#: assets/doctype/asset/asset.py:427
+#: assets/doctype/asset/asset.py:428
msgid "Opening Accumulated Depreciation must be less than or equal to {0}"
msgstr ""
@@ -44698,7 +44718,7 @@
msgid "Opening Entry"
msgstr ""
-#: accounts/general_ledger.py:677
+#: accounts/general_ledger.py:676
msgid "Opening Entry can not be created after Period Closing Voucher is created."
msgstr ""
@@ -44800,7 +44820,7 @@
msgid "Operating Cost Per BOM Quantity"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1319
+#: manufacturing/doctype/bom/bom.py:1321
msgid "Operating Cost as per Work Order / BOM"
msgstr ""
@@ -44984,7 +45004,7 @@
msgstr ""
#: manufacturing/doctype/work_order/work_order.js:220
-#: setup/doctype/company/company.py:340 templates/generators/bom.html:61
+#: setup/doctype/company/company.py:341 templates/generators/bom.html:61
msgid "Operations"
msgstr ""
@@ -45010,7 +45030,7 @@
msgid "Operations"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:964
+#: manufacturing/doctype/bom/bom.py:966
msgid "Operations cannot be left blank"
msgstr ""
@@ -45331,12 +45351,6 @@
msgid "Order Value"
msgstr ""
-#. Description of the 'Section Order' (Int) field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Order in which sections should appear. 0 is first, 1 is second and so on."
-msgstr ""
-
#: crm/report/campaign_efficiency/campaign_efficiency.py:27
#: crm/report/lead_owner_efficiency/lead_owner_efficiency.py:33
msgid "Order/Quot %"
@@ -45409,7 +45423,7 @@
#: buying/doctype/supplier/supplier_dashboard.py:14
#: selling/doctype/customer/customer_dashboard.py:21
-#: selling/doctype/sales_order/sales_order.py:731
+#: selling/doctype/sales_order/sales_order.py:745
#: setup/doctype/company/company_dashboard.py:23
msgid "Orders"
msgstr ""
@@ -45518,9 +45532,11 @@
msgid "Other Info"
msgstr ""
+#. Label of a Card Break in the Financial Reports Workspace
#. Label of a Card Break in the Buying Workspace
#. Label of a Card Break in the Selling Workspace
#. Label of a Card Break in the Stock Workspace
+#: accounts/workspace/financial_reports/financial_reports.json
#: buying/workspace/buying/buying.json selling/workspace/selling/selling.json
#: stock/workspace/stock/stock.json
msgid "Other Reports"
@@ -45588,7 +45604,7 @@
msgid "Out of Warranty"
msgstr ""
-#: templates/includes/macros.html:205
+#: templates/includes/macros.html:173
msgid "Out of stock"
msgstr ""
@@ -45644,7 +45660,7 @@
#: accounts/doctype/payment_entry/payment_entry.js:653
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:179
-#: accounts/report/accounts_receivable/accounts_receivable.py:1051
+#: accounts/report/accounts_receivable/accounts_receivable.py:1074
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:171
#: accounts/report/purchase_register/purchase_register.py:289
#: accounts/report/sales_register/sales_register.py:317
@@ -45750,11 +45766,11 @@
msgid "Over Delivery/Receipt Allowance (%)"
msgstr ""
-#: controllers/stock_controller.py:795
+#: controllers/stock_controller.py:896
msgid "Over Receipt"
msgstr ""
-#: controllers/status_updater.py:358
+#: controllers/status_updater.py:367
msgid "Over Receipt/Delivery of {0} {1} ignored for item {2} because you have {3} role."
msgstr ""
@@ -45770,17 +45786,17 @@
msgid "Over Transfer Allowance (%)"
msgstr ""
-#: controllers/status_updater.py:360
+#: controllers/status_updater.py:369
msgid "Overbilling of {0} {1} ignored for item {2} because you have {3} role."
msgstr ""
-#: controllers/accounts_controller.py:1680
+#: controllers/accounts_controller.py:1713
msgid "Overbilling of {} ignored because you have {} role."
msgstr ""
#: accounts/doctype/sales_invoice/sales_invoice.py:261
#: projects/report/project_summary/project_summary.py:94
-#: selling/doctype/sales_order/sales_order_list.js:16
+#: selling/doctype/sales_order/sales_order_list.js:18
msgid "Overdue"
msgstr ""
@@ -46020,6 +46036,12 @@
msgid "POS Invoice"
msgstr ""
+#. Label of a shortcut in the Receivables Workspace
+#: accounts/workspace/receivables/receivables.json
+msgctxt "POS Invoice"
+msgid "POS Invoice"
+msgstr ""
+
#. Label of a Link field in DocType 'POS Invoice Reference'
#: accounts/doctype/pos_invoice_reference/pos_invoice_reference.json
msgctxt "POS Invoice Reference"
@@ -46077,7 +46099,7 @@
msgid "POS Invoice isn't created by user {}"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:192
+#: accounts/doctype/pos_invoice/pos_invoice.py:191
msgid "POS Invoice should have {} field checked."
msgstr ""
@@ -46175,7 +46197,7 @@
msgid "POS Profile doesn't matches {}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1116
+#: accounts/doctype/sales_invoice/sales_invoice.py:1119
msgid "POS Profile required to make POS Entry"
msgstr ""
@@ -46227,7 +46249,7 @@
msgstr ""
#: selling/page/point_of_sale/pos_controller.js:363
-msgid "POS invoice {0} created succesfully"
+msgid "POS invoice {0} created successfully"
msgstr ""
#. Option for the 'Series' (Select) field in DocType 'Cashier Closing'
@@ -46332,7 +46354,7 @@
msgid "Packed Items"
msgstr ""
-#: controllers/stock_controller.py:748
+#: controllers/stock_controller.py:739
msgid "Packed Items cannot be transferred internally"
msgstr ""
@@ -46373,7 +46395,7 @@
msgstr ""
#. Name of a DocType
-#: stock/doctype/delivery_note/delivery_note.js:195
+#: stock/doctype/delivery_note/delivery_note.js:186
#: stock/doctype/packing_slip/packing_slip.json
msgid "Packing Slip"
msgstr ""
@@ -46529,7 +46551,7 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:170
-#: accounts/report/accounts_receivable/accounts_receivable.py:1045
+#: accounts/report/accounts_receivable/accounts_receivable.py:1068
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:169
#: accounts/report/customer_ledger_summary/customer_ledger_summary.py:111
#: accounts/report/pos_register/pos_register.py:214
@@ -46609,7 +46631,7 @@
msgid "Paid Amount After Tax (Company Currency)"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:870
+#: accounts/doctype/payment_entry/payment_entry.js:881
msgid "Paid Amount cannot be greater than total negative outstanding amount {0}"
msgstr ""
@@ -46632,7 +46654,7 @@
msgstr ""
#: accounts/doctype/purchase_invoice/purchase_invoice.py:324
-#: accounts/doctype/sales_invoice/sales_invoice.py:991
+#: accounts/doctype/sales_invoice/sales_invoice.py:994
msgid "Paid amount + Write Off Amount can not be greater than Grand Total"
msgstr ""
@@ -46776,7 +46798,7 @@
msgid "Parent Company"
msgstr ""
-#: setup/doctype/company/company.py:459
+#: setup/doctype/company/company.py:460
msgid "Parent Company must be a group company"
msgstr ""
@@ -46989,6 +47011,20 @@
msgid "Partially Paid"
msgstr ""
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Purchase
+#. Order'
+#: buying/doctype/purchase_order/purchase_order.json
+msgctxt "Purchase Order"
+msgid "Partially Paid"
+msgstr ""
+
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Sales
+#. Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "Partially Paid"
+msgstr ""
+
#: stock/doctype/material_request/material_request_list.js:21
msgid "Partially Received"
msgstr ""
@@ -47035,6 +47071,10 @@
msgid "Parties"
msgstr ""
+#: stock/doctype/purchase_receipt/purchase_receipt_list.js:14
+msgid "Partly Billed"
+msgstr ""
+
#. Option for the 'Billing Status' (Select) field in DocType 'Sales Order'
#: selling/doctype/sales_order/sales_order.json
msgctxt "Sales Order"
@@ -47101,7 +47141,7 @@
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:151
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.py:233
#: accounts/report/general_ledger/general_ledger.js:74
-#: accounts/report/general_ledger/general_ledger.py:630
+#: accounts/report/general_ledger/general_ledger.py:633
#: accounts/report/payment_ledger/payment_ledger.js:52
#: accounts/report/payment_ledger/payment_ledger.py:154
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js:46
@@ -47254,7 +47294,7 @@
msgid "Party Account No. (Bank Statement)"
msgstr ""
-#: controllers/accounts_controller.py:1914
+#: controllers/accounts_controller.py:1983
msgid "Party Account {0} currency ({1}) and document currency ({2}) should be same"
msgstr ""
@@ -47365,7 +47405,7 @@
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:145
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.py:223
#: accounts/report/general_ledger/general_ledger.js:65
-#: accounts/report/general_ledger/general_ledger.py:629
+#: accounts/report/general_ledger/general_ledger.py:632
#: accounts/report/payment_ledger/payment_ledger.js:42
#: accounts/report/payment_ledger/payment_ledger.py:150
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js:35
@@ -47483,7 +47523,7 @@
msgid "Party Type and Party is required for Receivable / Payable account {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:432
+#: accounts/doctype/payment_entry/payment_entry.py:434
msgid "Party Type is mandatory"
msgstr ""
@@ -47497,7 +47537,7 @@
msgid "Party can only be one of {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:435
+#: accounts/doctype/payment_entry/payment_entry.py:437
msgid "Party is mandatory"
msgstr ""
@@ -47622,6 +47662,11 @@
msgid "Payable Account"
msgstr ""
+#. Name of a Workspace
+#: accounts/workspace/payables/payables.json
+msgid "Payables"
+msgstr ""
+
#. Label of a Check field in DocType 'Email Digest'
#: setup/doctype/email_digest/email_digest.json
msgctxt "Email Digest"
@@ -47644,7 +47689,7 @@
#: accounts/doctype/sales_invoice/sales_invoice_list.js:31
#: buying/doctype/purchase_order/purchase_order.js:328
#: buying/doctype/purchase_order/purchase_order_dashboard.py:20
-#: selling/doctype/sales_order/sales_order.js:612
+#: selling/doctype/sales_order/sales_order.js:606
#: selling/doctype/sales_order/sales_order_dashboard.py:28
msgid "Payment"
msgstr ""
@@ -47752,7 +47797,7 @@
msgid "Payment Entries"
msgstr ""
-#: accounts/utils.py:909
+#: accounts/utils.py:937
msgid "Payment Entries {0} are un-linked"
msgstr ""
@@ -47785,7 +47830,13 @@
#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
+#. Label of a shortcut in the Payables Workspace
+#. Label of a Link in the Receivables Workspace
+#. Label of a shortcut in the Receivables Workspace
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
msgctxt "Payment Entry"
msgid "Payment Entry"
msgstr ""
@@ -47807,19 +47858,19 @@
msgid "Payment Entry Reference"
msgstr ""
-#: accounts/doctype/payment_request/payment_request.py:395
+#: accounts/doctype/payment_request/payment_request.py:410
msgid "Payment Entry already exists"
msgstr ""
-#: accounts/utils.py:583
+#: accounts/utils.py:604
msgid "Payment Entry has been modified after you pulled it. Please pull it again."
msgstr ""
-#: accounts/doctype/payment_request/payment_request.py:544
+#: accounts/doctype/payment_request/payment_request.py:568
msgid "Payment Entry is already created"
msgstr ""
-#: controllers/accounts_controller.py:1130
+#: controllers/accounts_controller.py:1164
msgid "Payment Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice."
msgstr ""
@@ -47862,8 +47913,8 @@
msgid "Payment Gateway Account"
msgstr ""
-#. Label of a Link in the Accounting Workspace
-#: accounts/workspace/accounting/accounting.json
+#. Label of a Link in the Receivables Workspace
+#: accounts/workspace/receivables/receivables.json
msgctxt "Payment Gateway Account"
msgid "Payment Gateway Account"
msgstr ""
@@ -47874,7 +47925,7 @@
msgid "Payment Gateway Account"
msgstr ""
-#: accounts/utils.py:1199
+#: accounts/utils.py:1227
msgid "Payment Gateway Account not created, please create one manually."
msgstr ""
@@ -47982,9 +48033,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Payment Period Based On Invoice Date"
msgstr ""
@@ -48013,8 +48064,10 @@
msgid "Payment Reconciliation"
msgstr ""
-#. Label of a Link in the Accounting Workspace
-#: accounts/workspace/accounting/accounting.json
+#. Label of a Link in the Payables Workspace
+#. Label of a Link in the Receivables Workspace
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
msgctxt "Payment Reconciliation"
msgid "Payment Reconciliation"
msgstr ""
@@ -48029,7 +48082,7 @@
msgid "Payment Reconciliation Invoice"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:118
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:120
msgid "Payment Reconciliation Job: {0} is running for this party. Can't reconcile now."
msgstr ""
@@ -48062,7 +48115,7 @@
#: accounts/doctype/purchase_invoice/purchase_invoice.js:125
#: accounts/doctype/sales_invoice/sales_invoice.js:140
#: buying/doctype/purchase_order/purchase_order.js:335
-#: selling/doctype/sales_order/sales_order.js:611
+#: selling/doctype/sales_order/sales_order.js:605
msgid "Payment Request"
msgstr ""
@@ -48079,8 +48132,8 @@
msgid "Payment Request"
msgstr ""
-#. Label of a Link in the Accounting Workspace
-#: accounts/workspace/accounting/accounting.json
+#. Label of a Link in the Receivables Workspace
+#: accounts/workspace/receivables/receivables.json
msgctxt "Payment Request"
msgid "Payment Request"
msgstr ""
@@ -48091,7 +48144,7 @@
msgid "Payment Request Type"
msgstr ""
-#: accounts/doctype/payment_request/payment_request.py:478
+#: accounts/doctype/payment_request/payment_request.py:502
msgid "Payment Request for {0}"
msgstr ""
@@ -48099,6 +48152,10 @@
msgid "Payment Request took too long to respond. Please try requesting for payment again."
msgstr ""
+#: accounts/doctype/payment_request/payment_request.py:450
+msgid "Payment Requests cannot be created against: {0}"
+msgstr ""
+
#. Name of a DocType
#: accounts/doctype/payment_schedule/payment_schedule.json
msgid "Payment Schedule"
@@ -48146,13 +48203,13 @@
msgid "Payment Schedule"
msgstr ""
-#: public/js/controllers/transaction.js:924
+#: public/js/controllers/transaction.js:925
msgid "Payment Schedule Table"
msgstr ""
#. Name of a DocType
#: accounts/doctype/payment_term/payment_term.json
-#: accounts/report/accounts_receivable/accounts_receivable.py:1041
+#: accounts/report/accounts_receivable/accounts_receivable.py:1064
#: accounts/report/gross_profit/gross_profit.py:348
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:30
msgid "Payment Term"
@@ -48320,19 +48377,19 @@
msgid "Payment Type"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:499
+#: accounts/doctype/payment_entry/payment_entry.py:501
msgid "Payment Type must be one of Receive, Pay and Internal Transfer"
msgstr ""
-#: accounts/utils.py:899
+#: accounts/utils.py:927
msgid "Payment Unlink Error"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:748
+#: accounts/doctype/journal_entry/journal_entry.py:764
msgid "Payment against {0} {1} cannot be greater than Outstanding Amount {2}"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:656
+#: accounts/doctype/pos_invoice/pos_invoice.py:649
msgid "Payment amount cannot be less than or equal to 0"
msgstr ""
@@ -48349,7 +48406,7 @@
msgid "Payment of {0} received successfully. Waiting for other requests to complete..."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:313
+#: accounts/doctype/pos_invoice/pos_invoice.py:311
msgid "Payment related to {0} is not completed"
msgstr ""
@@ -48357,13 +48414,19 @@
msgid "Payment request failed"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:711
+#: accounts/doctype/payment_entry/payment_entry.py:713
msgid "Payment term {0} not used in {1}"
msgstr ""
+#. Label of a Card Break in the Accounting Workspace
+#. Label of a Card Break in the Payables Workspace
+#. Label of a Card Break in the Receivables Workspace
#: accounts/doctype/bank_account/bank_account_dashboard.py:13
#: accounts/report/sales_payment_summary/sales_payment_summary.py:27
#: accounts/report/sales_payment_summary/sales_payment_summary.py:43
+#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
#: buying/doctype/supplier/supplier_dashboard.py:15
#: selling/doctype/customer/customer_dashboard.py:22
msgid "Payments"
@@ -48514,7 +48577,7 @@
#: buying/report/purchase_order_analysis/purchase_order_analysis.py:218
#: manufacturing/doctype/work_order/work_order.js:244
#: manufacturing/report/production_plan_summary/production_plan_summary.py:155
-#: selling/doctype/sales_order/sales_order.js:997
+#: selling/doctype/sales_order/sales_order.js:991
#: selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py:45
msgid "Pending Qty"
msgstr ""
@@ -48716,7 +48779,7 @@
msgid "Period Based On"
msgstr ""
-#: accounts/general_ledger.py:691
+#: accounts/general_ledger.py:690
msgid "Period Closed"
msgstr ""
@@ -48821,7 +48884,7 @@
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.js:64
#: accounts/report/financial_ratios/financial_ratios.js:33
#: manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.js:55
-#: public/js/financial_statements.js:161
+#: public/js/financial_statements.js:214
msgid "Periodicity"
msgstr ""
@@ -48866,7 +48929,8 @@
msgid "Personal"
msgstr ""
-#. Option for the 'Prefered Contact Email' (Select) field in DocType 'Employee'
+#. Option for the 'Preferred Contact Email' (Select) field in DocType
+#. 'Employee'
#. Label of a Data field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
@@ -48970,7 +49034,7 @@
msgstr ""
#. Name of a DocType
-#: selling/doctype/sales_order/sales_order.js:554
+#: selling/doctype/sales_order/sales_order.js:548
#: stock/doctype/material_request/material_request.js:113
#: stock/doctype/pick_list/pick_list.json
msgid "Pick List"
@@ -49347,7 +49411,7 @@
msgid "Please Select a Company."
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:148
+#: stock/doctype/delivery_note/delivery_note.js:139
msgid "Please Select a Customer"
msgstr ""
@@ -49361,7 +49425,7 @@
msgid "Please Set Supplier Group in Buying Settings."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1060
+#: accounts/doctype/payment_entry/payment_entry.js:1071
msgid "Please Specify Account"
msgstr ""
@@ -49385,7 +49449,7 @@
msgid "Please add a Temporary Opening account in Chart of Accounts"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:443
+#: public/js/utils/serial_no_batch_selector.js:535
msgid "Please add atleast one Serial No / Batch No"
msgstr ""
@@ -49405,7 +49469,7 @@
msgid "Please add {1} role to user {0}."
msgstr ""
-#: controllers/stock_controller.py:808
+#: controllers/stock_controller.py:909
msgid "Please adjust the qty or edit {0} to proceed."
msgstr ""
@@ -49413,11 +49477,11 @@
msgid "Please attach CSV file"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2764
+#: accounts/doctype/sales_invoice/sales_invoice.py:2735
msgid "Please cancel and amend the Payment Entry"
msgstr ""
-#: accounts/utils.py:898
+#: accounts/utils.py:926
msgid "Please cancel payment entry manually first"
msgstr ""
@@ -49426,11 +49490,11 @@
msgid "Please cancel related transaction."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:884
+#: accounts/doctype/journal_entry/journal_entry.py:836
msgid "Please check Multi Currency option to allow accounts with other currency"
msgstr ""
-#: accounts/deferred_revenue.py:578
+#: accounts/deferred_revenue.py:570
msgid "Please check Process Deferred Accounting {0} and submit manually after resolving errors."
msgstr ""
@@ -49450,7 +49514,7 @@
msgid "Please check your email to confirm the appointment"
msgstr ""
-#: public/js/controllers/transaction.js:916
+#: public/js/controllers/transaction.js:917
msgid "Please clear the"
msgstr ""
@@ -49466,7 +49530,7 @@
msgid "Please click on 'Generate Schedule' to get schedule"
msgstr ""
-#: selling/doctype/customer/customer.py:537
+#: selling/doctype/customer/customer.py:538
msgid "Please contact any of the following users to extend the credit limits for {0}: {1}"
msgstr ""
@@ -49474,7 +49538,7 @@
msgid "Please contact any of the following users to {} this transaction."
msgstr ""
-#: selling/doctype/customer/customer.py:530
+#: selling/doctype/customer/customer.py:531
msgid "Please contact your administrator to extend the credit limits for {0}."
msgstr ""
@@ -49482,7 +49546,7 @@
msgid "Please convert the parent account in corresponding child company to a group account."
msgstr ""
-#: selling/doctype/quotation/quotation.py:549
+#: selling/doctype/quotation/quotation.py:554
msgid "Please create Customer from Lead {0}."
msgstr ""
@@ -49494,11 +49558,11 @@
msgid "Please create a new Accounting Dimension if required."
msgstr ""
-#: controllers/accounts_controller.py:531
+#: controllers/accounts_controller.py:534
msgid "Please create purchase from internal sale or delivery document itself"
msgstr ""
-#: assets/doctype/asset/asset.py:326
+#: assets/doctype/asset/asset.py:327
msgid "Please create purchase receipt or purchase invoice for the item {0}"
msgstr ""
@@ -49506,11 +49570,11 @@
msgid "Please delete Product Bundle {0}, before merging {1} into {2}"
msgstr ""
-#: assets/doctype/asset/asset.py:365
+#: assets/doctype/asset/asset.py:366
msgid "Please do not book expense of multiple assets against one single Asset."
msgstr ""
-#: controllers/item_variant.py:230
+#: controllers/item_variant.py:234
msgid "Please do not create more than 500 items at a time"
msgstr ""
@@ -49523,7 +49587,7 @@
msgstr ""
#: buying/doctype/request_for_quotation/request_for_quotation.js:135
-#: public/js/utils/serial_no_batch_selector.js:217
+#: public/js/utils/serial_no_batch_selector.js:289
#: regional/report/electronic_invoice_register/electronic_invoice_register.js:49
msgid "Please enable pop-ups"
msgstr ""
@@ -49536,7 +49600,7 @@
msgid "Please enable {} in {} to allow same item in multiple rows"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:868
+#: accounts/doctype/sales_invoice/sales_invoice.py:871
msgid "Please ensure {} account is a Balance Sheet account."
msgstr ""
@@ -49548,7 +49612,7 @@
msgid "Please ensure {} account {} is a Payable account. Change the account type to Payable or select a different account."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:877
+#: accounts/doctype/sales_invoice/sales_invoice.py:880
msgid "Please ensure {} account {} is a Receivable account."
msgstr ""
@@ -49556,8 +49620,8 @@
msgid "Please enter <b>Difference Account</b> or set default <b>Stock Adjustment Account</b> for company {0}"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:432
-#: accounts/doctype/sales_invoice/sales_invoice.py:1021
+#: accounts/doctype/pos_invoice/pos_invoice.py:430
+#: accounts/doctype/sales_invoice/sales_invoice.py:1024
msgid "Please enter Account for Change Amount"
msgstr ""
@@ -49565,11 +49629,11 @@
msgid "Please enter Approving Role or Approving User"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:696
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:697
msgid "Please enter Cost Center"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:319
+#: selling/doctype/sales_order/sales_order.py:322
msgid "Please enter Delivery Date"
msgstr ""
@@ -49577,7 +49641,7 @@
msgid "Please enter Employee Id of this sales person"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:707
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:708
msgid "Please enter Expense Account"
msgstr ""
@@ -49586,7 +49650,7 @@
msgid "Please enter Item Code to get Batch Number"
msgstr ""
-#: public/js/controllers/transaction.js:2206
+#: public/js/controllers/transaction.js:2236
msgid "Please enter Item Code to get batch no"
msgstr ""
@@ -49595,7 +49659,7 @@
msgstr ""
#: maintenance/doctype/maintenance_schedule/maintenance_schedule.py:225
-msgid "Please enter Maintaince Details first"
+msgid "Please enter Maintenance Details first"
msgstr ""
#: manufacturing/doctype/production_plan/production_plan.py:177
@@ -49618,7 +49682,7 @@
msgid "Please enter Receipt Document"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:949
+#: accounts/doctype/journal_entry/journal_entry.py:901
msgid "Please enter Reference date"
msgstr ""
@@ -49630,6 +49694,10 @@
msgid "Please enter Root Type for account- {0}"
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:258
+msgid "Please enter Serial Nos"
+msgstr ""
+
#: stock/doctype/shipment/shipment.py:83
msgid "Please enter Shipment Parcel information"
msgstr ""
@@ -49647,7 +49715,7 @@
msgstr ""
#: accounts/doctype/purchase_invoice/purchase_invoice.py:609
-#: accounts/doctype/sales_invoice/sales_invoice.py:1017
+#: accounts/doctype/sales_invoice/sales_invoice.py:1020
msgid "Please enter Write Off Account"
msgstr ""
@@ -49659,7 +49727,7 @@
msgid "Please enter company name first"
msgstr ""
-#: controllers/accounts_controller.py:2309
+#: controllers/accounts_controller.py:2378
msgid "Please enter default currency in Company Master"
msgstr ""
@@ -49675,7 +49743,7 @@
msgid "Please enter parent cost center"
msgstr ""
-#: public/js/utils/barcode_scanner.js:145
+#: public/js/utils/barcode_scanner.js:160
msgid "Please enter quantity for item {0}"
msgstr ""
@@ -49687,11 +49755,11 @@
msgid "Please enter serial nos"
msgstr ""
-#: setup/doctype/company/company.js:147
+#: setup/doctype/company/company.js:155
msgid "Please enter the company name to confirm"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:659
+#: accounts/doctype/pos_invoice/pos_invoice.py:652
msgid "Please enter the phone number first"
msgstr ""
@@ -49739,7 +49807,7 @@
msgid "Please make sure the file you are using has 'Parent Account' column present in the header."
msgstr ""
-#: setup/doctype/company/company.js:149
+#: setup/doctype/company/company.js:157
msgid "Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone."
msgstr ""
@@ -49747,11 +49815,11 @@
msgid "Please mention 'Weight UOM' along with Weight."
msgstr ""
-#: accounts/general_ledger.py:556
+#: accounts/general_ledger.py:555
msgid "Please mention Round Off Account in Company"
msgstr ""
-#: accounts/general_ledger.py:559
+#: accounts/general_ledger.py:558
msgid "Please mention Round Off Cost Center in Company"
msgstr ""
@@ -49788,12 +49856,12 @@
msgid "Please select <b>Template Type</b> to download template"
msgstr ""
-#: controllers/taxes_and_totals.py:641
-#: public/js/controllers/taxes_and_totals.js:675
+#: controllers/taxes_and_totals.py:651
+#: public/js/controllers/taxes_and_totals.js:688
msgid "Please select Apply Discount On"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:1455
+#: selling/doctype/sales_order/sales_order.py:1469
msgid "Please select BOM against item {0}"
msgstr ""
@@ -49809,12 +49877,12 @@
msgid "Please select Category first"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1184
+#: accounts/doctype/payment_entry/payment_entry.js:1195
#: public/js/controllers/accounts.js:86 public/js/controllers/accounts.js:124
msgid "Please select Charge Type first"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:411
+#: accounts/doctype/journal_entry/journal_entry.js:401
msgid "Please select Company"
msgstr ""
@@ -49823,7 +49891,7 @@
msgid "Please select Company and Posting Date to getting entries"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:631
+#: accounts/doctype/journal_entry/journal_entry.js:606
msgid "Please select Company first"
msgstr ""
@@ -49836,7 +49904,7 @@
msgid "Please select Customer first"
msgstr ""
-#: setup/doctype/company/company.py:406
+#: setup/doctype/company/company.py:407
msgid "Please select Existing Company for creating Chart of Accounts"
msgstr ""
@@ -49864,15 +49932,15 @@
msgid "Please select Posting Date before selecting Party"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:632
+#: accounts/doctype/journal_entry/journal_entry.js:607
msgid "Please select Posting Date first"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1002
+#: manufacturing/doctype/bom/bom.py:1004
msgid "Please select Price List"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:1457
+#: selling/doctype/sales_order/sales_order.py:1471
msgid "Please select Qty against item {0}"
msgstr ""
@@ -49892,11 +49960,11 @@
msgid "Please select Subcontracting Order instead of Purchase Order {0}"
msgstr ""
-#: controllers/accounts_controller.py:2219
+#: controllers/accounts_controller.py:2288
msgid "Please select Unrealized Profit / Loss account or add default Unrealized Profit / Loss account account for company {0}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:1227
+#: manufacturing/doctype/bom/bom.py:1229
msgid "Please select a BOM"
msgstr ""
@@ -49905,9 +49973,9 @@
msgstr ""
#: accounts/doctype/payment_entry/payment_entry.js:168
-#: manufacturing/doctype/bom/bom.js:482 manufacturing/doctype/bom/bom.py:243
-#: public/js/controllers/accounts.js:248
-#: public/js/controllers/transaction.js:2454
+#: manufacturing/doctype/bom/bom.js:482 manufacturing/doctype/bom/bom.py:245
+#: public/js/controllers/accounts.js:249
+#: public/js/controllers/transaction.js:2484
msgid "Please select a Company first."
msgstr ""
@@ -49975,7 +50043,7 @@
msgid "Please select a value for {0} quotation_to {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1684
+#: accounts/doctype/journal_entry/journal_entry.py:1570
msgid "Please select correct account"
msgstr ""
@@ -50036,8 +50104,8 @@
msgid "Please select {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:980
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:547
+#: accounts/doctype/payment_entry/payment_entry.js:991
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:575
#: accounts/doctype/tax_withholding_category/tax_withholding_category.py:81
msgid "Please select {0} first"
msgstr ""
@@ -50046,11 +50114,11 @@
msgid "Please set 'Apply Additional Discount On'"
msgstr ""
-#: assets/doctype/asset/depreciation.py:788
+#: assets/doctype/asset/depreciation.py:790
msgid "Please set 'Asset Depreciation Cost Center' in Company {0}"
msgstr ""
-#: assets/doctype/asset/depreciation.py:785
+#: assets/doctype/asset/depreciation.py:787
msgid "Please set 'Gain/Loss Account on Asset Disposal' in Company {0}"
msgstr ""
@@ -50102,7 +50170,7 @@
msgid "Please set Fixed Asset Account in {} against {}."
msgstr ""
-#: assets/doctype/asset/asset.py:434
+#: assets/doctype/asset/asset.py:435
msgid "Please set Number of Depreciations Booked"
msgstr ""
@@ -50132,11 +50200,11 @@
msgid "Please set a Company"
msgstr ""
-#: assets/doctype/asset/asset.py:261
+#: assets/doctype/asset/asset.py:262
msgid "Please set a Cost Center for the Asset or set an Asset Depreciation Cost Center for the Company {}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:1246
+#: selling/doctype/sales_order/sales_order.py:1260
msgid "Please set a Supplier against the Items to be considered in the Purchase Order."
msgstr ""
@@ -50148,7 +50216,7 @@
msgid "Please set a default Holiday List for Employee {0} or Company {1}"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1003
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:991
msgid "Please set account in Warehouse {0}"
msgstr ""
@@ -50157,7 +50225,7 @@
msgid "Please set an Address on the Company '%s'"
msgstr ""
-#: controllers/stock_controller.py:342
+#: controllers/stock_controller.py:334
msgid "Please set an Expense Account in the Items table"
msgstr ""
@@ -50169,27 +50237,27 @@
msgid "Please set at least one row in the Taxes and Charges Table"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2064
+#: accounts/doctype/sales_invoice/sales_invoice.py:2041
msgid "Please set default Cash or Bank account in Mode of Payment {0}"
msgstr ""
#: accounts/doctype/pos_opening_entry/pos_opening_entry.py:66
#: accounts/doctype/pos_profile/pos_profile.py:163
-#: accounts/doctype/sales_invoice/sales_invoice.py:2628
+#: accounts/doctype/sales_invoice/sales_invoice.py:2599
msgid "Please set default Cash or Bank account in Mode of Payment {}"
msgstr ""
#: accounts/doctype/pos_opening_entry/pos_opening_entry.py:68
#: accounts/doctype/pos_profile/pos_profile.py:165
-#: accounts/doctype/sales_invoice/sales_invoice.py:2630
+#: accounts/doctype/sales_invoice/sales_invoice.py:2601
msgid "Please set default Cash or Bank account in Mode of Payments {}"
msgstr ""
-#: accounts/utils.py:2057
+#: accounts/utils.py:2086
msgid "Please set default Exchange Gain/Loss Account in Company {}"
msgstr ""
-#: assets/doctype/asset_repair/asset_repair.py:335
+#: assets/doctype/asset_repair/asset_repair.py:331
msgid "Please set default Expense Account in Company {0}"
msgstr ""
@@ -50197,11 +50265,11 @@
msgid "Please set default UOM in Stock Settings"
msgstr ""
-#: controllers/stock_controller.py:208
+#: controllers/stock_controller.py:204
msgid "Please set default cost of goods sold account in company {0} for booking rounding gain and loss during stock transfer"
msgstr ""
-#: accounts/utils.py:918
+#: accounts/utils.py:946
msgid "Please set default {0} in Company {1}"
msgstr ""
@@ -50218,11 +50286,11 @@
msgid "Please set filters"
msgstr ""
-#: controllers/accounts_controller.py:1827
+#: controllers/accounts_controller.py:1896
msgid "Please set one of the following:"
msgstr ""
-#: public/js/controllers/transaction.js:1937
+#: public/js/controllers/transaction.js:1967
msgid "Please set recurring after saving"
msgstr ""
@@ -50275,7 +50343,7 @@
msgid "Please share this email with your support team so that they can find and fix the issue."
msgstr ""
-#: public/js/controllers/transaction.js:1807
+#: public/js/controllers/transaction.js:1837
msgid "Please specify"
msgstr ""
@@ -50289,8 +50357,8 @@
msgid "Please specify Company to proceed"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1195
-#: controllers/accounts_controller.py:2442 public/js/controllers/accounts.js:97
+#: accounts/doctype/payment_entry/payment_entry.js:1206
+#: controllers/accounts_controller.py:2511 public/js/controllers/accounts.js:97
msgid "Please specify a valid Row ID for row {0} in table {1}"
msgstr ""
@@ -50302,7 +50370,7 @@
msgid "Please specify at least one attribute in the Attributes table"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:371
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:372
msgid "Please specify either Quantity or Valuation Rate or both"
msgstr ""
@@ -50439,7 +50507,7 @@
msgstr ""
#: accounts/doctype/payment_entry/payment_entry.js:644
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:258
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:279
#: accounts/doctype/period_closing_voucher/period_closing_voucher.py:109
#: accounts/report/accounts_payable/accounts_payable.js:16
#: accounts/report/accounts_payable_summary/accounts_payable_summary.js:15
@@ -50448,10 +50516,10 @@
#: accounts/report/bank_clearance_summary/bank_clearance_summary.py:35
#: accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py:64
#: accounts/report/billed_items_to_be_received/billed_items_to_be_received.py:67
-#: accounts/report/general_ledger/general_ledger.py:560
+#: accounts/report/general_ledger/general_ledger.py:563
#: accounts/report/gross_profit/gross_profit.py:212
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:183
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:193
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:200
#: accounts/report/payment_ledger/payment_ledger.py:136
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py:97
#: accounts/report/pos_register/pos_register.py:177
@@ -50759,7 +50827,7 @@
msgid "Posting Time"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1645
+#: stock/doctype/stock_entry/stock_entry.py:1641
msgid "Posting date and posting time is mandatory"
msgstr ""
@@ -50775,20 +50843,20 @@
msgid "Pre Sales"
msgstr ""
+#: setup/setup_wizard/operations/install_fixtures.py:260
+msgid "Preference"
+msgstr ""
+
#. Label of a Select field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
-msgid "Prefered Contact Email"
+msgid "Preferred Contact Email"
msgstr ""
#. Label of a Data field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
-msgid "Prefered Email"
-msgstr ""
-
-#: setup/setup_wizard/operations/install_fixtures.py:260
-msgid "Preference"
+msgid "Preferred Email"
msgstr ""
#. Label of a Data field in DocType 'Packed Item'
@@ -51325,7 +51393,7 @@
msgid "Price is not set for the item."
msgstr ""
-#: manufacturing/doctype/bom/bom.py:458
+#: manufacturing/doctype/bom/bom.py:460
msgid "Price not found for item {0} in price list {1}"
msgstr ""
@@ -52206,7 +52274,7 @@
msgid "Process Loss"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:985
+#: manufacturing/doctype/bom/bom.py:987
msgid "Process Loss Percentage cannot be greater than 100"
msgstr ""
@@ -52512,7 +52580,7 @@
#. Label of a Card Break in the Manufacturing Workspace
#: manufacturing/workspace/manufacturing/manufacturing.json
-#: setup/doctype/company/company.py:346
+#: setup/doctype/company/company.py:347
msgid "Production"
msgstr ""
@@ -52684,7 +52752,6 @@
msgstr ""
#: setup/setup_wizard/operations/install_fixtures.py:39
-#: templates/pages/home.html:31
msgid "Products"
msgstr ""
@@ -52721,7 +52788,7 @@
#. Label of a chart in the Accounting Workspace
#: accounts/workspace/accounting/accounting.json
-#: public/js/financial_statements.js:84
+#: public/js/financial_statements.js:136
msgid "Profit and Loss"
msgstr ""
@@ -52732,9 +52799,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Profit and Loss Statement"
msgstr ""
@@ -52755,15 +52822,15 @@
msgid "Profit for the year"
msgstr ""
-#. Label of a Card Break in the Accounting Workspace
-#: accounts/workspace/accounting/accounting.json
+#. Label of a Card Break in the Financial Reports Workspace
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Profitability"
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/profitability_analysis/profitability_analysis.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Profitability Analysis"
msgstr ""
@@ -52790,10 +52857,10 @@
#: accounts/doctype/sales_invoice/sales_invoice.js:973
#: accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py:73
#: accounts/report/general_ledger/general_ledger.js:162
-#: accounts/report/general_ledger/general_ledger.py:631
+#: accounts/report/general_ledger/general_ledger.py:634
#: accounts/report/gross_profit/gross_profit.py:300
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:220
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:258
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:265
#: accounts/report/purchase_register/purchase_register.py:207
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:73
#: accounts/report/sales_register/sales_register.py:228
@@ -52812,9 +52879,9 @@
#: projects/report/timesheet_billing_summary/timesheet_billing_summary.js:19
#: projects/report/timesheet_billing_summary/timesheet_billing_summary.js:51
#: projects/report/timesheet_billing_summary/timesheet_billing_summary.py:25
-#: public/js/financial_statements.js:194 public/js/projects/timer.js:10
+#: public/js/financial_statements.js:247 public/js/projects/timer.js:10
#: public/js/purchase_trends_filters.js:52 public/js/sales_trends_filters.js:28
-#: selling/doctype/sales_order/sales_order.js:593
+#: selling/doctype/sales_order/sales_order.js:587
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:94
#: stock/report/reserved_stock/reserved_stock.js:139
#: stock/report/reserved_stock/reserved_stock.py:184
@@ -53528,10 +53595,6 @@
msgid "Provisional Profit / Loss (Credit)"
msgstr ""
-#: templates/pages/home.html:51
-msgid "Publications"
-msgstr ""
-
#. Label of a Date field in DocType 'Video'
#: utilities/doctype/video/video.json
msgctxt "Video"
@@ -53548,7 +53611,7 @@
#: accounts/doctype/shipping_rule/shipping_rule_dashboard.py:11
#: accounts/doctype/tax_category/tax_category_dashboard.py:10
#: projects/doctype/project/project_dashboard.py:16
-#: setup/doctype/company/company.py:334
+#: setup/doctype/company/company.py:335
msgid "Purchase"
msgstr ""
@@ -53644,11 +53707,11 @@
#: accounts/report/billed_items_to_be_received/billed_items_to_be_received.js:23
#: accounts/report/billed_items_to_be_received/billed_items_to_be_received.py:54
#: buying/doctype/purchase_order/purchase_order.js:323
-#: buying/doctype/purchase_order/purchase_order_list.js:37
+#: buying/doctype/purchase_order/purchase_order_list.js:39
#: buying/doctype/supplier_quotation/supplier_quotation_list.js:18
#: stock/doctype/purchase_receipt/purchase_receipt.js:110
#: stock/doctype/purchase_receipt/purchase_receipt.js:230
-#: stock/doctype/purchase_receipt/purchase_receipt_list.js:20
+#: stock/doctype/purchase_receipt/purchase_receipt_list.js:22
#: stock/doctype/stock_entry/stock_entry.js:262
msgid "Purchase Invoice"
msgstr ""
@@ -53711,10 +53774,12 @@
msgid "Purchase Invoice"
msgstr ""
-#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
+#. Label of a shortcut in the Payables Workspace
#. Label of a Link in the Buying Workspace
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
#: buying/workspace/buying/buying.json
msgctxt "Purchase Invoice"
msgid "Purchase Invoice"
@@ -53762,15 +53827,15 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Label of a Link in the Buying Workspace
#: accounts/report/purchase_invoice_trends/purchase_invoice_trends.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: buying/workspace/buying/buying.json
msgid "Purchase Invoice Trends"
msgstr ""
-#: assets/doctype/asset/asset.py:212
+#: assets/doctype/asset/asset.py:213
msgid "Purchase Invoice cannot be made against an existing asset {0}"
msgstr ""
@@ -53779,7 +53844,7 @@
msgid "Purchase Invoice {0} is already submitted"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1811
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1769
msgid "Purchase Invoices"
msgstr ""
@@ -53794,7 +53859,7 @@
#: crm/doctype/contract/contract.json
#: crm/doctype/contract_template/contract_template.json
#: setup/doctype/incoterm/incoterm.json
-#: setup/doctype/supplier_group/supplier_group.json
+#: setup/doctype/supplier_group/supplier_group.json stock/doctype/bin/bin.json
#: stock/doctype/material_request/material_request.json
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
#: subcontracting/doctype/subcontracting_order/subcontracting_order.json
@@ -53822,8 +53887,8 @@
#: buying/report/purchase_order_analysis/purchase_order_analysis.py:167
#: controllers/buying_controller.py:624
#: manufacturing/doctype/blanket_order/blanket_order.js:45
-#: selling/doctype/sales_order/sales_order.js:109
-#: selling/doctype/sales_order/sales_order.js:582
+#: selling/doctype/sales_order/sales_order.js:112
+#: selling/doctype/sales_order/sales_order.js:576
#: stock/doctype/material_request/material_request.js:137
#: stock/doctype/purchase_receipt/purchase_receipt.js:194
msgid "Purchase Order"
@@ -53923,12 +53988,12 @@
msgid "Purchase Order Amount(Company Currency)"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#. Name of a report
#. Label of a Link in the Buying Workspace
#. Label of a shortcut in the Buying Workspace
#. Label of a Link in the Stock Workspace
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
#: buying/report/purchase_order_analysis/purchase_order_analysis.json
#: buying/workspace/buying/buying.json stock/workspace/stock/stock.json
msgid "Purchase Order Analysis"
@@ -54026,7 +54091,7 @@
msgid "Purchase Order Trends"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:963
+#: selling/doctype/sales_order/sales_order.js:957
msgid "Purchase Order already created for all Sales Order items"
msgstr ""
@@ -54038,7 +54103,7 @@
msgid "Purchase Order {0} is not submitted"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:820
+#: buying/doctype/purchase_order/purchase_order.py:824
msgid "Purchase Orders"
msgstr ""
@@ -54048,7 +54113,7 @@
msgid "Purchase Orders Items Overdue"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:297
+#: buying/doctype/purchase_order/purchase_order.py:301
msgid "Purchase Orders are not allowed for {0} due to a scorecard standing of {1}."
msgstr ""
@@ -54064,7 +54129,7 @@
msgid "Purchase Orders to Receive"
msgstr ""
-#: controllers/accounts_controller.py:1476
+#: controllers/accounts_controller.py:1517
msgid "Purchase Orders {0} are un-linked"
msgstr ""
@@ -54081,7 +54146,7 @@
#: accounts/report/purchase_register/purchase_register.py:223
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.py:20
#: buying/doctype/purchase_order/purchase_order.js:310
-#: buying/doctype/purchase_order/purchase_order_list.js:41
+#: buying/doctype/purchase_order/purchase_order_list.js:43
#: stock/doctype/purchase_receipt/purchase_receipt.json
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js:56
msgid "Purchase Receipt"
@@ -54236,9 +54301,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#: accounts/report/purchase_register/purchase_register.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
msgid "Purchase Register"
msgstr ""
@@ -54513,14 +54578,14 @@
#: public/js/bom_configurator/bom_configurator.bundle.js:266
#: public/js/bom_configurator/bom_configurator.bundle.js:271
#: public/js/bom_configurator/bom_configurator.bundle.js:344
-#: public/js/utils.js:660 selling/doctype/sales_order/sales_order.js:321
-#: selling/doctype/sales_order/sales_order.js:416
-#: selling/doctype/sales_order/sales_order.js:704
-#: selling/doctype/sales_order/sales_order.js:821
+#: public/js/utils.js:660 selling/doctype/sales_order/sales_order.js:315
+#: selling/doctype/sales_order/sales_order.js:410
+#: selling/doctype/sales_order/sales_order.js:698
+#: selling/doctype/sales_order/sales_order.js:815
#: selling/report/sales_order_analysis/sales_order_analysis.py:255
#: selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py:106
#: stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py:166
-#: stock/report/serial_no_ledger/serial_no_ledger.py:71
+#: stock/report/serial_no_ledger/serial_no_ledger.py:70
#: templates/generators/bom.html:50 templates/pages/rfq.html:40
msgid "Qty"
msgstr ""
@@ -54868,7 +54933,7 @@
msgid "Qty to Deliver"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:249
+#: public/js/utils/serial_no_batch_selector.js:321
msgid "Qty to Fetch"
msgstr ""
@@ -55218,7 +55283,7 @@
msgid "Quality Inspection(s)"
msgstr ""
-#: setup/doctype/company/company.py:376
+#: setup/doctype/company/company.py:377
msgid "Quality Management"
msgstr ""
@@ -55322,7 +55387,7 @@
#: manufacturing/doctype/bom/bom.js:306
#: manufacturing/doctype/bom_creator/bom_creator.js:69
#: public/js/controllers/buying.js:518 public/js/stock_analytics.js:37
-#: public/js/utils/serial_no_batch_selector.js:321
+#: public/js/utils/serial_no_batch_selector.js:393
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:42
#: selling/report/sales_analytics/sales_analytics.js:29
#: selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py:67
@@ -55591,11 +55656,11 @@
msgid "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:621
+#: manufacturing/doctype/bom/bom.py:623
msgid "Quantity required for Item {0} in row {1}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:566
+#: manufacturing/doctype/bom/bom.py:568
msgid "Quantity should be greater than 0"
msgstr ""
@@ -55623,7 +55688,7 @@
msgid "Quantity to Produce should be greater than zero."
msgstr ""
-#: public/js/utils/barcode_scanner.js:212
+#: public/js/utils/barcode_scanner.js:227
msgid "Quantity to Scan"
msgstr ""
@@ -55637,7 +55702,7 @@
#: buying/report/purchase_analytics/purchase_analytics.js:63
#: manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.js:59
#: manufacturing/report/production_analytics/production_analytics.js:36
-#: public/js/financial_statements.js:165
+#: public/js/financial_statements.js:218
#: public/js/purchase_trends_filters.js:20 public/js/sales_trends_filters.js:12
#: public/js/stock_analytics.js:54
#: selling/report/sales_analytics/sales_analytics.js:63
@@ -55737,7 +55802,7 @@
msgid "Quick Entry"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:537
+#: accounts/doctype/journal_entry/journal_entry.js:527
msgid "Quick Journal Entry"
msgstr ""
@@ -55780,7 +55845,7 @@
#: crm/report/lead_details/lead_details.js:38
#: manufacturing/doctype/blanket_order/blanket_order.js:33
#: selling/doctype/quotation/quotation.json
-#: selling/doctype/sales_order/sales_order.js:619
+#: selling/doctype/sales_order/sales_order.js:613
msgid "Quotation"
msgstr ""
@@ -55888,15 +55953,15 @@
msgid "Quotation Trends"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:380
+#: selling/doctype/sales_order/sales_order.py:383
msgid "Quotation {0} is cancelled"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:297
+#: selling/doctype/sales_order/sales_order.py:300
msgid "Quotation {0} not of type {1}"
msgstr ""
-#: selling/doctype/quotation/quotation.py:325
+#: selling/doctype/quotation/quotation.py:326
#: selling/page/sales_funnel/sales_funnel.py:57
msgid "Quotations"
msgstr ""
@@ -55973,7 +56038,7 @@
#: accounts/doctype/pos_closing_entry/closing_voucher_details.html:66
#: accounts/report/billed_items_to_be_received/billed_items_to_be_received.py:79
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:263
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:308
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:315
#: accounts/report/share_ledger/share_ledger.py:56 public/js/utils.js:669
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:45
#: selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py:68
@@ -56136,12 +56201,6 @@
msgid "Rate"
msgstr ""
-#. Label of a Float field in DocType 'Purchase Taxes and Charges'
-#: accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
-msgctxt "Purchase Taxes and Charges"
-msgid "Rate"
-msgstr ""
-
#. Label of a Currency field in DocType 'Quotation Item'
#: selling/doctype/quotation_item/quotation_item.json
msgctxt "Quotation Item"
@@ -56160,12 +56219,6 @@
msgid "Rate"
msgstr ""
-#. Label of a Float field in DocType 'Sales Taxes and Charges'
-#: accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
-msgctxt "Sales Taxes and Charges"
-msgid "Rate"
-msgstr ""
-
#. Label of a Int field in DocType 'Share Balance'
#: accounts/doctype/share_balance/share_balance.json
msgctxt "Share Balance"
@@ -56757,15 +56810,15 @@
msgid "Raw Materials Warehouse"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:614
+#: manufacturing/doctype/bom/bom.py:616
msgid "Raw Materials cannot be blank."
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:304
#: manufacturing/doctype/production_plan/production_plan.js:97
#: manufacturing/doctype/work_order/work_order.js:574
-#: selling/doctype/sales_order/sales_order.js:532
-#: selling/doctype/sales_order/sales_order_list.js:47
+#: selling/doctype/sales_order/sales_order.js:526
+#: selling/doctype/sales_order/sales_order_list.js:49
#: stock/doctype/material_request/material_request.js:166
#: subcontracting/doctype/subcontracting_order/subcontracting_order.js:106
msgid "Re-open"
@@ -56793,10 +56846,6 @@
msgid "Read Only"
msgstr ""
-#: templates/pages/home.html:63
-msgid "Read blog"
-msgstr ""
-
#. Label of a Data field in DocType 'Quality Inspection Reading'
#: stock/doctype/quality_inspection_reading/quality_inspection_reading.json
msgctxt "Quality Inspection Reading"
@@ -56889,7 +56938,7 @@
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:565
-#: selling/doctype/sales_order/sales_order.js:1118
+#: selling/doctype/sales_order/sales_order.js:1112
msgid "Reason for Hold"
msgstr ""
@@ -56899,11 +56948,11 @@
msgid "Reason for Leaving"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:1133
+#: selling/doctype/sales_order/sales_order.js:1127
msgid "Reason for hold:"
msgstr ""
-#: manufacturing/doctype/bom_creator/bom_creator.js:133
+#: manufacturing/doctype/bom_creator/bom_creator.js:144
msgid "Rebuild Tree"
msgstr ""
@@ -56997,7 +57046,7 @@
msgstr ""
#: accounts/report/accounts_receivable/accounts_receivable.js:67
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:229
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:236
#: accounts/report/sales_register/sales_register.py:215
#: accounts/report/sales_register/sales_register.py:269
msgid "Receivable Account"
@@ -57013,6 +57062,11 @@
msgid "Receivable/Payable Account: {0} doesn't belong to company {1}"
msgstr ""
+#. Name of a Workspace
+#: accounts/workspace/receivables/receivables.json
+msgid "Receivables"
+msgstr ""
+
#. Label of a Check field in DocType 'Email Digest'
#: setup/doctype/email_digest/email_digest.json
msgctxt "Email Digest"
@@ -57069,7 +57123,7 @@
msgid "Received Amount After Tax (Company Currency)"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:874
+#: accounts/doctype/payment_entry/payment_entry.py:891
msgid "Received Amount cannot be greater than Paid Amount"
msgstr ""
@@ -57078,9 +57132,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#: accounts/report/received_items_to_be_billed/received_items_to_be_billed.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
msgid "Received Items To Be Billed"
msgstr ""
@@ -57232,7 +57286,7 @@
msgid "Reconcile"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:304
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:325
msgid "Reconcile Entries"
msgstr ""
@@ -57303,7 +57357,7 @@
msgid "Records"
msgstr ""
-#: regional/united_arab_emirates/utils.py:178
+#: regional/united_arab_emirates/utils.py:176
msgid "Recoverable Standard Rated expenses should not be set when Reverse Charge Applicable is Y"
msgstr ""
@@ -57428,7 +57482,7 @@
#: manufacturing/doctype/job_card/job_card_dashboard.py:10
#: manufacturing/doctype/work_order/work_order_dashboard.py:10
#: selling/doctype/sales_order/sales_order_dashboard.py:27
-#: stock/doctype/delivery_note/delivery_note_dashboard.py:22
+#: stock/doctype/delivery_note/delivery_note_dashboard.py:23
#: stock/doctype/material_request/material_request_dashboard.py:14
#: stock/doctype/purchase_receipt/purchase_receipt_dashboard.py:27
#: subcontracting/doctype/subcontracting_order/subcontracting_order_dashboard.py:7
@@ -57576,7 +57630,7 @@
msgid "Reference"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:947
+#: accounts/doctype/journal_entry/journal_entry.py:899
msgid "Reference #{0} dated {1}"
msgstr ""
@@ -57590,7 +57644,7 @@
msgid "Reference Date"
msgstr ""
-#: public/js/controllers/transaction.js:2043
+#: public/js/controllers/transaction.js:2073
msgid "Reference Date for Early Payment Discount"
msgstr ""
@@ -57612,7 +57666,7 @@
msgid "Reference Doctype"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:553
+#: accounts/doctype/payment_entry/payment_entry.py:555
msgid "Reference Doctype must be one of {0}"
msgstr ""
@@ -57781,19 +57835,19 @@
msgid "Reference Name"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:516
+#: accounts/doctype/journal_entry/journal_entry.py:532
msgid "Reference No & Reference Date is required for {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1067
+#: accounts/doctype/payment_entry/payment_entry.py:1087
msgid "Reference No and Reference Date is mandatory for Bank transaction"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:521
+#: accounts/doctype/journal_entry/journal_entry.py:537
msgid "Reference No is mandatory if you entered Reference Date"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:255
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:260
msgid "Reference No."
msgstr ""
@@ -57974,7 +58028,7 @@
msgid "References"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:629
+#: accounts/doctype/payment_entry/payment_entry.py:631
msgid "References {0} of type {1} had no outstanding amount left before submitting the Payment Entry. Now they have a negative outstanding amount."
msgstr ""
@@ -58010,7 +58064,7 @@
msgid "Refresh Token"
msgstr ""
-#: stock/reorder_item.py:264
+#: stock/reorder_item.py:303
msgid "Regards,"
msgstr ""
@@ -58141,7 +58195,7 @@
#: buying/doctype/purchase_order/purchase_order_dashboard.py:19
#: buying/doctype/supplier_quotation/supplier_quotation_dashboard.py:14
-#: stock/doctype/delivery_note/delivery_note_dashboard.py:21
+#: stock/doctype/delivery_note/delivery_note_dashboard.py:22
#: stock/doctype/purchase_receipt/purchase_receipt_dashboard.py:23
msgid "Related"
msgstr ""
@@ -58184,7 +58238,7 @@
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:186
-#: accounts/report/accounts_receivable/accounts_receivable.py:1062
+#: accounts/report/accounts_receivable/accounts_receivable.py:1085
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:181
msgid "Remaining Balance"
msgstr ""
@@ -58212,8 +58266,8 @@
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:240
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:311
#: accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.html:11
-#: accounts/report/accounts_receivable/accounts_receivable.py:1094
-#: accounts/report/general_ledger/general_ledger.py:658
+#: accounts/report/accounts_receivable/accounts_receivable.py:1117
+#: accounts/report/general_ledger/general_ledger.py:661
#: accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py:116
#: accounts/report/purchase_register/purchase_register.py:296
#: accounts/report/sales_register/sales_register.py:333
@@ -58336,7 +58390,7 @@
msgid "Remarks Column Length"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:322
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:323
msgid "Removed items with no change in quantity or value."
msgstr ""
@@ -58389,9 +58443,9 @@
msgid "Rented"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order_list.js:32
+#: buying/doctype/purchase_order/purchase_order_list.js:34
#: crm/doctype/opportunity/opportunity.js:113
-#: stock/doctype/delivery_note/delivery_note.js:237
+#: stock/doctype/delivery_note/delivery_note.js:228
#: stock/doctype/purchase_receipt/purchase_receipt.js:240
#: support/doctype/issue/issue.js:30
msgid "Reopen"
@@ -58549,14 +58603,21 @@
msgid "Report Type is mandatory"
msgstr ""
-#. Label of a Card Break in the Accounting Workspace
+#: accounts/report/balance_sheet/balance_sheet.js:17
+#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:17
+msgid "Report View"
+msgstr ""
+
+#. Label of a Card Break in the Payables Workspace
+#. Label of a Card Break in the Receivables Workspace
#. Label of a Card Break in the Assets Workspace
#. Label of a Card Break in the CRM Workspace
#. Label of a Card Break in the Manufacturing Workspace
#. Label of a Card Break in the Projects Workspace
#. Label of a Card Break in the Support Workspace
#: accounts/doctype/cost_center/cost_center_dashboard.py:7
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
+#: accounts/workspace/receivables/receivables.json
#: assets/workspace/assets/assets.json config/projects.py:73
#: crm/workspace/crm/crm.json
#: manufacturing/workspace/manufacturing/manufacturing.json
@@ -58825,7 +58886,7 @@
msgid "Request for Quotation Supplier"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:577
+#: selling/doctype/sales_order/sales_order.js:571
msgid "Request for Raw Materials"
msgstr ""
@@ -58839,6 +58900,13 @@
msgid "Requested"
msgstr ""
+#. Option for the 'Advance Payment Status' (Select) field in DocType 'Sales
+#. Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "Requested"
+msgstr ""
+
#. Name of a report
#. Label of a Link in the Stock Workspace
#: stock/report/requested_items_to_be_transferred/requested_items_to_be_transferred.json
@@ -59038,7 +59106,7 @@
msgid "Research"
msgstr ""
-#: setup/doctype/company/company.py:382
+#: setup/doctype/company/company.py:383
msgid "Research & Development"
msgstr ""
@@ -59089,7 +59157,7 @@
msgid "Reserve"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:328
+#: selling/doctype/sales_order/sales_order.js:322
msgid "Reserve Stock"
msgstr ""
@@ -59180,16 +59248,16 @@
msgid "Reserved Quantity for Production"
msgstr ""
-#: stock/stock_ledger.py:1893
+#: stock/stock_ledger.py:1982
msgid "Reserved Serial No."
msgstr ""
#. Name of a report
#: selling/doctype/sales_order/sales_order.js:79
-#: selling/doctype/sales_order/sales_order.js:380
+#: selling/doctype/sales_order/sales_order.js:374
#: stock/doctype/pick_list/pick_list.js:120
#: stock/report/reserved_stock/reserved_stock.json
-#: stock/report/stock_balance/stock_balance.py:459 stock/stock_ledger.py:1873
+#: stock/report/stock_balance/stock_balance.py:459 stock/stock_ledger.py:1962
msgid "Reserved Stock"
msgstr ""
@@ -59199,7 +59267,7 @@
msgid "Reserved Stock"
msgstr ""
-#: stock/stock_ledger.py:1923
+#: stock/stock_ledger.py:2012
msgid "Reserved Stock for Batch"
msgstr ""
@@ -59231,7 +59299,7 @@
msgid "Reserved for sub contracting"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:341
+#: selling/doctype/sales_order/sales_order.js:335
#: stock/doctype/pick_list/pick_list.js:237
msgid "Reserving Stock..."
msgstr ""
@@ -59481,7 +59549,7 @@
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:290
-#: selling/doctype/sales_order/sales_order.js:521
+#: selling/doctype/sales_order/sales_order.js:515
msgid "Resume"
msgstr ""
@@ -59739,7 +59807,7 @@
#: accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py:25
#: accounts/doctype/sales_invoice/sales_invoice_dashboard.py:35
-#: stock/doctype/delivery_note/delivery_note_dashboard.py:23
+#: stock/doctype/delivery_note/delivery_note_dashboard.py:24
#: stock/doctype/purchase_receipt/purchase_receipt_dashboard.py:30
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py:27
msgid "Returns"
@@ -60236,7 +60304,7 @@
msgid "Rounding Loss Allowance should be between 0 and 1"
msgstr ""
-#: controllers/stock_controller.py:222 controllers/stock_controller.py:239
+#: controllers/stock_controller.py:216 controllers/stock_controller.py:231
msgid "Rounding gain/loss Entry for Stock Transfer"
msgstr ""
@@ -60246,12 +60314,6 @@
msgid "Route"
msgstr ""
-#. Label of a Data field in DocType 'Homepage Section Card'
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgctxt "Homepage Section Card"
-msgid "Route"
-msgstr ""
-
#. Label of a Data field in DocType 'Sales Partner'
#: setup/doctype/sales_partner/sales_partner.json
msgctxt "Sales Partner"
@@ -60283,11 +60345,11 @@
msgid "Routing Name"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:427
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:428
msgid "Row #"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:333
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:334
msgid "Row # {0}:"
msgstr ""
@@ -60303,13 +60365,13 @@
msgid "Row # {0}: Returned Item {1} does not exist in {2} {3}"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:441
-#: accounts/doctype/sales_invoice/sales_invoice.py:1738
+#: accounts/doctype/pos_invoice/pos_invoice.py:439
+#: accounts/doctype/sales_invoice/sales_invoice.py:1715
msgid "Row #{0} (Payment Table): Amount must be negative"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:439
-#: accounts/doctype/sales_invoice/sales_invoice.py:1733
+#: accounts/doctype/pos_invoice/pos_invoice.py:437
+#: accounts/doctype/sales_invoice/sales_invoice.py:1710
msgid "Row #{0} (Payment Table): Amount must be positive"
msgstr ""
@@ -60338,20 +60400,20 @@
msgid "Row #{0}: Accepted Warehouse is mandatory for the accepted Item {1}"
msgstr ""
-#: controllers/accounts_controller.py:853
+#: controllers/accounts_controller.py:887
msgid "Row #{0}: Account {1} does not belong to company {2}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:303
-#: accounts/doctype/payment_entry/payment_entry.py:387
+#: accounts/doctype/payment_entry/payment_entry.py:305
+#: accounts/doctype/payment_entry/payment_entry.py:389
msgid "Row #{0}: Allocated Amount cannot be greater than outstanding amount."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:399
+#: accounts/doctype/payment_entry/payment_entry.py:401
msgid "Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:300
+#: assets/doctype/asset_capitalization/asset_capitalization.py:309
msgid "Row #{0}: Amount must be a positive number"
msgstr ""
@@ -60359,7 +60421,7 @@
msgid "Row #{0}: Asset {1} cannot be submitted, it is already {2}"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:347
+#: buying/doctype/purchase_order/purchase_order.py:351
msgid "Row #{0}: BOM is not specified for subcontracting item {0}"
msgstr ""
@@ -60367,27 +60429,27 @@
msgid "Row #{0}: Batch No {1} is already selected."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:734
+#: accounts/doctype/payment_entry/payment_entry.py:736
msgid "Row #{0}: Cannot allocate more than {1} against payment term {2}"
msgstr ""
-#: controllers/accounts_controller.py:3005
+#: controllers/accounts_controller.py:3064
msgid "Row #{0}: Cannot delete item {1} which has already been billed."
msgstr ""
-#: controllers/accounts_controller.py:2979
+#: controllers/accounts_controller.py:3038
msgid "Row #{0}: Cannot delete item {1} which has already been delivered"
msgstr ""
-#: controllers/accounts_controller.py:2998
+#: controllers/accounts_controller.py:3057
msgid "Row #{0}: Cannot delete item {1} which has already been received"
msgstr ""
-#: controllers/accounts_controller.py:2985
+#: controllers/accounts_controller.py:3044
msgid "Row #{0}: Cannot delete item {1} which has work order assigned to it."
msgstr ""
-#: controllers/accounts_controller.py:2991
+#: controllers/accounts_controller.py:3050
msgid "Row #{0}: Cannot delete item {1} which is assigned to customer's purchase order."
msgstr ""
@@ -60395,7 +60457,7 @@
msgid "Row #{0}: Cannot select Supplier Warehouse while suppling raw materials to subcontractor"
msgstr ""
-#: controllers/accounts_controller.py:3250
+#: controllers/accounts_controller.py:3309
msgid "Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}."
msgstr ""
@@ -60411,23 +60473,23 @@
msgid "Row #{0}: Clearance date {1} cannot be before Cheque Date {2}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:277
+#: assets/doctype/asset_capitalization/asset_capitalization.py:286
msgid "Row #{0}: Consumed Asset {1} cannot be Draft"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:279
+#: assets/doctype/asset_capitalization/asset_capitalization.py:288
msgid "Row #{0}: Consumed Asset {1} cannot be cancelled"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:264
+#: assets/doctype/asset_capitalization/asset_capitalization.py:273
msgid "Row #{0}: Consumed Asset {1} cannot be the same as the Target Asset"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:273
+#: assets/doctype/asset_capitalization/asset_capitalization.py:282
msgid "Row #{0}: Consumed Asset {1} cannot be {2}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:283
+#: assets/doctype/asset_capitalization/asset_capitalization.py:292
msgid "Row #{0}: Consumed Asset {1} does not belong to company {2}"
msgstr ""
@@ -60443,31 +60505,31 @@
msgid "Row #{0}: Dates overlapping with other row"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:371
+#: buying/doctype/purchase_order/purchase_order.py:375
msgid "Row #{0}: Default BOM not found for FG Item {1}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:270
+#: accounts/doctype/payment_entry/payment_entry.py:272
msgid "Row #{0}: Duplicate entry in References {1} {2}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:234
+#: selling/doctype/sales_order/sales_order.py:237
msgid "Row #{0}: Expected Delivery Date cannot be before Purchase Order Date"
msgstr ""
-#: controllers/stock_controller.py:344
+#: controllers/stock_controller.py:336
msgid "Row #{0}: Expense Account not set for the Item {1}. {2}"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:374
+#: buying/doctype/purchase_order/purchase_order.py:378
msgid "Row #{0}: Finished Good Item Qty can not be zero"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:358
+#: buying/doctype/purchase_order/purchase_order.py:362
msgid "Row #{0}: Finished Good Item is not specified for service item {1}"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:365
+#: buying/doctype/purchase_order/purchase_order.py:369
msgid "Row #{0}: Finished Good Item {1} must be a sub-contracted item"
msgstr ""
@@ -60475,11 +60537,11 @@
msgid "Row #{0}: Finished Good reference is mandatory for Scrap Item {1}."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:555
+#: accounts/doctype/journal_entry/journal_entry.py:571
msgid "Row #{0}: For {1}, you can select reference document only if account gets credited"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:561
+#: accounts/doctype/journal_entry/journal_entry.py:577
msgid "Row #{0}: For {1}, you can select reference document only if account gets debited"
msgstr ""
@@ -60487,7 +60549,7 @@
msgid "Row #{0}: From Date cannot be before To Date"
msgstr ""
-#: public/js/utils/barcode_scanner.js:474
+#: public/js/utils/barcode_scanner.js:489
msgid "Row #{0}: Item added"
msgstr ""
@@ -60499,19 +60561,19 @@
msgid "Row #{0}: Item {1} has been picked, please reserve stock from the Pick List."
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:490
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:491
msgid "Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it."
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:294
+#: assets/doctype/asset_capitalization/asset_capitalization.py:303
msgid "Row #{0}: Item {1} is not a service item"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:252
+#: assets/doctype/asset_capitalization/asset_capitalization.py:261
msgid "Row #{0}: Item {1} is not a stock item"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:655
+#: accounts/doctype/payment_entry/payment_entry.py:657
msgid "Row #{0}: Journal Entry {1} does not have account {2} or already matched against another voucher"
msgstr ""
@@ -60519,7 +60581,7 @@
msgid "Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:532
+#: selling/doctype/sales_order/sales_order.py:535
msgid "Row #{0}: Not allowed to change Supplier as Purchase Order already exists"
msgstr ""
@@ -60551,16 +60613,16 @@
msgid "Row #{0}: Please set reorder quantity"
msgstr ""
-#: controllers/accounts_controller.py:364
+#: controllers/accounts_controller.py:367
msgid "Row #{0}: Please update deferred revenue/expense account in item row or default account in company master"
msgstr ""
-#: public/js/utils/barcode_scanner.js:472
+#: public/js/utils/barcode_scanner.js:487
msgid "Row #{0}: Qty increased by {1}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:255
-#: assets/doctype/asset_capitalization/asset_capitalization.py:297
+#: assets/doctype/asset_capitalization/asset_capitalization.py:264
+#: assets/doctype/asset_capitalization/asset_capitalization.py:306
msgid "Row #{0}: Qty must be a positive number"
msgstr ""
@@ -60568,8 +60630,8 @@
msgid "Row #{0}: Qty should be less than or equal to Available Qty to Reserve (Actual Qty - Reserved Qty) {1} for Iem {2} against Batch {3} in Warehouse {4}."
msgstr ""
-#: controllers/accounts_controller.py:984
-#: controllers/accounts_controller.py:3107
+#: controllers/accounts_controller.py:1018
+#: controllers/accounts_controller.py:3166
msgid "Row #{0}: Quantity for Item {1} cannot be zero."
msgstr ""
@@ -60585,11 +60647,11 @@
msgid "Row #{0}: Received Qty must be equal to Accepted + Rejected Qty for Item {1}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:1005
+#: accounts/doctype/payment_entry/payment_entry.js:1016
msgid "Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:997
+#: accounts/doctype/payment_entry/payment_entry.js:1008
msgid "Row #{0}: Reference Document Type must be one of Sales Order, Sales Invoice, Journal Entry or Dunning"
msgstr ""
@@ -60633,19 +60695,19 @@
msgid "Row #{0}: Serial No {1} is already selected."
msgstr ""
-#: controllers/accounts_controller.py:392
+#: controllers/accounts_controller.py:395
msgid "Row #{0}: Service End Date cannot be before Invoice Posting Date"
msgstr ""
-#: controllers/accounts_controller.py:388
+#: controllers/accounts_controller.py:391
msgid "Row #{0}: Service Start Date cannot be greater than Service End Date"
msgstr ""
-#: controllers/accounts_controller.py:384
+#: controllers/accounts_controller.py:387
msgid "Row #{0}: Service Start and End Date is required for deferred accounting"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:388
+#: selling/doctype/sales_order/sales_order.py:391
msgid "Row #{0}: Set Supplier for item {1}"
msgstr ""
@@ -60653,7 +60715,7 @@
msgid "Row #{0}: Status is mandatory"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:365
+#: accounts/doctype/journal_entry/journal_entry.py:381
msgid "Row #{0}: Status must be {1} for Invoice Discounting {2}"
msgstr ""
@@ -60689,7 +60751,7 @@
msgid "Row #{0}: The batch {1} has already expired."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1710
+#: accounts/doctype/sales_invoice/sales_invoice.py:1687
msgid "Row #{0}: The following Serial Nos are not present in Delivery Note {1}:"
msgstr ""
@@ -60701,11 +60763,11 @@
msgid "Row #{0}: You cannot use the inventory dimension '{1}' in Stock Reconciliation to modify the quantity or valuation rate. Stock reconciliation with inventory dimensions is intended solely for performing opening entries."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1409
+#: accounts/doctype/sales_invoice/sales_invoice.py:1402
msgid "Row #{0}: You must select an Asset for Item {1}."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1719
+#: accounts/doctype/sales_invoice/sales_invoice.py:1696
msgid "Row #{0}: {1} Serial numbers required for Item {2}. You have provided {3}."
msgstr ""
@@ -60733,15 +60795,15 @@
msgid "Row #{}: Currency of {} - {} doesn't matches company currency."
msgstr ""
-#: assets/doctype/asset/asset.py:274
+#: assets/doctype/asset/asset.py:275
msgid "Row #{}: Depreciation Posting Date should not be equal to Available for Use Date."
msgstr ""
-#: assets/doctype/asset/asset.py:307
+#: assets/doctype/asset/asset.py:308
msgid "Row #{}: Finance Book should not be empty since you're using multiple."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:340
+#: accounts/doctype/pos_invoice/pos_invoice.py:338
msgid "Row #{}: Item Code: {} is not available under warehouse {}."
msgstr ""
@@ -60762,23 +60824,23 @@
msgstr ""
#: assets/doctype/asset_maintenance/asset_maintenance.py:43
-msgid "Row #{}: Please asign task to a member."
+msgid "Row #{}: Please assign task to a member."
msgstr ""
-#: assets/doctype/asset/asset.py:299
+#: assets/doctype/asset/asset.py:300
msgid "Row #{}: Please use a different Finance Book."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:400
+#: accounts/doctype/pos_invoice/pos_invoice.py:398
msgid "Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {}"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:347
+#: accounts/doctype/pos_invoice/pos_invoice.py:345
msgid "Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:373
-msgid "Row #{}: You cannot add postive quantities in a return invoice. Please remove item {} to complete the return."
+#: accounts/doctype/pos_invoice/pos_invoice.py:371
+msgid "Row #{}: You cannot add positive quantities in a return invoice. Please remove item {} to complete the return."
msgstr ""
#: stock/doctype/pick_list/pick_list.py:83
@@ -60821,11 +60883,11 @@
msgid "Row {0}: Accepted Qty and Rejected Qty can't be zero at the same time."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:493
+#: accounts/doctype/journal_entry/journal_entry.py:509
msgid "Row {0}: Account {1} and Party Type {2} have different account types"
msgstr ""
-#: controllers/accounts_controller.py:2467
+#: controllers/accounts_controller.py:2536
msgid "Row {0}: Account {1} is a Group Account"
msgstr ""
@@ -60833,19 +60895,19 @@
msgid "Row {0}: Activity Type is mandatory."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:545
+#: accounts/doctype/journal_entry/journal_entry.py:561
msgid "Row {0}: Advance against Customer must be credit"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:547
+#: accounts/doctype/journal_entry/journal_entry.py:563
msgid "Row {0}: Advance against Supplier must be debit"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:643
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:671
msgid "Row {0}: Allocated amount {1} must be less than or equal to invoice outstanding amount {2}"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:635
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:663
msgid "Row {0}: Allocated amount {1} must be less than or equal to remaining payment amount {2}"
msgstr ""
@@ -60853,7 +60915,7 @@
msgid "Row {0}: Bill of Materials not found for the Item {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:844
+#: accounts/doctype/journal_entry/journal_entry.py:796
msgid "Row {0}: Both Debit and Credit values cannot be zero"
msgstr ""
@@ -60861,7 +60923,7 @@
msgid "Row {0}: Conversion Factor is mandatory"
msgstr ""
-#: controllers/accounts_controller.py:2480
+#: controllers/accounts_controller.py:2549
msgid "Row {0}: Cost Center {1} does not belong to Company {2}"
msgstr ""
@@ -60869,15 +60931,15 @@
msgid "Row {0}: Cost center is required for an item {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:631
+#: accounts/doctype/journal_entry/journal_entry.py:647
msgid "Row {0}: Credit entry can not be linked with a {1}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:432
+#: manufacturing/doctype/bom/bom.py:434
msgid "Row {0}: Currency of the BOM #{1} should be equal to the selected currency {2}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:626
+#: accounts/doctype/journal_entry/journal_entry.py:642
msgid "Row {0}: Debit entry can not be linked with a {1}"
msgstr ""
@@ -60885,11 +60947,11 @@
msgid "Row {0}: Delivery Warehouse ({1}) and Customer Warehouse ({2}) can not be same"
msgstr ""
-#: assets/doctype/asset/asset.py:416
+#: assets/doctype/asset/asset.py:417
msgid "Row {0}: Depreciation Start Date is required"
msgstr ""
-#: controllers/accounts_controller.py:2140
+#: controllers/accounts_controller.py:2209
msgid "Row {0}: Due Date in the Payment Terms table cannot be before Posting Date"
msgstr ""
@@ -60901,12 +60963,12 @@
msgid "Row {0}: Enter location for the asset item {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:934
-#: controllers/taxes_and_totals.py:1106
+#: accounts/doctype/journal_entry/journal_entry.py:886
+#: controllers/taxes_and_totals.py:1115
msgid "Row {0}: Exchange Rate is mandatory"
msgstr ""
-#: assets/doctype/asset/asset.py:407
+#: assets/doctype/asset/asset.py:408
msgid "Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount"
msgstr ""
@@ -60935,7 +60997,7 @@
msgid "Row {0}: From Time and To Time of {1} is overlapping with {2}"
msgstr ""
-#: controllers/stock_controller.py:739
+#: controllers/stock_controller.py:730
msgid "Row {0}: From Warehouse is mandatory for internal transfers"
msgstr ""
@@ -60947,11 +61009,11 @@
msgid "Row {0}: Hours value must be greater than zero."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:649
+#: accounts/doctype/journal_entry/journal_entry.py:665
msgid "Row {0}: Invalid reference {1}"
msgstr ""
-#: controllers/taxes_and_totals.py:127
+#: controllers/taxes_and_totals.py:128
msgid "Row {0}: Item Tax template updated as per validity and rate applied"
msgstr ""
@@ -60975,11 +61037,11 @@
msgid "Row {0}: Packing Slip is already created for Item {1}."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:671
+#: accounts/doctype/journal_entry/journal_entry.py:687
msgid "Row {0}: Party / Account does not match with {1} / {2} in {3} {4}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:484
+#: accounts/doctype/journal_entry/journal_entry.py:500
msgid "Row {0}: Party Type and Party is required for Receivable / Payable account {1}"
msgstr ""
@@ -60987,11 +61049,11 @@
msgid "Row {0}: Payment Term is mandatory"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:538
+#: accounts/doctype/journal_entry/journal_entry.py:554
msgid "Row {0}: Payment against Sales/Purchase Order should always be marked as advance"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:531
+#: accounts/doctype/journal_entry/journal_entry.py:547
msgid "Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry."
msgstr ""
@@ -61055,7 +61117,7 @@
msgid "Row {0}: Subcontracted Item is mandatory for the raw material {1}"
msgstr ""
-#: controllers/stock_controller.py:730
+#: controllers/stock_controller.py:721
msgid "Row {0}: Target Warehouse is mandatory for internal transfers"
msgstr ""
@@ -61067,7 +61129,7 @@
msgid "Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}"
msgstr ""
-#: assets/doctype/asset/asset.py:440
+#: assets/doctype/asset/asset.py:441
msgid "Row {0}: Total Number of Depreciations cannot be less than or equal to Number of Depreciations Booked"
msgstr ""
@@ -61075,7 +61137,7 @@
msgid "Row {0}: UOM Conversion Factor is mandatory"
msgstr ""
-#: controllers/accounts_controller.py:783
+#: controllers/accounts_controller.py:786
msgid "Row {0}: user has not applied the rule {1} on the item {2}"
msgstr ""
@@ -61087,15 +61149,15 @@
msgid "Row {0}: {1} must be greater than 0"
msgstr ""
-#: controllers/accounts_controller.py:508
+#: controllers/accounts_controller.py:511
msgid "Row {0}: {1} {2} cannot be same as {3} (Party Account) {4}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:685
+#: accounts/doctype/journal_entry/journal_entry.py:701
msgid "Row {0}: {1} {2} does not match with {3}"
msgstr ""
-#: controllers/accounts_controller.py:2459
+#: controllers/accounts_controller.py:2528
msgid "Row {0}: {3} Account {1} does not belong to Company {2}"
msgstr ""
@@ -61130,7 +61192,7 @@
msgid "Rows with Same Account heads will be merged on Ledger"
msgstr ""
-#: controllers/accounts_controller.py:2149
+#: controllers/accounts_controller.py:2218
msgid "Rows with duplicate due dates in other rows were found: {0}"
msgstr ""
@@ -61138,7 +61200,7 @@
msgid "Rows: {0} have 'Payment Entry' as reference_type. This should not be set manually."
msgstr ""
-#: controllers/accounts_controller.py:208
+#: controllers/accounts_controller.py:211
msgid "Rows: {0} in {1} section are Invalid. Reference Name should point to a valid Payment Entry or Journal Entry."
msgstr ""
@@ -61377,7 +61439,7 @@
#: accounts/doctype/tax_category/tax_category_dashboard.py:9
#: projects/doctype/project/project_dashboard.py:15
#: regional/report/vat_audit_report/vat_audit_report.py:184
-#: setup/doctype/company/company.py:328 setup/doctype/company/company.py:491
+#: setup/doctype/company/company.py:329 setup/doctype/company/company.py:492
#: setup/doctype/company/company_dashboard.py:9
#: setup/doctype/sales_person/sales_person_dashboard.py:12
#: setup/setup_wizard/operations/install_fixtures.py:250
@@ -61415,7 +61477,7 @@
msgid "Sales"
msgstr ""
-#: setup/doctype/company/company.py:491
+#: setup/doctype/company/company.py:492
msgid "Sales Account"
msgstr ""
@@ -61461,9 +61523,9 @@
#: accounts/report/gross_profit/gross_profit.py:199
#: accounts/report/gross_profit/gross_profit.py:206
#: selling/doctype/quotation/quotation_list.js:20
-#: selling/doctype/sales_order/sales_order.js:571
-#: selling/doctype/sales_order/sales_order_list.js:51
-#: stock/doctype/delivery_note/delivery_note.js:231
+#: selling/doctype/sales_order/sales_order.js:565
+#: selling/doctype/sales_order/sales_order_list.js:53
+#: stock/doctype/delivery_note/delivery_note.js:222
#: stock/doctype/delivery_note/delivery_note_list.js:61
msgid "Sales Invoice"
msgstr ""
@@ -61525,11 +61587,13 @@
msgid "Sales Invoice"
msgstr ""
-#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
+#. Label of a shortcut in the Receivables Workspace
#. Label of a Link in the Selling Workspace
#. Label of a shortcut in the Home Workspace
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
#: selling/workspace/selling/selling.json setup/workspace/home/home.json
msgctxt "Sales Invoice"
msgid "Sales Invoice"
@@ -61604,10 +61668,10 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Label of a Link in the Selling Workspace
#: accounts/report/sales_invoice_trends/sales_invoice_trends.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: selling/workspace/selling/selling.json
msgid "Sales Invoice Trends"
msgstr ""
@@ -61616,7 +61680,7 @@
msgid "Sales Invoice {0} has already been submitted"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:469
+#: selling/doctype/sales_order/sales_order.py:472
msgid "Sales Invoice {0} must be deleted before cancelling this Sales Order"
msgstr ""
@@ -61648,7 +61712,7 @@
#: setup/doctype/incoterm/incoterm.json
#: setup/doctype/sales_partner/sales_partner.json
#: setup/doctype/sales_person/sales_person.json
-#: setup/doctype/territory/territory.json
+#: setup/doctype/territory/territory.json stock/doctype/bin/bin.json
#: stock/doctype/packing_slip/packing_slip.json
msgid "Sales Manager"
msgstr ""
@@ -61679,10 +61743,14 @@
msgid "Sales Monthly History"
msgstr ""
+#: selling/page/sales_funnel/sales_funnel.js:129
+msgid "Sales Opportunities by Source"
+msgstr ""
+
#. Name of a DocType
#. Title of an Onboarding Step
#: accounts/doctype/sales_invoice/sales_invoice.js:236
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:272
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:279
#: accounts/report/sales_register/sales_register.py:236
#: controllers/selling_controller.py:421
#: maintenance/doctype/maintenance_schedule/maintenance_schedule.js:64
@@ -61700,7 +61768,7 @@
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:13
#: selling/report/sales_order_analysis/sales_order_analysis.js:34
#: selling/report/sales_order_analysis/sales_order_analysis.py:222
-#: stock/doctype/delivery_note/delivery_note.js:143
+#: stock/doctype/delivery_note/delivery_note.js:134
#: stock/doctype/material_request/material_request.js:161
#: stock/report/delayed_item_report/delayed_item_report.js:31
#: stock/report/delayed_item_report/delayed_item_report.py:155
@@ -61832,11 +61900,11 @@
msgid "Sales Order"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#. Name of a report
#. Label of a Link in the Selling Workspace
#. Label of a Link in the Stock Workspace
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
#: selling/report/sales_order_analysis/sales_order_analysis.json
#: selling/workspace/selling/selling.json stock/workspace/stock/stock.json
msgid "Sales Order Analysis"
@@ -61855,8 +61923,8 @@
msgstr ""
#. Name of a DocType
-#: selling/doctype/sales_order/sales_order.js:266
-#: selling/doctype/sales_order/sales_order.js:710
+#: selling/doctype/sales_order/sales_order.js:260
+#: selling/doctype/sales_order/sales_order.js:704
#: selling/doctype/sales_order_item/sales_order_item.json
msgid "Sales Order Item"
msgstr ""
@@ -61945,11 +62013,11 @@
msgid "Sales Order required for Item {0}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:255
+#: selling/doctype/sales_order/sales_order.py:258
msgid "Sales Order {0} already exists against Customer's Purchase Order {1}. To allow multiple Sales Orders, Enable {2} in {3}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1139
+#: accounts/doctype/sales_invoice/sales_invoice.py:1142
msgid "Sales Order {0} is not submitted"
msgstr ""
@@ -61991,7 +62059,7 @@
#. Name of a DocType
#: accounts/report/accounts_receivable/accounts_receivable.js:133
-#: accounts/report/accounts_receivable/accounts_receivable.py:1083
+#: accounts/report/accounts_receivable/accounts_receivable.py:1106
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:117
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:197
#: accounts/report/customer_ledger_summary/customer_ledger_summary.js:74
@@ -62123,25 +62191,25 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Label of a Link in the Selling Workspace
#: accounts/report/sales_partners_commission/sales_partners_commission.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: selling/workspace/selling/selling.json
msgid "Sales Partners Commission"
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/sales_payment_summary/sales_payment_summary.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Sales Payment Summary"
msgstr ""
#. Name of a DocType
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:155
#: accounts/report/accounts_receivable/accounts_receivable.js:139
-#: accounts/report/accounts_receivable/accounts_receivable.py:1080
+#: accounts/report/accounts_receivable/accounts_receivable.py:1103
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:123
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:194
#: accounts/report/customer_ledger_summary/customer_ledger_summary.js:80
@@ -62237,19 +62305,23 @@
msgid "Sales Pipeline Analytics"
msgstr ""
+#: selling/page/sales_funnel/sales_funnel.js:131
+msgid "Sales Pipeline by Stage"
+msgstr ""
+
#: stock/report/item_prices/item_prices.py:58
msgid "Sales Price List"
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Receivables Workspace
#: accounts/report/sales_register/sales_register.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/receivables/receivables.json
msgid "Sales Register"
msgstr ""
#: accounts/report/gross_profit/gross_profit.py:777
-#: stock/doctype/delivery_note/delivery_note.js:184
+#: stock/doctype/delivery_note/delivery_note.js:175
msgid "Sales Return"
msgstr ""
@@ -62522,7 +62594,7 @@
msgid "Same Item"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:349
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:350
msgid "Same item and warehouse combination already entered."
msgstr ""
@@ -62553,7 +62625,7 @@
msgstr ""
#: manufacturing/report/quality_inspection_summary/quality_inspection_summary.py:93
-#: public/js/controllers/transaction.js:2101
+#: public/js/controllers/transaction.js:2131
msgid "Sample Size"
msgstr ""
@@ -62563,7 +62635,7 @@
msgid "Sample Size"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2828
+#: stock/doctype/stock_entry/stock_entry.py:2824
msgid "Sample quantity {0} cannot be more than received quantity {1}"
msgstr ""
@@ -62637,7 +62709,7 @@
msgstr ""
#: accounts/doctype/bank_statement_import/bank_statement_import.js:139
-#: accounts/doctype/journal_entry/journal_entry.js:560
+#: accounts/doctype/journal_entry/journal_entry.js:550
#: accounts/doctype/ledger_merge/ledger_merge.js:75
#: accounts/doctype/purchase_invoice/purchase_invoice.js:252
#: accounts/doctype/purchase_invoice/purchase_invoice.js:288
@@ -62658,7 +62730,7 @@
msgid "Savings"
msgstr ""
-#: public/js/utils/barcode_scanner.js:191
+#: public/js/utils/barcode_scanner.js:206
msgid "Scan Barcode"
msgstr ""
@@ -62734,7 +62806,7 @@
msgid "Scan Barcode"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:147
+#: public/js/utils/serial_no_batch_selector.js:151
msgid "Scan Batch No"
msgstr ""
@@ -62750,11 +62822,11 @@
msgid "Scan Mode"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:132
+#: public/js/utils/serial_no_batch_selector.js:136
msgid "Scan Serial No"
msgstr ""
-#: public/js/utils/barcode_scanner.js:157
+#: public/js/utils/barcode_scanner.js:172
msgid "Scan barcode for item {0}"
msgstr ""
@@ -62768,7 +62840,7 @@
msgid "Scanned Cheque"
msgstr ""
-#: public/js/utils/barcode_scanner.js:223
+#: public/js/utils/barcode_scanner.js:238
msgid "Scanned Quantity"
msgstr ""
@@ -63060,36 +63132,11 @@
msgid "Secondary Role"
msgstr ""
-#. Label of a Select field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Section Based On"
-msgstr ""
-
-#. Label of a Section Break field in DocType 'Homepage Section'
-#. Label of a Table field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Section Cards"
-msgstr ""
-
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:169
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:174
#: accounts/report/tds_computation_summary/tds_computation_summary.py:117
msgid "Section Code"
msgstr ""
-#. Label of a Code field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Section HTML"
-msgstr ""
-
-#. Label of a Int field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Section Order"
-msgstr ""
-
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:95
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:140
msgid "Secured Loans"
@@ -63109,7 +63156,7 @@
msgstr ""
#: buying/doctype/purchase_order/purchase_order.js:180
-#: selling/doctype/sales_order/sales_order.js:894
+#: selling/doctype/sales_order/sales_order.js:888
msgid "Select"
msgstr ""
@@ -63129,19 +63176,19 @@
msgid "Select Attribute Values"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:695
+#: selling/doctype/sales_order/sales_order.js:689
msgid "Select BOM"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:684
+#: selling/doctype/sales_order/sales_order.js:678
msgid "Select BOM and Qty for Production"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:809
+#: selling/doctype/sales_order/sales_order.js:803
msgid "Select BOM, Qty and For Warehouse"
msgstr ""
-#: public/js/utils/sales_common.js:316
+#: public/js/utils/sales_common.js:325
#: selling/page/point_of_sale/pos_item_details.js:203
#: stock/doctype/pick_list/pick_list.js:318
msgid "Select Batch No"
@@ -63190,7 +63237,7 @@
msgid "Select Default Supplier"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:231
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:252
msgid "Select Difference Account"
msgstr ""
@@ -63212,19 +63259,19 @@
msgid "Select Finished Good"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:968
+#: selling/doctype/sales_order/sales_order.js:962
msgid "Select Items"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:867
+#: selling/doctype/sales_order/sales_order.js:861
msgid "Select Items based on Delivery Date"
msgstr ""
-#: public/js/controllers/transaction.js:2129
+#: public/js/controllers/transaction.js:2159
msgid "Select Items for Quality Inspection"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:719
+#: selling/doctype/sales_order/sales_order.js:713
msgid "Select Items to Manufacture"
msgstr ""
@@ -63248,13 +63295,13 @@
msgid "Select Quantity"
msgstr ""
-#: public/js/utils/sales_common.js:316
+#: public/js/utils/sales_common.js:325
#: selling/page/point_of_sale/pos_item_details.js:203
#: stock/doctype/pick_list/pick_list.js:318
msgid "Select Serial No"
msgstr ""
-#: public/js/utils/sales_common.js:319 stock/doctype/pick_list/pick_list.js:321
+#: public/js/utils/sales_common.js:328 stock/doctype/pick_list/pick_list.js:321
msgid "Select Serial and Batch"
msgstr ""
@@ -63290,6 +63337,11 @@
msgid "Select Time"
msgstr ""
+#: accounts/report/balance_sheet/balance_sheet.js:14
+#: accounts/report/profit_and_loss_statement/profit_and_loss_statement.js:14
+msgid "Select View"
+msgstr ""
+
#: public/js/bank_reconciliation_tool/dialog_manager.js:248
msgid "Select Vouchers to Match"
msgstr ""
@@ -63330,7 +63382,7 @@
msgid "Select a company"
msgstr ""
-#: stock/doctype/item/item.js:823
+#: stock/doctype/item/item.js:809
msgid "Select an Item Group."
msgstr ""
@@ -63342,7 +63394,7 @@
msgid "Select an item from each set to be used in the Sales Order."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1566
+#: accounts/doctype/sales_invoice/sales_invoice.py:1549
msgid "Select change amount account"
msgstr ""
@@ -63357,7 +63409,7 @@
msgid "Select company name first."
msgstr ""
-#: controllers/accounts_controller.py:2325
+#: controllers/accounts_controller.py:2394
msgid "Select finance book for the item {0} at row {1}"
msgstr ""
@@ -63429,7 +63481,7 @@
msgid "Selected POS Opening Entry should be open."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2221
+#: accounts/doctype/sales_invoice/sales_invoice.py:2192
msgid "Selected Price List should have buying and selling fields checked."
msgstr ""
@@ -63711,7 +63763,7 @@
msgid "Serial / Batch Bundle"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:364
+#: accounts/doctype/pos_invoice/pos_invoice.py:362
msgid "Serial / Batch Bundle Missing"
msgstr ""
@@ -63728,14 +63780,14 @@
#. Name of a DocType
#: manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.js:73
#: manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py:116
-#: public/js/controllers/transaction.js:2114
-#: public/js/utils/serial_no_batch_selector.js:278
+#: public/js/controllers/transaction.js:2144
+#: public/js/utils/serial_no_batch_selector.js:350
#: stock/doctype/serial_no/serial_no.json
#: stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py:160
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.js:64
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.py:150
#: stock/report/serial_no_ledger/serial_no_ledger.js:39
-#: stock/report/serial_no_ledger/serial_no_ledger.py:58
+#: stock/report/serial_no_ledger/serial_no_ledger.py:57
#: stock/report/stock_ledger/stock_ledger.py:246
msgid "Serial No"
msgstr ""
@@ -63940,7 +63992,7 @@
msgid "Serial No and Batch for Finished Good"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:574
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:577
msgid "Serial No is mandatory"
msgstr ""
@@ -63948,11 +64000,11 @@
msgid "Serial No is mandatory for Item {0}"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:388
+#: public/js/utils/serial_no_batch_selector.js:480
msgid "Serial No {0} already exists"
msgstr ""
-#: public/js/utils/barcode_scanner.js:296
+#: public/js/utils/barcode_scanner.js:311
msgid "Serial No {0} already scanned"
msgstr ""
@@ -63969,12 +64021,16 @@
msgid "Serial No {0} does not exist"
msgstr ""
-#: public/js/utils/barcode_scanner.js:387
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:2112
+msgid "Serial No {0} does not exists"
+msgstr ""
+
+#: public/js/utils/barcode_scanner.js:402
msgid "Serial No {0} has already scanned."
msgstr ""
-#: public/js/utils/barcode_scanner.js:482
-#: public/js/utils/barcode_scanner.js:489
+#: public/js/utils/barcode_scanner.js:499
+#: public/js/utils/barcode_scanner.js:506
msgid "Serial No {0} is already added"
msgstr ""
@@ -63994,19 +64050,19 @@
msgid "Serial No: {0} has already been transacted into another POS Invoice."
msgstr ""
-#: public/js/utils/barcode_scanner.js:247
+#: public/js/utils/barcode_scanner.js:262
#: public/js/utils/serial_no_batch_selector.js:15
-#: public/js/utils/serial_no_batch_selector.js:174
+#: public/js/utils/serial_no_batch_selector.js:178
#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:48
msgid "Serial Nos"
msgstr ""
#: public/js/utils/serial_no_batch_selector.js:20
-#: public/js/utils/serial_no_batch_selector.js:179
+#: public/js/utils/serial_no_batch_selector.js:183
msgid "Serial Nos / Batch Nos"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1715
+#: accounts/doctype/sales_invoice/sales_invoice.py:1692
msgid "Serial Nos Mismatch"
msgstr ""
@@ -64016,11 +64072,11 @@
msgid "Serial Nos and Batches"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1048
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1074
msgid "Serial Nos are created successfully"
msgstr ""
-#: stock/stock_ledger.py:1883
+#: stock/stock_ledger.py:1972
msgid "Serial Nos are reserved in Stock Reservation Entries, you need to unreserve them before proceeding."
msgstr ""
@@ -64141,11 +64197,11 @@
msgid "Serial and Batch Bundle"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1227
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1253
msgid "Serial and Batch Bundle created"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1269
+#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py:1295
msgid "Serial and Batch Bundle updated"
msgstr ""
@@ -64200,11 +64256,11 @@
msgid "Serial and Batch Summary"
msgstr ""
-#: stock/utils.py:380
+#: stock/utils.py:427
msgid "Serial number {0} entered more than once"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:555
+#: accounts/doctype/journal_entry/journal_entry.js:545
msgid "Series"
msgstr ""
@@ -64743,11 +64799,11 @@
msgid "Service Stop Date"
msgstr ""
-#: accounts/deferred_revenue.py:48 public/js/controllers/transaction.js:1237
+#: accounts/deferred_revenue.py:48 public/js/controllers/transaction.js:1239
msgid "Service Stop Date cannot be after Service End Date"
msgstr ""
-#: accounts/deferred_revenue.py:45 public/js/controllers/transaction.js:1234
+#: accounts/deferred_revenue.py:45 public/js/controllers/transaction.js:1236
msgid "Service Stop Date cannot be before Service Start Date"
msgstr ""
@@ -64825,10 +64881,6 @@
msgid "Set Loyalty Program"
msgstr ""
-#: portal/doctype/homepage/homepage.js:6
-msgid "Set Meta Tags"
-msgstr ""
-
#: accounts/doctype/purchase_invoice/purchase_invoice.js:272
msgid "Set New Release Date"
msgstr ""
@@ -64945,7 +64997,7 @@
msgid "Set Valuation Rate Based on Source Warehouse"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:190
+#: selling/doctype/sales_order/sales_order.js:184
msgid "Set Warehouse"
msgstr ""
@@ -64958,7 +65010,7 @@
msgid "Set as Completed"
msgstr ""
-#: public/js/utils/sales_common.js:397
+#: public/js/utils/sales_common.js:406
#: selling/doctype/quotation/quotation.js:124
msgid "Set as Lost"
msgstr ""
@@ -64968,11 +65020,11 @@
msgid "Set as Open"
msgstr ""
-#: setup/doctype/company/company.py:418
+#: setup/doctype/company/company.py:419
msgid "Set default inventory account for perpetual inventory"
msgstr ""
-#: setup/doctype/company/company.py:428
+#: setup/doctype/company/company.py:429
msgid "Set default {0} account for non stock items"
msgstr ""
@@ -65022,15 +65074,15 @@
msgid "Set up your Warehouse"
msgstr ""
-#: assets/doctype/asset/asset.py:664
+#: assets/doctype/asset/asset.py:672
msgid "Set {0} in asset category {1} for company {2}"
msgstr ""
-#: assets/doctype/asset/asset.py:949
+#: assets/doctype/asset/asset.py:953
msgid "Set {0} in asset category {1} or company {2}"
msgstr ""
-#: assets/doctype/asset/asset.py:945
+#: assets/doctype/asset/asset.py:949
msgid "Set {0} in company {1}"
msgstr ""
@@ -65110,12 +65162,11 @@
msgid "Setting up company"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:954
+#: manufacturing/doctype/bom/bom.py:956
#: manufacturing/doctype/work_order/work_order.py:978
msgid "Setting {} is required"
msgstr ""
-#. Label of a Card Break in the Accounting Workspace
#. Label of a Card Break in the Buying Workspace
#. Label of a Card Break in the CRM Workspace
#. Label of a Card Break in the Manufacturing Workspace
@@ -65124,7 +65175,6 @@
#. Name of a Workspace
#. Label of a Card Break in the Stock Workspace
#. Label of a Card Break in the Support Workspace
-#: accounts/workspace/accounting/accounting.json
#: buying/workspace/buying/buying.json crm/workspace/crm/crm.json
#: manufacturing/workspace/manufacturing/manufacturing.json
#: projects/workspace/projects/projects.json
@@ -65281,7 +65331,7 @@
msgstr ""
#. Name of a DocType
-#: stock/doctype/delivery_note/delivery_note.js:175
+#: stock/doctype/delivery_note/delivery_note.js:166
#: stock/doctype/shipment/shipment.json
msgid "Shipment"
msgstr ""
@@ -65701,7 +65751,7 @@
msgid "Show Completed"
msgstr ""
-#: accounts/report/budget_variance_report/budget_variance_report.js:111
+#: accounts/report/budget_variance_report/budget_variance_report.js:107
msgid "Show Cumulative Amount"
msgstr ""
@@ -65862,7 +65912,7 @@
msgid "Show only the Immediate Upcoming Term"
msgstr ""
-#: stock/utils.py:541
+#: stock/utils.py:588
msgid "Show pending entries"
msgstr ""
@@ -66036,12 +66086,6 @@
msgid "Skype ID"
msgstr ""
-#. Option for the 'Hero Section Based On' (Select) field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Slideshow"
-msgstr ""
-
#: setup/setup_wizard/operations/install_fixtures.py:223
msgid "Small"
msgstr ""
@@ -66052,7 +66096,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:32
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:45
-msgid "Softwares"
+msgid "Software"
msgstr ""
#: assets/doctype/asset/asset_list.js:11
@@ -66318,7 +66362,7 @@
msgid "Spacer"
msgstr ""
-#: assets/doctype/asset/asset.js:467 stock/doctype/batch/batch.js:146
+#: assets/doctype/asset/asset.js:467 stock/doctype/batch/batch.js:143
#: support/doctype/issue/issue.js:100
msgid "Split"
msgstr ""
@@ -66327,7 +66371,7 @@
msgid "Split Asset"
msgstr ""
-#: stock/doctype/batch/batch.js:145
+#: stock/doctype/batch/batch.js:142
msgid "Split Batch"
msgstr ""
@@ -66352,11 +66396,11 @@
msgid "Split Qty"
msgstr ""
-#: assets/doctype/asset/asset.py:1044
+#: assets/doctype/asset/asset.py:1050
msgid "Split qty cannot be grater than or equal to asset qty"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1810
+#: accounts/doctype/payment_entry/payment_entry.py:1827
msgid "Splitting {0} {1} into {2} rows as per Payment Terms"
msgstr ""
@@ -66451,7 +66495,7 @@
#: assets/report/fixed_asset_register/fixed_asset_register.js:68
#: projects/report/project_summary/project_summary.py:70
#: projects/report/timesheet_billing_summary/timesheet_billing_summary.js:52
-#: public/js/financial_statements.js:131
+#: public/js/financial_statements.js:184
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js:17
msgid "Start Date"
msgstr ""
@@ -66574,11 +66618,11 @@
#: accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.js:48
#: accounts/report/financial_ratios/financial_ratios.js:17
#: assets/report/fixed_asset_register/fixed_asset_register.js:82
-#: public/js/financial_statements.js:145
+#: public/js/financial_statements.js:198
msgid "Start Year"
msgstr ""
-#: accounts/report/financial_statements.py:134
+#: accounts/report/financial_statements.py:122
msgid "Start Year and End Year are mandatory"
msgstr ""
@@ -66693,22 +66737,22 @@
#: projects/report/delayed_tasks_summary/delayed_tasks_summary.py:92
#: projects/report/project_summary/project_summary.js:24
#: projects/report/project_summary/project_summary.py:58
-#: selling/doctype/sales_order/sales_order.js:523
-#: selling/doctype/sales_order/sales_order.js:527
-#: selling/doctype/sales_order/sales_order.js:534
-#: selling/doctype/sales_order/sales_order.js:545
-#: selling/doctype/sales_order/sales_order.js:547
+#: selling/doctype/sales_order/sales_order.js:517
+#: selling/doctype/sales_order/sales_order.js:521
+#: selling/doctype/sales_order/sales_order.js:528
+#: selling/doctype/sales_order/sales_order.js:539
+#: selling/doctype/sales_order/sales_order.js:541
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.js:90
#: selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py:68
#: selling/report/sales_order_analysis/sales_order_analysis.js:55
#: selling/report/sales_order_analysis/sales_order_analysis.py:228
-#: stock/doctype/delivery_note/delivery_note.js:219
-#: stock/doctype/delivery_note/delivery_note.js:238
+#: stock/doctype/delivery_note/delivery_note.js:210
+#: stock/doctype/delivery_note/delivery_note.js:229
#: stock/doctype/purchase_receipt/purchase_receipt.js:222
#: stock/doctype/purchase_receipt/purchase_receipt.js:240
#: stock/report/reserved_stock/reserved_stock.js:127
#: stock/report/reserved_stock/reserved_stock.py:178
-#: stock/report/serial_no_ledger/serial_no_ledger.py:52
+#: stock/report/serial_no_ledger/serial_no_ledger.py:51
#: subcontracting/doctype/subcontracting_order/subcontracting_order.js:106
#: subcontracting/doctype/subcontracting_order/subcontracting_order.js:108
#: support/report/issue_analytics/issue_analytics.js:52
@@ -67236,7 +67280,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:50
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:73
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1211
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1187
#: accounts/report/account_balance/account_balance.js:56
msgid "Stock Adjustment"
msgstr ""
@@ -67400,7 +67444,7 @@
msgid "Stock Entry {0} created"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1254
+#: accounts/doctype/journal_entry/journal_entry.py:1140
msgid "Stock Entry {0} is not submitted"
msgstr ""
@@ -67412,7 +67456,7 @@
#. Label of a Date field in DocType 'Stock Settings'
#: stock/doctype/stock_settings/stock_settings.json
msgctxt "Stock Settings"
-msgid "Stock Frozen Upto"
+msgid "Stock Frozen Up To"
msgstr ""
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:20
@@ -67481,6 +67525,7 @@
msgstr ""
#. Name of a role
+#: accounts/doctype/fiscal_year/fiscal_year.json
#: assets/doctype/asset_movement/asset_movement.json
#: assets/doctype/location/location.json
#: buying/doctype/buying_settings/buying_settings.json
@@ -67488,6 +67533,7 @@
#: selling/doctype/product_bundle/product_bundle.json
#: setup/doctype/incoterm/incoterm.json
#: setup/doctype/item_group/item_group.json setup/doctype/uom/uom.json
+#: stock/doctype/bin/bin.json
#: stock/doctype/customs_tariff_number/customs_tariff_number.json
#: stock/doctype/delivery_note/delivery_note.json
#: stock/doctype/inventory_dimension/inventory_dimension.json
@@ -67533,7 +67579,7 @@
msgstr ""
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:254
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:299
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:306
#: stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py:34
msgid "Stock Qty"
msgstr ""
@@ -67629,11 +67675,11 @@
#: selling/doctype/sales_order/sales_order.js:68
#: selling/doctype/sales_order/sales_order.js:74
#: selling/doctype/sales_order/sales_order.js:79
-#: selling/doctype/sales_order/sales_order.js:184
+#: selling/doctype/sales_order/sales_order.js:178
#: stock/doctype/pick_list/pick_list.js:110
#: stock/doctype/pick_list/pick_list.js:119
#: stock/doctype/pick_list/pick_list.js:120
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:466
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:467
#: stock/doctype/stock_reservation_entry/stock_reservation_entry.py:965
#: stock/doctype/stock_reservation_entry/stock_reservation_entry.py:978
#: stock/doctype/stock_reservation_entry/stock_reservation_entry.py:992
@@ -67658,7 +67704,7 @@
msgstr ""
#. Name of a DocType
-#: selling/doctype/sales_order/sales_order.js:389
+#: selling/doctype/sales_order/sales_order.js:383
#: stock/doctype/stock_reservation_entry/stock_reservation_entry.json
#: stock/report/reserved_stock/reserved_stock.js:56
#: stock/report/reserved_stock/reserved_stock.py:171
@@ -67693,7 +67739,7 @@
msgid "Stock Reserved Qty (in Stock UOM)"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1502
+#: stock/doctype/stock_entry/stock_entry.py:1498
msgid "Stock Return"
msgstr ""
@@ -67733,7 +67779,7 @@
msgstr ""
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:256
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:301
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:308
#: buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py:215
#: buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py:232
#: stock/report/batch_item_expiry_status/batch_item_expiry_status.py:35
@@ -67917,7 +67963,7 @@
msgid "Stock UOM Quantity"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:374
+#: selling/doctype/sales_order/sales_order.js:368
msgid "Stock Unreservation"
msgstr ""
@@ -68028,7 +68074,7 @@
msgid "Stock cannot be reserved in the group warehouse {0}."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1008
+#: accounts/doctype/sales_invoice/sales_invoice.py:1011
msgid "Stock cannot be updated against Delivery Note {0}"
msgstr ""
@@ -68062,7 +68108,7 @@
msgid "Stock will be reserved on submission of <b>Purchase Receipt</b> created against Material Receipt for Sales Order."
msgstr ""
-#: stock/utils.py:532
+#: stock/utils.py:579
msgid "Stock/Accounts can not be frozen as processing of backdated entries is going on. Please try again later."
msgstr ""
@@ -68147,7 +68193,7 @@
msgid "Stopped Work Order cannot be cancelled, Unstop it first to cancel"
msgstr ""
-#: setup/doctype/company/company.py:259
+#: setup/doctype/company/company.py:260
#: setup/setup_wizard/operations/defaults_setup.py:34
#: setup/setup_wizard/operations/install_fixtures.py:481
#: stock/doctype/item/item.py:282
@@ -68305,7 +68351,7 @@
#. Name of a DocType
#: buying/doctype/purchase_order/purchase_order.js:318
-#: controllers/subcontracting_controller.py:802
+#: controllers/subcontracting_controller.py:806
#: subcontracting/doctype/subcontracting_order/subcontracting_order.json
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js:78
msgid "Subcontracting Order"
@@ -68357,7 +68403,7 @@
msgid "Subcontracting Order Supplied Item"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:857
+#: buying/doctype/purchase_order/purchase_order.py:861
msgid "Subcontracting Order {0} created."
msgstr ""
@@ -68482,7 +68528,7 @@
msgid "Submit"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:853
+#: buying/doctype/purchase_order/purchase_order.py:857
#: subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py:698
msgid "Submit Action Failed"
msgstr ""
@@ -68636,7 +68682,7 @@
#: accounts/doctype/subscription/subscription.json
#: buying/doctype/supplier_quotation/supplier_quotation_dashboard.py:16
#: selling/doctype/quotation/quotation_dashboard.py:12
-#: stock/doctype/delivery_note/delivery_note_dashboard.py:24
+#: stock/doctype/delivery_note/delivery_note_dashboard.py:25
#: stock/doctype/purchase_receipt/purchase_receipt_dashboard.py:31
msgid "Subscription"
msgstr ""
@@ -68673,11 +68719,11 @@
msgid "Subscription End Date"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:350
+#: accounts/doctype/subscription/subscription.py:380
msgid "Subscription End Date is mandatory to follow calendar months"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:340
+#: accounts/doctype/subscription/subscription.py:370
msgid "Subscription End Date must be after {0} as per the subscription plan"
msgstr ""
@@ -68776,12 +68822,6 @@
msgid "Subscriptions"
msgstr ""
-#. Label of a Data field in DocType 'Homepage Section Card'
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgctxt "Homepage Section Card"
-msgid "Subtitle"
-msgstr ""
-
#. Label of a Int field in DocType 'Bulk Transaction Log'
#: bulk_transaction/doctype/bulk_transaction_log/bulk_transaction_log.json
msgctxt "Bulk Transaction Log"
@@ -68827,7 +68867,7 @@
msgid "Successful"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:516
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.py:538
msgid "Successfully Reconciled"
msgstr ""
@@ -68839,10 +68879,6 @@
msgid "Successfully changed Stock UOM, please redefine conversion factors for new UOM."
msgstr ""
-#: setup/doctype/company/company.js:164
-msgid "Successfully deleted all transactions related to this company!"
-msgstr ""
-
#: accounts/doctype/bank_statement_import/bank_statement_import.js:468
msgid "Successfully imported {0}"
msgstr ""
@@ -69044,7 +69080,7 @@
#: public/js/purchase_trends_filters.js:66
#: regional/report/irs_1099/irs_1099.py:79
#: selling/doctype/customer/customer.js:207
-#: selling/doctype/sales_order/sales_order.js:1011
+#: selling/doctype/sales_order/sales_order.js:1005
#: stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.js:8
msgid "Supplier"
msgstr ""
@@ -69211,11 +69247,11 @@
msgid "Supplier"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Payables Workspace
#. Label of a Link in the Buying Workspace
#. Label of a Link in the Home Workspace
#. Label of a shortcut in the Home Workspace
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/payables/payables.json
#: buying/workspace/buying/buying.json setup/workspace/home/home.json
msgctxt "Supplier"
msgid "Supplier"
@@ -69352,7 +69388,7 @@
#. Name of a DocType
#: accounts/report/accounts_payable/accounts_payable.js:122
#: accounts/report/accounts_payable_summary/accounts_payable_summary.js:105
-#: accounts/report/accounts_receivable/accounts_receivable.py:1087
+#: accounts/report/accounts_receivable/accounts_receivable.py:1110
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:201
#: accounts/report/customer_ledger_summary/customer_ledger_summary.py:176
#: accounts/report/purchase_register/purchase_register.js:27
@@ -69440,7 +69476,7 @@
msgid "Supplier Invoice"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:213
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:218
msgid "Supplier Invoice Date"
msgstr ""
@@ -69450,13 +69486,13 @@
msgid "Supplier Invoice Date"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1536
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1494
msgid "Supplier Invoice Date cannot be greater than Posting Date"
msgstr ""
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html:59
-#: accounts/report/general_ledger/general_ledger.py:653
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:207
+#: accounts/report/general_ledger/general_ledger.py:656
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:212
msgid "Supplier Invoice No"
msgstr ""
@@ -69472,7 +69508,7 @@
msgid "Supplier Invoice No"
msgstr ""
-#: accounts/doctype/purchase_invoice/purchase_invoice.py:1561
+#: accounts/doctype/purchase_invoice/purchase_invoice.py:1519
msgid "Supplier Invoice No exists in Purchase Invoice {0}"
msgstr ""
@@ -69494,13 +69530,15 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
+#. Label of a Link in the Payables Workspace
#: accounts/report/supplier_ledger_summary/supplier_ledger_summary.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
+#: accounts/workspace/payables/payables.json
msgid "Supplier Ledger Summary"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1018
+#: accounts/report/accounts_receivable/accounts_receivable.py:1041
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:160
#: accounts/report/item_wise_purchase_register/item_wise_purchase_register.py:197
#: accounts/report/purchase_register/purchase_register.py:177
@@ -70008,8 +70046,6 @@
#: manufacturing/doctype/bom_update_log/bom_update_log.json
#: manufacturing/doctype/downtime_entry/downtime_entry.json
#: manufacturing/doctype/job_card/job_card.json
-#: portal/doctype/homepage/homepage.json
-#: portal/doctype/homepage_section/homepage_section.json
#: projects/doctype/activity_type/activity_type.json
#: projects/doctype/project_template/project_template.json
#: projects/doctype/project_type/project_type.json
@@ -70097,7 +70133,7 @@
msgid "System will fetch all the entries if limit value is zero."
msgstr ""
-#: controllers/accounts_controller.py:1640
+#: controllers/accounts_controller.py:1673
msgid "System will not check over billing since amount for Item {0} in {1} is zero"
msgstr ""
@@ -70108,7 +70144,7 @@
msgid "System will notify to increase or decrease quantity or amount "
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:224
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:229
#: accounts/report/tds_computation_summary/tds_computation_summary.py:125
msgid "TCS Rate %"
msgstr ""
@@ -70122,7 +70158,7 @@
msgid "TDS Payable"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:224
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:229
#: accounts/report/tds_computation_summary/tds_computation_summary.py:125
msgid "TDS Rate %"
msgstr ""
@@ -70137,12 +70173,6 @@
msgid "Tag"
msgstr ""
-#. Label of a Data field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Tag Line"
-msgstr ""
-
#. Label of an action in the Onboarding Step 'Accounts Settings'
#: accounts/onboarding_step/accounts_settings/accounts_settings.json
msgid "Take a quick walk-through of Accounts Settings"
@@ -70219,23 +70249,23 @@
msgid "Target Asset Location"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:239
+#: assets/doctype/asset_capitalization/asset_capitalization.py:248
msgid "Target Asset {0} cannot be cancelled"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:237
+#: assets/doctype/asset_capitalization/asset_capitalization.py:246
msgid "Target Asset {0} cannot be submitted"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:233
+#: assets/doctype/asset_capitalization/asset_capitalization.py:242
msgid "Target Asset {0} cannot be {1}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:243
+#: assets/doctype/asset_capitalization/asset_capitalization.py:252
msgid "Target Asset {0} does not belong to company {1}"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:224
+#: assets/doctype/asset_capitalization/asset_capitalization.py:233
msgid "Target Asset {0} needs to be composite asset"
msgstr ""
@@ -70315,15 +70345,15 @@
msgid "Target Item Name"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:194
+#: assets/doctype/asset_capitalization/asset_capitalization.py:203
msgid "Target Item {0} is neither a Fixed Asset nor a Stock Item"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:198
+#: assets/doctype/asset_capitalization/asset_capitalization.py:207
msgid "Target Item {0} must be a Fixed Asset item"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:200
+#: assets/doctype/asset_capitalization/asset_capitalization.py:209
msgid "Target Item {0} must be a Stock Item"
msgstr ""
@@ -70363,7 +70393,7 @@
msgid "Target Qty"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:205
+#: assets/doctype/asset_capitalization/asset_capitalization.py:214
msgid "Target Qty must be a positive number"
msgstr ""
@@ -70433,7 +70463,7 @@
msgid "Target Warehouse Address"
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:215
+#: assets/doctype/asset_capitalization/asset_capitalization.py:224
msgid "Target Warehouse is mandatory for Decapitalization"
msgstr ""
@@ -70631,7 +70661,7 @@
msgid "Tax Account"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:242
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:247
#: accounts/report/tds_computation_summary/tds_computation_summary.py:137
msgid "Tax Amount"
msgstr ""
@@ -70896,6 +70926,11 @@
msgid "Tax Id: "
msgstr ""
+#. Label of a Card Break in the Accounting Workspace
+#: accounts/workspace/accounting/accounting.json
+msgid "Tax Masters"
+msgstr ""
+
#: accounts/doctype/account/account_tree.js:119
msgid "Tax Rate"
msgstr ""
@@ -70906,6 +70941,18 @@
msgid "Tax Rate"
msgstr ""
+#. Label of a Float field in DocType 'Purchase Taxes and Charges'
+#: accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
+msgctxt "Purchase Taxes and Charges"
+msgid "Tax Rate"
+msgstr ""
+
+#. Label of a Float field in DocType 'Sales Taxes and Charges'
+#: accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json
+msgctxt "Sales Taxes and Charges"
+msgid "Tax Rate"
+msgstr ""
+
#. Label of a Table field in DocType 'Item Tax Template'
#: accounts/doctype/item_tax_template/item_tax_template.json
msgctxt "Item Tax Template"
@@ -71102,7 +71149,7 @@
msgid "Tax will be withheld only for amount exceeding the cumulative threshold"
msgstr ""
-#: controllers/taxes_and_totals.py:1009
+#: controllers/taxes_and_totals.py:1018
msgid "Taxable Amount"
msgstr ""
@@ -71112,12 +71159,10 @@
msgid "Taxable Amount"
msgstr ""
-#. Label of a Card Break in the Accounting Workspace
#: accounts/doctype/pos_closing_entry/closing_voucher_details.html:60
#: accounts/doctype/tax_category/tax_category_dashboard.py:12
#: accounts/report/sales_payment_summary/sales_payment_summary.py:26
#: accounts/report/sales_payment_summary/sales_payment_summary.py:42
-#: accounts/workspace/accounting/accounting.json
msgid "Taxes"
msgstr ""
@@ -71656,7 +71701,9 @@
msgid "Terms and Conditions"
msgstr ""
+#. Label of a Link in the Accounting Workspace
#. Label of a Text Editor field in DocType 'Terms and Conditions'
+#: accounts/workspace/accounting/accounting.json
#: setup/doctype/terms_and_conditions/terms_and_conditions.json
msgctxt "Terms and Conditions"
msgid "Terms and Conditions"
@@ -71704,10 +71751,8 @@
msgid "Terms and Conditions Help"
msgstr ""
-#. Label of a Link in the Accounting Workspace
#. Label of a Link in the Buying Workspace
#. Label of a Link in the Selling Workspace
-#: accounts/workspace/accounting/accounting.json
#: buying/workspace/buying/buying.json selling/workspace/selling/selling.json
msgctxt "Terms and Conditions"
msgid "Terms and Conditions Template"
@@ -71715,7 +71760,7 @@
#. Name of a DocType
#: accounts/report/accounts_receivable/accounts_receivable.js:145
-#: accounts/report/accounts_receivable/accounts_receivable.py:1071
+#: accounts/report/accounts_receivable/accounts_receivable.py:1094
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.js:111
#: accounts/report/accounts_receivable_summary/accounts_receivable_summary.py:185
#: accounts/report/customer_ledger_summary/customer_ledger_summary.js:68
@@ -71723,7 +71768,7 @@
#: accounts/report/gross_profit/gross_profit.py:335
#: accounts/report/inactive_sales_items/inactive_sales_items.js:9
#: accounts/report/inactive_sales_items/inactive_sales_items.py:21
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:247
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:254
#: accounts/report/sales_register/sales_register.py:207
#: crm/report/lead_details/lead_details.js:47
#: crm/report/lead_details/lead_details.py:34
@@ -71974,7 +72019,7 @@
msgid "The Loyalty Program isn't valid for the selected company"
msgstr ""
-#: accounts/doctype/payment_request/payment_request.py:723
+#: accounts/doctype/payment_request/payment_request.py:747
msgid "The Payment Request {0} is already paid, cannot process payment twice"
msgstr ""
@@ -71986,7 +72031,7 @@
msgid "The Pick List having Stock Reservation Entries cannot be updated. If you need to make changes, we recommend canceling the existing Stock Reservation Entries before updating the Pick List."
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:1765
+#: stock/doctype/stock_entry/stock_entry.py:1761
msgid "The Process Loss Qty has reset as per job cards Process Loss Qty"
msgstr ""
@@ -72162,7 +72207,7 @@
msgid "The selected BOMs are not for the same item"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:417
+#: accounts/doctype/pos_invoice/pos_invoice.py:415
msgid "The selected change account {} doesn't belongs to Company {}."
msgstr ""
@@ -72178,7 +72223,7 @@
msgid "The seller and the buyer cannot be the same"
msgstr ""
-#: stock/doctype/batch/batch.py:376
+#: stock/doctype/batch/batch.py:378
msgid "The serial no {0} does not belong to item {1}"
msgstr ""
@@ -72194,7 +72239,7 @@
msgid "The shares don't exist with the {0}"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:460
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:461
msgid "The stock has been reserved for the following Items and Warehouses, un-reserve the same to {0} the Stock Reconciliation: <br /><br /> {1}"
msgstr ""
@@ -72202,6 +72247,11 @@
msgid "The sync has started in the background, please check the {0} list for new records."
msgstr ""
+#: accounts/doctype/journal_entry/journal_entry.py:155
+#: accounts/doctype/journal_entry/journal_entry.py:162
+msgid "The task has been enqueued as a background job."
+msgstr ""
+
#: stock/doctype/stock_entry/stock_entry.py:244
msgid "The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Draft stage"
msgstr ""
@@ -72210,11 +72260,11 @@
msgid "The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Submitted stage"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:753
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:754
msgid "The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Draft stage"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:764
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:765
msgid "The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Reconciliation and revert to the Submitted stage"
msgstr ""
@@ -72237,7 +72287,7 @@
msgid "The value of {0} differs between Items {1} and {2}"
msgstr ""
-#: controllers/item_variant.py:147
+#: controllers/item_variant.py:151
msgid "The value {0} is already assigned to an existing Item {1}."
msgstr ""
@@ -72258,14 +72308,14 @@
msgstr ""
#: stock/doctype/material_request/material_request.py:779
-msgid "The {0} {1} created sucessfully"
+msgid "The {0} {1} created successfully"
msgstr ""
#: manufacturing/doctype/job_card/job_card.py:762
msgid "The {0} {1} is used to calculate the valuation cost for the finished good {2}."
msgstr ""
-#: assets/doctype/asset/asset.py:500
+#: assets/doctype/asset/asset.py:501
msgid "There are active maintenance or repairs against the asset. You must complete all of them before cancelling the asset."
msgstr ""
@@ -72285,7 +72335,7 @@
msgid "There are only {0} asset created or linked to {1}. Please create or link {2} Assets with respective document."
msgstr ""
-#: stock/doctype/item/item.js:843
+#: stock/doctype/item/item.js:829
msgid "There are two options to maintain valuation of stock. FIFO (first in - first out) and Moving Average. To understand this topic in detail please visit <a href='https://docs.erpnext.com/docs/v13/user/manual/en/stock/articles/item-valuation-fifo-and-moving-average' target='_blank'>Item Valuation, FIFO and Moving Average.</a>"
msgstr ""
@@ -72309,7 +72359,7 @@
msgid "There is already an active Subcontracting BOM {0} for the Finished Good {1}."
msgstr ""
-#: stock/doctype/batch/batch.py:384
+#: stock/doctype/batch/batch.py:386
msgid "There is no batch found against the {0}: {1}"
msgstr ""
@@ -72346,7 +72396,7 @@
msgid "There were errors while sending email. Please try again."
msgstr ""
-#: accounts/utils.py:896
+#: accounts/utils.py:924
msgid "There were issues unlinking payment entry {0}."
msgstr ""
@@ -72393,11 +72443,11 @@
msgid "This covers all scorecards tied to this Setup"
msgstr ""
-#: controllers/status_updater.py:341
+#: controllers/status_updater.py:350
msgid "This document is over limit by {0} {1} for item {4}. Are you making another {3} against the same {2}?"
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:369
+#: stock/doctype/delivery_note/delivery_note.js:360
msgid "This field is used to set the 'Customer'."
msgstr ""
@@ -72465,10 +72515,6 @@
msgid "This is a root territory and cannot be edited."
msgstr ""
-#: portal/doctype/homepage/homepage.py:31
-msgid "This is an example website auto-generated from ERPNext"
-msgstr ""
-
#: stock/doctype/item/item_dashboard.py:7
msgid "This is based on stock movement. See {0} for details"
msgstr ""
@@ -72501,7 +72547,7 @@
msgid "This is enabled by default. If you want to plan materials for sub-assemblies of the Item you're manufacturing leave this enabled. If you plan and manufacture the sub-assemblies separately, you can disable this checkbox."
msgstr ""
-#: stock/doctype/item/item.js:833
+#: stock/doctype/item/item.js:819
msgid "This is for raw material Items that'll be used to create finished goods. If the Item is an additional service like 'washing' that'll be used in the BOM, keep this unchecked."
msgstr ""
@@ -72509,7 +72555,7 @@
msgid "This item filter has already been applied for the {0}"
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:380
+#: stock/doctype/delivery_note/delivery_note.js:371
msgid "This option can be checked to edit the 'Posting Date' and 'Posting Time' fields."
msgstr ""
@@ -72517,7 +72563,7 @@
msgid "This schedule was created when Asset {0} was adjusted through Asset Value Adjustment {1}."
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:509
+#: assets/doctype/asset_capitalization/asset_capitalization.py:516
msgid "This schedule was created when Asset {0} was consumed through Asset Capitalization {1}."
msgstr ""
@@ -72525,7 +72571,7 @@
msgid "This schedule was created when Asset {0} was repaired through Asset Repair {1}."
msgstr ""
-#: assets/doctype/asset_capitalization/asset_capitalization.py:676
+#: assets/doctype/asset_capitalization/asset_capitalization.py:674
msgid "This schedule was created when Asset {0} was restored on Asset Capitalization {1}'s cancellation."
msgstr ""
@@ -72533,7 +72579,7 @@
msgid "This schedule was created when Asset {0} was restored."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1328
+#: accounts/doctype/sales_invoice/sales_invoice.py:1325
msgid "This schedule was created when Asset {0} was returned through Sales Invoice {1}."
msgstr ""
@@ -72541,11 +72587,11 @@
msgid "This schedule was created when Asset {0} was scrapped."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1339
+#: accounts/doctype/sales_invoice/sales_invoice.py:1336
msgid "This schedule was created when Asset {0} was sold through Sales Invoice {1}."
msgstr ""
-#: assets/doctype/asset/asset.py:1111
+#: assets/doctype/asset/asset.py:1117
msgid "This schedule was created when Asset {0} was updated after being split into new Asset {1}."
msgstr ""
@@ -72561,7 +72607,7 @@
msgid "This schedule was created when Asset {0}'s shifts were adjusted through Asset Shift Allocation {1}."
msgstr ""
-#: assets/doctype/asset/asset.py:1174
+#: assets/doctype/asset/asset.py:1180
msgid "This schedule was created when new Asset {0} was split from Asset {1}."
msgstr ""
@@ -72572,7 +72618,7 @@
msgid "This section allows the user to set the Body and Closing text of the Dunning Letter for the Dunning Type based on language, which can be used in Print."
msgstr ""
-#: stock/doctype/delivery_note/delivery_note.js:374
+#: stock/doctype/delivery_note/delivery_note.js:365
msgid "This table is used to set details about the 'Item', 'Qty', 'Basic Rate', etc."
msgstr ""
@@ -72880,7 +72926,7 @@
msgid "Timesheet for tasks."
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:753
+#: accounts/doctype/sales_invoice/sales_invoice.py:756
msgid "Timesheet {0} is already completed or cancelled"
msgstr ""
@@ -72895,7 +72941,7 @@
msgstr ""
#: utilities/activation.py:126
-msgid "Timesheets help keep track of time, cost and billing for activites done by your team"
+msgid "Timesheets help keep track of time, cost and billing for activities done by your team"
msgstr ""
#. Label of a Section Break field in DocType 'Communication Medium'
@@ -72927,18 +72973,6 @@
msgid "Title"
msgstr ""
-#. Label of a Data field in DocType 'Homepage'
-#: portal/doctype/homepage/homepage.json
-msgctxt "Homepage"
-msgid "Title"
-msgstr ""
-
-#. Label of a Data field in DocType 'Homepage Section Card'
-#: portal/doctype/homepage_section_card/homepage_section_card.json
-msgctxt "Homepage Section Card"
-msgid "Title"
-msgstr ""
-
#. Label of a Data field in DocType 'Incoterm'
#: setup/doctype/incoterm/incoterm.json
msgctxt "Incoterm"
@@ -73122,9 +73156,9 @@
msgid "To Be Paid"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order_list.js:20
-#: selling/doctype/sales_order/sales_order_list.js:34
-#: selling/doctype/sales_order/sales_order_list.js:37
+#: buying/doctype/purchase_order/purchase_order_list.js:22
+#: selling/doctype/sales_order/sales_order_list.js:36
+#: selling/doctype/sales_order/sales_order_list.js:39
#: stock/doctype/delivery_note/delivery_note_list.js:12
#: stock/doctype/purchase_receipt/purchase_receipt_list.js:12
msgid "To Bill"
@@ -73356,7 +73390,7 @@
msgid "To Date"
msgstr ""
-#: controllers/accounts_controller.py:377
+#: controllers/accounts_controller.py:380
#: setup/doctype/holiday_list/holiday_list.py:115
msgid "To Date cannot be before From Date"
msgstr ""
@@ -73367,7 +73401,7 @@
msgid "To Date cannot be before From Date."
msgstr ""
-#: accounts/report/financial_statements.py:145
+#: accounts/report/financial_statements.py:133
msgid "To Date cannot be less than From Date"
msgstr ""
@@ -73385,8 +73419,8 @@
msgid "To Datetime"
msgstr ""
-#: selling/doctype/sales_order/sales_order_list.js:20
-#: selling/doctype/sales_order/sales_order_list.js:28
+#: selling/doctype/sales_order/sales_order_list.js:22
+#: selling/doctype/sales_order/sales_order_list.js:30
msgid "To Deliver"
msgstr ""
@@ -73403,7 +73437,7 @@
msgid "To Deliver"
msgstr ""
-#: selling/doctype/sales_order/sales_order_list.js:24
+#: selling/doctype/sales_order/sales_order_list.js:26
msgid "To Deliver and Bill"
msgstr ""
@@ -73482,6 +73516,17 @@
msgid "To Package No."
msgstr ""
+#: buying/doctype/purchase_order/purchase_order_list.js:12
+#: selling/doctype/sales_order/sales_order_list.js:14
+msgid "To Pay"
+msgstr ""
+
+#. Option for the 'Status' (Select) field in DocType 'Sales Order'
+#: selling/doctype/sales_order/sales_order.json
+msgctxt "Sales Order"
+msgid "To Pay"
+msgstr ""
+
#. Label of a Date field in DocType 'Payment Reconciliation'
#: accounts/doctype/payment_reconciliation/payment_reconciliation.json
msgctxt "Payment Reconciliation"
@@ -73511,7 +73556,7 @@
msgid "To Range"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order_list.js:16
+#: buying/doctype/purchase_order/purchase_order_list.js:18
msgid "To Receive"
msgstr ""
@@ -73521,7 +73566,7 @@
msgid "To Receive"
msgstr ""
-#: buying/doctype/purchase_order/purchase_order_list.js:13
+#: buying/doctype/purchase_order/purchase_order_list.js:15
msgid "To Receive and Bill"
msgstr ""
@@ -73656,11 +73701,11 @@
msgid "To add subcontracted Item's raw materials if include exploded items is disabled."
msgstr ""
-#: controllers/status_updater.py:336
+#: controllers/status_updater.py:345
msgid "To allow over billing, update \"Over Billing Allowance\" in Accounts Settings or the Item."
msgstr ""
-#: controllers/status_updater.py:332
+#: controllers/status_updater.py:341
msgid "To allow over receipt / delivery, update \"Over Receipt/Delivery Allowance\" in Stock Settings or the Item."
msgstr ""
@@ -73677,7 +73722,7 @@
msgid "To be Delivered to Customer"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:520
+#: accounts/doctype/sales_invoice/sales_invoice.py:521
msgid "To cancel a {} you need to cancel the POS Closing Entry {}."
msgstr ""
@@ -73697,8 +73742,8 @@
msgid "To include non-stock items in the material request planning. i.e. Items for which 'Maintain Stock' checkbox is unticked."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1615
-#: controllers/accounts_controller.py:2490
+#: accounts/doctype/payment_entry/payment_entry.py:1625
+#: controllers/accounts_controller.py:2559
msgid "To include tax in row {0} in Item rate, taxes in rows {1} must also be included"
msgstr ""
@@ -73710,7 +73755,7 @@
msgid "To overrule this, enable '{0}' in company {1}"
msgstr ""
-#: controllers/item_variant.py:150
+#: controllers/item_variant.py:154
msgid "To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings."
msgstr ""
@@ -73727,7 +73772,7 @@
msgid "To use a different finance book, please uncheck 'Include Default FB Assets'"
msgstr ""
-#: accounts/report/financial_statements.py:588
+#: accounts/report/financial_statements.py:576
#: accounts/report/general_ledger/general_ledger.py:273
#: accounts/report/trial_balance/trial_balance.py:278
msgid "To use a different finance book, please uncheck 'Include Default FB Entries'"
@@ -73768,9 +73813,9 @@
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:277
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html:315
#: accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py:233
-#: accounts/report/financial_statements.py:664
+#: accounts/report/financial_statements.py:652
#: accounts/report/general_ledger/general_ledger.py:56
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:621
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:636
#: accounts/report/profitability_analysis/profitability_analysis.py:93
#: accounts/report/profitability_analysis/profitability_analysis.py:98
#: accounts/report/trial_balance/trial_balance.py:344
@@ -74024,7 +74069,7 @@
msgid "Total Allocations"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:230
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:235
#: accounts/report/tds_computation_summary/tds_computation_summary.py:131
#: selling/page/sales_funnel/sales_funnel.py:151
#: stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py:67
@@ -74251,7 +74296,7 @@
msgid "Total Credit"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:208
+#: accounts/doctype/journal_entry/journal_entry.py:225
msgid "Total Credit/ Debit Amount should be same as linked Journal Entry"
msgstr ""
@@ -74261,7 +74306,7 @@
msgid "Total Debit"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:850
+#: accounts/doctype/journal_entry/journal_entry.py:802
msgid "Total Debit must be equal to Total Credit. The difference is {0}"
msgstr ""
@@ -74459,7 +74504,7 @@
msgid "Total Order Value"
msgstr ""
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:614
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:629
msgid "Total Other Charges"
msgstr ""
@@ -74491,7 +74536,7 @@
msgid "Total Paid Amount"
msgstr ""
-#: controllers/accounts_controller.py:2197
+#: controllers/accounts_controller.py:2266
msgid "Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"
msgstr ""
@@ -74675,7 +74720,7 @@
msgid "Total Tasks"
msgstr ""
-#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:607
+#: accounts/report/item_wise_sales_register/item_wise_sales_register.py:622
#: accounts/report/purchase_register/purchase_register.py:263
msgid "Total Tax"
msgstr ""
@@ -74907,7 +74952,7 @@
msgid "Total Working Hours"
msgstr ""
-#: controllers/accounts_controller.py:1800
+#: controllers/accounts_controller.py:1838
msgid "Total advance ({0}) against Order {1} cannot be greater than the Grand Total ({2})"
msgstr ""
@@ -74915,12 +74960,12 @@
msgid "Total allocated percentage for sales team should be 100"
msgstr ""
-#: selling/doctype/customer/customer.py:156
+#: selling/doctype/customer/customer.py:157
msgid "Total contribution percentage should be equal to 100"
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:446
-#: accounts/doctype/sales_invoice/sales_invoice.py:504
+#: accounts/doctype/pos_invoice/pos_invoice.py:444
+#: accounts/doctype/sales_invoice/sales_invoice.py:505
msgid "Total payments amount can't be greater than {}"
msgstr ""
@@ -74930,8 +74975,8 @@
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.py:765
#: accounts/report/consolidated_financial_statement/consolidated_financial_statement.py:766
-#: accounts/report/financial_statements.py:351
-#: accounts/report/financial_statements.py:352
+#: accounts/report/financial_statements.py:339
+#: accounts/report/financial_statements.py:340
msgid "Total {0} ({1})"
msgstr ""
@@ -75178,7 +75223,7 @@
msgid "Transaction Settings"
msgstr ""
-#: accounts/report/tax_withholding_details/tax_withholding_details.py:253
+#: accounts/report/tax_withholding_details/tax_withholding_details.py:258
msgid "Transaction Type"
msgstr ""
@@ -75192,11 +75237,15 @@
msgid "Transaction currency must be same as Payment Gateway currency"
msgstr ""
+#: accounts/doctype/bank_transaction/bank_transaction.py:64
+msgid "Transaction currency: {0} cannot be different from Bank Account({1}) currency: {2}"
+msgstr ""
+
#: manufacturing/doctype/job_card/job_card.py:647
msgid "Transaction not allowed against stopped Work Order {0}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1092
+#: accounts/doctype/payment_entry/payment_entry.py:1112
msgid "Transaction reference no {0} dated {1}"
msgstr ""
@@ -75290,7 +75339,7 @@
msgstr ""
#: stock/doctype/material_request/material_request_list.js:27
-msgid "Transfered"
+msgid "Transferred"
msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Material Request'
@@ -75428,10 +75477,11 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
#. Label of a shortcut in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/trial_balance/trial_balance.json
#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Trial Balance"
msgstr ""
@@ -75441,9 +75491,9 @@
msgstr ""
#. Name of a report
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#: accounts/report/trial_balance_for_party/trial_balance_for_party.json
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
msgid "Trial Balance for Party"
msgstr ""
@@ -75453,7 +75503,7 @@
msgid "Trial Period End Date"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:326
+#: accounts/doctype/subscription/subscription.py:356
msgid "Trial Period End Date Cannot be before Trial Period Start Date"
msgstr ""
@@ -75463,18 +75513,18 @@
msgid "Trial Period Start Date"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:332
+#: accounts/doctype/subscription/subscription.py:362
msgid "Trial Period Start date cannot be after Subscription Start Date"
msgstr ""
#: accounts/doctype/subscription/subscription_list.js:4
-msgid "Trialling"
+msgid "Trialing"
msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Subscription'
#: accounts/doctype/subscription/subscription.json
msgctxt "Subscription"
-msgid "Trialling"
+msgid "Trialing"
msgstr ""
#. Description of the 'General Ledger' (Int) field in DocType 'Accounts
@@ -75669,9 +75719,9 @@
msgid "Types of activities for Time Logs"
msgstr ""
-#. Label of a Link in the Accounting Workspace
+#. Label of a Link in the Financial Reports Workspace
#. Name of a report
-#: accounts/workspace/accounting/accounting.json
+#: accounts/workspace/financial_reports/financial_reports.json
#: regional/report/uae_vat_201/uae_vat_201.json
msgid "UAE VAT 201"
msgstr ""
@@ -75699,7 +75749,7 @@
#: manufacturing/report/bom_explorer/bom_explorer.py:58
#: manufacturing/report/bom_operations_time/bom_operations_time.py:110
#: public/js/stock_analytics.js:63 public/js/utils.js:632
-#: selling/doctype/sales_order/sales_order.js:1005
+#: selling/doctype/sales_order/sales_order.js:999
#: selling/report/item_wise_sales_history/item_wise_sales_history.py:43
#: selling/report/sales_analytics/sales_analytics.py:76
#: setup/doctype/uom/uom.json
@@ -76044,7 +76094,7 @@
msgid "UOM Name"
msgstr ""
-#: stock/doctype/stock_entry/stock_entry.py:2777
+#: stock/doctype/stock_entry/stock_entry.py:2773
msgid "UOM conversion factor required for UOM: {0} in Item: {1}"
msgstr ""
@@ -76092,10 +76142,6 @@
msgid "UnReconcile"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:791
-msgid "Unable to automatically determine {0} accounts. Set them up in the {1} table if needed."
-msgstr ""
-
#: setup/utils.py:117
msgid "Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually"
msgstr ""
@@ -76381,11 +76427,11 @@
msgid "Unreserve"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:424
+#: selling/doctype/sales_order/sales_order.js:418
msgid "Unreserve Stock"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:436
+#: selling/doctype/sales_order/sales_order.js:430
#: stock/doctype/pick_list/pick_list.js:252
msgid "Unreserving Stock..."
msgstr ""
@@ -76472,9 +76518,9 @@
#: accounts/doctype/cost_center/cost_center.js:102
#: public/js/bom_configurator/bom_configurator.bundle.js:367
#: public/js/utils.js:551 public/js/utils.js:767
-#: public/js/utils/barcode_scanner.js:161
+#: public/js/utils/barcode_scanner.js:176
#: public/js/utils/serial_no_batch_selector.js:17
-#: public/js/utils/serial_no_batch_selector.js:176
+#: public/js/utils/serial_no_batch_selector.js:180
#: stock/doctype/stock_reconciliation/stock_reconciliation.js:160
msgid "Update"
msgstr ""
@@ -76690,7 +76736,7 @@
msgid "Update latest price in all BOMs"
msgstr ""
-#: assets/doctype/asset/asset.py:337
+#: assets/doctype/asset/asset.py:338
msgid "Update stock must be enabled for the purchase invoice {0}"
msgstr ""
@@ -76819,12 +76865,6 @@
msgid "Use for Shopping Cart"
msgstr ""
-#. Description of the 'Section HTML' (Code) field in DocType 'Homepage Section'
-#: portal/doctype/homepage_section/homepage_section.json
-msgctxt "Homepage Section"
-msgid "Use this field to render any custom HTML in the section."
-msgstr ""
-
#. Label of a Int field in DocType 'Coupon Code'
#: accounts/doctype/coupon_code/coupon_code.json
msgctxt "Coupon Code"
@@ -76904,7 +76944,8 @@
msgstr ""
#. Label of a Link field in DocType 'Employee'
-#. Option for the 'Prefered Contact Email' (Select) field in DocType 'Employee'
+#. Option for the 'Preferred Contact Email' (Select) field in DocType
+#. 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
msgid "User ID"
@@ -76914,7 +76955,7 @@
msgid "User ID not set for Employee {0}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.js:554
+#: accounts/doctype/journal_entry/journal_entry.js:544
msgid "User Remark"
msgstr ""
@@ -77009,10 +77050,6 @@
msgid "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts"
msgstr ""
-#: stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js:77
-msgid "Using CSV File"
-msgstr ""
-
#: stock/doctype/stock_settings/stock_settings.js:22
msgid "Using negative stock disables FIFO/Moving average valuation when inventory is negative."
msgstr ""
@@ -77094,7 +77131,7 @@
msgstr ""
#: stock/doctype/item_price/item_price.py:62
-msgid "Valid From Date must be lesser than Valid Upto Date."
+msgid "Valid From Date must be lesser than Valid Up To Date."
msgstr ""
#: regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py:45
@@ -77125,45 +77162,45 @@
#. Label of a Date field in DocType 'Coupon Code'
#: accounts/doctype/coupon_code/coupon_code.json
msgctxt "Coupon Code"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#. Label of a Date field in DocType 'Employee'
#: setup/doctype/employee/employee.json
msgctxt "Employee"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#. Label of a Date field in DocType 'Item Price'
#: stock/doctype/item_price/item_price.json
msgctxt "Item Price"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#. Label of a Date field in DocType 'Lower Deduction Certificate'
#: regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
msgctxt "Lower Deduction Certificate"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#. Label of a Date field in DocType 'Pricing Rule'
#: accounts/doctype/pricing_rule/pricing_rule.json
msgctxt "Pricing Rule"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#. Label of a Date field in DocType 'Promotional Scheme'
#: accounts/doctype/promotional_scheme/promotional_scheme.json
msgctxt "Promotional Scheme"
-msgid "Valid Upto"
+msgid "Valid Up To"
msgstr ""
#: regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py:40
-msgid "Valid Upto date cannot be before Valid From date"
+msgid "Valid Up To date cannot be before Valid From date"
msgstr ""
#: regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py:48
-msgid "Valid Upto date not in Fiscal Year {0}"
+msgid "Valid Up To date not in Fiscal Year {0}"
msgstr ""
#. Label of a Table field in DocType 'Shipping Rule'
@@ -77180,7 +77217,7 @@
msgid "Valid till Date cannot be before Transaction Date"
msgstr ""
-#: selling/doctype/quotation/quotation.py:145
+#: selling/doctype/quotation/quotation.py:146
msgid "Valid till date cannot be before transaction date"
msgstr ""
@@ -77238,7 +77275,7 @@
msgid "Validity in Days"
msgstr ""
-#: selling/doctype/quotation/quotation.py:343
+#: selling/doctype/quotation/quotation.py:344
msgid "Validity period of this quotation has ended."
msgstr ""
@@ -77266,7 +77303,7 @@
#: accounts/report/gross_profit/gross_profit.py:266
#: stock/report/item_prices/item_prices.py:57
-#: stock/report/serial_no_ledger/serial_no_ledger.py:65
+#: stock/report/serial_no_ledger/serial_no_ledger.py:64
#: stock/report/stock_balance/stock_balance.py:449
#: stock/report/stock_ledger/stock_ledger.py:207
msgid "Valuation Rate"
@@ -77355,11 +77392,11 @@
msgid "Valuation Rate (In / Out)"
msgstr ""
-#: stock/stock_ledger.py:1599
+#: stock/stock_ledger.py:1688
msgid "Valuation Rate Missing"
msgstr ""
-#: stock/stock_ledger.py:1577
+#: stock/stock_ledger.py:1666
msgid "Valuation Rate for the Item {0}, is required to do accounting entries for {1} {2}."
msgstr ""
@@ -77367,7 +77404,7 @@
msgid "Valuation Rate is mandatory if Opening Stock entered"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:513
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:514
msgid "Valuation Rate required for Item {0} at row {1}"
msgstr ""
@@ -77378,16 +77415,16 @@
msgid "Valuation and Total"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:730
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:731
msgid "Valuation rate for customer provided items has been set to zero."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1639
-#: controllers/accounts_controller.py:2514
+#: accounts/doctype/payment_entry/payment_entry.py:1649
+#: controllers/accounts_controller.py:2583
msgid "Valuation type charges can not be marked as Inclusive"
msgstr ""
-#: public/js/controllers/accounts.js:202
+#: public/js/controllers/accounts.js:203
msgid "Valuation type charges can not marked as Inclusive"
msgstr ""
@@ -77477,7 +77514,7 @@
msgid "Value Proposition"
msgstr ""
-#: controllers/item_variant.py:121
+#: controllers/item_variant.py:125
msgid "Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3} for Item {4}"
msgstr ""
@@ -77862,12 +77899,12 @@
msgid "Voucher Name"
msgstr ""
-#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:252
-#: accounts/report/accounts_receivable/accounts_receivable.py:1027
+#: accounts/doctype/payment_reconciliation/payment_reconciliation.js:273
+#: accounts/report/accounts_receivable/accounts_receivable.py:1050
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.js:42
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.py:213
#: accounts/report/general_ledger/general_ledger.js:49
-#: accounts/report/general_ledger/general_ledger.py:622
+#: accounts/report/general_ledger/general_ledger.py:625
#: accounts/report/payment_ledger/payment_ledger.js:65
#: accounts/report/payment_ledger/payment_ledger.py:167
#: accounts/report/voucher_wise_balance/voucher_wise_balance.py:19
@@ -77880,7 +77917,7 @@
#: stock/report/reserved_stock/reserved_stock.py:151
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.js:51
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.py:114
-#: stock/report/serial_no_ledger/serial_no_ledger.py:31
+#: stock/report/serial_no_ledger/serial_no_ledger.py:30
#: stock/report/stock_and_account_value_comparison/stock_and_account_value_comparison.py:118
#: stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py:142
#: stock/report/stock_ledger_variance/stock_ledger_variance.py:72
@@ -77951,7 +77988,7 @@
msgid "Voucher Qty"
msgstr ""
-#: accounts/report/general_ledger/general_ledger.py:616
+#: accounts/report/general_ledger/general_ledger.py:619
msgid "Voucher Subtype"
msgstr ""
@@ -77961,9 +77998,9 @@
msgid "Voucher Subtype"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1025
+#: accounts/report/accounts_receivable/accounts_receivable.py:1048
#: accounts/report/general_and_payment_ledger_comparison/general_and_payment_ledger_comparison.py:203
-#: accounts/report/general_ledger/general_ledger.py:614
+#: accounts/report/general_ledger/general_ledger.py:617
#: accounts/report/payment_ledger/payment_ledger.py:158
#: accounts/report/purchase_register/purchase_register.py:158
#: accounts/report/sales_register/sales_register.py:172
@@ -78051,11 +78088,11 @@
msgid "Voucher Type"
msgstr ""
-#: accounts/doctype/bank_transaction/bank_transaction.py:159
+#: accounts/doctype/bank_transaction/bank_transaction.py:177
msgid "Voucher {0} is over-allocated by {1}"
msgstr ""
-#: accounts/doctype/bank_transaction/bank_transaction.py:231
+#: accounts/doctype/bank_transaction/bank_transaction.py:249
msgid "Voucher {0} value is broken: {1}"
msgstr ""
@@ -78165,9 +78202,9 @@
#: manufacturing/report/production_planning_report/production_planning_report.py:405
#: manufacturing/report/work_order_stock_report/work_order_stock_report.js:9
#: public/js/stock_analytics.js:45 public/js/utils.js:498
-#: public/js/utils/serial_no_batch_selector.js:86
-#: selling/doctype/sales_order/sales_order.js:306
-#: selling/doctype/sales_order/sales_order.js:407
+#: public/js/utils/serial_no_batch_selector.js:90
+#: selling/doctype/sales_order/sales_order.js:300
+#: selling/doctype/sales_order/sales_order.js:401
#: selling/report/sales_order_analysis/sales_order_analysis.js:49
#: selling/report/sales_order_analysis/sales_order_analysis.py:334
#: selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py:78
@@ -78192,7 +78229,7 @@
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.js:34
#: stock/report/serial_and_batch_summary/serial_and_batch_summary.py:140
#: stock/report/serial_no_ledger/serial_no_ledger.js:22
-#: stock/report/serial_no_ledger/serial_no_ledger.py:45
+#: stock/report/serial_no_ledger/serial_no_ledger.py:44
#: stock/report/stock_ageing/stock_ageing.js:23
#: stock/report/stock_ageing/stock_ageing.py:146
#: stock/report/stock_analytics/stock_analytics.js:50
@@ -78406,6 +78443,10 @@
msgid "Warehouse"
msgstr ""
+#: stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js:4
+msgid "Warehouse Capacity Summary"
+msgstr ""
+
#: stock/doctype/putaway_rule/putaway_rule.py:78
msgid "Warehouse Capacity for Item '{0}' must be greater than the existing stock level of {1} {2}."
msgstr ""
@@ -78527,11 +78568,11 @@
msgid "Warehouse not found against the account {0}"
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:366
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:367
msgid "Warehouse not found in the system"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1002
+#: accounts/doctype/sales_invoice/sales_invoice.py:1005
#: stock/doctype/delivery_note/delivery_note.py:362
msgid "Warehouse required for stock Item {0}"
msgstr ""
@@ -78554,11 +78595,11 @@
msgid "Warehouse {0} does not belong to Company {1}."
msgstr ""
-#: stock/utils.py:394
+#: stock/utils.py:441
msgid "Warehouse {0} does not belong to company {1}"
msgstr ""
-#: controllers/stock_controller.py:252
+#: controllers/stock_controller.py:244
msgid "Warehouse {0} is not linked to any account, please mention the account in the warehouse record or set default inventory account in company {1}."
msgstr ""
@@ -78680,8 +78721,8 @@
msgid "Warn for new Request for Quotations"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:637
-#: controllers/accounts_controller.py:1643
+#: accounts/doctype/payment_entry/payment_entry.py:639
+#: controllers/accounts_controller.py:1676
#: stock/doctype/delivery_trip/delivery_trip.js:123
#: utilities/transaction_base.py:122
msgid "Warning"
@@ -78695,7 +78736,7 @@
msgid "Warning!"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:1260
+#: accounts/doctype/journal_entry/journal_entry.py:1146
msgid "Warning: Another {0} # {1} exists against stock entry {2}"
msgstr ""
@@ -78703,7 +78744,7 @@
msgid "Warning: Material Requested Qty is less than Minimum Order Qty"
msgstr ""
-#: selling/doctype/sales_order/sales_order.py:249
+#: selling/doctype/sales_order/sales_order.py:252
msgid "Warning: Sales Order {0} already exists against Customer's Purchase Order {1}"
msgstr ""
@@ -79236,7 +79277,7 @@
msgid "Wheels"
msgstr ""
-#: stock/doctype/item/item.js:848
+#: stock/doctype/item/item.js:834
msgid "When creating an Item, entering a value for this field will automatically create an Item Price at the backend."
msgstr ""
@@ -79323,7 +79364,7 @@
msgid "Work Done"
msgstr ""
-#: setup/doctype/company/company.py:260
+#: setup/doctype/company/company.py:261
msgid "Work In Progress"
msgstr ""
@@ -79363,7 +79404,7 @@
#: manufacturing/report/process_loss_report/process_loss_report.py:68
#: manufacturing/report/work_order_consumed_materials/work_order_consumed_materials.js:30
#: manufacturing/report/work_order_stock_report/work_order_stock_report.py:104
-#: selling/doctype/sales_order/sales_order.js:566
+#: selling/doctype/sales_order/sales_order.js:560
#: stock/doctype/material_request/material_request.js:152
#: stock/doctype/material_request/material_request.py:779
#: templates/pages/material_request_info.html:45
@@ -79476,7 +79517,7 @@
msgid "Work Order has been {0}"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:673
+#: selling/doctype/sales_order/sales_order.js:667
msgid "Work Order not created"
msgstr ""
@@ -79489,7 +79530,7 @@
msgid "Work Orders"
msgstr ""
-#: selling/doctype/sales_order/sales_order.js:737
+#: selling/doctype/sales_order/sales_order.js:731
msgid "Work Orders Created: {0}"
msgstr ""
@@ -79686,7 +79727,7 @@
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py:72
#: accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py:96
-#: setup/doctype/company/company.py:509
+#: setup/doctype/company/company.py:510
msgid "Write Off"
msgstr ""
@@ -79877,7 +79918,7 @@
msgid "Wrong Company"
msgstr ""
-#: setup/doctype/company/company.js:167
+#: setup/doctype/company/company.js:172
msgid "Wrong Password"
msgstr ""
@@ -79941,7 +79982,7 @@
#: buying/report/purchase_analytics/purchase_analytics.js:64
#: manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.js:61
#: manufacturing/report/production_analytics/production_analytics.js:37
-#: public/js/financial_statements.js:167
+#: public/js/financial_statements.js:220
#: public/js/purchase_trends_filters.js:22 public/js/sales_trends_filters.js:14
#: public/js/stock_analytics.js:55
#: selling/report/sales_analytics/sales_analytics.js:64
@@ -80082,11 +80123,11 @@
msgid "Yes"
msgstr ""
-#: controllers/accounts_controller.py:3092
+#: controllers/accounts_controller.py:3151
msgid "You are not allowed to update as per the conditions set in {} Workflow."
msgstr ""
-#: accounts/general_ledger.py:666
+#: accounts/general_ledger.py:665
msgid "You are not authorized to add or update entries before {0}"
msgstr ""
@@ -80114,7 +80155,7 @@
msgid "You can also set default CWIP account in Company {}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:870
+#: accounts/doctype/sales_invoice/sales_invoice.py:873
msgid "You can change the parent account to a Balance Sheet account or select a different account."
msgstr ""
@@ -80122,11 +80163,11 @@
msgid "You can not cancel this Period Closing Voucher, please cancel the future Period Closing Vouchers first"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:567
+#: accounts/doctype/journal_entry/journal_entry.py:583
msgid "You can not enter current voucher in 'Against Journal Entry' column"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:184
+#: accounts/doctype/subscription/subscription.py:183
msgid "You can only have Plans with the same billing cycle in a Subscription"
msgstr ""
@@ -80172,11 +80213,11 @@
msgid "You cannot create or cancel any accounting entries with in the closed Accounting Period {0}"
msgstr ""
-#: accounts/general_ledger.py:690
+#: accounts/general_ledger.py:689
msgid "You cannot create/amend any accounting entries till this date."
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:857
+#: accounts/doctype/journal_entry/journal_entry.py:809
msgid "You cannot credit and debit same account at the same time"
msgstr ""
@@ -80196,7 +80237,7 @@
msgid "You cannot repost item valuation before {}"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:703
+#: accounts/doctype/subscription/subscription.py:735
msgid "You cannot restart a Subscription that is not cancelled."
msgstr ""
@@ -80208,7 +80249,7 @@
msgid "You cannot submit the order without payment."
msgstr ""
-#: controllers/accounts_controller.py:3068
+#: controllers/accounts_controller.py:3127
msgid "You do not have permissions to {} items in a {}."
msgstr ""
@@ -80252,7 +80293,7 @@
msgid "You must select a customer before adding an item."
msgstr ""
-#: accounts/doctype/pos_invoice/pos_invoice.py:253
+#: accounts/doctype/pos_invoice/pos_invoice.py:251
msgid "You need to cancel POS Closing Entry {} to be able to cancel this document."
msgstr ""
@@ -80337,11 +80378,11 @@
msgid "Zip File"
msgstr ""
-#: stock/reorder_item.py:244
+#: stock/reorder_item.py:283
msgid "[Important] [ERPNext] Auto Reorder Errors"
msgstr ""
-#: controllers/status_updater.py:238
+#: controllers/status_updater.py:247
msgid "`Allow Negative rates for Items`"
msgstr ""
@@ -80545,7 +80586,7 @@
msgid "old_parent"
msgstr ""
-#: controllers/accounts_controller.py:999
+#: controllers/accounts_controller.py:1033
msgid "or"
msgstr ""
@@ -80553,7 +80594,7 @@
msgid "or its descendants"
msgstr ""
-#: templates/includes/macros.html:239 templates/includes/macros.html:243
+#: templates/includes/macros.html:207 templates/includes/macros.html:211
msgid "out of 5"
msgstr ""
@@ -80598,7 +80639,7 @@
msgid "per hour"
msgstr ""
-#: stock/stock_ledger.py:1592
+#: stock/stock_ledger.py:1681
msgid "performing either one below:"
msgstr ""
@@ -80622,11 +80663,11 @@
msgid "quotation_item"
msgstr ""
-#: templates/includes/macros.html:234
+#: templates/includes/macros.html:202
msgid "ratings"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1085
+#: accounts/doctype/payment_entry/payment_entry.py:1105
msgid "received from"
msgstr ""
@@ -80703,15 +80744,15 @@
msgid "sandbox"
msgstr ""
-#: public/js/controllers/transaction.js:919
+#: public/js/controllers/transaction.js:920
msgid "selected Payment Terms Template"
msgstr ""
-#: accounts/doctype/subscription/subscription.py:679
+#: accounts/doctype/subscription/subscription.py:711
msgid "subscription is already cancelled."
msgstr ""
-#: controllers/status_updater.py:344 controllers/status_updater.py:364
+#: controllers/status_updater.py:353 controllers/status_updater.py:373
msgid "target_ref_field"
msgstr ""
@@ -80727,12 +80768,12 @@
msgid "title"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:1085
+#: accounts/doctype/payment_entry/payment_entry.py:1105
#: accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html:27
msgid "to"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2766
+#: accounts/doctype/sales_invoice/sales_invoice.py:2737
msgid "to unallocate the amount of this Return Invoice before cancelling it."
msgstr ""
@@ -80768,7 +80809,7 @@
msgid "{0}"
msgstr ""
-#: controllers/accounts_controller.py:844
+#: controllers/accounts_controller.py:878
msgid "{0} '{1}' is disabled"
msgstr ""
@@ -80788,7 +80829,7 @@
msgid "{0} <b>{1}</b> has submitted Assets. Remove Item <b>{2}</b> from table to continue."
msgstr ""
-#: controllers/accounts_controller.py:1824
+#: controllers/accounts_controller.py:1893
msgid "{0} Account not found against Customer {1}."
msgstr ""
@@ -80804,7 +80845,7 @@
msgid "{0} Digest"
msgstr ""
-#: accounts/utils.py:1258
+#: accounts/utils.py:1286
msgid "{0} Number {1} is already used in {2} {3}"
msgstr ""
@@ -80832,19 +80873,19 @@
msgid "{0} account not found while submitting purchase receipt"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:978
+#: accounts/doctype/journal_entry/journal_entry.py:930
msgid "{0} against Bill {1} dated {2}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:987
+#: accounts/doctype/journal_entry/journal_entry.py:939
msgid "{0} against Purchase Order {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:954
+#: accounts/doctype/journal_entry/journal_entry.py:906
msgid "{0} against Sales Invoice {1}"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:961
+#: accounts/doctype/journal_entry/journal_entry.py:913
msgid "{0} against Sales Order {1}"
msgstr ""
@@ -80878,11 +80919,11 @@
msgid "{0} created"
msgstr ""
-#: setup/doctype/company/company.py:190
+#: setup/doctype/company/company.py:191
msgid "{0} currency must be same as company's default currency. Please select another account."
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:306
+#: buying/doctype/purchase_order/purchase_order.py:310
msgid "{0} currently has a {1} Supplier Scorecard standing, and Purchase Orders to this supplier should be issued with caution."
msgstr ""
@@ -80906,7 +80947,7 @@
msgid "{0} for {1}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:362
+#: accounts/doctype/payment_entry/payment_entry.py:364
msgid "{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
msgstr ""
@@ -80914,7 +80955,7 @@
msgid "{0} has been submitted successfully"
msgstr ""
-#: controllers/accounts_controller.py:2143
+#: controllers/accounts_controller.py:2212
msgid "{0} in row {1}"
msgstr ""
@@ -80922,18 +80963,18 @@
msgid "{0} is a mandatory Accounting Dimension. <br>Please set a value for {0} in Accounting Dimensions section."
msgstr ""
-#: controllers/accounts_controller.py:159
+#: controllers/accounts_controller.py:162
msgid "{0} is blocked so this transaction cannot proceed"
msgstr ""
#: accounts/doctype/budget/budget.py:57
-#: accounts/doctype/payment_entry/payment_entry.py:540
+#: accounts/doctype/payment_entry/payment_entry.py:542
#: accounts/report/general_ledger/general_ledger.py:62
#: accounts/report/pos_register/pos_register.py:110 controllers/trends.py:50
msgid "{0} is mandatory"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:972
+#: accounts/doctype/sales_invoice/sales_invoice.py:975
msgid "{0} is mandatory for Item {1}"
msgstr ""
@@ -80946,11 +80987,11 @@
msgid "{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}"
msgstr ""
-#: controllers/accounts_controller.py:2422
+#: controllers/accounts_controller.py:2491
msgid "{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}."
msgstr ""
-#: selling/doctype/customer/customer.py:198
+#: selling/doctype/customer/customer.py:199
msgid "{0} is not a company bank account"
msgstr ""
@@ -80962,7 +81003,7 @@
msgid "{0} is not a stock Item"
msgstr ""
-#: controllers/item_variant.py:140
+#: controllers/item_variant.py:144
msgid "{0} is not a valid Value for Attribute {1} of Item {2}."
msgstr ""
@@ -80978,7 +81019,7 @@
msgid "{0} is not the default supplier for any items."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:2277
+#: accounts/doctype/payment_entry/payment_entry.py:2300
msgid "{0} is on hold till {1}"
msgstr ""
@@ -81001,11 +81042,11 @@
msgid "{0} must be negative in return document"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:2011
+#: accounts/doctype/sales_invoice/sales_invoice.py:1988
msgid "{0} not allowed to transact with {1}. Please change the Company."
msgstr ""
-#: manufacturing/doctype/bom/bom.py:465
+#: manufacturing/doctype/bom/bom.py:467
msgid "{0} not found for item {1}"
msgstr ""
@@ -81017,11 +81058,11 @@
msgid "{0} payment entries can not be filtered by {1}"
msgstr ""
-#: controllers/stock_controller.py:798
+#: controllers/stock_controller.py:899
msgid "{0} qty of Item {1} is being received into Warehouse {2} with capacity {3}."
msgstr ""
-#: stock/doctype/stock_reconciliation/stock_reconciliation.py:450
+#: stock/doctype/stock_reconciliation/stock_reconciliation.py:451
msgid "{0} units are reserved for Item {1} in Warehouse {2}, please un-reserve the same to {3} the Stock Reconciliation."
msgstr ""
@@ -81037,20 +81078,20 @@
msgid "{0} units of {1} are required in {2}{3}, on {4} {5} for {6} to complete the transaction."
msgstr ""
-#: stock/stock_ledger.py:1235 stock/stock_ledger.py:1740
-#: stock/stock_ledger.py:1756
+#: stock/stock_ledger.py:1340 stock/stock_ledger.py:1829
+#: stock/stock_ledger.py:1845
msgid "{0} units of {1} needed in {2} on {3} {4} for {5} to complete this transaction."
msgstr ""
-#: stock/stock_ledger.py:1866 stock/stock_ledger.py:1916
+#: stock/stock_ledger.py:1955 stock/stock_ledger.py:2005
msgid "{0} units of {1} needed in {2} on {3} {4} to complete this transaction."
msgstr ""
-#: stock/stock_ledger.py:1229
+#: stock/stock_ledger.py:1334
msgid "{0} units of {1} needed in {2} to complete this transaction."
msgstr ""
-#: stock/utils.py:385
+#: stock/utils.py:432
msgid "{0} valid serial nos for Item {1}"
msgstr ""
@@ -81066,6 +81107,10 @@
msgid "{0} {1}"
msgstr ""
+#: public/js/utils/serial_no_batch_selector.js:203
+msgid "{0} {1} Manually"
+msgstr ""
+
#: accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py:433
msgid "{0} {1} Partially Reconciled"
msgstr ""
@@ -81078,9 +81123,9 @@
msgid "{0} {1} created"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:504
-#: accounts/doctype/payment_entry/payment_entry.py:560
-#: accounts/doctype/payment_entry/payment_entry.py:2042
+#: accounts/doctype/payment_entry/payment_entry.py:506
+#: accounts/doctype/payment_entry/payment_entry.py:562
+#: accounts/doctype/payment_entry/payment_entry.py:2065
msgid "{0} {1} does not exist"
msgstr ""
@@ -81088,16 +81133,16 @@
msgid "{0} {1} has accounting entries in currency {2} for company {3}. Please select a receivable or payable account with currency {2}."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:372
+#: accounts/doctype/payment_entry/payment_entry.py:374
msgid "{0} {1} has already been fully paid."
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:382
+#: accounts/doctype/payment_entry/payment_entry.py:384
msgid "{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
msgstr ""
-#: buying/doctype/purchase_order/purchase_order.py:445
-#: selling/doctype/sales_order/sales_order.py:478
+#: buying/doctype/purchase_order/purchase_order.py:449
+#: selling/doctype/sales_order/sales_order.py:481
#: stock/doctype/material_request/material_request.py:198
msgid "{0} {1} has been modified. Please refresh."
msgstr ""
@@ -81106,16 +81151,16 @@
msgid "{0} {1} has not been submitted so the action cannot be completed"
msgstr ""
-#: accounts/doctype/bank_transaction/bank_transaction.py:72
+#: accounts/doctype/bank_transaction/bank_transaction.py:90
msgid "{0} {1} is allocated twice in this Bank Transaction"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:589
+#: accounts/doctype/payment_entry/payment_entry.py:591
msgid "{0} {1} is associated with {2}, but Party Account is {3}"
msgstr ""
#: controllers/buying_controller.py:624 controllers/selling_controller.py:421
-#: controllers/subcontracting_controller.py:802
+#: controllers/subcontracting_controller.py:806
msgid "{0} {1} is cancelled or closed"
msgstr ""
@@ -81127,7 +81172,7 @@
msgid "{0} {1} is cancelled so the action cannot be completed"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:709
+#: accounts/doctype/journal_entry/journal_entry.py:725
msgid "{0} {1} is closed"
msgstr ""
@@ -81139,7 +81184,7 @@
msgid "{0} {1} is frozen"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:706
+#: accounts/doctype/journal_entry/journal_entry.py:722
msgid "{0} {1} is fully billed"
msgstr ""
@@ -81147,7 +81192,7 @@
msgid "{0} {1} is not active"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:567
+#: accounts/doctype/payment_entry/payment_entry.py:569
msgid "{0} {1} is not associated with {2} {3}"
msgstr ""
@@ -81155,12 +81200,12 @@
msgid "{0} {1} is not in any active Fiscal Year"
msgstr ""
-#: accounts/doctype/journal_entry/journal_entry.py:703
-#: accounts/doctype/journal_entry/journal_entry.py:744
+#: accounts/doctype/journal_entry/journal_entry.py:719
+#: accounts/doctype/journal_entry/journal_entry.py:760
msgid "{0} {1} is not submitted"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:596
+#: accounts/doctype/payment_entry/payment_entry.py:598
msgid "{0} {1} is on hold"
msgstr ""
@@ -81168,7 +81213,7 @@
msgid "{0} {1} is {2}"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.py:601
+#: accounts/doctype/payment_entry/payment_entry.py:603
msgid "{0} {1} must be submitted"
msgstr ""
@@ -81180,7 +81225,7 @@
msgid "{0} {1} status is {2}"
msgstr ""
-#: public/js/utils/serial_no_batch_selector.js:185
+#: public/js/utils/serial_no_batch_selector.js:189
msgid "{0} {1} via CSV File"
msgstr ""
@@ -81207,7 +81252,7 @@
msgid "{0} {1}: Accounting Entry for {2} can only be made in currency: {3}"
msgstr ""
-#: controllers/stock_controller.py:373
+#: controllers/stock_controller.py:365
msgid "{0} {1}: Cost Center is mandatory for Item {2}"
msgstr ""
@@ -81264,19 +81309,19 @@
msgid "{0}: {1} does not exists"
msgstr ""
-#: accounts/doctype/payment_entry/payment_entry.js:713
+#: accounts/doctype/payment_entry/payment_entry.js:724
msgid "{0}: {1} must be less than {2}"
msgstr ""
-#: manufacturing/doctype/bom/bom.py:212
+#: manufacturing/doctype/bom/bom.py:214
msgid "{0}{1} Did you rename the item? Please contact Administrator / Tech support"
msgstr ""
-#: controllers/stock_controller.py:1062
+#: controllers/stock_controller.py:1160
msgid "{item_name}'s Sample Size ({sample_size}) cannot be greater than the Accepted Quantity ({accepted_quantity})"
msgstr ""
-#: accounts/report/accounts_receivable/accounts_receivable.py:1125
+#: accounts/report/accounts_receivable/accounts_receivable.py:1148
msgid "{range4}-Above"
msgstr ""
@@ -81288,7 +81333,7 @@
msgid "{} Assets created for {}"
msgstr ""
-#: accounts/doctype/sales_invoice/sales_invoice.py:1798
+#: accounts/doctype/sales_invoice/sales_invoice.py:1775
msgid "{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {}"
msgstr ""
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index ceb4406..75d890c 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -222,7 +222,7 @@
def validate_maintenance_detail(self):
if not self.get("items"):
- throw(_("Please enter Maintaince Details first"))
+ throw(_("Please enter Maintenance Details first"))
for d in self.get("items"):
if not d.item_code:
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
index 6a72c4f..dcf122c 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
@@ -90,6 +90,7 @@
def update_item(source, target, source_parent):
target_qty = source.get("qty") - source.get("ordered_qty")
target.qty = target_qty if flt(target_qty) >= 0 else 0
+ target.rate = source.get("rate")
item = get_item_defaults(target.item_code, source_parent.company)
if item:
target.item_name = item.get("item_name")
@@ -111,6 +112,10 @@
},
},
)
+
+ if target_doc.doctype == "Purchase Order":
+ target_doc.set_missing_values()
+
return target_doc
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index f034ed2..6f35206 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -176,8 +176,10 @@
def autoname(self):
# ignore amended documents while calculating current index
+
+ search_key = f"{self.doctype}-{self.item}%"
existing_boms = frappe.get_all(
- "BOM", filters={"item": self.item, "amended_from": ["is", "not set"]}, pluck="name"
+ "BOM", filters={"name": ("like", search_key), "amended_from": ["is", "not set"]}, pluck="name"
)
if existing_boms:
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 23650b6..079350b 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -955,6 +955,14 @@
if update_status:
self.db_set("status", self.status)
+ if self.status in ["Completed", "Work In Progress"]:
+ status = {
+ "Completed": "Off",
+ "Work In Progress": "Production",
+ }.get(self.status)
+
+ self.update_status_in_workstation(status)
+
def set_wip_warehouse(self):
if not self.wip_warehouse:
self.wip_warehouse = frappe.db.get_single_value(
@@ -1035,6 +1043,12 @@
return False
+ def update_status_in_workstation(self, status):
+ if not self.workstation:
+ return
+
+ frappe.db.set_value("Workstation", self.workstation, "status", status)
+
@frappe.whitelist()
def make_time_log(args):
diff --git a/erpnext/manufacturing/doctype/plant_floor/__init__.py b/erpnext/manufacturing/doctype/plant_floor/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/__init__.py
diff --git a/erpnext/manufacturing/doctype/plant_floor/plant_floor.js b/erpnext/manufacturing/doctype/plant_floor/plant_floor.js
new file mode 100644
index 0000000..67e5acd
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/plant_floor.js
@@ -0,0 +1,256 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Plant Floor", {
+ setup(frm) {
+ frm.trigger("setup_queries");
+ },
+
+ setup_queries(frm) {
+ frm.set_query("warehouse", (doc) => {
+ if (!doc.company) {
+ frappe.throw(__("Please select Company first"));
+ }
+
+ return {
+ filters: {
+ "is_group": 0,
+ "company": doc.company
+ }
+ }
+ });
+ },
+
+ refresh(frm) {
+ frm.trigger('prepare_stock_dashboard')
+ frm.trigger('prepare_workstation_dashboard')
+ },
+
+ prepare_workstation_dashboard(frm) {
+ let wrapper = $(frm.fields_dict["plant_dashboard"].wrapper);
+ wrapper.empty();
+
+ frappe.visual_plant_floor = new frappe.ui.VisualPlantFloor({
+ wrapper: wrapper,
+ skip_filters: true,
+ plant_floor: frm.doc.name,
+ });
+ },
+
+ prepare_stock_dashboard(frm) {
+ if (!frm.doc.warehouse) {
+ return;
+ }
+
+ let wrapper = $(frm.fields_dict["stock_summary"].wrapper);
+ wrapper.empty();
+
+ frappe.visual_stock = new VisualStock({
+ wrapper: wrapper,
+ frm: frm,
+ });
+ },
+});
+
+
+class VisualStock {
+ constructor(opts) {
+ Object.assign(this, opts);
+ this.make();
+ }
+
+ make() {
+ this.prepare_filters();
+ this.prepare_stock_summary({
+ start:0
+ });
+ }
+
+ prepare_filters() {
+ this.wrapper.append(`
+ <div class="row">
+ <div class="col-sm-12 filter-section section-body">
+
+ </div>
+ </div>
+ `);
+
+ this.item_filter = frappe.ui.form.make_control({
+ df: {
+ fieldtype: "Link",
+ fieldname: "item_code",
+ placeholder: __("Item"),
+ options: "Item",
+ onchange: () => this.prepare_stock_summary({
+ start:0,
+ item_code: this.item_filter.value
+ })
+ },
+ parent: this.wrapper.find('.filter-section'),
+ render_input: true,
+ });
+
+ this.item_filter.$wrapper.addClass('form-column col-sm-3');
+ this.item_filter.$wrapper.find('.clearfix').hide();
+
+ this.item_group_filter = frappe.ui.form.make_control({
+ df: {
+ fieldtype: "Link",
+ fieldname: "item_group",
+ placeholder: __("Item Group"),
+ options: "Item Group",
+ change: () => this.prepare_stock_summary({
+ start:0,
+ item_group: this.item_group_filter.value
+ })
+ },
+ parent: this.wrapper.find('.filter-section'),
+ render_input: true,
+ });
+
+ this.item_group_filter.$wrapper.addClass('form-column col-sm-3');
+ this.item_group_filter.$wrapper.find('.clearfix').hide();
+ }
+
+ prepare_stock_summary(args) {
+ let {start, item_code, item_group} = args;
+
+ this.get_stock_summary(start, item_code, item_group).then(stock_summary => {
+ this.wrapper.find('.stock-summary-container').remove();
+ this.wrapper.append(`<div class="col-sm-12 stock-summary-container" style="margin-bottom:20px"></div>`);
+ this.stock_summary = stock_summary.message;
+ this.render_stock_summary();
+ this.bind_events();
+ });
+ }
+
+ async get_stock_summary(start, item_code, item_group) {
+ let stock_summary = await frappe.call({
+ method: "erpnext.manufacturing.doctype.plant_floor.plant_floor.get_stock_summary",
+ args: {
+ warehouse: this.frm.doc.warehouse,
+ start: start,
+ item_code: item_code,
+ item_group: item_group
+ }
+ });
+
+ return stock_summary;
+ }
+
+ render_stock_summary() {
+ let template = frappe.render_template("stock_summary_template", {
+ stock_summary: this.stock_summary
+ });
+
+ this.wrapper.find('.stock-summary-container').append(template);
+ }
+
+ bind_events() {
+ this.wrapper.find('.btn-add').click((e) => {
+ this.item_code = decodeURI($(e.currentTarget).attr('data-item-code'));
+
+ this.make_stock_entry([
+ {
+ label: __("For Item"),
+ fieldname: "item_code",
+ fieldtype: "Data",
+ read_only: 1,
+ default: this.item_code
+ },
+ {
+ label: __("Quantity"),
+ fieldname: "qty",
+ fieldtype: "Float",
+ reqd: 1
+ }
+ ], __("Add Stock"), "Material Receipt")
+ });
+
+ this.wrapper.find('.btn-move').click((e) => {
+ this.item_code = decodeURI($(e.currentTarget).attr('data-item-code'));
+
+ this.make_stock_entry([
+ {
+ label: __("For Item"),
+ fieldname: "item_code",
+ fieldtype: "Data",
+ read_only: 1,
+ default: this.item_code
+ },
+ {
+ label: __("Quantity"),
+ fieldname: "qty",
+ fieldtype: "Float",
+ reqd: 1
+ },
+ {
+ label: __("To Warehouse"),
+ fieldname: "to_warehouse",
+ fieldtype: "Link",
+ options: "Warehouse",
+ reqd: 1,
+ get_query: () => {
+ return {
+ filters: {
+ "is_group": 0,
+ "company": this.frm.doc.company
+ }
+ }
+ }
+ }
+ ], __("Move Stock"), "Material Transfer")
+ });
+ }
+
+ make_stock_entry(fields, title, stock_entry_type) {
+ frappe.prompt(fields,
+ (values) => {
+ this.values = values;
+ this.stock_entry_type = stock_entry_type;
+ this.update_values();
+
+ this.frm.call({
+ method: "make_stock_entry",
+ doc: this.frm.doc,
+ args: {
+ kwargs: this.values,
+ },
+ callback: (r) => {
+ if (!r.exc) {
+ var doc = frappe.model.sync(r.message);
+ frappe.set_route("Form", r.message.doctype, r.message.name);
+ }
+ }
+ })
+ }, __(title), __("Create")
+ );
+ }
+
+ update_values() {
+ if (!this.values.qty) {
+ frappe.throw(__("Quantity is required"));
+ }
+
+ let from_warehouse = "";
+ let to_warehouse = "";
+
+ if (this.stock_entry_type == "Material Receipt") {
+ to_warehouse = this.frm.doc.warehouse;
+ } else {
+ from_warehouse = this.frm.doc.warehouse;
+ to_warehouse = this.values.to_warehouse;
+ }
+
+ this.values = {
+ ...this.values,
+ ...{
+ "company": this.frm.doc.company,
+ "item_code": this.item_code,
+ "from_warehouse": from_warehouse,
+ "to_warehouse": to_warehouse,
+ "purpose": this.stock_entry_type,
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/plant_floor/plant_floor.json b/erpnext/manufacturing/doctype/plant_floor/plant_floor.json
new file mode 100644
index 0000000..be0052c
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/plant_floor.json
@@ -0,0 +1,97 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "field:floor_name",
+ "creation": "2023-10-06 15:06:07.976066",
+ "default_view": "List",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "workstations_tab",
+ "plant_dashboard",
+ "stock_summary_tab",
+ "stock_summary",
+ "details_tab",
+ "column_break_mvbx",
+ "floor_name",
+ "company",
+ "warehouse"
+ ],
+ "fields": [
+ {
+ "fieldname": "floor_name",
+ "fieldtype": "Data",
+ "label": "Floor Name",
+ "unique": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "workstations_tab",
+ "fieldtype": "Tab Break",
+ "label": "Workstations"
+ },
+ {
+ "fieldname": "plant_dashboard",
+ "fieldtype": "HTML",
+ "label": "Plant Dashboard"
+ },
+ {
+ "fieldname": "details_tab",
+ "fieldtype": "Tab Break",
+ "label": "Floor"
+ },
+ {
+ "fieldname": "column_break_mvbx",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal && doc.warehouse",
+ "fieldname": "stock_summary_tab",
+ "fieldtype": "Tab Break",
+ "label": "Stock Summary"
+ },
+ {
+ "fieldname": "stock_summary",
+ "fieldtype": "HTML",
+ "label": "Stock Summary"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2024-01-30 11:59:07.508535",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Plant Floor",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/plant_floor/plant_floor.py b/erpnext/manufacturing/doctype/plant_floor/plant_floor.py
new file mode 100644
index 0000000..d30b7d1
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/plant_floor.py
@@ -0,0 +1,129 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe.model.document import Document
+from frappe.query_builder import Order
+from frappe.utils import get_link_to_form, nowdate, nowtime
+
+
+class PlantFloor(Document):
+ # begin: auto-generated types
+ # This code is auto-generated. Do not modify anything in this block.
+
+ from typing import TYPE_CHECKING
+
+ if TYPE_CHECKING:
+ from frappe.types import DF
+
+ company: DF.Link | None
+ floor_name: DF.Data | None
+ warehouse: DF.Link | None
+ # end: auto-generated types
+
+ @frappe.whitelist()
+ def make_stock_entry(self, kwargs):
+ if isinstance(kwargs, str):
+ kwargs = frappe.parse_json(kwargs)
+
+ if isinstance(kwargs, dict):
+ kwargs = frappe._dict(kwargs)
+
+ stock_entry = frappe.new_doc("Stock Entry")
+ stock_entry.update(
+ {
+ "company": kwargs.company,
+ "from_warehouse": kwargs.from_warehouse,
+ "to_warehouse": kwargs.to_warehouse,
+ "purpose": kwargs.purpose,
+ "stock_entry_type": kwargs.purpose,
+ "posting_date": nowdate(),
+ "posting_time": nowtime(),
+ "items": self.get_item_details(kwargs),
+ }
+ )
+
+ stock_entry.set_missing_values()
+
+ return stock_entry
+
+ def get_item_details(self, kwargs) -> list[dict]:
+ item_details = frappe.db.get_value(
+ "Item", kwargs.item_code, ["item_name", "stock_uom", "item_group", "description"], as_dict=True
+ )
+ item_details.update(
+ {
+ "qty": kwargs.qty,
+ "uom": item_details.stock_uom,
+ "item_code": kwargs.item_code,
+ "conversion_factor": 1,
+ "s_warehouse": kwargs.from_warehouse,
+ "t_warehouse": kwargs.to_warehouse,
+ }
+ )
+
+ return [item_details]
+
+
+@frappe.whitelist()
+def get_stock_summary(warehouse, start=0, item_code=None, item_group=None):
+ stock_details = get_stock_details(
+ warehouse, start=start, item_code=item_code, item_group=item_group
+ )
+
+ max_count = 0.0
+ for d in stock_details:
+ d.actual_or_pending = (
+ d.projected_qty
+ + d.reserved_qty
+ + d.reserved_qty_for_production
+ + d.reserved_qty_for_sub_contract
+ )
+ d.pending_qty = 0
+ d.total_reserved = (
+ d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract
+ )
+ if d.actual_or_pending > d.actual_qty:
+ d.pending_qty = d.actual_or_pending - d.actual_qty
+
+ d.max_count = max(d.actual_or_pending, d.actual_qty, d.total_reserved, max_count)
+ max_count = d.max_count
+ d.item_link = get_link_to_form("Item", d.item_code)
+
+ return stock_details
+
+
+def get_stock_details(warehouse, start=0, item_code=None, item_group=None):
+ item_table = frappe.qb.DocType("Item")
+ bin_table = frappe.qb.DocType("Bin")
+
+ query = (
+ frappe.qb.from_(bin_table)
+ .inner_join(item_table)
+ .on(bin_table.item_code == item_table.name)
+ .select(
+ bin_table.item_code,
+ bin_table.actual_qty,
+ bin_table.projected_qty,
+ bin_table.reserved_qty,
+ bin_table.reserved_qty_for_production,
+ bin_table.reserved_qty_for_sub_contract,
+ bin_table.reserved_qty_for_production_plan,
+ bin_table.reserved_stock,
+ item_table.item_name,
+ item_table.item_group,
+ item_table.image,
+ )
+ .where(bin_table.warehouse == warehouse)
+ .limit(20)
+ .offset(start)
+ .orderby(bin_table.actual_qty, order=Order.desc)
+ )
+
+ if item_code:
+ query = query.where(bin_table.item_code == item_code)
+
+ if item_group:
+ query = query.where(item_table.item_group == item_group)
+
+ return query.run(as_dict=True)
diff --git a/erpnext/manufacturing/doctype/plant_floor/stock_summary_template.html b/erpnext/manufacturing/doctype/plant_floor/stock_summary_template.html
new file mode 100644
index 0000000..8824c98
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/stock_summary_template.html
@@ -0,0 +1,61 @@
+{% $.each(stock_summary, (idx, row) => { %}
+<div class="row" style="border-bottom:1px solid var(--border-color); padding:4px 5px; margin-top: 3px;margin-bottom: 3px;">
+ <div class="col-sm-1">
+ {% if(row.image) { %}
+ <img style="width:50px;height:50px;" src="{{row.image}}">
+ {% } else { %}
+ <div style="width:50px;height:50px;background-color:var(--control-bg);text-align:center;padding-top:15px">{{frappe.get_abbr(row.item_code, 2)}}</div>
+ {% } %}
+ </div>
+ <div class="col-sm-3">
+ {% if (row.item_code === row.item_name) { %}
+ {{row.item_link}}
+ {% } else { %}
+ {{row.item_link}}
+ <p>
+ {{row.item_name}}
+ </p>
+ {% } %}
+
+ </div>
+ <div class="col-sm-1" title="{{ __('Actual Qty') }}">
+ {{ frappe.format(row.actual_qty, { fieldtype: "Float"})}}
+ </div>
+ <div class="col-sm-1" title="{{ __('Reserved Stock') }}">
+ {{ frappe.format(row.reserved_stock, { fieldtype: "Float"})}}
+ </div>
+ <div class="col-sm-4 small">
+ <span class="inline-graph">
+ <span class="inline-graph-half" title="{{ __("Reserved Qty") }}">
+ <span class="inline-graph-count">{{ row.total_reserved }}</span>
+ <span class="inline-graph-bar">
+ <span class="inline-graph-bar-inner"
+ style="width: {{ cint(Math.abs(row.total_reserved)/row.max_count * 100) || 5 }}%">
+ </span>
+ </span>
+ </span>
+ <span class="inline-graph-half" title="{{ __("Actual Qty {0} / Waiting Qty {1}", [row.actual_qty, row.pending_qty]) }}">
+ <span class="inline-graph-count">
+ {{ row.actual_qty }} {{ (row.pending_qty > 0) ? ("(" + row.pending_qty+ ")") : "" }}
+ </span>
+ <span class="inline-graph-bar">
+ <span class="inline-graph-bar-inner dark"
+ style="width: {{ cint(row.actual_qty/row.max_count * 100) }}%">
+ </span>
+ {% if row.pending_qty > 0 %}
+ <span class="inline-graph-bar-inner" title="{{ __("Projected Qty") }}"
+ style="width: {{ cint(row.pending_qty/row.max_count * 100) }}%">
+ </span>
+ {% endif %}
+ </span>
+ </span>
+ </span>
+ </div>
+ <div class="col-sm-1">
+ <button style="margin-left: 7px;" class="btn btn-default btn-xs btn-add" data-item-code="{{ escape(row.item_code) }}">Add</button>
+ </div>
+ <div class="col-sm-1">
+ <button style="margin-left: 7px;" class="btn btn-default btn-xs btn-move" data-item-code="{{ escape(row.item_code) }}">Move</button>
+ </div>
+</div>
+{% }); %}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/plant_floor/test_plant_floor.py b/erpnext/manufacturing/doctype/plant_floor/test_plant_floor.py
new file mode 100644
index 0000000..2fac211
--- /dev/null
+++ b/erpnext/manufacturing/doctype/plant_floor/test_plant_floor.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestPlantFloor(FrappeTestCase):
+ pass
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 5dc5c38..f0392be 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -1334,10 +1334,10 @@
)
date_field_mapper = {
- "from_date": self.from_date >= so.transaction_date,
- "to_date": self.to_date <= so.transaction_date,
- "from_delivery_date": self.from_delivery_date >= so_item.delivery_date,
- "to_delivery_date": self.to_delivery_date <= so_item.delivery_date,
+ "from_date": so.transaction_date >= self.from_date,
+ "to_date": so.transaction_date <= self.to_date,
+ "from_delivery_date": so_item.delivery_date >= self.from_delivery_date,
+ "to_delivery_date": so_item.delivery_date <= self.to_delivery_date,
}
for field, value in date_field_mapper.items():
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index aa5db57..f6e9a07 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -998,12 +998,6 @@
make_job_card(wo_order.name, operations)
job_card = frappe.db.get_value("Job Card", {"work_order": wo_order.name, "docstatus": 0}, "name")
- update_job_card(job_card, 10, 2)
-
- stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
- for row in stock_entry.items:
- if row.is_scrap_item:
- self.assertEqual(row.qty, 2)
def test_close_work_order(self):
items = [
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 0acc2b1..39beb36 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -1511,16 +1511,16 @@
def validate_operation_data(row):
- if row.get("qty") <= 0:
+ if flt(row.get("qty")) <= 0:
frappe.throw(
_("Quantity to Manufacture can not be zero for the operation {0}").format(
frappe.bold(row.get("operation"))
)
)
- if row.get("qty") > row.get("pending_qty"):
+ if flt(row.get("qty")) > flt(row.get("pending_qty")):
frappe.throw(
- _("For operation {0}: Quantity ({1}) can not be greter than pending quantity({2})").format(
+ _("For operation {0}: Quantity ({1}) can not be greater than pending quantity({2})").format(
frappe.bold(row.get("operation")),
frappe.bold(row.get("qty")),
frappe.bold(row.get("pending_qty")),
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.js b/erpnext/manufacturing/doctype/workstation/workstation.js
index f830b17..e3ad3fe 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.js
+++ b/erpnext/manufacturing/doctype/workstation/workstation.js
@@ -2,6 +2,28 @@
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Workstation", {
+ set_illustration_image(frm) {
+ let status_image_field = frm.doc.status == "Production" ? frm.doc.on_status_image : frm.doc.off_status_image;
+ if (status_image_field) {
+ frm.sidebar.image_wrapper.find(".sidebar-image").attr("src", status_image_field);
+ }
+ },
+
+ refresh(frm) {
+ frm.trigger("set_illustration_image");
+ frm.trigger("prepapre_dashboard");
+ },
+
+ prepapre_dashboard(frm) {
+ let $parent = $(frm.fields_dict["workstation_dashboard"].wrapper);
+ $parent.empty();
+
+ let workstation_dashboard = new WorkstationDashboard({
+ wrapper: $parent,
+ frm: frm
+ });
+ },
+
onload(frm) {
if(frm.is_new())
{
@@ -54,3 +76,243 @@
];
+
+
+class WorkstationDashboard {
+ constructor({ wrapper, frm }) {
+ this.$wrapper = $(wrapper);
+ this.frm = frm;
+
+ this.prepapre_dashboard();
+ }
+
+ prepapre_dashboard() {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.workstation.workstation.get_job_cards",
+ args: {
+ workstation: this.frm.doc.name
+ },
+ callback: (r) => {
+ if (r.message) {
+ this.job_cards = r.message;
+ this.render_job_cards();
+ }
+ }
+ });
+ }
+
+ render_job_cards() {
+ let template = frappe.render_template("workstation_job_card", {
+ data: this.job_cards
+ });
+
+ this.$wrapper.html(template);
+ this.prepare_timer();
+ this.toggle_job_card();
+ this.bind_events();
+ }
+
+ toggle_job_card() {
+ this.$wrapper.find(".collapse-indicator-job").on("click", (e) => {
+ $(e.currentTarget).closest(".form-dashboard-section").find(".section-body-job-card").toggleClass("hide")
+ if ($(e.currentTarget).closest(".form-dashboard-section").find(".section-body-job-card").hasClass("hide"))
+ $(e.currentTarget).html(frappe.utils.icon("es-line-down", "sm", "mb-1"))
+ else
+ $(e.currentTarget).html(frappe.utils.icon("es-line-up", "sm", "mb-1"))
+ });
+ }
+
+ bind_events() {
+ this.$wrapper.find(".make-material-request").on("click", (e) => {
+ let job_card = $(e.currentTarget).attr("job-card");
+ this.make_material_request(job_card);
+ });
+
+ this.$wrapper.find(".btn-start").on("click", (e) => {
+ let job_card = $(e.currentTarget).attr("job-card");
+ this.start_job(job_card);
+ });
+
+ this.$wrapper.find(".btn-complete").on("click", (e) => {
+ let job_card = $(e.currentTarget).attr("job-card");
+ let pending_qty = flt($(e.currentTarget).attr("pending-qty"));
+ this.complete_job(job_card, pending_qty);
+ });
+ }
+
+ start_job(job_card) {
+ let me = this;
+ frappe.prompt([
+ {
+ fieldtype: 'Datetime',
+ label: __('Start Time'),
+ fieldname: 'start_time',
+ reqd: 1,
+ default: frappe.datetime.now_datetime()
+ },
+ {
+ label: __('Operator'),
+ fieldname: 'employee',
+ fieldtype: 'Link',
+ options: 'Employee',
+ }
+ ], data => {
+ this.frm.call({
+ method: "start_job",
+ doc: this.frm.doc,
+ args: {
+ job_card: job_card,
+ from_time: data.start_time,
+ employee: data.employee,
+ },
+ callback(r) {
+ if (r.message) {
+ me.job_cards = [r.message];
+ me.prepare_timer()
+ me.update_job_card_details();
+ }
+ }
+ });
+ }, __("Enter Value"), __("Start Job"));
+ }
+
+ complete_job(job_card, qty_to_manufacture) {
+ let me = this;
+ let fields = [
+ {
+ fieldtype: 'Float',
+ label: __('Completed Quantity'),
+ fieldname: 'qty',
+ reqd: 1,
+ default: flt(qty_to_manufacture || 0)
+ },
+ {
+ fieldtype: 'Datetime',
+ label: __('End Time'),
+ fieldname: 'end_time',
+ default: frappe.datetime.now_datetime()
+ },
+ ];
+
+ frappe.prompt(fields, data => {
+ if (data.qty <= 0) {
+ frappe.throw(__("Quantity should be greater than 0"));
+ }
+
+ this.frm.call({
+ method: "complete_job",
+ doc: this.frm.doc,
+ args: {
+ job_card: job_card,
+ qty: data.qty,
+ to_time: data.end_time,
+ },
+ callback: function(r) {
+ if (r.message) {
+ me.job_cards = [r.message];
+ me.prepare_timer()
+ me.update_job_card_details();
+ }
+ }
+ });
+ }, __("Enter Value"), __("Submit"));
+ }
+
+ make_material_request(job_card) {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.job_card.job_card.make_material_request",
+ args: {
+ source_name: job_card,
+ },
+ callback: (r) => {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ }
+ });
+ }
+
+ prepare_timer() {
+ this.job_cards.forEach((data) => {
+ if (data.time_logs?.length) {
+ data._current_time = this.get_current_time(data);
+ if (data.time_logs[cint(data.time_logs.length) - 1].to_time) {
+ this.updateStopwatch(data);
+ } else {
+ this.initialiseTimer(data);
+ }
+ }
+ });
+ }
+
+ update_job_card_details() {
+ let color_map = {
+ "Pending": "var(--bg-blue)",
+ "In Process": "var(--bg-yellow)",
+ "Submitted": "var(--bg-blue)",
+ "Open": "var(--bg-gray)",
+ "Closed": "var(--bg-green)",
+ "Work In Progress": "var(--bg-orange)",
+ }
+
+ this.job_cards.forEach((data) => {
+ let job_card_selector = this.$wrapper.find(`
+ [data-name='${data.name}']`
+ );
+
+ $(job_card_selector).find(".job-card-status").text(data.status);
+ $(job_card_selector).find(".job-card-status").css("backgroundColor", color_map[data.status]);
+
+ if (data.status === "Work In Progress") {
+ $(job_card_selector).find(".btn-start").addClass("hide");
+ $(job_card_selector).find(".btn-complete").removeClass("hide");
+ } else if (data.status === "Completed") {
+ $(job_card_selector).find(".btn-start").addClass("hide");
+ $(job_card_selector).find(".btn-complete").addClass("hide");
+ }
+ });
+ }
+
+ initialiseTimer(data) {
+ setInterval(() => {
+ data._current_time += 1;
+ this.updateStopwatch(data);
+ }, 1000);
+ }
+
+ updateStopwatch(data) {
+ let increment = data._current_time;
+ let hours = Math.floor(increment / 3600);
+ let minutes = Math.floor((increment - (hours * 3600)) / 60);
+ let seconds = cint(increment - (hours * 3600) - (minutes * 60));
+
+ let job_card_selector = `[data-job-card='${data.name}']`
+ let timer_selector = this.$wrapper.find(job_card_selector)
+
+ $(timer_selector).find(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString());
+ $(timer_selector).find(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString());
+ $(timer_selector).find(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString());
+ }
+
+ get_current_time(data) {
+ let current_time = 0.0;
+ data.time_logs.forEach(d => {
+ if (d.to_time) {
+ if (d.time_in_mins) {
+ current_time += flt(d.time_in_mins, 2) * 60;
+ } else {
+ current_time += this.get_seconds_diff(d.to_time, d.from_time);
+ }
+ } else {
+ current_time += this.get_seconds_diff(frappe.datetime.now_datetime(), d.from_time);
+ }
+ });
+
+ return current_time;
+ }
+
+ get_seconds_diff(d1, d2) {
+ return moment(d1).diff(d2, "seconds");
+ }
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.json b/erpnext/manufacturing/doctype/workstation/workstation.json
index 881cba0..5912714 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.json
+++ b/erpnext/manufacturing/doctype/workstation/workstation.json
@@ -8,10 +8,24 @@
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
+ "dashboard_tab",
+ "workstation_dashboard",
+ "details_tab",
"workstation_name",
- "production_capacity",
- "column_break_3",
"workstation_type",
+ "plant_floor",
+ "column_break_3",
+ "production_capacity",
+ "warehouse",
+ "production_capacity_section",
+ "parts_per_hour",
+ "workstation_status_tab",
+ "status",
+ "column_break_glcv",
+ "illustration_section",
+ "on_status_image",
+ "column_break_etmc",
+ "off_status_image",
"over_heads",
"hour_rate_electricity",
"hour_rate_consumable",
@@ -24,7 +38,9 @@
"description",
"working_hours_section",
"holiday_list",
- "working_hours"
+ "working_hours",
+ "total_working_hours",
+ "connections_tab"
],
"fields": [
{
@@ -120,9 +136,10 @@
},
{
"default": "1",
+ "description": "Run parallel job cards in a workstation",
"fieldname": "production_capacity",
"fieldtype": "Int",
- "label": "Production Capacity",
+ "label": "Job Capacity",
"reqd": 1
},
{
@@ -145,12 +162,97 @@
{
"fieldname": "section_break_11",
"fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "plant_floor",
+ "fieldtype": "Link",
+ "label": "Plant Floor",
+ "options": "Plant Floor"
+ },
+ {
+ "fieldname": "workstation_status_tab",
+ "fieldtype": "Tab Break",
+ "label": "Workstation Status"
+ },
+ {
+ "fieldname": "illustration_section",
+ "fieldtype": "Section Break",
+ "label": "Status Illustration"
+ },
+ {
+ "fieldname": "column_break_etmc",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "options": "Production\nOff\nIdle\nProblem\nMaintenance\nSetup"
+ },
+ {
+ "fieldname": "column_break_glcv",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "on_status_image",
+ "fieldtype": "Attach Image",
+ "label": "Active Status"
+ },
+ {
+ "fieldname": "off_status_image",
+ "fieldtype": "Attach Image",
+ "label": "Inactive Status"
+ },
+ {
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "production_capacity_section",
+ "fieldtype": "Section Break",
+ "label": "Production Capacity"
+ },
+ {
+ "fieldname": "parts_per_hour",
+ "fieldtype": "Float",
+ "label": "Parts Per Hour"
+ },
+ {
+ "fieldname": "total_working_hours",
+ "fieldtype": "Float",
+ "label": "Total Working Hours"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "dashboard_tab",
+ "fieldtype": "Tab Break",
+ "label": "Job Cards"
+ },
+ {
+ "fieldname": "details_tab",
+ "fieldtype": "Tab Break",
+ "label": "Details"
+ },
+ {
+ "fieldname": "connections_tab",
+ "fieldtype": "Tab Break",
+ "label": "Connections",
+ "show_dashboard": 1
+ },
+ {
+ "fieldname": "workstation_dashboard",
+ "fieldtype": "HTML",
+ "label": "Workstation Dashboard"
}
],
"icon": "icon-wrench",
"idx": 1,
+ "image_field": "on_status_image",
"links": [],
- "modified": "2022-11-04 17:39:01.549346",
+ "modified": "2023-11-30 12:43:35.808845",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Workstation",
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py
index 0f05eaa..3d40a2d 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation.py
@@ -11,7 +11,11 @@
comma_and,
flt,
formatdate,
+ get_link_to_form,
+ get_time,
+ get_url_to_form,
getdate,
+ time_diff_in_hours,
time_diff_in_seconds,
to_timedelta,
)
@@ -60,6 +64,23 @@
def before_save(self):
self.set_data_based_on_workstation_type()
self.set_hour_rate()
+ self.set_total_working_hours()
+
+ def set_total_working_hours(self):
+ self.total_working_hours = 0.0
+ for row in self.working_hours:
+ self.validate_working_hours(row)
+
+ if row.start_time and row.end_time:
+ row.hours = flt(time_diff_in_hours(row.end_time, row.start_time), row.precision("hours"))
+ self.total_working_hours += row.hours
+
+ def validate_working_hours(self, row):
+ if not (row.start_time and row.end_time):
+ frappe.throw(_("Row #{0}: Start Time and End Time are required").format(row.idx))
+
+ if get_time(row.start_time) >= get_time(row.end_time):
+ frappe.throw(_("Row #{0}: Start Time must be before End Time").format(row.idx))
def set_hour_rate(self):
self.hour_rate = (
@@ -143,6 +164,141 @@
return schedule_date
+ @frappe.whitelist()
+ def start_job(self, job_card, from_time, employee):
+ doc = frappe.get_doc("Job Card", job_card)
+ doc.append("time_logs", {"from_time": from_time, "employee": employee})
+ doc.save(ignore_permissions=True)
+
+ return doc
+
+ @frappe.whitelist()
+ def complete_job(self, job_card, qty, to_time):
+ doc = frappe.get_doc("Job Card", job_card)
+ for row in doc.time_logs:
+ if not row.to_time:
+ row.to_time = to_time
+ row.time_in_mins = time_diff_in_hours(row.to_time, row.from_time) / 60
+ row.completed_qty = qty
+
+ doc.save(ignore_permissions=True)
+ doc.submit()
+
+ return doc
+
+
+@frappe.whitelist()
+def get_job_cards(workstation):
+ if frappe.has_permission("Job Card", "read"):
+ jc_data = frappe.get_all(
+ "Job Card",
+ fields=[
+ "name",
+ "production_item",
+ "work_order",
+ "operation",
+ "total_completed_qty",
+ "for_quantity",
+ "transferred_qty",
+ "status",
+ "expected_start_date",
+ "expected_end_date",
+ "time_required",
+ "wip_warehouse",
+ ],
+ filters={
+ "workstation": workstation,
+ "docstatus": ("<", 2),
+ "status": ["not in", ["Completed", "Stopped"]],
+ },
+ order_by="expected_start_date, expected_end_date",
+ )
+
+ job_cards = [row.name for row in jc_data]
+ raw_materials = get_raw_materials(job_cards)
+ time_logs = get_time_logs(job_cards)
+
+ allow_excess_transfer = frappe.db.get_single_value(
+ "Manufacturing Settings", "job_card_excess_transfer"
+ )
+
+ for row in jc_data:
+ row.progress_percent = (
+ flt(row.total_completed_qty / row.for_quantity * 100, 2) if row.for_quantity else 0
+ )
+ row.progress_title = _("Total completed quantity: {0}").format(row.total_completed_qty)
+ row.status_color = get_status_color(row.status)
+ row.job_card_link = get_link_to_form("Job Card", row.name)
+ row.work_order_link = get_link_to_form("Work Order", row.work_order)
+
+ row.raw_materials = raw_materials.get(row.name, [])
+ row.time_logs = time_logs.get(row.name, [])
+ row.make_material_request = False
+ if row.for_quantity > row.transferred_qty or allow_excess_transfer:
+ row.make_material_request = True
+
+ return jc_data
+
+
+def get_status_color(status):
+ color_map = {
+ "Pending": "var(--bg-blue)",
+ "In Process": "var(--bg-yellow)",
+ "Submitted": "var(--bg-blue)",
+ "Open": "var(--bg-gray)",
+ "Closed": "var(--bg-green)",
+ "Work In Progress": "var(--bg-orange)",
+ }
+
+ return color_map.get(status, "var(--bg-blue)")
+
+
+def get_raw_materials(job_cards):
+ raw_materials = {}
+
+ data = frappe.get_all(
+ "Job Card Item",
+ fields=[
+ "parent",
+ "item_code",
+ "item_group",
+ "uom",
+ "item_name",
+ "source_warehouse",
+ "required_qty",
+ "transferred_qty",
+ ],
+ filters={"parent": ["in", job_cards]},
+ )
+
+ for row in data:
+ raw_materials.setdefault(row.parent, []).append(row)
+
+ return raw_materials
+
+
+def get_time_logs(job_cards):
+ time_logs = {}
+
+ data = frappe.get_all(
+ "Job Card Time Log",
+ fields=[
+ "parent",
+ "name",
+ "employee",
+ "from_time",
+ "to_time",
+ "time_in_mins",
+ ],
+ filters={"parent": ["in", job_cards], "parentfield": "time_logs"},
+ order_by="parent, idx",
+ )
+
+ for row in data:
+ time_logs.setdefault(row.parent, []).append(row)
+
+ return time_logs
+
@frappe.whitelist()
def get_default_holiday_list():
@@ -201,3 +357,52 @@
+ "\n".join(applicable_holidays),
WorkstationHolidayError,
)
+
+
+@frappe.whitelist()
+def get_workstations(**kwargs):
+ kwargs = frappe._dict(kwargs)
+ _workstation = frappe.qb.DocType("Workstation")
+
+ query = (
+ frappe.qb.from_(_workstation)
+ .select(
+ _workstation.name,
+ _workstation.description,
+ _workstation.status,
+ _workstation.on_status_image,
+ _workstation.off_status_image,
+ )
+ .orderby(_workstation.workstation_type, _workstation.name)
+ .where(_workstation.plant_floor == kwargs.plant_floor)
+ )
+
+ if kwargs.workstation:
+ query = query.where(_workstation.name == kwargs.workstation)
+
+ if kwargs.workstation_type:
+ query = query.where(_workstation.workstation_type == kwargs.workstation_type)
+
+ if kwargs.workstation_status:
+ query = query.where(_workstation.status == kwargs.workstation_status)
+
+ data = query.run(as_dict=True)
+
+ color_map = {
+ "Production": "var(--green-600)",
+ "Off": "var(--gray-600)",
+ "Idle": "var(--gray-600)",
+ "Problem": "var(--red-600)",
+ "Maintenance": "var(--yellow-600)",
+ "Setup": "var(--blue-600)",
+ }
+
+ for d in data:
+ d.workstation_name = get_link_to_form("Workstation", d.name)
+ d.status_image = d.on_status_image
+ d.background_color = color_map.get(d.status, "var(--red-600)")
+ d.workstation_link = get_url_to_form("Workstation", d.name)
+ if d.status != "Production":
+ d.status_image = d.off_status_image
+
+ return data
diff --git a/erpnext/manufacturing/doctype/workstation/workstation_job_card.html b/erpnext/manufacturing/doctype/workstation/workstation_job_card.html
new file mode 100644
index 0000000..9770785
--- /dev/null
+++ b/erpnext/manufacturing/doctype/workstation/workstation_job_card.html
@@ -0,0 +1,125 @@
+<style>
+ .job-card-link {
+ min-height: 100px;
+ }
+
+ .section-head-job-card {
+ margin-bottom: 0px;
+ padding-bottom: 0px;
+ }
+</style>
+
+<div style = "max-height: 400px; overflow-y: auto;">
+{% $.each(data, (idx, d) => { %}
+ <div class="row form-dashboard-section job-card-link form-links border-gray-200" data-name="{{d.name}}">
+ <div class="section-head section-head-job-card">
+ {{ d.operation }} - {{ d.production_item }}
+ <span class="ml-2 collapse-indicator-job mb-1" style="">
+ {{frappe.utils.icon("es-line-down", "sm", "mb-1")}}
+ </span>
+ </div>
+ <div class="row form-section" style="width:100%;margin-bottom:10px">
+ <div class="form-column col-sm-3">
+ <div class="frappe-control" title="{{__('Job Card')}}" style="text-decoration:underline">
+ {{ d.job_card_link }}
+ </div>
+ <div class="frappe-control" title="{{__('Work Order')}}" style="text-decoration:underline">
+ {{ d.work_order_link }}
+ </div>
+ </div>
+ <div class="form-column col-sm-2">
+ <div class="frappe-control timer" title="{{__('Timer')}}" style="text-align:center;font-size:14px;" data-job-card = {{escape(d.name)}}>
+ <span class="hours">00</span>
+ <span class="colon">:</span>
+ <span class="minutes">00</span>
+ <span class="colon">:</span>
+ <span class="seconds">00</span>
+ </div>
+
+ {% if(d.status === "Open") { %}
+ <div class="frappe-control" title="{{__('Expected Start Date')}}" style="text-align:center;font-size:11px;padding-top: 4px;">
+ {{ frappe.format(d.expected_start_date, { fieldtype: 'Datetime' }) }}
+ </div>
+ {% } else { %}
+ <div class="frappe-control" title="{{__('Expected End Date')}}" style="text-align:center;font-size:11px;padding-top: 4px;">
+ {{ frappe.format(d.expected_end_date, { fieldtype: 'Datetime' }) }}
+ </div>
+ {% } %}
+
+ </div>
+ <div class="form-column col-sm-2">
+ <div class="frappe-control job-card-status" title="{{__('Status')}}" style="background:{{d.status_color}};text-align:center;border-radius:var(--border-radius-full)">
+ {{ d.status }}
+ </div>
+ </div>
+ <div class="form-column col-sm-2">
+ <div class="frappe-control" title="{{__('Qty to Manufacture')}}">
+ <div class="progress" title = "{{d.progress_title}}">
+ <div class="progress-bar progress-bar-success" style="width: {{d.progress_percent}}%">
+ </div>
+ </div>
+ </div>
+ <div class="frappe-control" style="text-align: center; font-size: 10px;">
+ {{ d.for_quantity }} / {{ d.total_completed_qty }}
+ </div>
+ </div>
+ <div class="form-column col-sm-2 text-center">
+ <button style="width: 85px;" class="btn btn-default btn-start {% if(d.status !== "Open") { %} hide {% } %}" job-card="{{d.name}}"> {{__("Start")}} </button>
+ <button style="width: 85px;" class="btn btn-default btn-complete {% if(d.status === "Open") { %} hide {% } %}" job-card="{{d.name}}" pending-qty="{{d.for_quantity - d.transferred_qty}}"> {{__("Complete")}} </button>
+ </div>
+ </div>
+
+ <div class="section-body section-body-job-card form-section hide">
+ <hr>
+ <div class="row">
+ <div class="form-column col-sm-2">
+ {{ __("Raw Materials") }}
+ </div>
+ {% if(d.make_material_request) { %}
+ <div class="form-column col-sm-10 text-right">
+ <button class="btn btn-default btn-xs make-material-request" job-card="{{d.name}}">{{ __("Material Request") }}</button>
+ </div>
+ {% } %}
+ </div>
+
+ {% if(d.raw_materials) { %}
+ <table class="table table-bordered table-condensed">
+ <thead>
+ <tr>
+ <th style="width: 5%" class="table-sr">Sr</th>
+
+ <th style="width: 15%">{{ __("Item") }}</th>
+ <th style="width: 15%">{{ __("Warehouse") }}</th>
+ <th style="width: 10%">{{__("UOM")}}</th>
+ <th style="width: 15%">{{__("Item Group")}}</th>
+ <th style="width: 20%" >{{__("Required Qty")}}</th>
+ <th style="width: 20%" >{{__("Transferred Qty")}}</th>
+ </tr>
+ </thead>
+ <tbody>
+
+ {% $.each(d.raw_materials, (row_index, child_row) => { %}
+ <tr>
+ <td class="table-sr">{{ row_index+1 }}</td>
+ {% if(child_row.item_code === child_row.item_name) { %}
+ <td>{{ child_row.item_code }}</td>
+ {% } else { %}
+ <td>{{ child_row.item_code }}: {{child_row.item_name}}</td>
+ {% } %}
+ <td>{{ child_row.source_warehouse }}</td>
+ <td>{{ child_row.uom }}</td>
+ <td>{{ child_row.item_group }}</td>
+ <td>{{ child_row.required_qty }}</td>
+ <td>{{ child_row.transferred_qty }}</td>
+ </tr>
+ {% }); %}
+
+ </tbody>
+ {% } %}
+
+ </table>
+ </div>
+
+ </div>
+{% }); %}
+</div>
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/workstation/workstation_list.js b/erpnext/manufacturing/doctype/workstation/workstation_list.js
index 61f2062..86928ca 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation_list.js
+++ b/erpnext/manufacturing/doctype/workstation/workstation_list.js
@@ -1,5 +1,16 @@
frappe.listview_settings['Workstation'] = {
- // add_fields: ["status"],
- // filters:[["status","=", "Open"]]
+ add_fields: ["status"],
+ get_indicator: function(doc) {
+ let color_map = {
+ "Production": "green",
+ "Off": "gray",
+ "Idle": "gray",
+ "Problem": "red",
+ "Maintenance": "yellow",
+ "Setup": "blue",
+ }
+
+ return [__(doc.status), color_map[doc.status], true];
+ }
};
diff --git a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.json b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.json
index a79182f..b185f7d 100644
--- a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.json
+++ b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.json
@@ -1,150 +1,58 @@
{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-12-24 14:46:40.678236",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2014-12-24 14:46:40.678236",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "start_time",
+ "hours",
+ "column_break_2",
+ "end_time",
+ "enabled"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "start_time",
- "fieldtype": "Time",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Start Time",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "start_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "Start Time",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "end_time",
- "fieldtype": "Time",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "End Time",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "end_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "End Time",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "enabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Enabled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Enabled"
+ },
+ {
+ "fieldname": "hours",
+ "fieldtype": "Float",
+ "label": "Hours",
+ "read_only": 1
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2016-12-13 05:02:36.754145",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Workstation Working Hour",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2023-10-25 14:48:29.697498",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Workstation Working Hour",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.html b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.html
new file mode 100644
index 0000000..ca97516
--- /dev/null
+++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.html
@@ -0,0 +1,19 @@
+<p><b>{{ _("Material Request Type") }}</b>: {{ doc.material_request_type }}<br>
+<b>{{ _("Company") }}</b>: {{ doc.company }}</p>
+
+<h3>{{ _("Order Summary") }}</h3>
+
+<table border=2 >
+ <tr align="center">
+ <th>{{ _("Item Name") }}</th>
+ <th>{{ _("Received Quantity") }}</th>
+ </tr>
+ {% for item in doc.items %}
+ {% if frappe.utils.flt(item.received_qty, 2) > 0.0 %}
+ <tr align="center">
+ <td>{{ item.item_code }}</td>
+ <td>{{ frappe.utils.flt(item.received_qty, 2) }}</td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+</table>
diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json
index 5391a31..6ef2ea3 100644
--- a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json
+++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json
@@ -11,19 +11,21 @@
"event": "Value Change",
"idx": 0,
"is_standard": 1,
- "message": "<b>Material Request Type</b>: {{ doc.material_request_type }}<br>\n<b>Company</b>: {{ doc.company }}\n\n<h3>Order Summary</h3>\n\n<table border=2 >\n <tr align=\"center\">\n <th>Item Name</th>\n <th>Received Quantity</th>\n </tr>\n {% for item in doc.items %}\n {% if frappe.utils.flt(item.received_qty, 2) > 0.0 %}\n <tr align=\"center\">\n <td>{{ item.item_code }}</td>\n <td>{{ frappe.utils.flt(item.received_qty, 2) }}</td>\n </tr>\n {% endif %}\n {% endfor %}\n</table>",
+ "message_type": "HTML",
"method": "",
- "modified": "2019-05-01 18:02:51.090037",
+ "modified": "2023-11-17 08:53:29.525296",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Material Request Receipt Notification",
"owner": "Administrator",
"recipients": [
{
- "email_by_document_field": "requested_by"
+ "receiver_by_document_field": "requested_by"
}
],
+ "send_system_notification": 0,
+ "send_to_all_assignees": 0,
"sender_email": "",
"subject": "{{ doc.name }} has been received",
"value_changed": "status"
-}
\ No newline at end of file
+}
diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md
deleted file mode 100644
index e6feee9..0000000
--- a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md
+++ /dev/null
@@ -1,19 +0,0 @@
-<b>Material Request Type</b>: {{ doc.material_request_type }}<br>
-<b>Company</b>: {{ doc.company }}
-
-<h3>Order Summary</h3>
-
-<table border=2 >
- <tr align="center">
- <th>Item Name</th>
- <th>Received Quantity</th>
- </tr>
- {% for item in doc.items %}
- {% if frappe.utils.flt(item.received_qty, 2) > 0.0 %}
- <tr align="center">
- <td>{{ item.item_code }}</td>
- <td>{{ frappe.utils.flt(item.received_qty, 2) }}</td>
- </tr>
- {% endif %}
- {% endfor %}
-</table>
\ No newline at end of file
diff --git a/erpnext/manufacturing/page/visual_plant_floor/__init__.py b/erpnext/manufacturing/page/visual_plant_floor/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/manufacturing/page/visual_plant_floor/__init__.py
diff --git a/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.js b/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.js
new file mode 100644
index 0000000..38667e8
--- /dev/null
+++ b/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.js
@@ -0,0 +1,13 @@
+
+
+frappe.pages['visual-plant-floor'].on_page_load = function(wrapper) {
+ var page = frappe.ui.make_app_page({
+ parent: wrapper,
+ title: 'Visual Plant Floor',
+ single_column: true
+ });
+
+ frappe.visual_plant_floor = new frappe.ui.VisualPlantFloor(
+ {wrapper: $(wrapper).find('.layout-main-section')}, wrapper.page
+ );
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.json b/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.json
new file mode 100644
index 0000000..a907e97
--- /dev/null
+++ b/erpnext/manufacturing/page/visual_plant_floor/visual_plant_floor.json
@@ -0,0 +1,29 @@
+{
+ "content": null,
+ "creation": "2023-10-06 15:17:39.215300",
+ "docstatus": 0,
+ "doctype": "Page",
+ "idx": 0,
+ "modified": "2023-10-06 15:18:00.622073",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "visual-plant-floor",
+ "owner": "Administrator",
+ "page_name": "visual-plant-floor",
+ "roles": [
+ {
+ "role": "Manufacturing User"
+ },
+ {
+ "role": "Manufacturing Manager"
+ },
+ {
+ "role": "Operator"
+ }
+ ],
+ "script": null,
+ "standard": "Yes",
+ "style": null,
+ "system_page": 0,
+ "title": "Visual Plant Floor"
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
index 8e07850..d2520d6 100644
--- a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
+++ b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json
@@ -1,6 +1,6 @@
{
"charts": [],
- "content": "[{\"id\":\"csBCiDglCE\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"YHCQG3wAGv\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Creator\",\"col\":3}},{\"id\":\"xit0dg7KvY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM\",\"col\":3}},{\"id\":\"LRhGV9GAov\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Plan\",\"col\":3}},{\"id\":\"69KKosI6Hg\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Work Order\",\"col\":3}},{\"id\":\"PwndxuIpB3\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Job Card\",\"col\":3}},{\"id\":\"OaiDqTT03Y\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Forecasting\",\"col\":3}},{\"id\":\"OtMcArFRa5\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Stock Report\",\"col\":3}},{\"id\":\"76yYsI5imF\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Planning Report\",\"col\":3}},{\"id\":\"PIQJYZOMnD\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Manufacturing\",\"col\":3}},{\"id\":\"bN_6tHS-Ct\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"yVEFZMqVwd\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"id\":\"rwrmsTI58-\",\"type\":\"card\",\"data\":{\"card_name\":\"Production\",\"col\":4}},{\"id\":\"6dnsyX-siZ\",\"type\":\"card\",\"data\":{\"card_name\":\"Bill of Materials\",\"col\":4}},{\"id\":\"CIq-v5f5KC\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"8RRiQeYr0G\",\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"id\":\"Pu8z7-82rT\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
+ "content": "[{\"id\":\"csBCiDglCE\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"YHCQG3wAGv\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Creator\",\"col\":3}},{\"id\":\"xit0dg7KvY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM\",\"col\":3}},{\"id\":\"LRhGV9GAov\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Plan\",\"col\":3}},{\"id\":\"69KKosI6Hg\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Work Order\",\"col\":3}},{\"id\":\"PwndxuIpB3\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Job Card\",\"col\":3}},{\"id\":\"Ubj6zXcmIQ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Plant Floor\",\"col\":3}},{\"id\":\"OtMcArFRa5\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"BOM Stock Report\",\"col\":3}},{\"id\":\"76yYsI5imF\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Production Planning Report\",\"col\":3}},{\"id\":\"PIQJYZOMnD\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Manufacturing\",\"col\":3}},{\"id\":\"OaiDqTT03Y\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Forecasting\",\"col\":3}},{\"id\":\"bN_6tHS-Ct\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"yVEFZMqVwd\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"id\":\"rwrmsTI58-\",\"type\":\"card\",\"data\":{\"card_name\":\"Production\",\"col\":4}},{\"id\":\"6dnsyX-siZ\",\"type\":\"card\",\"data\":{\"card_name\":\"Bill of Materials\",\"col\":4}},{\"id\":\"CIq-v5f5KC\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"8RRiQeYr0G\",\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"id\":\"Pu8z7-82rT\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"creation": "2020-03-02 17:11:37.032604",
"custom_blocks": [],
"docstatus": 0,
@@ -316,7 +316,7 @@
"type": "Link"
}
],
- "modified": "2023-08-08 22:28:39.633891",
+ "modified": "2024-01-30 21:49:58.577218",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing",
@@ -339,6 +339,13 @@
{
"color": "Grey",
"doc_view": "List",
+ "label": "Plant Floor",
+ "link_to": "Plant Floor",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "doc_view": "List",
"label": "BOM Creator",
"link_to": "BOM Creator",
"type": "DocType"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 1110617..4ead7e7 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -352,6 +352,7 @@
execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction")
execute:frappe.db.set_default("date_format", frappe.db.get_single_value("System Settings", "date_format"))
erpnext.patches.v14_0.update_total_asset_cost_field
+erpnext.patches.v15_0.create_advance_payment_status
# below migration patch should always run last
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2023-12-20
diff --git a/erpnext/patches/v14_0/migrate_gl_to_payment_ledger.py b/erpnext/patches/v14_0/migrate_gl_to_payment_ledger.py
index 72c8c07..95b5bc5 100644
--- a/erpnext/patches/v14_0/migrate_gl_to_payment_ledger.py
+++ b/erpnext/patches/v14_0/migrate_gl_to_payment_ledger.py
@@ -188,4 +188,4 @@
raise err
else:
break
- print(f"{processed} records have been sucessfully migrated")
+ print(f"{processed} records have been successfully migrated")
diff --git a/erpnext/patches/v15_0/create_advance_payment_status.py b/erpnext/patches/v15_0/create_advance_payment_status.py
new file mode 100644
index 0000000..18ab9fa
--- /dev/null
+++ b/erpnext/patches/v15_0/create_advance_payment_status.py
@@ -0,0 +1,54 @@
+import frappe
+
+
+def execute():
+ """
+ Description:
+ Calculate the new Advance Payment Statuse column in SO & PO
+ """
+
+ if frappe.reload_doc("selling", "doctype", "Sales Order"):
+ so = frappe.qb.DocType("Sales Order")
+ frappe.qb.update(so).set(so.advance_payment_status, "Not Requested").where(
+ so.docstatus == 1
+ ).where(so.advance_paid == 0.0).run()
+
+ frappe.qb.update(so).set(so.advance_payment_status, "Partially Paid").where(
+ so.docstatus == 1
+ ).where(so.advance_payment_status.isnull()).where(
+ so.advance_paid < (so.rounded_total or so.grand_total)
+ ).run()
+
+ frappe.qb.update(so).set(so.advance_payment_status, "Fully Paid").where(so.docstatus == 1).where(
+ so.advance_payment_status.isnull()
+ ).where(so.advance_paid == (so.rounded_total or so.grand_total)).run()
+
+ pr = frappe.qb.DocType("Payment Request")
+ frappe.qb.update(so).join(pr).on(so.name == pr.reference_name).set(
+ so.advance_payment_status, "Requested"
+ ).where(so.docstatus == 1).where(pr.docstatus == 1).where(
+ so.advance_payment_status == "Not Requested"
+ ).run()
+
+ if frappe.reload_doc("buying", "doctype", "Purchase Order"):
+ po = frappe.qb.DocType("Purchase Order")
+ frappe.qb.update(po).set(po.advance_payment_status, "Not Initiated").where(
+ po.docstatus == 1
+ ).where(po.advance_paid == 0.0).run()
+
+ frappe.qb.update(po).set(po.advance_payment_status, "Partially Paid").where(
+ po.docstatus == 1
+ ).where(po.advance_payment_status.isnull()).where(
+ po.advance_paid < (po.rounded_total or po.grand_total)
+ ).run()
+
+ frappe.qb.update(po).set(po.advance_payment_status, "Fully Paid").where(po.docstatus == 1).where(
+ po.advance_payment_status.isnull()
+ ).where(po.advance_paid == (po.rounded_total or po.grand_total)).run()
+
+ pr = frappe.qb.DocType("Payment Request")
+ frappe.qb.update(po).join(pr).on(po.name == pr.reference_name).set(
+ po.advance_payment_status, "Initiated"
+ ).where(po.docstatus == 1).where(pr.docstatus == 1).where(
+ po.advance_payment_status == "Not Initiated"
+ ).run()
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 7879173..f0d8cbb 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -160,7 +160,7 @@
let tax = frappe.get_doc(cdt, cdn);
try {
me.validate_taxes_and_charges(cdt, cdn);
- me.validate_inclusive_tax(tax);
+ me.validate_inclusive_tax(tax, frm);
} catch(e) {
tax.included_in_print_rate = 0;
refresh_field("included_in_print_rate", tax.name, tax.parentfield);
@@ -170,7 +170,8 @@
});
},
- validate_inclusive_tax: function(tax) {
+ validate_inclusive_tax: function(tax, frm) {
+ this.frm = this.frm || frm;
let actual_type_error = function() {
var msg = __("Actual type tax cannot be included in Item rate in row {0}", [tax.idx])
frappe.throw(msg);
@@ -186,12 +187,12 @@
if(tax.charge_type == "Actual") {
// inclusive tax cannot be of type Actual
actual_type_error();
- } else if(tax.charge_type == "On Previous Row Amount" &&
+ } else if (tax.charge_type == "On Previous Row Amount" && this.frm &&
!cint(this.frm.doc["taxes"][tax.row_id - 1].included_in_print_rate)
) {
// referred row should also be an inclusive tax
on_previous_row_error(tax.row_id);
- } else if(tax.charge_type == "On Previous Row Total") {
+ } else if (tax.charge_type == "On Previous Row Total" && this.frm) {
var taxes_not_included = $.map(this.frm.doc["taxes"].slice(0, tax.row_id),
function(t) { return cint(t.included_in_print_rate) ? null : t; });
if(taxes_not_included.length > 0) {
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index d24c4e6..bd5a136 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -103,7 +103,7 @@
this.determine_exclusive_rate();
this.calculate_net_total();
this.calculate_taxes();
- this.manipulate_grand_total_for_inclusive_tax();
+ this.adjust_grand_total_for_inclusive_tax();
this.calculate_totals();
this._cleanup();
}
@@ -185,7 +185,7 @@
if (!this.discount_amount_applied) {
erpnext.accounts.taxes.validate_taxes_and_charges(tax.doctype, tax.name);
- erpnext.accounts.taxes.validate_inclusive_tax(tax);
+ erpnext.accounts.taxes.validate_inclusive_tax(tax, this.frm);
}
frappe.model.round_floats_in(tax);
});
@@ -248,7 +248,7 @@
if(!me.discount_amount_applied && item.qty && (total_inclusive_tax_amount_per_qty || cumulated_tax_fraction)) {
var amount = flt(item.amount) - total_inclusive_tax_amount_per_qty;
- item.net_amount = flt(amount / (1 + cumulated_tax_fraction));
+ item.net_amount = flt(amount / (1 + cumulated_tax_fraction), precision("net_amount", item));
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
@@ -303,6 +303,8 @@
me.frm.doc.net_total += item.net_amount;
me.frm.doc.base_net_total += item.base_net_amount;
});
+
+ frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]);
}
calculate_shipping_charges() {
@@ -521,8 +523,17 @@
}
}
+ /**
+ * @deprecated Use adjust_grand_total_for_inclusive_tax instead.
+ */
manipulate_grand_total_for_inclusive_tax() {
+ // for backward compatablility - if in case used by an external application
+ this.adjust_grand_total_for_inclusive_tax()
+ }
+
+ adjust_grand_total_for_inclusive_tax() {
var me = this;
+
// if fully inclusive taxes and diff
if (this.frm.doc["taxes"] && this.frm.doc["taxes"].length) {
var any_inclusive_tax = false;
@@ -548,7 +559,9 @@
diff = flt(diff, precision("rounding_adjustment"));
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
- me.frm.doc.rounding_adjustment = diff;
+ me.frm.doc.grand_total_diff = diff;
+ } else {
+ me.frm.doc.grand_total_diff = 0;
}
}
}
@@ -559,7 +572,7 @@
var me = this;
var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0;
this.frm.doc.grand_total = flt(tax_count
- ? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.rounding_adjustment)
+ ? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.grand_total_diff)
: this.frm.doc.net_total);
if(in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"], this.frm.doc.doctype)) {
@@ -619,7 +632,7 @@
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = round_based_on_smallest_currency_fraction(this.frm.doc.grand_total,
this.frm.doc.currency, precision("rounded_total"));
- this.frm.doc.rounding_adjustment += flt(this.frm.doc.rounded_total - this.frm.doc.grand_total,
+ this.frm.doc.rounding_adjustment = flt(this.frm.doc.rounded_total - this.frm.doc.grand_total,
precision("rounding_adjustment"));
this.set_in_company_currency(this.frm.doc, ["rounding_adjustment", "rounded_total"]);
@@ -687,8 +700,7 @@
if (total_for_discount_amount) {
$.each(this.frm._items || [], function(i, item) {
distributed_amount = flt(me.frm.doc.discount_amount) * item.net_amount / total_for_discount_amount;
- item.net_amount = flt(item.net_amount - distributed_amount,
- precision("base_amount", item));
+ item.net_amount = flt(item.net_amount - distributed_amount, precision("net_amount", item));
net_total += item.net_amount;
// discount amount rounding loss adjustment if no taxes
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 6406735..ba53cf8 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -7,6 +7,7 @@
super.setup();
let me = this;
+ this.set_fields_onload_for_line_item();
this.frm.ignore_doctypes_on_cancel_all = ['Serial and Batch Bundle'];
frappe.flags.hide_serial_batch_dialog = true;
@@ -105,6 +106,7 @@
frappe.ui.form.on(this.frm.doctype + " Item", {
items_add: function(frm, cdt, cdn) {
+ debugger
var item = frappe.get_doc(cdt, cdn);
if (!item.warehouse && frm.doc.set_warehouse) {
item.warehouse = frm.doc.set_warehouse;
@@ -118,6 +120,13 @@
item.from_warehouse = frm.doc.set_from_warehouse;
}
+ if (item.docstatus === 0
+ && frappe.meta.has_field(item.doctype, "use_serial_batch_fields")
+ && cint(frappe.user_defaults?.use_serial_batch_fields) === 1
+ ) {
+ frappe.model.set_value(item.doctype, item.name, "use_serial_batch_fields", 1);
+ }
+
erpnext.accounts.dimensions.copy_dimension_from_first_row(frm, cdt, cdn, 'items');
}
});
@@ -222,7 +231,19 @@
};
});
}
+ }
+ set_fields_onload_for_line_item() {
+ if (this.frm.is_new && this.frm.doc?.items) {
+ this.frm.doc.items.forEach(item => {
+ if (item.docstatus === 0
+ && frappe.meta.has_field(item.doctype, "use_serial_batch_fields")
+ && cint(frappe.user_defaults?.use_serial_batch_fields) === 1
+ ) {
+ frappe.model.set_value(item.doctype, item.name, "use_serial_batch_fields", 1);
+ }
+ })
+ }
}
toggle_enable_for_stock_uom(field) {
@@ -462,6 +483,11 @@
this.frm.doc.doctype === 'Delivery Note') {
show_batch_dialog = 1;
}
+
+ if (show_batch_dialog && item.use_serial_batch_fields === 1) {
+ show_batch_dialog = 0;
+ }
+
item.barcode = null;
@@ -502,6 +528,7 @@
project: item.project || me.frm.doc.project,
qty: item.qty || 1,
net_rate: item.rate,
+ base_net_rate: item.base_net_rate,
stock_qty: item.stock_qty,
conversion_factor: item.conversion_factor,
weight_per_unit: item.weight_per_unit,
@@ -705,10 +732,10 @@
item.serial_no = item.serial_no.replace(/,/g, '\n');
item.conversion_factor = item.conversion_factor || 1;
refresh_field("serial_no", item.name, item.parentfield);
- if (!doc.is_return && cint(frappe.user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
+ if (!doc.is_return) {
setTimeout(() => {
me.update_qty(cdt, cdn);
- }, 10000);
+ }, 3000);
}
}
}
@@ -790,24 +817,25 @@
if (me.frm.doc.price_list_currency == company_currency) {
me.frm.set_value('plc_conversion_rate', 1.0);
}
- if (company_doc && company_doc.default_letter_head) {
- if(me.frm.fields_dict.letter_head) {
- me.frm.set_value("letter_head", company_doc.default_letter_head);
+ if (company_doc){
+ if (company_doc.default_letter_head) {
+ if(me.frm.fields_dict.letter_head) {
+ me.frm.set_value("letter_head", company_doc.default_letter_head);
+ }
+ }
+ let selling_doctypes_for_tc = ["Sales Invoice", "Quotation", "Sales Order", "Delivery Note"];
+ if (company_doc.default_selling_terms && frappe.meta.has_field(me.frm.doc.doctype, "tc_name") &&
+ selling_doctypes_for_tc.includes(me.frm.doc.doctype) && !me.frm.doc.tc_name) {
+ me.frm.set_value("tc_name", company_doc.default_selling_terms);
+ }
+ let buying_doctypes_for_tc = ["Request for Quotation", "Supplier Quotation", "Purchase Order",
+ "Material Request", "Purchase Receipt"];
+ // Purchase Invoice is excluded as per issue #3345
+ if (company_doc.default_buying_terms && frappe.meta.has_field(me.frm.doc.doctype, "tc_name") &&
+ buying_doctypes_for_tc.includes(me.frm.doc.doctype) && !me.frm.doc.tc_name) {
+ me.frm.set_value("tc_name", company_doc.default_buying_terms);
}
}
- let selling_doctypes_for_tc = ["Sales Invoice", "Quotation", "Sales Order", "Delivery Note"];
- if (company_doc.default_selling_terms && frappe.meta.has_field(me.frm.doc.doctype, "tc_name") &&
- selling_doctypes_for_tc.indexOf(me.frm.doc.doctype) != -1) {
- me.frm.set_value("tc_name", company_doc.default_selling_terms);
- }
- let buying_doctypes_for_tc = ["Request for Quotation", "Supplier Quotation", "Purchase Order",
- "Material Request", "Purchase Receipt"];
- // Purchase Invoice is excluded as per issue #3345
- if (company_doc.default_buying_terms && frappe.meta.has_field(me.frm.doc.doctype, "tc_name") &&
- buying_doctypes_for_tc.indexOf(me.frm.doc.doctype) != -1) {
- me.frm.set_value("tc_name", company_doc.default_buying_terms);
- }
-
frappe.run_serially([
() => me.frm.script_manager.trigger("currency"),
() => me.update_item_tax_map(),
@@ -1240,20 +1268,6 @@
}
}
- sync_bundle_data() {
- let doctypes = ["Sales Invoice", "Purchase Invoice", "Delivery Note", "Purchase Receipt"];
-
- if (this.frm.is_new() && doctypes.includes(this.frm.doc.doctype)) {
- const barcode_scanner = new erpnext.utils.BarcodeScanner({frm:this.frm});
- barcode_scanner.sync_bundle_data();
- barcode_scanner.remove_item_from_localstorage();
- }
- }
-
- before_save(doc) {
- this.sync_bundle_data();
- }
-
service_start_date(frm, cdt, cdn) {
var child = locals[cdt][cdn];
@@ -1901,7 +1915,7 @@
if (item.item_code) {
// Use combination of name and item code in case same item is added multiple times
item_codes.push([item.item_code, item.name]);
- item_rates[item.name] = item.net_rate;
+ item_rates[item.name] = item.base_net_rate;
item_tax_templates[item.name] = item.item_tax_template;
}
});
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index dee9a06..b847e57 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -5,6 +5,8 @@
import "./utils/party";
import "./controllers/stock_controller";
import "./payment/payments";
+import "./templates/visual_plant_floor_template.html";
+import "./plant_floor_visual/visual_plant";
import "./controllers/taxes_and_totals";
import "./controllers/transaction";
import "./templates/item_selector.html";
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 17341d1..43e58c2 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -2,7 +2,58 @@
erpnext.financial_statements = {
"filters": get_filters(),
+ "baseData": null,
"formatter": function(value, row, column, data, default_formatter, filter) {
+ if(frappe.query_report.get_filter_value("selected_view") == "Growth" && data && column.colIndex >= 3){
+ //Assuming that the first three columns are s.no, account name and the very first year of the accounting values, to calculate the relative percentage values of the successive columns.
+ const lastAnnualValue = row[column.colIndex - 1].content;
+ const currentAnnualvalue = data[column.fieldname];
+ if(currentAnnualvalue == undefined) return 'NA'; //making this not applicable for undefined/null values
+ let annualGrowth = 0;
+ if(lastAnnualValue == 0 && currentAnnualvalue > 0){
+ //If the previous year value is 0 and the current value is greater than 0
+ annualGrowth = 1;
+ }
+ else if(lastAnnualValue > 0){
+ annualGrowth = (currentAnnualvalue - lastAnnualValue) / lastAnnualValue;
+ }
+
+ const growthPercent = (Math.round(annualGrowth*10000)/100); //calculating the rounded off percentage
+
+ value = $(`<span>${((growthPercent >=0)? '+':'' )+growthPercent+'%'}</span>`);
+ if(growthPercent < 0){
+ value = $(value).addClass("text-danger");
+ }
+ else{
+ value = $(value).addClass("text-success");
+ }
+ value = $(value).wrap("<p></p>").parent().html();
+
+ return value;
+ }
+ else if(frappe.query_report.get_filter_value("selected_view") == "Margin" && data){
+ if(column.fieldname =="account" && data.account_name == __("Income")){
+ //Taking the total income from each column (for all the financial years) as the base (100%)
+ this.baseData = row;
+ }
+ if(column.colIndex >= 2){
+ //Assuming that the first two columns are s.no and account name, to calculate the relative percentage values of the successive columns.
+ const currentAnnualvalue = data[column.fieldname];
+ const baseValue = this.baseData[column.colIndex].content;
+ if(currentAnnualvalue == undefined || baseValue <= 0) return 'NA';
+ const marginPercent = Math.round((currentAnnualvalue/baseValue)*10000)/100;
+
+ value = $(`<span>${marginPercent+'%'}</span>`);
+ if(marginPercent < 0)
+ value = $(value).addClass("text-danger");
+ else
+ value = $(value).addClass("text-success");
+ value = $(value).wrap("<p></p>").parent().html();
+ return value;
+ }
+
+ }
+
if (data && column.fieldname=="account") {
value = data.account_name || value;
@@ -74,22 +125,24 @@
});
});
- const views_menu = report.page.add_custom_button_group(__('Financial Statements'));
+ if (report.page){
+ const views_menu = report.page.add_custom_button_group(__('Financial Statements'));
- report.page.add_custom_menu_item(views_menu, __("Balance Sheet"), function() {
- var filters = report.get_values();
- frappe.set_route('query-report', 'Balance Sheet', {company: filters.company});
- });
+ report.page.add_custom_menu_item(views_menu, __("Balance Sheet"), function() {
+ var filters = report.get_values();
+ frappe.set_route('query-report', 'Balance Sheet', {company: filters.company});
+ });
- report.page.add_custom_menu_item(views_menu, __("Profit and Loss"), function() {
- var filters = report.get_values();
- frappe.set_route('query-report', 'Profit and Loss Statement', {company: filters.company});
- });
+ report.page.add_custom_menu_item(views_menu, __("Profit and Loss"), function() {
+ var filters = report.get_values();
+ frappe.set_route('query-report', 'Profit and Loss Statement', {company: filters.company});
+ });
- report.page.add_custom_menu_item(views_menu, __("Cash Flow Statement"), function() {
- var filters = report.get_values();
- frappe.set_route('query-report', 'Cash Flow', {company: filters.company});
- });
+ report.page.add_custom_menu_item(views_menu, __("Cash Flow Statement"), function() {
+ var filters = report.get_values();
+ frappe.set_route('query-report', 'Cash Flow', {company: filters.company});
+ });
+ }
}
};
diff --git a/erpnext/public/js/plant_floor_visual/visual_plant.js b/erpnext/public/js/plant_floor_visual/visual_plant.js
new file mode 100644
index 0000000..8cd73ad
--- /dev/null
+++ b/erpnext/public/js/plant_floor_visual/visual_plant.js
@@ -0,0 +1,157 @@
+class VisualPlantFloor {
+ constructor({wrapper, skip_filters=false, plant_floor=null}, page=null) {
+ this.wrapper = wrapper;
+ this.plant_floor = plant_floor;
+ this.skip_filters = skip_filters;
+
+ this.make();
+ if (!this.skip_filters) {
+ this.page = page;
+ this.add_filter();
+ this.prepare_menu();
+ }
+ }
+
+ make() {
+ this.wrapper.append(`
+ <div class="plant-floor">
+ <div class="plant-floor-filter">
+ </div>
+ <div class="plant-floor-container col-sm-12">
+ </div>
+ </div>
+ `);
+
+ if (!this.skip_filters) {
+ this.filter_wrapper = this.wrapper.find('.plant-floor-filter');
+ this.visualization_wrapper = this.wrapper.find('.plant-floor-visualization');
+ } else if(this.plant_floor) {
+ this.wrapper.find('.plant-floor').css('border', 'none');
+ this.prepare_data();
+ }
+ }
+
+ prepare_data() {
+ frappe.call({
+ method: 'erpnext.manufacturing.doctype.workstation.workstation.get_workstations',
+ args: {
+ plant_floor: this.plant_floor,
+ },
+ callback: (r) => {
+ this.workstations = r.message;
+ this.render_workstations();
+ }
+ });
+ }
+
+ add_filter() {
+ this.plant_floor = frappe.ui.form.make_control({
+ df: {
+ fieldtype: 'Link',
+ options: 'Plant Floor',
+ fieldname: 'plant_floor',
+ label: __('Plant Floor'),
+ reqd: 1,
+ onchange: () => {
+ this.render_plant_visualization();
+ }
+ },
+ parent: this.filter_wrapper,
+ render_input: true,
+ });
+
+ this.plant_floor.$wrapper.addClass('form-column col-sm-2');
+
+ this.workstation_type = frappe.ui.form.make_control({
+ df: {
+ fieldtype: 'Link',
+ options: 'Workstation Type',
+ fieldname: 'workstation_type',
+ label: __('Machine Type'),
+ onchange: () => {
+ this.render_plant_visualization();
+ }
+ },
+ parent: this.filter_wrapper,
+ render_input: true,
+ });
+
+ this.workstation_type.$wrapper.addClass('form-column col-sm-2');
+
+ this.workstation = frappe.ui.form.make_control({
+ df: {
+ fieldtype: 'Link',
+ options: 'Workstation',
+ fieldname: 'workstation',
+ label: __('Machine'),
+ onchange: () => {
+ this.render_plant_visualization();
+ },
+ get_query: () => {
+ if (this.workstation_type.get_value()) {
+ return {
+ filters: {
+ 'workstation_type': this.workstation_type.get_value() || ''
+ }
+ }
+ }
+ }
+ },
+ parent: this.filter_wrapper,
+ render_input: true,
+ });
+
+ this.workstation.$wrapper.addClass('form-column col-sm-2');
+
+ this.workstation_status = frappe.ui.form.make_control({
+ df: {
+ fieldtype: 'Select',
+ options: '\nProduction\nOff\nIdle\nProblem\nMaintenance\nSetup',
+ fieldname: 'workstation_status',
+ label: __('Status'),
+ onchange: () => {
+ this.render_plant_visualization();
+ },
+ },
+ parent: this.filter_wrapper,
+ render_input: true,
+ });
+ }
+
+ render_plant_visualization() {
+ let plant_floor = this.plant_floor.get_value();
+
+ if (plant_floor) {
+ frappe.call({
+ method: 'erpnext.manufacturing.doctype.workstation.workstation.get_workstations',
+ args: {
+ plant_floor: plant_floor,
+ workstation_type: this.workstation_type.get_value(),
+ workstation: this.workstation.get_value(),
+ workstation_status: this.workstation_status.get_value()
+ },
+ callback: (r) => {
+ this.workstations = r.message;
+ this.render_workstations();
+ }
+ });
+ }
+ }
+
+ render_workstations() {
+ this.wrapper.find('.plant-floor-container').empty();
+ let template = frappe.render_template("visual_plant_floor_template", {
+ workstations: this.workstations
+ });
+
+ $(template).appendTo(this.wrapper.find('.plant-floor-container'));
+ }
+
+ prepare_menu() {
+ this.page.add_menu_item(__('Refresh'), () => {
+ this.render_plant_visualization();
+ });
+ }
+}
+
+frappe.ui.VisualPlantFloor = VisualPlantFloor;
\ No newline at end of file
diff --git a/erpnext/public/js/templates/visual_plant_floor_template.html b/erpnext/public/js/templates/visual_plant_floor_template.html
new file mode 100644
index 0000000..2e67085
--- /dev/null
+++ b/erpnext/public/js/templates/visual_plant_floor_template.html
@@ -0,0 +1,19 @@
+{% $.each(workstations, (idx, row) => { %}
+ <div class="workstation-wrapper">
+ <div class="workstation-image">
+ <div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
+ <a class="workstation-image-link" href="{{row.workstation_link}}">
+ {% if(row.status_image) { %}
+ <img class="workstation-image-cls" src="{{row.status_image}}">
+ {% } else { %}
+ <div class="workstation-image-cls workstation-abbr">{{frappe.get_abbr(row.name, 2)}}</div>
+ {% } %}
+ </a>
+ </div>
+ </div>
+ <div class="workstation-card text-center">
+ <p style="background-color:{{row.background_color}};color:#fff">{{row.status}}</p>
+ <div>{{row.workstation_name}}</div>
+ </div>
+ </div>
+{% }); %}
\ No newline at end of file
diff --git a/erpnext/public/js/utils/barcode_scanner.js b/erpnext/public/js/utils/barcode_scanner.js
index cf7fab8..4d1c0c1 100644
--- a/erpnext/public/js/utils/barcode_scanner.js
+++ b/erpnext/public/js/utils/barcode_scanner.js
@@ -1,12 +1,15 @@
erpnext.utils.BarcodeScanner = class BarcodeScanner {
constructor(opts) {
this.frm = opts.frm;
+ // frappe.flags.trigger_from_barcode_scanner is used for custom scripts
// field from which to capture input of scanned data
this.scan_field_name = opts.scan_field_name || "scan_barcode";
this.scan_barcode_field = this.frm.fields_dict[this.scan_field_name];
this.barcode_field = opts.barcode_field || "barcode";
+ this.serial_no_field = opts.serial_no_field || "serial_no";
+ this.batch_no_field = opts.batch_no_field || "batch_no";
this.uom_field = opts.uom_field || "uom";
this.qty_field = opts.qty_field || "qty";
// field name on row which defines max quantity to be scanned e.g. picklist
@@ -105,38 +108,52 @@
this.frm.has_items = false;
}
- if (serial_no && this.is_duplicate_serial_no(row, item_code, serial_no)) {
+ if (this.is_duplicate_serial_no(row, serial_no)) {
this.clean_up();
reject();
return;
}
frappe.run_serially([
- () => this.set_serial_and_batch(row, item_code, serial_no, batch_no),
- () => this.set_barcode(row, barcode),
+ () => this.set_selector_trigger_flag(data),
() => this.set_item(row, item_code, barcode, batch_no, serial_no).then(qty => {
this.show_scan_message(row.idx, row.item_code, qty);
}),
() => this.set_barcode_uom(row, uom),
+ () => this.set_serial_no(row, serial_no),
+ () => this.set_batch_no(row, batch_no),
+ () => this.set_barcode(row, barcode),
() => this.clean_up(),
- () => resolve(row),
- () => {
- if (row.serial_and_batch_bundle && !this.frm.is_new()) {
- this.frm.save();
- }
-
- frappe.flags.trigger_from_barcode_scanner = false;
- }
+ () => this.revert_selector_flag(),
+ () => resolve(row)
]);
});
}
+ // batch and serial selector is reduandant when all info can be added by scan
+ // this flag on item row is used by transaction.js to avoid triggering selector
+ set_selector_trigger_flag(data) {
+ const {batch_no, serial_no, has_batch_no, has_serial_no} = data;
+
+ const require_selecting_batch = has_batch_no && !batch_no;
+ const require_selecting_serial = has_serial_no && !serial_no;
+
+ if (!(require_selecting_batch || require_selecting_serial)) {
+ frappe.flags.hide_serial_batch_dialog = true;
+ }
+ }
+
+ revert_selector_flag() {
+ frappe.flags.hide_serial_batch_dialog = false;
+ frappe.flags.trigger_from_barcode_scanner = false;
+ }
+
set_item(row, item_code, barcode, batch_no, serial_no) {
return new Promise(resolve => {
const increment = async (value = 1) => {
- const item_data = {item_code: item_code};
- item_data[this.qty_field] = Number((row[this.qty_field] || 0)) + Number(value);
+ const item_data = {item_code: item_code, use_serial_batch_fields: 1.0};
frappe.flags.trigger_from_barcode_scanner = true;
+ item_data[this.qty_field] = Number((row[this.qty_field] || 0)) + Number(value);
await frappe.model.set_value(row.doctype, row.name, item_data);
return value;
};
@@ -145,6 +162,8 @@
frappe.prompt(__("Please enter quantity for item {0}", [item_code]), ({value}) => {
increment(value).then((value) => resolve(value));
});
+ } else if (this.frm.has_items) {
+ this.prepare_item_for_scan(row, item_code, barcode, batch_no, serial_no);
} else {
increment().then((value) => resolve(value));
}
@@ -167,8 +186,9 @@
frappe.model.set_value(row.doctype, row.name, item_data);
frappe.run_serially([
+ () => this.set_batch_no(row, this.dialog.get_value("batch_no")),
() => this.set_barcode(row, this.dialog.get_value("barcode")),
- () => this.set_serial_and_batch(row, item_code, this.dialog.get_value("serial_no"), this.dialog.get_value("batch_no")),
+ () => this.set_serial_no(row, this.dialog.get_value("serial_no")),
() => this.add_child_for_remaining_qty(row),
() => this.clean_up()
]);
@@ -322,144 +342,32 @@
}
}
- async set_serial_and_batch(row, item_code, serial_no, batch_no) {
- if (this.frm.is_new() || !row.serial_and_batch_bundle) {
- this.set_bundle_in_localstorage(row, item_code, serial_no, batch_no);
- } else if(row.serial_and_batch_bundle) {
- frappe.call({
- method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.update_serial_or_batch",
- args: {
- bundle_id: row.serial_and_batch_bundle,
- serial_no: serial_no,
- batch_no: batch_no,
- },
- })
- }
- }
+ async set_serial_no(row, serial_no) {
+ if (serial_no && frappe.meta.has_field(row.doctype, this.serial_no_field)) {
+ const existing_serial_nos = row[this.serial_no_field];
+ let new_serial_nos = "";
- get_key_for_localstorage() {
- let parts = this.frm.doc.name.split("-");
- return parts[parts.length - 1] + this.frm.doc.doctype;
- }
-
- update_localstorage_scanned_data() {
- let docname = this.frm.doc.name
- if (localStorage[docname]) {
- let items = JSON.parse(localStorage[docname]);
- let existing_items = this.frm.doc.items.map(d => d.item_code);
- if (!existing_items.length) {
- localStorage.removeItem(docname);
- return;
+ if (!!existing_serial_nos) {
+ new_serial_nos = existing_serial_nos + "\n" + serial_no;
+ } else {
+ new_serial_nos = serial_no;
}
-
- for (let item_code in items) {
- if (!existing_items.includes(item_code)) {
- delete items[item_code];
- }
- }
-
- localStorage[docname] = JSON.stringify(items);
+ await frappe.model.set_value(row.doctype, row.name, this.serial_no_field, new_serial_nos);
}
}
- async set_bundle_in_localstorage(row, item_code, serial_no, batch_no) {
- let docname = this.frm.doc.name
-
- let entries = JSON.parse(localStorage.getItem(docname));
- if (!entries) {
- entries = {};
- }
-
- let key = item_code;
- if (!entries[key]) {
- entries[key] = [];
- }
-
- let existing_row = [];
- if (!serial_no && batch_no) {
- existing_row = entries[key].filter((e) => e.batch_no === batch_no);
- if (existing_row.length) {
- existing_row[0].qty += 1;
- }
- } else if (serial_no) {
- existing_row = entries[key].filter((e) => e.serial_no === serial_no);
- if (existing_row.length) {
- frappe.throw(__("Serial No {0} has already scanned.", [serial_no]));
- }
- }
-
- if (!existing_row.length) {
- entries[key].push({
- "serial_no": serial_no,
- "batch_no": batch_no,
- "qty": 1
- });
- }
-
- localStorage.setItem(docname, JSON.stringify(entries));
-
- // Auto remove from localstorage after 1 hour
- setTimeout(() => {
- localStorage.removeItem(docname);
- }, 3600000)
- }
-
- remove_item_from_localstorage() {
- let docname = this.frm.doc.name;
- if (localStorage[docname]) {
- localStorage.removeItem(docname);
- }
- }
-
- async sync_bundle_data() {
- let docname = this.frm.doc.name;
-
- if (localStorage[docname]) {
- let entries = JSON.parse(localStorage[docname]);
- if (entries) {
- for (let entry in entries) {
- let row = this.frm.doc.items.filter((item) => {
- if (item.item_code === entry) {
- return true;
- }
- })[0];
-
- if (row) {
- this.create_serial_and_batch_bundle(row, entries, entry)
- .then(() => {
- if (!entries) {
- localStorage.removeItem(docname);
- }
- });
- }
- }
- }
- }
- }
-
- async create_serial_and_batch_bundle(row, entries, key) {
- frappe.call({
- method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers",
- args: {
- entries: entries[key],
- child_row: row,
- doc: this.frm.doc,
- warehouse: row.warehouse,
- do_not_save: 1
- },
- callback: function(r) {
- row.serial_and_batch_bundle = r.message.name;
- delete entries[key];
- }
- })
- }
-
async set_barcode_uom(row, uom) {
if (uom && frappe.meta.has_field(row.doctype, this.uom_field)) {
await frappe.model.set_value(row.doctype, row.name, this.uom_field, uom);
}
}
+ async set_batch_no(row, batch_no) {
+ if (batch_no && frappe.meta.has_field(row.doctype, this.batch_no_field)) {
+ await frappe.model.set_value(row.doctype, row.name, this.batch_no_field, batch_no);
+ }
+ }
+
async set_barcode(row, barcode) {
if (barcode && frappe.meta.has_field(row.doctype, this.barcode_field)) {
await frappe.model.set_value(row.doctype, row.name, this.barcode_field, barcode);
@@ -475,52 +383,13 @@
}
}
- is_duplicate_serial_no(row, item_code, serial_no) {
- if (this.frm.is_new() || !row.serial_and_batch_bundle) {
- let is_duplicate = this.check_duplicate_serial_no_in_localstorage(item_code, serial_no);
- if (is_duplicate) {
- this.show_alert(__("Serial No {0} is already added", [serial_no]), "orange");
- }
+ is_duplicate_serial_no(row, serial_no) {
+ const is_duplicate = row[this.serial_no_field]?.includes(serial_no);
- return is_duplicate;
- } else if (row.serial_and_batch_bundle) {
- this.check_duplicate_serial_no_in_db(row, serial_no, (r) => {
- if (r.message) {
- this.show_alert(__("Serial No {0} is already added", [serial_no]), "orange");
- }
-
- return r.message;
- })
+ if (is_duplicate) {
+ this.show_alert(__("Serial No {0} is already added", [serial_no]), "orange");
}
- }
-
- async check_duplicate_serial_no_in_db(row, serial_no, response) {
- frappe.call({
- method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_duplicate_serial_no",
- args: {
- serial_no: serial_no,
- bundle_id: row.serial_and_batch_bundle
- },
- callback(r) {
- response(r);
- }
- })
- }
-
- check_duplicate_serial_no_in_localstorage(item_code, serial_no) {
- let docname = this.frm.doc.name
- let entries = JSON.parse(localStorage.getItem(docname));
-
- if (!entries) {
- return false;
- }
-
- let existing_row = [];
- if (entries[item_code]) {
- existing_row = entries[item_code].filter((e) => e.serial_no === serial_no);
- }
-
- return existing_row.length;
+ return is_duplicate;
}
get_row_to_modify_on_scan(item_code, batch_no, uom, barcode) {
@@ -566,4 +435,4 @@
show_alert(msg, indicator, duration=3) {
frappe.show_alert({message: msg, indicator: indicator}, duration);
}
-};
+};
\ No newline at end of file
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 3f70c09..27d00ba 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -25,6 +25,10 @@
},
setup_filters(frm, doctype) {
+ if (doctype == 'Payment Entry' && this.accounting_dimensions) {
+ frm.dimension_filters = this.accounting_dimensions
+ }
+
if (this.accounting_dimensions) {
this.accounting_dimensions.forEach((dimension) => {
frappe.model.with_doctype(dimension['document_type'], () => {
diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js
index b92b02e..b8ec77f 100644
--- a/erpnext/public/js/utils/sales_common.js
+++ b/erpnext/public/js/utils/sales_common.js
@@ -22,6 +22,15 @@
}
};
});
+
+ this.frm.set_query('project', function(doc) {
+ return {
+ query: "erpnext.controllers.queries.get_project_name",
+ filters: {
+ 'customer': doc.customer
+ }
+ }
+ });
}
setup_queries() {
@@ -439,4 +448,4 @@
}
});
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index bf362e3..80ade70 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -71,6 +71,10 @@
let warehouse = this.item?.type_of_transaction === "Outward" ?
(this.item.warehouse || this.item.s_warehouse) : "";
+ if (!warehouse && this.frm.doc.doctype === 'Stock Reconciliation') {
+ warehouse = this.get_warehouse();
+ }
+
return {
'item_code': this.item.item_code,
'warehouse': ["=", warehouse]
@@ -135,7 +139,7 @@
filters: this.get_serial_no_filters()
};
},
- onchange: () => this.update_serial_batch_no()
+ onchange: () => this.scan_barcode_data()
});
}
@@ -145,7 +149,7 @@
options: 'Barcode',
fieldname: 'scan_batch_no',
label: __('Scan Batch No'),
- onchange: () => this.update_serial_batch_no()
+ onchange: () => this.scan_barcode_data()
});
}
@@ -179,11 +183,54 @@
label = __('Serial Nos / Batch Nos');
}
- return [
+ let fields = [
{
fieldtype: 'Section Break',
label: __('{0} {1} via CSV File', [primary_label, label])
- },
+ }
+ ]
+
+ if (this.item?.has_serial_no) {
+ fields = [...fields,
+ {
+ fieldtype: 'Check',
+ label: __('Import Using CSV file'),
+ fieldname: 'import_using_csv_file',
+ default: 0,
+ },
+ {
+ fieldtype: 'Section Break',
+ label: __('{0} {1} Manually', [primary_label, label]),
+ depends_on: 'eval:doc.import_using_csv_file === 0',
+ },
+ {
+ fieldtype: 'Small Text',
+ label: __('Enter Serial Nos'),
+ fieldname: 'upload_serial_nos',
+ depends_on: 'eval:doc.import_using_csv_file === 0',
+ description: __('Enter each serial no in a new line'),
+ },
+ {
+ fieldtype: 'Column Break',
+ depends_on: 'eval:doc.import_using_csv_file === 0',
+ },
+ {
+ fieldtype: 'Button',
+ fieldname: 'make_serial_nos',
+ label: __('Create Serial Nos'),
+ depends_on: 'eval:doc.import_using_csv_file === 0',
+ click: () => {
+ this.create_serial_nos();
+ }
+ },
+ {
+ fieldtype: 'Section Break',
+ depends_on: 'eval:doc.import_using_csv_file === 1',
+ }
+ ];
+ }
+
+ fields = [...fields,
{
fieldtype: 'Button',
fieldname: 'download_csv',
@@ -199,7 +246,32 @@
label: __('Attach CSV File'),
onchange: () => this.upload_csv_file()
}
- ]
+ ];
+
+ return fields;
+ }
+
+ create_serial_nos() {
+ let {upload_serial_nos} = this.dialog.get_values();
+
+ if (!upload_serial_nos) {
+ frappe.throw(__('Please enter Serial Nos'));
+ }
+
+ frappe.call({
+ method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.create_serial_nos',
+ args: {
+ item_code: this.item.item_code,
+ serial_nos: upload_serial_nos
+ },
+ callback: (r) => {
+ if (r.message) {
+ this.dialog.fields_dict.entries.df.data = [];
+ this.set_data(r.message);
+ this.update_bundle_entries();
+ }
+ }
+ });
}
download_csv_file() {
@@ -374,6 +446,26 @@
}
}
+ scan_barcode_data() {
+ const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
+
+ if (scan_serial_no || scan_batch_no) {
+ frappe.call({
+ method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_serial_batch_no_exists',
+ args: {
+ item_code: this.item.item_code,
+ type_of_transaction: this.item.type_of_transaction,
+ serial_no: scan_serial_no,
+ batch_no: scan_batch_no,
+ },
+ callback: (r) => {
+ this.update_serial_batch_no();
+ }
+
+ })
+ }
+ }
+
update_serial_batch_no() {
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
diff --git a/erpnext/public/scss/erpnext.scss b/erpnext/public/scss/erpnext.scss
index 8ab5973..1626b7c 100644
--- a/erpnext/public/scss/erpnext.scss
+++ b/erpnext/public/scss/erpnext.scss
@@ -490,3 +490,53 @@
.exercise-col {
padding: 10px;
}
+
+.plant-floor, .workstation-wrapper, .workstation-card p {
+ border-radius: var(--border-radius-md);
+ border: 1px solid var(--border-color);
+ box-shadow: none;
+ background-color: var(--card-bg);
+ position: relative;
+}
+
+.plant-floor {
+ padding-bottom: 25px;
+}
+
+.plant-floor-filter {
+ padding-top: 10px;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.plant-floor-container {
+ display: grid;
+ grid-template-columns: repeat(6,minmax(0,1fr));
+ gap: var(--margin-xl);
+}
+
+@media screen and (max-width: 620px) {
+ .plant-floor-container {
+ grid-template-columns: repeat(2,minmax(0,1fr));
+ }
+}
+
+.plant-floor-container .workstation-card {
+ padding: 5px;
+}
+
+.plant-floor-container .workstation-image-link {
+ width: 100%;
+ font-size: 50px;
+ margin: var(--margin-sm);
+ min-height: 9rem;
+}
+
+.workstation-abbr {
+ display: flex;
+ background-color: var(--control-bg);
+ height:100%;
+ width:100%;
+ align-items: center;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
index d332b4e..ecc198a 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
@@ -64,7 +64,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto",
+ "label": "Valid Up To",
"reqd": 1
},
{
@@ -135,7 +135,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-04-18 08:25:35.302081",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Regional",
"name": "Lower Deduction Certificate",
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index 72b3a49..6982ad1 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -37,7 +37,7 @@
def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
- frappe.throw(_("Valid Upto date cannot be before Valid From date"))
+ frappe.throw(_("Valid Up To date cannot be before Valid From date"))
fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
@@ -45,7 +45,7 @@
frappe.throw(_("Valid From date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
if not (fiscal_year.year_start_date <= getdate(self.valid_upto) <= fiscal_year.year_end_date):
- frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
+ frappe.throw(_("Valid Up To date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
def validate_supplier_against_tax_category(self):
duplicate_certificate = frappe.db.get_value(
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index efb9820..3744922 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -124,6 +124,7 @@
),
title=_("Note"),
indicator="yellow",
+ alert=True,
)
return new_customer_name
@@ -229,6 +230,7 @@
if self.flags.is_new_doc:
self.link_lead_address_and_contact()
+ self.copy_communication()
self.update_customer_groups()
@@ -290,6 +292,17 @@
linked_doc.append("links", dict(link_doctype="Customer", link_name=self.name))
linked_doc.save(ignore_permissions=self.flags.ignore_permissions)
+ def copy_communication(self):
+ if not self.lead_name or not frappe.db.get_single_value(
+ "CRM Settings", "carry_forward_communication_and_comments"
+ ):
+ return
+
+ from erpnext.crm.utils import copy_comments, link_communications
+
+ copy_comments("Lead", self.lead_name, self)
+ link_communications("Lead", self.lead_name, self)
+
def validate_name_with_customer_group(self):
if frappe.db.exists("Customer Group", self.name):
frappe.throw(
@@ -559,15 +572,14 @@
@frappe.whitelist()
-def send_emails(args):
- args = json.loads(args)
- subject = _("Credit limit reached for customer {0}").format(args.get("customer"))
+def send_emails(customer, customer_outstanding, credit_limit, credit_controller_users_list):
+ if isinstance(credit_controller_users_list, str):
+ credit_controller_users_list = json.loads(credit_controller_users_list)
+ subject = _("Credit limit reached for customer {0}").format(customer)
message = _("Credit limit has been crossed for customer {0} ({1}/{2})").format(
- args.get("customer"), args.get("customer_outstanding"), args.get("credit_limit")
+ customer, customer_outstanding, credit_limit
)
- frappe.sendmail(
- recipients=args.get("credit_controller_users_list"), subject=subject, message=message
- )
+ frappe.sendmail(recipients=credit_controller_users_list, subject=subject, message=message)
def get_customer_outstanding(
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 29dbd4f..47153a8 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -427,11 +427,11 @@
if not allowed_to_interact_with:
allowed_to_interact_with = represents_company
- exisiting_representative = frappe.db.get_value(
+ existing_representative = frappe.db.get_value(
"Customer", {"represents_company": represents_company}
)
- if exisiting_representative:
- return exisiting_representative
+ if existing_representative:
+ return existing_representative
if not frappe.db.exists("Customer", customer_name):
customer = frappe.get_doc(
diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.json b/erpnext/selling/doctype/product_bundle/product_bundle.json
index c4f21b6..1c37b85 100644
--- a/erpnext/selling/doctype/product_bundle/product_bundle.json
+++ b/erpnext/selling/doctype/product_bundle/product_bundle.json
@@ -2,7 +2,7 @@
"actions": [],
"allow_import": 1,
"creation": "2013-06-20 11:53:21",
- "description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials",
+ "description": "Aggregate a group of Items into another Item. This is useful if you are maintaining the stock of the packed items and not the bundled item",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
@@ -77,7 +77,7 @@
"icon": "fa fa-sitemap",
"idx": 1,
"links": [],
- "modified": "2023-11-22 15:20:46.805114",
+ "modified": "2024-01-30 13:57:04.951788",
"modified_by": "Administrator",
"module": "Selling",
"name": "Product Bundle",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index ab74f7f..13d17d6 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -127,7 +127,8 @@
def validate(self):
super(Quotation, self).validate()
self.set_status()
- self.validate_uom_is_integer("stock_uom", "qty")
+ self.validate_uom_is_integer("stock_uom", "stock_qty")
+ self.validate_uom_is_integer("uom", "qty")
self.validate_valid_till()
self.set_customer_name()
if self.items:
@@ -345,8 +346,8 @@
return _make_sales_order(source_name, target_doc)
-def _make_sales_order(source_name, target_doc=None, customer_group=None, ignore_permissions=False):
- customer = _make_customer(source_name, ignore_permissions, customer_group)
+def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
+ customer = _make_customer(source_name, ignore_permissions)
ordered_items = frappe._dict(
frappe.db.get_all(
"Sales Order Item",
@@ -390,7 +391,6 @@
balance_qty = obj.qty - ordered_items.get(obj.item_code, 0.0)
target.qty = balance_qty if balance_qty > 0 else 0
target.stock_qty = flt(target.qty) * flt(obj.conversion_factor)
- target.delivery_date = nowdate()
if obj.against_blanket_order:
target.against_blanket_order = obj.against_blanket_order
@@ -506,50 +506,51 @@
return doclist
-def _make_customer(source_name, ignore_permissions=False, customer_group=None):
+def _make_customer(source_name, ignore_permissions=False):
quotation = frappe.db.get_value(
- "Quotation", source_name, ["order_type", "party_name", "customer_name"], as_dict=1
+ "Quotation",
+ source_name,
+ ["order_type", "quotation_to", "party_name", "customer_name"],
+ as_dict=1,
)
- if quotation and quotation.get("party_name"):
- if not frappe.db.exists("Customer", quotation.get("party_name")):
- lead_name = quotation.get("party_name")
- customer_name = frappe.db.get_value(
- "Customer", {"lead_name": lead_name}, ["name", "customer_name"], as_dict=True
- )
- if not customer_name:
- from erpnext.crm.doctype.lead.lead import _make_customer
+ if quotation.quotation_to == "Customer":
+ return frappe.get_doc("Customer", quotation.party_name)
- customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions)
- customer = frappe.get_doc(customer_doclist)
- customer.flags.ignore_permissions = ignore_permissions
- customer.customer_group = customer_group
+ # If the Quotation is not to a Customer, it must be to a Lead.
+ # Check if a Customer already exists for the Lead.
+ existing_customer_for_lead = frappe.db.get_value("Customer", {"lead_name": quotation.party_name})
+ if existing_customer_for_lead:
+ return frappe.get_doc("Customer", existing_customer_for_lead)
- try:
- customer.insert()
- return customer
- except frappe.NameError:
- if frappe.defaults.get_global_default("cust_master_name") == "Customer Name":
- customer.run_method("autoname")
- customer.name += "-" + lead_name
- customer.insert()
- return customer
- else:
- raise
- except frappe.MandatoryError as e:
- mandatory_fields = e.args[0].split(":")[1].split(",")
- mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
+ # If no Customer exists for the Lead, create a new Customer.
+ return create_customer_from_lead(quotation.party_name, ignore_permissions=ignore_permissions)
- frappe.local.message_log = []
- lead_link = frappe.utils.get_link_to_form("Lead", lead_name)
- message = (
- _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
- )
- message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
- message += _("Please create Customer from Lead {0}.").format(lead_link)
- frappe.throw(message, title=_("Mandatory Missing"))
- else:
- return customer_name
- else:
- return frappe.get_doc("Customer", quotation.get("party_name"))
+def create_customer_from_lead(lead_name, ignore_permissions=False):
+ from erpnext.crm.doctype.lead.lead import _make_customer
+
+ customer = _make_customer(lead_name, ignore_permissions=ignore_permissions)
+ customer.flags.ignore_permissions = ignore_permissions
+
+ try:
+ customer.insert()
+ return customer
+ except frappe.MandatoryError as e:
+ handle_mandatory_error(e, customer, lead_name)
+
+
+def handle_mandatory_error(e, customer, lead_name):
+ from frappe.utils import get_link_to_form
+
+ mandatory_fields = e.args[0].split(":")[1].split(",")
+ mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
+
+ frappe.local.message_log = []
+ message = (
+ _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
+ )
+ message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
+ message += _("Please create Customer from Lead {0}.").format(get_link_to_form("Lead", lead_name))
+
+ frappe.throw(message, title=_("Mandatory Missing"))
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index ecb7d09..0b0d6e7 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -99,7 +99,6 @@
self.assertEqual(sales_order.get("items")[0].prevdoc_docname, quotation.name)
self.assertEqual(sales_order.customer, "_Test Customer")
- sales_order.delivery_date = "2014-01-01"
sales_order.naming_series = "_T-Quotation-"
sales_order.transaction_date = nowdate()
sales_order.insert()
@@ -132,7 +131,6 @@
self.assertEqual(sales_order.get("items")[0].prevdoc_docname, quotation.name)
self.assertEqual(sales_order.customer, "_Test Customer")
- sales_order.delivery_date = "2014-01-01"
sales_order.naming_series = "_T-Quotation-"
sales_order.transaction_date = nowdate()
sales_order.insert()
@@ -593,6 +591,77 @@
quotation.reload()
self.assertEqual(quotation.status, "Ordered")
+ def test_uom_validation(self):
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ item = "_Test Item FOR UOM Validation"
+ make_item(item, {"is_stock_item": 1})
+
+ if not frappe.db.exists("UOM", "lbs"):
+ frappe.get_doc({"doctype": "UOM", "uom_name": "lbs", "must_be_whole_number": 1}).insert()
+ else:
+ frappe.db.set_value("UOM", "lbs", "must_be_whole_number", 1)
+
+ quotation = make_quotation(item_code=item, qty=1, rate=100, do_not_submit=1)
+ quotation.items[0].uom = "lbs"
+ quotation.items[0].conversion_factor = 2.23
+ self.assertRaises(frappe.ValidationError, quotation.save)
+
+ def test_item_tax_template_for_quotation(self):
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ if not frappe.db.exists("Account", {"account_name": "_Test Vat", "company": "_Test Company"}):
+ frappe.get_doc(
+ {
+ "doctype": "Account",
+ "account_name": "_Test Vat",
+ "company": "_Test Company",
+ "account_type": "Tax",
+ "root_type": "Asset",
+ "is_group": 0,
+ "parent_account": "Tax Assets - _TC",
+ "tax_rate": 10,
+ }
+ ).insert()
+
+ if not frappe.db.exists("Item Tax Template", "Vat Template - _TC"):
+ doc = frappe.get_doc(
+ {
+ "doctype": "Item Tax Template",
+ "name": "Vat Template",
+ "title": "Vat Template",
+ "company": "_Test Company",
+ "taxes": [
+ {
+ "tax_type": "_Test Vat - _TC",
+ "tax_rate": 5,
+ }
+ ],
+ }
+ ).insert()
+
+ item_doc = make_item("_Test Item Tax Template QTN", {"is_stock_item": 1})
+ if not frappe.db.exists(
+ "Item Tax", {"parent": item_doc.name, "item_tax_template": "Vat Template - _TC"}
+ ):
+ item_doc.append("taxes", {"item_tax_template": "Vat Template - _TC"})
+ item_doc.save()
+
+ quotation = make_quotation(
+ item_code="_Test Item Tax Template QTN", qty=1, rate=100, do_not_submit=1
+ )
+ self.assertFalse(quotation.taxes)
+
+ quotation.append_taxes_from_item_tax_template()
+ quotation.save()
+ self.assertTrue(quotation.taxes)
+ for row in quotation.taxes:
+ self.assertEqual(row.account_head, "_Test Vat - _TC")
+ self.assertAlmostEqual(row.base_tax_amount, quotation.total * 5 / 100)
+
+ item_doc.taxes = []
+ item_doc.save()
+
test_records = frappe.get_test_records("Quotation")
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 56c745c..2bb093d 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -144,15 +144,6 @@
};
});
- frm.set_query('project', function(doc, cdt, cdn) {
- return {
- query: "erpnext.controllers.queries.get_project_name",
- filters: {
- 'customer': doc.customer
- }
- }
- });
-
frm.set_query('warehouse', 'items', function(doc, cdt, cdn) {
let row = locals[cdt][cdn];
let query = {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 01d047c..3c516d0 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -131,6 +131,7 @@
"per_billed",
"per_picked",
"billing_status",
+ "advance_payment_status",
"sales_team_section_break",
"sales_partner",
"column_break7",
@@ -1269,7 +1270,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nOn Hold\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nCancelled\nClosed",
+ "options": "\nDraft\nOn Hold\nTo Pay\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nCancelled\nClosed",
"print_hide": 1,
"read_only": 1,
"reqd": 1,
@@ -1638,6 +1639,18 @@
"no_copy": 1,
"print_hide": 1,
"report_hide": 1
+ },
+ {
+ "fieldname": "advance_payment_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "hide_days": 1,
+ "hide_seconds": 1,
+ "in_standard_filter": 1,
+ "label": "Advance Payment Status",
+ "no_copy": 1,
+ "options": "Not Requested\nRequested\nPartially Paid\nFully Paid",
+ "print_hide": 1
}
],
"icon": "fa fa-file-text",
@@ -1722,4 +1735,4 @@
"title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 5ef2c50..9661bac 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -223,6 +223,8 @@
self.billing_status = "Not Billed"
if not self.delivery_status:
self.delivery_status = "Not Delivered"
+ if not self.advance_payment_status:
+ self.advance_payment_status = "Not Requested"
self.reset_default_field_value("set_warehouse", "items", "warehouse")
@@ -641,7 +643,7 @@
if not frappe.get_cached_value("Item", item.item_code, "has_serial_no"):
frappe.throw(
_(
- "Item {0} has no Serial No. Only serilialized items can have delivery based on Serial No"
+ "Item {0} has no Serial No. Only serialized items can have delivery based on Serial No"
).format(item.item_code)
)
if not frappe.db.exists("BOM", {"item": item.item_code, "is_active": 1}):
@@ -904,6 +906,7 @@
target.run_method("set_missing_values")
target.run_method("set_po_nos")
target.run_method("calculate_taxes_and_totals")
+ target.run_method("set_use_serial_batch_fields")
if source.company_address:
target.update({"company_address": source.company_address})
@@ -1024,6 +1027,7 @@
target.run_method("set_missing_values")
target.run_method("set_po_nos")
target.run_method("calculate_taxes_and_totals")
+ target.run_method("set_use_serial_batch_fields")
if source.company_address:
target.update({"company_address": source.company_address})
@@ -1606,7 +1610,11 @@
"Sales Order",
source_name,
{
- "Sales Order": {"doctype": "Pick List", "validation": {"docstatus": ["=", 1]}},
+ "Sales Order": {
+ "doctype": "Pick List",
+ "field_map": {"set_warehouse": "parent_warehouse"},
+ "validation": {"docstatus": ["=", 1]},
+ },
"Sales Order Item": {
"doctype": "Pick List Item",
"field_map": {"parent": "sales_order", "name": "sales_order_item"},
diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js
index 518f018..37686a8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_list.js
+++ b/erpnext/selling/doctype/sales_order/sales_order_list.js
@@ -1,6 +1,6 @@
frappe.listview_settings['Sales Order'] = {
add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date",
- "per_delivered", "per_billed", "status", "order_type", "name", "skip_delivery_note"],
+ "per_delivered", "per_billed", "status", "advance_payment_status", "order_type", "name", "skip_delivery_note"],
get_indicator: function (doc) {
if (doc.status === "Closed") {
// Closed
@@ -10,6 +10,8 @@
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.status === "Completed") {
return [__("Completed"), "green", "status,=,Completed"];
+ } else if (doc.advance_payment_status === "Requested") {
+ return [__("To Pay"), "gray", "advance_payment_status,=,Requested"];
} else if (!doc.skip_delivery_note && flt(doc.per_delivered, 2) < 100) {
if (frappe.datetime.get_diff(doc.delivery_date) < 0) {
// not delivered & overdue
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index ac7fdb1..5ae48ee 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1996,6 +1996,33 @@
self.assertEqual(so.items[0].rate, scenario.get("expected_rate"))
self.assertEqual(so.packed_items[0].rate, scenario.get("expected_rate"))
+ def test_sales_order_advance_payment_status(self):
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+ from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
+
+ so = make_sales_order(qty=1, rate=100)
+ self.assertEqual(
+ frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Not Requested"
+ )
+
+ pr = make_payment_request(dt=so.doctype, dn=so.name, submit_doc=True, return_doc=True)
+ self.assertEqual(frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Requested")
+
+ pe = get_payment_entry(so.doctype, so.name).save().submit()
+ self.assertEqual(
+ frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Fully Paid"
+ )
+
+ pe.reload()
+ pe.cancel()
+ self.assertEqual(frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Requested")
+
+ pr.reload()
+ pr.cancel()
+ self.assertEqual(
+ frappe.db.get_value(so.doctype, so.name, "advance_payment_status"), "Not Requested"
+ )
+
def automatically_fetch_payment_terms(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 87aeeac..9599980 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -118,6 +118,7 @@
"oldfieldtype": "Link",
"options": "Item",
"print_width": "150px",
+ "reqd": 1,
"width": "150px"
},
{
@@ -908,7 +909,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-24 13:24:55.756320",
+ "modified": "2024-01-25 14:24:00.330219",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
index 25f5b4b..fa7b9b9 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
@@ -43,7 +43,8 @@
gross_profit: DF.Currency
image: DF.Attach | None
is_free_item: DF.Check
- item_code: DF.Link | None
+ is_stock_item: DF.Check
+ item_code: DF.Link
item_group: DF.Link | None
item_name: DF.Data
item_tax_rate: DF.Code | None
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index feecd9c..80e1c20 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -360,7 +360,7 @@
this.order_summary.load_summary_of(this.frm.doc, true);
frappe.show_alert({
indicator: 'green',
- message: __('POS invoice {0} created succesfully', [r.doc.name])
+ message: __('POS invoice {0} created successfully', [r.doc.name])
});
});
}
diff --git a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py
index 3682c5f..72b7fa2 100644
--- a/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py
+++ b/erpnext/selling/report/payment_terms_status_for_sales_order/payment_terms_status_for_sales_order.py
@@ -209,8 +209,7 @@
)
.where(
(so.docstatus == 1)
- & (so.status.isin(["To Deliver and Bill", "To Bill"]))
- & (so.payment_terms_template != "NULL")
+ & (so.status.isin(["To Deliver and Bill", "To Bill", "To Pay"]))
& (so.company == conditions.company)
& (so.transaction_date[conditions.start_date : conditions.end_date])
)
diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.js b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.js
index ac3d3db..fc685e0 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.js
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.js
@@ -56,7 +56,7 @@
"fieldtype": "MultiSelectList",
"width": "80",
get_data: function(txt) {
- let status = ["To Bill", "To Deliver", "To Deliver and Bill", "Completed"]
+ let status = ["To Pay", "To Bill", "To Deliver", "To Deliver and Bill", "Completed"]
let options = []
for (let option of status){
options.push({
diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py
index 9446fb4..27313ae 100644
--- a/erpnext/setup/doctype/authorization_control/authorization_control.py
+++ b/erpnext/setup/doctype/authorization_control/authorization_control.py
@@ -54,7 +54,7 @@
if not has_common(appr_roles, frappe.get_roles()) and not has_common(
appr_users, [session["user"]]
):
- frappe.msgprint(_("Not authroized since {0} exceeds limits").format(_(based_on)))
+ frappe.msgprint(_("Not authorized since {0} exceeds limits").format(_(based_on)))
frappe.throw(_("Can be approved by {0}").format(comma_or(appr_roles + appr_users)))
def validate_auth_rule(self, doctype_name, total, based_on, cond, company, master_name=""):
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 1bd469b..340a917 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -140,38 +140,48 @@
},
delete_company_transactions: function(frm) {
- frappe.verify_password(function() {
- var d = frappe.prompt({
- fieldtype:"Data",
- fieldname: "company_name",
- label: __("Please enter the company name to confirm"),
- reqd: 1,
- description: __("Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone.")
+ frappe.call({
+ method: "erpnext.setup.doctype.company.company.is_deletion_job_running",
+ args: {
+ company: frm.doc.name
},
- function(data) {
- if(data.company_name !== frm.doc.name) {
- frappe.msgprint(__("Company name not same"));
- return;
+ freeze: true,
+ callback: function(r) {
+ if(!r.exc) {
+ frappe.verify_password(function() {
+ var d = frappe.prompt({
+ fieldtype:"Data",
+ fieldname: "company_name",
+ label: __("Please enter the company name to confirm"),
+ reqd: 1,
+ description: __("Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone.")
+ },
+ function(data) {
+ if(data.company_name !== frm.doc.name) {
+ frappe.msgprint(__("Company name not same"));
+ return;
+ }
+ frappe.call({
+ method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
+ args: {
+ company: data.company_name
+ },
+ freeze: true,
+ callback: function(r, rt) { },
+ onerror: function() {
+ frappe.msgprint(__("Wrong Password"));
+ }
+ });
+ },
+ __("Delete all the Transactions for this Company"), __("Delete")
+ );
+ d.get_primary_btn().addClass("btn-danger");
+ });
}
- frappe.call({
- method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
- args: {
- company: data.company_name
- },
- freeze: true,
- callback: function(r, rt) {
- if(!r.exc)
- frappe.msgprint(__("Successfully deleted all transactions related to this company!"));
- },
- onerror: function() {
- frappe.msgprint(__("Wrong Password"));
- }
- });
+
},
- __("Delete all the Transactions for this Company"), __("Delete")
- );
- d.get_primary_btn().addClass("btn-danger");
});
+
}
});
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index ec953b8..876b6a4 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -11,7 +11,8 @@
from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.desk.page.setup_wizard.setup_wizard import make_records
-from frappe.utils import cint, formatdate, get_timestamp, today
+from frappe.utils import cint, formatdate, get_link_to_form, get_timestamp, today
+from frappe.utils.background_jobs import get_job, is_job_enqueued
from frappe.utils.nestedset import NestedSet, rebuild_tree
from erpnext.accounts.doctype.account.account import get_account_currency
@@ -900,8 +901,37 @@
return None
+def generate_id_for_deletion_job(company):
+ return "delete_company_transactions_" + company
+
+
+@frappe.whitelist()
+def is_deletion_job_running(company):
+ job_id = generate_id_for_deletion_job(company)
+ if is_job_enqueued(job_id):
+ job_name = get_job(job_id).get_id() # job name will have site prefix
+ frappe.throw(
+ _("A Transaction Deletion Job: {0} is already running for {1}").format(
+ frappe.bold(get_link_to_form("RQ Job", job_name)), frappe.bold(company)
+ )
+ )
+
+
@frappe.whitelist()
def create_transaction_deletion_request(company):
+ is_deletion_job_running(company)
+ job_id = generate_id_for_deletion_job(company)
+
tdr = frappe.get_doc({"doctype": "Transaction Deletion Record", "company": company})
tdr.insert()
- tdr.submit()
+
+ frappe.enqueue(
+ "frappe.utils.background_jobs.run_doc_method",
+ doctype=tdr.doctype,
+ name=tdr.name,
+ doc_method="submit",
+ job_id=job_id,
+ queue="long",
+ enqueue_after_commit=True,
+ )
+ frappe.msgprint(_("A Transaction Deletion Job is triggered for {0}").format(frappe.bold(company)))
diff --git a/erpnext/setup/doctype/employee/employee.json b/erpnext/setup/doctype/employee/employee.json
index daf2df5..fc1fc9b 100644
--- a/erpnext/setup/doctype/employee/employee.json
+++ b/erpnext/setup/doctype/employee/employee.json
@@ -441,13 +441,13 @@
{
"fieldname": "prefered_contact_email",
"fieldtype": "Select",
- "label": "Prefered Contact Email",
+ "label": "Preferred Contact Email",
"options": "\nCompany Email\nPersonal Email\nUser ID"
},
{
"fieldname": "prefered_email",
"fieldtype": "Data",
- "label": "Prefered Email",
+ "label": "Preferred Email",
"options": "Email",
"read_only": 1
},
@@ -524,7 +524,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Up To"
},
{
"fieldname": "place_of_issue",
@@ -824,7 +824,7 @@
"image_field": "image",
"is_tree": 1,
"links": [],
- "modified": "2024-01-03 17:36:20.984421",
+ "modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Setup",
"name": "Employee",
diff --git a/erpnext/setup/doctype/item_group/item_group.json b/erpnext/setup/doctype/item_group/item_group.json
index dfa5a8e..7c9233f 100644
--- a/erpnext/setup/doctype/item_group/item_group.json
+++ b/erpnext/setup/doctype/item_group/item_group.json
@@ -4,7 +4,7 @@
"allow_rename": 1,
"autoname": "field:item_group_name",
"creation": "2013-03-28 10:35:29",
- "description": "Item Classification",
+ "description": "An Item Group is a way to classify items based on types.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -135,7 +135,7 @@
"is_tree": 1,
"links": [],
"max_attachments": 3,
- "modified": "2023-10-12 13:44:13.611287",
+ "modified": "2024-01-30 14:08:38.485616",
"modified_by": "Administrator",
"module": "Setup",
"name": "Item Group",
diff --git a/erpnext/setup/doctype/sales_person/sales_person.json b/erpnext/setup/doctype/sales_person/sales_person.json
index e526ac4..79bd841 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.json
+++ b/erpnext/setup/doctype/sales_person/sales_person.json
@@ -4,7 +4,7 @@
"allow_rename": 1,
"autoname": "field:sales_person_name",
"creation": "2013-01-10 16:34:24",
- "description": "All Sales Transactions can be tagged against multiple **Sales Persons** so that you can set and monitor targets.",
+ "description": "All Sales Transactions can be tagged against multiple Sales Persons so that you can set and monitor targets.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -145,10 +145,11 @@
"idx": 1,
"is_tree": 1,
"links": [],
- "modified": "2020-03-18 18:11:13.968024",
+ "modified": "2024-01-30 13:57:26.436991",
"modified_by": "Administrator",
"module": "Setup",
"name": "Sales Person",
+ "naming_rule": "By fieldname",
"nsm_parent_field": "parent_sales_person",
"owner": "Administrator",
"permissions": [
@@ -181,5 +182,6 @@
"search_fields": "parent_sales_person",
"show_name_in_global_search": 1,
"sort_field": "modified",
- "sort_order": "ASC"
+ "sort_order": "ASC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
index f884864..76e52ae 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
@@ -4,7 +4,7 @@
"allow_rename": 1,
"autoname": "field:title",
"creation": "2013-01-10 16:34:24",
- "description": "Standard Terms and Conditions that can be added to Sales and Purchases.\n\nExamples:\n\n1. Validity of the offer.\n1. Payment Terms (In Advance, On Credit, part advance etc).\n1. What is extra (or payable by the Customer).\n1. Safety / usage warning.\n1. Warranty if any.\n1. Returns Policy.\n1. Terms of shipping, if applicable.\n1. Ways of addressing disputes, indemnity, liability, etc.\n1. Address and Contact of your Company.",
+ "description": "Standard Terms and Conditions that can be added to Sales and Purchases. Examples: Validity of the offer, Payment Terms, Safety and Usage, etc.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -77,7 +77,7 @@
"icon": "icon-legal",
"idx": 1,
"links": [],
- "modified": "2023-02-01 14:33:39.246532",
+ "modified": "2024-01-30 12:47:52.325531",
"modified_by": "Administrator",
"module": "Setup",
"name": "Terms and Conditions",
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
index 319d435..844e786 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -4,9 +4,10 @@
import unittest
import frappe
+from frappe.tests.utils import FrappeTestCase
-class TestTransactionDeletionRecord(unittest.TestCase):
+class TestTransactionDeletionRecord(FrappeTestCase):
def setUp(self):
create_company("Dunder Mifflin Paper Co")
@@ -14,7 +15,7 @@
frappe.db.rollback()
def test_doctypes_contain_company_field(self):
- tdr = create_transaction_deletion_request("Dunder Mifflin Paper Co")
+ tdr = create_transaction_deletion_doc("Dunder Mifflin Paper Co")
for doctype in tdr.doctypes:
contains_company = False
doctype_fields = frappe.get_meta(doctype.doctype_name).as_dict()["fields"]
@@ -27,17 +28,27 @@
def test_no_of_docs_is_correct(self):
for i in range(5):
create_task("Dunder Mifflin Paper Co")
- tdr = create_transaction_deletion_request("Dunder Mifflin Paper Co")
+ tdr = create_transaction_deletion_doc("Dunder Mifflin Paper Co")
for doctype in tdr.doctypes:
if doctype.doctype_name == "Task":
self.assertEqual(doctype.no_of_docs, 5)
def test_deletion_is_successful(self):
create_task("Dunder Mifflin Paper Co")
- create_transaction_deletion_request("Dunder Mifflin Paper Co")
+ create_transaction_deletion_doc("Dunder Mifflin Paper Co")
tasks_containing_company = frappe.get_all("Task", filters={"company": "Dunder Mifflin Paper Co"})
self.assertEqual(tasks_containing_company, [])
+ def test_company_transaction_deletion_request(self):
+ from erpnext.setup.doctype.company.company import create_transaction_deletion_request
+
+ # don't reuse below company for other test cases
+ company = "Deep Space Exploration"
+ create_company(company)
+
+ # below call should not raise any exceptions or throw errors
+ create_transaction_deletion_request(company)
+
def create_company(company_name):
company = frappe.get_doc(
@@ -46,7 +57,7 @@
company.insert(ignore_if_duplicate=True)
-def create_transaction_deletion_request(company):
+def create_transaction_deletion_doc(company):
tdr = frappe.get_doc({"doctype": "Transaction Deletion Record", "company": company})
tdr.insert()
tdr.submit()
diff --git a/erpnext/stock/doctype/batch/batch.js b/erpnext/stock/doctype/batch/batch.js
index 7bf7a1f..f4a935a 100644
--- a/erpnext/stock/doctype/batch/batch.js
+++ b/erpnext/stock/doctype/batch/batch.js
@@ -52,7 +52,7 @@
// sort by qty
r.message.sort(function(a, b) { a.qty > b.qty ? 1 : -1 });
- var rows = $('<div></div>').appendTo(section);
+ const rows = $('<div></div>').appendTo(section);
// show
(r.message || []).forEach(function(d) {
@@ -76,7 +76,7 @@
// move - ask for target warehouse and make stock entry
rows.find('.btn-move').on('click', function() {
- var $btn = $(this);
+ const $btn = $(this);
const fields = [
{
fieldname: 'to_warehouse',
@@ -115,7 +115,7 @@
// split - ask for new qty and batch ID (optional)
// and make stock entry via batch.batch_split
rows.find('.btn-split').on('click', function() {
- var $btn = $(this);
+ const $btn = $(this);
frappe.prompt([{
fieldname: 'qty',
label: __('New Batch Qty'),
@@ -128,19 +128,16 @@
fieldtype: 'Data',
}],
(data) => {
- frappe.call({
- method: 'erpnext.stock.doctype.batch.batch.split_batch',
- args: {
+ frappe.xcall(
+ 'erpnext.stock.doctype.batch.batch.split_batch',
+ {
item_code: frm.doc.item,
batch_no: frm.doc.name,
qty: data.qty,
warehouse: $btn.attr('data-warehouse'),
new_batch_id: data.new_batch_id
- },
- callback: (r) => {
- frm.refresh();
- },
- });
+ }
+ ).then(() => frm.reload_doc());
},
__('Split Batch'),
__('Split')
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 7b23f9e..e8e94fd 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -9,7 +9,7 @@
from frappe.model.document import Document
from frappe.model.naming import make_autoname, revert_series_if_last
from frappe.query_builder.functions import CurDate, Sum
-from frappe.utils import cint, flt, get_link_to_form, nowtime, today
+from frappe.utils import cint, flt, get_link_to_form
from frappe.utils.data import add_days
from frappe.utils.jinja import render_template
@@ -248,8 +248,9 @@
@frappe.whitelist()
-def split_batch(batch_no, item_code, warehouse, qty, new_batch_id=None):
-
+def split_batch(
+ batch_no: str, item_code: str, warehouse: str, qty: float, new_batch_id: str | None = None
+):
"""Split the batch into a new batch"""
batch = frappe.get_doc(dict(doctype="Batch", item=item_code, batch_id=new_batch_id)).insert()
qty = flt(qty)
@@ -257,29 +258,21 @@
company = frappe.db.get_value("Warehouse", warehouse, "company")
from_bundle_id = make_batch_bundle(
- frappe._dict(
- {
- "item_code": item_code,
- "warehouse": warehouse,
- "batches": frappe._dict({batch_no: qty}),
- "company": company,
- "type_of_transaction": "Outward",
- "qty": qty,
- }
- )
+ item_code=item_code,
+ warehouse=warehouse,
+ batches=frappe._dict({batch_no: qty}),
+ company=company,
+ type_of_transaction="Outward",
+ qty=qty,
)
to_bundle_id = make_batch_bundle(
- frappe._dict(
- {
- "item_code": item_code,
- "warehouse": warehouse,
- "batches": frappe._dict({batch.name: qty}),
- "company": company,
- "type_of_transaction": "Inward",
- "qty": qty,
- }
- )
+ item_code=item_code,
+ warehouse=warehouse,
+ batches=frappe._dict({batch.name: qty}),
+ company=company,
+ type_of_transaction="Inward",
+ qty=qty,
)
stock_entry = frappe.get_doc(
@@ -304,21 +297,30 @@
return batch.name
-def make_batch_bundle(kwargs):
+def make_batch_bundle(
+ item_code: str,
+ warehouse: str,
+ batches: dict[str, float],
+ company: str,
+ type_of_transaction: str,
+ qty: float,
+):
+ from frappe.utils import nowtime, today
+
from erpnext.stock.serial_batch_bundle import SerialBatchCreation
return (
SerialBatchCreation(
{
- "item_code": kwargs.item_code,
- "warehouse": kwargs.warehouse,
+ "item_code": item_code,
+ "warehouse": warehouse,
"posting_date": today(),
"posting_time": nowtime(),
"voucher_type": "Stock Entry",
- "qty": flt(kwargs.qty),
- "type_of_transaction": kwargs.type_of_transaction,
- "company": kwargs.company,
- "batches": kwargs.batches,
+ "qty": qty,
+ "type_of_transaction": type_of_transaction,
+ "company": company,
+ "batches": batches,
"do_not_submit": True,
}
)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index ec68549..14aedca 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -31,15 +31,6 @@
});
erpnext.queries.setup_warehouse_query(frm);
- frm.set_query('project', function(doc) {
- return {
- query: "erpnext.controllers.queries.get_project_name",
- filters: {
- 'customer': doc.customer
- }
- }
- })
-
frm.set_query('transporter', function() {
return {
filters: {
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 7d7b0cd..4eacbc1 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -398,6 +398,8 @@
self.check_credit_limit()
elif self.issue_credit_note:
self.make_return_invoice()
+
+ self.make_bundle_using_old_serial_batch_fields()
# Updating stock ledger should always be called after updating prevdoc status,
# because updating reserved qty in bin depends upon updated delivered qty in SO
self.update_stock_ledger()
@@ -796,36 +798,36 @@
updated_dn = []
for dnd in dn_details:
- billed_amt_agianst_dn = 0
+ billed_amt_against_dn = 0
# If delivered against Sales Invoice
if dnd.si_detail:
- billed_amt_agianst_dn = flt(dnd.amount)
- billed_against_so -= billed_amt_agianst_dn
+ billed_amt_against_dn = flt(dnd.amount)
+ billed_against_so -= billed_amt_against_dn
else:
# Get billed amount directly against Delivery Note
- billed_amt_agianst_dn = frappe.db.sql(
+ billed_amt_against_dn = frappe.db.sql(
"""select sum(amount) from `tabSales Invoice Item`
where dn_detail=%s and docstatus=1""",
dnd.name,
)
- billed_amt_agianst_dn = billed_amt_agianst_dn and billed_amt_agianst_dn[0][0] or 0
+ billed_amt_against_dn = billed_amt_against_dn and billed_amt_against_dn[0][0] or 0
# Distribute billed amount directly against SO between DNs based on FIFO
- if billed_against_so and billed_amt_agianst_dn < dnd.amount:
- pending_to_bill = flt(dnd.amount) - billed_amt_agianst_dn
+ if billed_against_so and billed_amt_against_dn < dnd.amount:
+ pending_to_bill = flt(dnd.amount) - billed_amt_against_dn
if pending_to_bill <= billed_against_so:
- billed_amt_agianst_dn += pending_to_bill
+ billed_amt_against_dn += pending_to_bill
billed_against_so -= pending_to_bill
else:
- billed_amt_agianst_dn += billed_against_so
+ billed_amt_against_dn += billed_against_so
billed_against_so = 0
frappe.db.set_value(
"Delivery Note Item",
dnd.name,
"billed_amt",
- billed_amt_agianst_dn,
+ billed_amt_against_dn,
update_modified=update_modified,
)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
index d4a574d..2440701 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_dashboard.py
@@ -8,6 +8,7 @@
"Stock Entry": "delivery_note_no",
"Quality Inspection": "reference_name",
"Auto Repeat": "reference_document",
+ "Purchase Receipt": "inter_company_reference",
},
"internal_links": {
"Sales Order": ["items", "against_sales_order"],
@@ -22,6 +23,9 @@
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
{"label": _("Returns"), "items": ["Stock Entry"]},
{"label": _("Subscription"), "items": ["Auto Repeat"]},
- {"label": _("Internal Transfer"), "items": ["Material Request", "Purchase Order"]},
+ {
+ "label": _("Internal Transfer"),
+ "items": ["Material Request", "Purchase Order", "Purchase Receipt"],
+ },
],
}
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 3fdda2c..459e7e7 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -200,7 +200,6 @@
},
)
- frappe.flags.ignore_serial_batch_bundle_validation = True
serial_nos = [
"OSN-1",
"OSN-2",
@@ -239,6 +238,8 @@
)
se_doc.items[0].serial_no = "\n".join(serial_nos)
+
+ frappe.flags.use_serial_and_batch_fields = True
se_doc.submit()
self.assertEqual(sorted(get_serial_nos(se_doc.items[0].serial_no)), sorted(serial_nos))
@@ -294,6 +295,8 @@
self.assertTrue(serial_no in serial_nos)
self.assertFalse(serial_no in returned_serial_nos1)
+ frappe.flags.use_serial_and_batch_fields = False
+
def test_sales_return_for_non_bundled_items_partial(self):
company = frappe.db.get_value("Warehouse", "Stores - TCP1", "company")
@@ -1563,7 +1566,7 @@
dn.return_against = args.return_against
bundle_id = None
- if args.get("batch_no") or args.get("serial_no"):
+ if not args.use_serial_batch_fields and (args.get("batch_no") or args.get("serial_no")):
type_of_transaction = args.type_of_transaction or "Outward"
if dn.is_return:
@@ -1597,14 +1600,17 @@
{
"item_code": args.item or args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
- "qty": args.qty if args.get("qty") is not None else 1,
- "rate": args.rate if args.get("rate") is not None else 100,
+ "qty": args.get("qty", 1),
+ "rate": args.get("rate", 100),
"conversion_factor": 1.0,
"serial_and_batch_bundle": bundle_id,
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1,
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"target_warehouse": args.target_warehouse,
+ "use_serial_batch_fields": args.use_serial_batch_fields,
+ "serial_no": args.serial_no if args.use_serial_batch_fields else None,
+ "batch_no": args.batch_no if args.use_serial_batch_fields else None,
},
)
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index a44b9ac..247672f 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -80,8 +80,11 @@
"section_break_40",
"pick_serial_and_batch",
"serial_and_batch_bundle",
+ "use_serial_batch_fields",
"column_break_eaoe",
+ "section_break_qyjv",
"serial_no",
+ "column_break_rxvc",
"batch_no",
"available_qty_section",
"actual_batch_qty",
@@ -850,6 +853,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -859,6 +863,7 @@
"search_index": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "pick_serial_and_batch",
"fieldtype": "Button",
"label": "Pick Serial / Batch No"
@@ -874,27 +879,40 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Text",
- "hidden": 1,
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
- "hidden": 1,
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_qyjv",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_rxvc",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-14 18:37:38.638144",
+ "modified": "2024-02-04 14:10:31.750340",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
index c11c410..b76f742 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py
@@ -82,6 +82,7 @@
target_warehouse: DF.Link | None
total_weight: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
weight_per_unit: DF.Float
weight_uom: DF.Link | None
diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json
index f4d9bb0..707f346 100644
--- a/erpnext/stock/doctype/item_price/item_price.json
+++ b/erpnext/stock/doctype/item_price/item_price.json
@@ -3,7 +3,7 @@
"allow_import": 1,
"autoname": "hash",
"creation": "2013-05-02 16:29:48",
- "description": "Multiple Item prices.",
+ "description": "Log the selling and buying rate of an Item",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
@@ -191,7 +191,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
- "label": "Valid Upto"
+ "label": "Valid Up To"
},
{
"fieldname": "section_break_24",
@@ -220,7 +220,7 @@
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2022-11-15 08:26:04.041861",
+ "modified": "2024-01-30 14:02:19.304854",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Price",
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index 89a130a..de2add6 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -59,7 +59,7 @@
def validate_dates(self):
if self.valid_from and self.valid_upto:
if getdate(self.valid_from) > getdate(self.valid_upto):
- frappe.throw(_("Valid From Date must be lesser than Valid Upto Date."))
+ frappe.throw(_("Valid From Date must be lesser than Valid Up To Date."))
def update_price_list_details(self):
if self.price_list:
diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py
index 8fd4938..63d717c 100644
--- a/erpnext/stock/doctype/item_price/test_item_price.py
+++ b/erpnext/stock/doctype/item_price/test_item_price.py
@@ -64,7 +64,7 @@
# Enter invalid dates valid_from >= valid_upto
doc.valid_from = "2017-04-20"
doc.valid_upto = "2017-04-17"
- # Valid Upto Date can not be less/equal than Valid From Date
+ # Valid Up To Date can not be less/equal than Valid From Date
self.assertRaises(frappe.ValidationError, doc.save)
def test_price_in_a_qty(self):
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index b4f7708..dec7506 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -149,6 +149,13 @@
self.get("items")[item_count - 1].applicable_charges += diff
def validate_applicable_charges_for_item(self):
+ if self.distribute_charges_based_on == "Distribute Manually" and len(self.taxes) > 1:
+ frappe.throw(
+ _(
+ "Please keep one Applicable Charges, when 'Distribute Charges Based On' is 'Distribute Manually'. For more charges, please create another Landed Cost Voucher."
+ )
+ )
+
based_on = self.distribute_charges_based_on.lower()
if based_on != "distribute manually":
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index d90b71a..e80218a 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -429,6 +429,9 @@
rate: function(frm, doctype, name) {
const item = locals[doctype][name];
+ item.amount = flt(item.qty) * flt(item.rate);
+ frappe.model.set_value(doctype, name, "amount", item.amount);
+ refresh_field("amount", item.name, item.parentfield);
frm.events.get_item_data(frm, item, false);
},
@@ -514,6 +517,13 @@
schedule_date() {
set_schedule_date(this.frm);
}
+
+ qty(doc, cdt, cdn) {
+ var row = frappe.get_doc(cdt, cdn);
+ row.amount = flt(row.qty) * flt(row.rate);
+ frappe.model.set_value(cdt, cdn, "amount", row.amount);
+ refresh_field("amount", row.name, row.parentfield);
+ }
};
// for backward compatibility: combine new and previous states
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index ad9b34c..02fbd3d 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -462,6 +462,7 @@
postprocess,
)
+ doclist.set_onload("load_after_mapping", False)
return doclist
@@ -776,7 +777,7 @@
)
else:
msgprint(
- _("The {0} {1} created sucessfully").format(frappe.bold(_("Work Order")), work_orders_list[0])
+ _("The {0} {1} created successfully").format(frappe.bold(_("Work Order")), work_orders_list[0])
)
if errors:
diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js
index de7a3d0..c85bd71 100644
--- a/erpnext/stock/doctype/material_request/material_request_list.js
+++ b/erpnext/stock/doctype/material_request/material_request_list.js
@@ -24,7 +24,7 @@
} else if (doc.material_request_type == "Purchase") {
return [__("Ordered"), "green", "per_ordered,=,100"];
} else if (doc.material_request_type == "Material Transfer") {
- return [__("Transfered"), "green", "per_ordered,=,100"];
+ return [__("Transferred"), "green", "per_ordered,=,100"];
} else if (doc.material_request_type == "Material Issue") {
return [__("Issued"), "green", "per_ordered,=,100"];
} else if (doc.material_request_type == "Customer Provided") {
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 3e44049..48397a3 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -774,6 +774,62 @@
self.assertEqual(mr.per_ordered, 100)
self.assertEqual(existing_requested_qty, current_requested_qty)
+ def test_auto_email_users_with_company_user_permissions(self):
+ from erpnext.stock.reorder_item import get_email_list
+
+ comapnywise_users = {
+ "_Test Company": "test_auto_email_@example.com",
+ "_Test Company 1": "test_auto_email_1@example.com",
+ }
+
+ permissions = []
+
+ for company, user in comapnywise_users.items():
+ if not frappe.db.exists("User", user):
+ frappe.get_doc(
+ {
+ "doctype": "User",
+ "email": user,
+ "first_name": user,
+ "send_notifications": 0,
+ "enabled": 1,
+ "user_type": "System User",
+ "roles": [{"role": "Purchase Manager"}],
+ }
+ ).insert(ignore_permissions=True)
+
+ if not frappe.db.exists(
+ "User Permission", {"user": user, "allow": "Company", "for_value": company}
+ ):
+ perm_doc = frappe.get_doc(
+ {
+ "doctype": "User Permission",
+ "user": user,
+ "allow": "Company",
+ "for_value": company,
+ "apply_to_all_doctypes": 1,
+ }
+ ).insert(ignore_permissions=True)
+
+ permissions.append(perm_doc)
+
+ comapnywise_mr_list = frappe._dict({})
+ mr1 = make_material_request()
+ comapnywise_mr_list.setdefault(mr1.company, []).append(mr1.name)
+
+ mr2 = make_material_request(
+ company="_Test Company 1", warehouse="Stores - _TC1", cost_center="Main - _TC1"
+ )
+ comapnywise_mr_list.setdefault(mr2.company, []).append(mr2.name)
+
+ for company, mr_list in comapnywise_mr_list.items():
+ emails = get_email_list(company)
+
+ self.assertTrue(comapnywise_users[company] in emails)
+
+ for perm in permissions:
+ perm.delete()
+
def get_in_transit_warehouse(company):
if not frappe.db.exists("Warehouse Type", "Transit"):
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index 5dd8934..1daf679 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -20,9 +20,12 @@
"uom",
"section_break_9",
"pick_serial_and_batch",
- "serial_and_batch_bundle",
- "serial_no",
+ "use_serial_batch_fields",
"column_break_11",
+ "serial_and_batch_bundle",
+ "section_break_bgys",
+ "serial_no",
+ "column_break_qlha",
"batch_no",
"actual_batch_qty",
"section_break_13",
@@ -118,10 +121,10 @@
"fieldtype": "Section Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Text",
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
"fieldname": "column_break_11",
@@ -131,8 +134,7 @@
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
- "options": "Batch",
- "read_only": 1
+ "options": "Batch"
},
{
"fieldname": "section_break_13",
@@ -259,6 +261,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -267,16 +270,32 @@
"print_hide": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "pick_serial_and_batch",
"fieldtype": "Button",
"label": "Pick Serial / Batch No"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_bgys",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_qlha",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-04-28 13:16:38.460806",
+ "modified": "2024-02-04 16:30:44.263964",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index ed667c2..c115e33 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -47,6 +47,7 @@
serial_no: DF.Text | None
target_warehouse: DF.Link | None
uom: DF.Link | None
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
# end: auto-generated types
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index afd6ce8..aa0e125 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -16,7 +16,6 @@
frm.set_query('parent_warehouse', () => {
return {
filters: {
- 'is_group': 1,
'company': frm.doc.company
}
};
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 7259dc0..bd84aad 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -51,7 +51,7 @@
"description": "Items under this warehouse will be suggested",
"fieldname": "parent_warehouse",
"fieldtype": "Link",
- "label": "Parent Warehouse",
+ "label": "Warehouse",
"options": "Warehouse"
},
{
@@ -188,7 +188,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2023-01-24 10:33:43.244476",
+ "modified": "2024-02-01 16:17:44.877426",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 758448a..e2edb20 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -13,7 +13,7 @@
from frappe.query_builder import Case
from frappe.query_builder.custom import GROUP_CONCAT
from frappe.query_builder.functions import Coalesce, Locate, Replace, Sum
-from frappe.utils import cint, floor, flt
+from frappe.utils import ceil, cint, floor, flt
from frappe.utils.nestedset import get_descendants_of
from erpnext.selling.doctype.sales_order.sales_order import (
@@ -122,11 +122,42 @@
def on_submit(self):
self.validate_serial_and_batch_bundle()
+ self.make_bundle_using_old_serial_batch_fields()
self.update_status()
self.update_bundle_picked_qty()
self.update_reference_qty()
self.update_sales_order_picking_status()
+ def make_bundle_using_old_serial_batch_fields(self):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+ for row in self.locations:
+ if not row.serial_no and not row.batch_no:
+ continue
+
+ if not row.use_serial_batch_fields and (row.serial_no or row.batch_no):
+ frappe.throw(_("Please enable Use Old Serial / Batch Fields to make_bundle"))
+
+ if row.use_serial_batch_fields and (not row.serial_and_batch_bundle):
+ sn_doc = SerialBatchCreation(
+ {
+ "item_code": row.item_code,
+ "warehouse": row.warehouse,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "voucher_detail_no": row.name,
+ "qty": row.stock_qty,
+ "type_of_transaction": "Outward",
+ "company": self.company,
+ "serial_nos": get_serial_nos(row.serial_no) if row.serial_no else None,
+ "batches": frappe._dict({row.batch_no: row.stock_qty}) if row.batch_no else None,
+ "batch_no": row.batch_no,
+ }
+ ).make_serial_and_batch_bundle()
+
+ row.serial_and_batch_bundle = sn_doc.name
+ row.db_set("serial_and_batch_bundle", sn_doc.name)
+
def on_update_after_submit(self) -> None:
if self.has_reserved_stock():
msg = _(
@@ -156,6 +187,7 @@
{"is_cancelled": 1, "voucher_no": ""},
)
+ frappe.get_doc("Serial and Batch Bundle", row.serial_and_batch_bundle).cancel()
row.db_set("serial_and_batch_bundle", None)
def on_update(self):
@@ -324,7 +356,6 @@
locations_replica = self.get("locations")
# reset
- self.remove_serial_and_batch_bundle()
self.delete_key("locations")
updated_locations = frappe._dict()
for item_doc in items:
@@ -639,13 +670,19 @@
if not stock_qty:
break
+ serial_nos = None
+ if item_location.serial_nos:
+ serial_nos = "\n".join(item_location.serial_nos[0 : cint(stock_qty)])
+
locations.append(
frappe._dict(
{
"qty": qty,
"stock_qty": stock_qty,
"warehouse": item_location.warehouse,
- "serial_and_batch_bundle": item_location.serial_and_batch_bundle,
+ "serial_no": serial_nos,
+ "batch_no": item_location.batch_no,
+ "use_serial_batch_fields": 1,
}
)
)
@@ -681,7 +718,15 @@
has_serial_no = frappe.get_cached_value("Item", item_code, "has_serial_no")
has_batch_no = frappe.get_cached_value("Item", item_code, "has_batch_no")
- if has_serial_no:
+ if has_batch_no and has_serial_no:
+ locations = get_available_item_locations_for_serial_and_batched_item(
+ item_code,
+ from_warehouses,
+ required_qty,
+ company,
+ total_picked_qty,
+ )
+ elif has_serial_no:
locations = get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company, total_picked_qty
)
@@ -724,6 +769,47 @@
return locations
+def get_available_item_locations_for_serial_and_batched_item(
+ item_code,
+ from_warehouses,
+ required_qty,
+ company,
+ total_picked_qty=0,
+):
+ # Get batch nos by FIFO
+ locations = get_available_item_locations_for_batched_item(
+ item_code,
+ from_warehouses,
+ required_qty,
+ company,
+ )
+
+ if locations:
+ sn = frappe.qb.DocType("Serial No")
+ conditions = (sn.item_code == item_code) & (sn.company == company)
+
+ for location in locations:
+ location.qty = (
+ required_qty if location.qty > required_qty else location.qty
+ ) # if extra qty in batch
+
+ serial_nos = (
+ frappe.qb.from_(sn)
+ .select(sn.name)
+ .where(
+ (conditions) & (sn.batch_no == location.batch_no) & (sn.warehouse == location.warehouse)
+ )
+ .orderby(sn.creation)
+ .limit(ceil(location.qty + total_picked_qty))
+ ).run(as_dict=True)
+
+ serial_nos = [sn.name for sn in serial_nos]
+ location.serial_nos = serial_nos
+ location.qty = len(serial_nos)
+
+ return locations
+
+
def get_available_item_locations_for_serialized_item(
item_code, from_warehouses, required_qty, company, total_picked_qty=0
):
@@ -757,28 +843,16 @@
picked_qty -= 1
locations = []
+
for warehouse, serial_nos in warehouse_serial_nos_map.items():
qty = len(serial_nos)
- bundle_doc = SerialBatchCreation(
- {
- "item_code": item_code,
- "warehouse": warehouse,
- "voucher_type": "Pick List",
- "total_qty": qty * -1,
- "serial_nos": serial_nos,
- "type_of_transaction": "Outward",
- "company": company,
- "do_not_submit": True,
- }
- ).make_serial_and_batch_bundle()
-
locations.append(
{
"qty": qty,
"warehouse": warehouse,
"item_code": item_code,
- "serial_and_batch_bundle": bundle_doc.name,
+ "serial_nos": serial_nos,
}
)
@@ -808,29 +882,17 @@
warehouse_wise_batches[d.warehouse][d.batch_no] += d.qty
for warehouse, batches in warehouse_wise_batches.items():
- qty = sum(batches.values())
-
- bundle_doc = SerialBatchCreation(
- {
- "item_code": item_code,
- "warehouse": warehouse,
- "voucher_type": "Pick List",
- "total_qty": qty * -1,
- "batches": batches,
- "type_of_transaction": "Outward",
- "company": company,
- "do_not_submit": True,
- }
- ).make_serial_and_batch_bundle()
-
- locations.append(
- {
- "qty": qty,
- "warehouse": warehouse,
- "item_code": item_code,
- "serial_and_batch_bundle": bundle_doc.name,
- }
- )
+ for batch_no, qty in batches.items():
+ locations.append(
+ frappe._dict(
+ {
+ "qty": qty,
+ "warehouse": warehouse,
+ "item_code": item_code,
+ "batch_no": batch_no,
+ }
+ )
+ )
return locations
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index 322b0b4..cffd0d2 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -217,6 +217,8 @@
)
pick_list.save()
+ pick_list.submit()
+
self.assertEqual(pick_list.locations[0].item_code, "_Test Serialized Item")
self.assertEqual(pick_list.locations[0].warehouse, "_Test Warehouse - _TC")
self.assertEqual(pick_list.locations[0].qty, 5)
@@ -239,7 +241,7 @@
pr1 = make_purchase_receipt(item_code="Batched Item", qty=1, rate=100.0)
pr1.load_from_db()
- oldest_batch_no = pr1.items[0].batch_no
+ oldest_batch_no = get_batch_from_bundle(pr1.items[0].serial_and_batch_bundle)
pr2 = make_purchase_receipt(item_code="Batched Item", qty=2, rate=100.0)
@@ -302,6 +304,8 @@
}
)
pick_list.set_item_locations()
+ pick_list.submit()
+ pick_list.reload()
self.assertEqual(
get_batch_from_bundle(pick_list.locations[0].serial_and_batch_bundle), oldest_batch_no
@@ -310,6 +314,7 @@
get_serial_nos_from_bundle(pick_list.locations[0].serial_and_batch_bundle), oldest_serial_nos
)
+ pick_list.cancel()
pr1.cancel()
pr2.cancel()
@@ -671,29 +676,22 @@
so = make_sales_order(item_code=item, qty=25.0, rate=100)
pl = create_pick_list(so.name)
+ pl.submit()
# pick half the qty
for loc in pl.locations:
self.assertEqual(loc.qty, 25.0)
self.assertTrue(loc.serial_and_batch_bundle)
- data = frappe.get_all(
- "Serial and Batch Entry",
- fields=["qty", "batch_no"],
- filters={"parent": loc.serial_and_batch_bundle},
- )
-
- for d in data:
- self.assertEqual(d.batch_no, "PICKLT-000001")
- self.assertEqual(d.qty, 25.0 * -1)
-
pl.save()
pl.submit()
so1 = make_sales_order(item_code=item, qty=10.0, rate=100)
- pl = create_pick_list(so1.name)
+ pl1 = create_pick_list(so1.name)
+ pl1.submit()
+
# pick half the qty
- for loc in pl.locations:
- self.assertEqual(loc.qty, 10.0)
+ for loc in pl1.locations:
+ self.assertEqual(loc.qty, 5.0)
self.assertTrue(loc.serial_and_batch_bundle)
data = frappe.get_all(
@@ -709,8 +707,7 @@
elif d.batch_no == "PICKLT-000002":
self.assertEqual(d.qty, 5.0 * -1)
- pl.save()
- pl.submit()
+ pl1.cancel()
pl.cancel()
def test_picklist_for_serial_item(self):
@@ -723,6 +720,7 @@
so = make_sales_order(item_code=item, qty=25.0, rate=100)
pl = create_pick_list(so.name)
+ pl.submit()
picked_serial_nos = []
# pick half the qty
for loc in pl.locations:
@@ -736,13 +734,11 @@
picked_serial_nos = [d.serial_no for d in data]
self.assertEqual(len(picked_serial_nos), 25)
- pl.save()
- pl.submit()
-
so1 = make_sales_order(item_code=item, qty=10.0, rate=100)
- pl = create_pick_list(so1.name)
+ pl1 = create_pick_list(so1.name)
+ pl1.submit()
# pick half the qty
- for loc in pl.locations:
+ for loc in pl1.locations:
self.assertEqual(loc.qty, 10.0)
self.assertTrue(loc.serial_and_batch_bundle)
@@ -756,8 +752,7 @@
for d in data:
self.assertTrue(d.serial_no not in picked_serial_nos)
- pl.save()
- pl.submit()
+ pl1.cancel()
pl.cancel()
def test_picklist_with_bundles(self):
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index e8e4afc..962fa9f 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -24,8 +24,11 @@
"serial_no_and_batch_section",
"pick_serial_and_batch",
"serial_and_batch_bundle",
- "serial_no",
+ "use_serial_batch_fields",
"column_break_20",
+ "section_break_ecxc",
+ "serial_no",
+ "column_break_belw",
"batch_no",
"column_break_15",
"sales_order",
@@ -72,19 +75,17 @@
"read_only": 1
},
{
- "depends_on": "serial_no",
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
- "depends_on": "batch_no",
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
},
{
@@ -195,6 +196,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -204,6 +206,7 @@
"search_index": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "pick_serial_and_batch",
"fieldtype": "Button",
"label": "Pick Serial / Batch No"
@@ -218,11 +221,26 @@
"print_hide": 1,
"read_only": 1,
"report_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_ecxc",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_belw",
+ "fieldtype": "Column Break"
}
],
"istable": 1,
"links": [],
- "modified": "2023-07-26 12:54:15.785962",
+ "modified": "2024-02-04 16:12:16.257951",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.py b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
index 6e5a94e..f3f6298 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.py
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.py
@@ -37,6 +37,7 @@
stock_reserved_qty: DF.Float
stock_uom: DF.Link | None
uom: DF.Link | None
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
# end: auto-generated types
diff --git a/erpnext/stock/doctype/price_list/price_list.json b/erpnext/stock/doctype/price_list/price_list.json
index 56340fb..38cd1ee 100644
--- a/erpnext/stock/doctype/price_list/price_list.json
+++ b/erpnext/stock/doctype/price_list/price_list.json
@@ -1,434 +1,134 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:price_list_name",
- "beta": 0,
"creation": "2013-01-25 11:35:09",
- "custom": 0,
- "description": "Price List Master",
- "docstatus": 0,
+ "description": "A Price List is a collection of Item Prices either Selling, Buying, or both",
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "enabled",
+ "sb_1",
+ "price_list_name",
+ "currency",
+ "buying",
+ "selling",
+ "price_not_uom_dependent",
+ "column_break_3",
+ "countries"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "1",
- "fetch_if_empty": 0,
"fieldname": "enabled",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Enabled",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Enabled"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sb_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "price_list_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Price List Name",
- "length": 0,
"no_copy": 1,
"oldfieldname": "price_list_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Currency",
- "length": 0,
- "no_copy": 0,
"options": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "buying",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Buying",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Buying"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "selling",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Selling",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Selling"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "price_not_uom_dependent",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price Not UOM Dependent",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Price Not UOM Dependent"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "countries",
"fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Applicable for Countries",
- "length": 0,
- "no_copy": 0,
- "options": "Price List Country",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Price List Country"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-tags",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
+ "links": [],
"max_attachments": 1,
- "modified": "2019-06-24 17:16:28.027302",
+ "modified": "2024-01-30 14:39:26.328837",
"modified_by": "Administrator",
"module": "Stock",
"name": "Price List",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
"report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales User"
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
- "email": 0,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
- "print": 0,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
"report": 1,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Purchase User"
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
"report": 1,
"role": "Purchase Master Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
- "report": 0,
- "role": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Manufacturing User"
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
"search_fields": "currency",
"show_name_in_global_search": 1,
+ "sort_field": "modified",
"sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index fcb7a6d..c9fe7d2 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -369,6 +369,7 @@
else:
self.db_set("status", "Completed")
+ self.make_bundle_using_old_serial_batch_fields()
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty, reserved_qty_for_subcontract in bin
# depends upon updated ordered qty in PO
@@ -951,32 +952,32 @@
billed_against_po = flt(po_billed_amt_details.get(pr_item.purchase_order_item))
# Get billed amount directly against Purchase Receipt
- billed_amt_agianst_pr = flt(pr_items_billed_amount.get(pr_item.name, 0))
+ billed_amt_against_pr = flt(pr_items_billed_amount.get(pr_item.name, 0))
# Distribute billed amount directly against PO between PRs based on FIFO
- if billed_against_po and billed_amt_agianst_pr < pr_item.amount:
- pending_to_bill = flt(pr_item.amount) - billed_amt_agianst_pr
+ if billed_against_po and billed_amt_against_pr < pr_item.amount:
+ pending_to_bill = flt(pr_item.amount) - billed_amt_against_pr
if pending_to_bill <= billed_against_po:
- billed_amt_agianst_pr += pending_to_bill
+ billed_amt_against_pr += pending_to_bill
billed_against_po -= pending_to_bill
else:
- billed_amt_agianst_pr += billed_against_po
+ billed_amt_against_pr += billed_against_po
billed_against_po = 0
po_billed_amt_details[pr_item.purchase_order_item] = billed_against_po
- if pr_item.billed_amt != billed_amt_agianst_pr:
+ if pr_item.billed_amt != billed_amt_against_pr:
# update existing doc if possible
if pr_doc and pr_item.parent == pr_doc.name:
pr_item = next((item for item in pr_doc.items if item.name == pr_item.name), None)
- pr_item.db_set("billed_amt", billed_amt_agianst_pr, update_modified=update_modified)
+ pr_item.db_set("billed_amt", billed_amt_against_pr, update_modified=update_modified)
else:
frappe.db.set_value(
"Purchase Receipt Item",
pr_item.name,
"billed_amt",
- billed_amt_agianst_pr,
+ billed_amt_against_pr,
update_modified=update_modified,
)
@@ -1360,16 +1361,16 @@
for lcv in landed_cost_vouchers:
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
+ based_on_field = None
# Use amount field for total item cost for manually cost distributed LCVs
- if landed_cost_voucher_doc.distribute_charges_based_on == "Distribute Manually":
- based_on_field = "amount"
- else:
+ if landed_cost_voucher_doc.distribute_charges_based_on != "Distribute Manually":
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
total_item_cost = 0
- for item in landed_cost_voucher_doc.items:
- total_item_cost += item.get(based_on_field)
+ if based_on_field:
+ for item in landed_cost_voucher_doc.items:
+ total_item_cost += item.get(based_on_field)
for item in landed_cost_voucher_doc.items:
if item.receipt_document == purchase_document:
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index 4029f0c..f19f1ff 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -8,8 +8,10 @@
return [__("Closed"), "green", "status,=,Closed"];
} else if (flt(doc.per_returned, 2) === 100) {
return [__("Return Issued"), "grey", "per_returned,=,100"];
- } else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) < 100) {
+ } else if (flt(doc.grand_total) !== 0 && flt(doc.per_billed, 2) == 0) {
return [__("To Bill"), "orange", "per_billed,<,100"];
+ } else if (flt(doc.per_billed, 2) > 0 && flt(doc.per_billed, 2) < 100) {
+ return [__("Partly Billed"), "yellow", "per_billed,<,100"];
} else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) === 100) {
return [__("Completed"), "green", "per_billed,=,100"];
}
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 57ba5bb..2d20922 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -21,9 +21,7 @@
get_serial_nos_from_bundle,
make_serial_batch_bundle,
)
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
class TestPurchaseReceipt(FrappeTestCase):
@@ -722,7 +720,7 @@
pr2.load_from_db()
self.assertEqual(pr2.get("items")[0].billed_amt, 2000)
self.assertEqual(pr2.per_billed, 80)
- self.assertEqual(pr2.status, "To Bill")
+ self.assertEqual(pr2.status, "Partly Billed")
pr2.cancel()
pi2.reload()
@@ -735,7 +733,6 @@
po.cancel()
def test_serial_no_against_purchase_receipt(self):
- from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
item_code = "Test Manual Created Serial No"
if not frappe.db.exists("Item", item_code):
@@ -1020,6 +1017,11 @@
def test_stock_transfer_from_purchase_receipt_with_valuation(self):
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+ )
+ from erpnext.stock.get_item_details import get_valuation_rate
+ from erpnext.stock.utils import get_stock_balance
prepare_data_for_internal_transfer()
@@ -1034,6 +1036,22 @@
company="_Test Company with perpetual inventory",
)
+ if (
+ get_valuation_rate(
+ pr1.items[0].item_code, "_Test Company with perpetual inventory", warehouse="Stores - TCP1"
+ )
+ != 50
+ ):
+ balance = get_stock_balance(item_code=pr1.items[0].item_code, warehouse="Stores - TCP1")
+ create_stock_reconciliation(
+ item_code=pr1.items[0].item_code,
+ company="_Test Company with perpetual inventory",
+ warehouse="Stores - TCP1",
+ qty=balance,
+ rate=50,
+ do_not_save=True,
+ )
+
customer = "_Test Internal Customer 2"
company = "_Test Company with perpetual inventory"
@@ -1071,7 +1089,8 @@
sl_entries = get_sl_entries("Purchase Receipt", pr.name)
expected_gle = [
- ["Stock In Hand - TCP1", 272.5, 0.0],
+ ["Stock In Hand - TCP1", 250.0, 0.0],
+ ["Cost of Goods Sold - TCP1", 22.5, 0.0],
["_Test Account Stock In Hand - TCP1", 0.0, 250.0],
["_Test Account Shipping Charges - TCP1", 0.0, 22.5],
]
@@ -1133,7 +1152,7 @@
pi.load_from_db()
pr.load_from_db()
- self.assertEqual(pr.status, "To Bill")
+ self.assertEqual(pr.status, "Partly Billed")
self.assertAlmostEqual(pr.per_billed, 50.0, places=2)
def test_purchase_receipt_with_exchange_rate_difference(self):
@@ -1656,9 +1675,10 @@
make_stock_entry(
purpose="Material Receipt",
item_code=item.name,
- qty=15,
+ qty=20,
company=company,
to_warehouse=from_warehouse,
+ posting_date=add_days(today(), -3),
)
# Step 3: Create Delivery Note with Internal Customer
@@ -1681,13 +1701,15 @@
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
pr = make_inter_company_purchase_receipt(dn.name)
+ pr.set_posting_time = 1
+ pr.posting_date = today()
pr.items[0].qty = 15
pr.items[0].from_warehouse = target_warehouse
pr.items[0].warehouse = to_warehouse
pr.items[0].rejected_warehouse = from_warehouse
pr.save()
- self.assertRaises(OverAllowanceError, pr.submit)
+ self.assertRaises(frappe.ValidationError, pr.submit)
# Step 5: Test Over Receipt Allowance
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 50)
@@ -1699,8 +1721,10 @@
company=company,
from_warehouse=from_warehouse,
to_warehouse=target_warehouse,
+ posting_date=add_days(pr.posting_date, -1),
)
+ pr.reload()
pr.submit()
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 0)
@@ -2206,6 +2230,93 @@
pr_doc.reload()
self.assertFalse(pr_doc.items[0].from_warehouse)
+ def test_use_serial_batch_fields_for_serial_nos(self):
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+ create_stock_reconciliation,
+ )
+
+ item_code = make_item(
+ "_Test Use Serial Fields Item Serial Item",
+ properties={"has_serial_no": 1, "serial_no_series": "SNU-TSFISI-.#####"},
+ ).name
+
+ serial_nos = [
+ "SNU-TSFISI-000011",
+ "SNU-TSFISI-000012",
+ "SNU-TSFISI-000013",
+ "SNU-TSFISI-000014",
+ "SNU-TSFISI-000015",
+ ]
+
+ pr = make_purchase_receipt(
+ item_code=item_code,
+ qty=5,
+ serial_no="\n".join(serial_nos),
+ use_serial_batch_fields=1,
+ rate=100,
+ )
+
+ self.assertEqual(pr.items[0].use_serial_batch_fields, 1)
+ self.assertFalse(pr.items[0].serial_no)
+ self.assertTrue(pr.items[0].serial_and_batch_bundle)
+
+ sbb_doc = frappe.get_doc("Serial and Batch Bundle", pr.items[0].serial_and_batch_bundle)
+
+ for row in sbb_doc.entries:
+ self.assertTrue(row.serial_no in serial_nos)
+
+ serial_nos.remove("SNU-TSFISI-000015")
+
+ sr = create_stock_reconciliation(
+ item_code=item_code,
+ serial_no="\n".join(serial_nos),
+ qty=4,
+ warehouse=pr.items[0].warehouse,
+ use_serial_batch_fields=1,
+ do_not_submit=True,
+ )
+ sr.reload()
+
+ serial_nos = get_serial_nos(sr.items[0].current_serial_no)
+ self.assertEqual(len(serial_nos), 5)
+ self.assertEqual(sr.items[0].current_qty, 5)
+
+ new_serial_nos = get_serial_nos(sr.items[0].serial_no)
+ self.assertEqual(len(new_serial_nos), 4)
+ self.assertEqual(sr.items[0].qty, 4)
+ self.assertEqual(sr.items[0].use_serial_batch_fields, 1)
+ self.assertFalse(sr.items[0].current_serial_and_batch_bundle)
+ self.assertFalse(sr.items[0].serial_and_batch_bundle)
+ self.assertTrue(sr.items[0].current_serial_no)
+ sr.submit()
+
+ sr.reload()
+ self.assertTrue(sr.items[0].current_serial_and_batch_bundle)
+ self.assertTrue(sr.items[0].serial_and_batch_bundle)
+
+ serial_no_status = frappe.db.get_value("Serial No", "SNU-TSFISI-000015", "status")
+
+ self.assertTrue(serial_no_status != "Active")
+
+ dn = create_delivery_note(
+ item_code=item_code,
+ qty=4,
+ serial_no="\n".join(new_serial_nos),
+ use_serial_batch_fields=1,
+ )
+
+ self.assertTrue(dn.items[0].serial_and_batch_bundle)
+ self.assertEqual(dn.items[0].qty, 4)
+ doc = frappe.get_doc("Serial and Batch Bundle", dn.items[0].serial_and_batch_bundle)
+ for row in doc.entries:
+ self.assertTrue(row.serial_no in new_serial_nos)
+
+ for sn in new_serial_nos:
+ serial_no_status = frappe.db.get_value("Serial No", sn, "status")
+ self.assertTrue(serial_no_status != "Active")
+
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
@@ -2375,7 +2486,7 @@
uom = args.uom or frappe.db.get_value("Item", item_code, "stock_uom") or "_Test UOM"
bundle_id = None
- if args.get("batch_no") or args.get("serial_no"):
+ if not args.use_serial_batch_fields and (args.get("batch_no") or args.get("serial_no")):
batches = {}
if args.get("batch_no"):
batches = frappe._dict({args.batch_no: qty})
@@ -2417,6 +2528,9 @@
"cost_center": args.cost_center
or frappe.get_cached_value("Company", pr.company, "cost_center"),
"asset_location": args.location or "Test Location",
+ "use_serial_batch_fields": args.use_serial_batch_fields or 0,
+ "serial_no": args.serial_no if args.use_serial_batch_fields else "",
+ "batch_no": args.batch_no if args.use_serial_batch_fields else "",
},
)
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 9bd692a..6b01047 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -94,6 +94,7 @@
"section_break_45",
"add_serial_batch_bundle",
"serial_and_batch_bundle",
+ "use_serial_batch_fields",
"col_break5",
"add_serial_batch_for_rejected_qty",
"rejected_serial_and_batch_bundle",
@@ -1003,6 +1004,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -1020,24 +1022,22 @@
{
"fieldname": "serial_no",
"fieldtype": "Text",
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
"fieldname": "rejected_serial_no",
"fieldtype": "Text",
- "label": "Rejected Serial No",
- "read_only": 1
+ "label": "Rejected Serial No"
},
{
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "rejected_serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Rejected Serial and Batch Bundle",
@@ -1045,11 +1045,13 @@
"options": "Serial and Batch Bundle"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0",
"fieldname": "add_serial_batch_for_rejected_qty",
"fieldtype": "Button",
"label": "Add Serial / Batch No (Rejected Qty)"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "section_break_3vxt",
"fieldtype": "Section Break"
},
@@ -1058,6 +1060,7 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0",
"fieldname": "add_serial_batch_bundle",
"fieldtype": "Button",
"label": "Add Serial / Batch No"
@@ -1098,12 +1101,18 @@
"read_only": 1,
"report_hide": 1,
"search_index": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-12-25 22:32:09.801965",
+ "modified": "2024-02-04 11:48:06.653771",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
index aed8d21..3c6dcdc 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py
@@ -99,6 +99,7 @@
supplier_part_no: DF.Data | None
total_weight: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency
warehouse: DF.Link | None
weight_per_unit: DF.Float
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
index 9f01ee9..91b7430 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.js
@@ -74,7 +74,7 @@
let fields = [
{
- "label": __("Using CSV File"),
+ "label": __("Import Using CSV file"),
"fieldname": "using_csv_file",
"default": 1,
"fieldtype": "Check",
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index 2b87fcd..eb4df29 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -250,6 +250,7 @@
for d in self.entries:
available_qty = 0
+
if self.has_serial_no:
d.incoming_rate = abs(sn_obj.serial_no_incoming_rate.get(d.serial_no, 0.0))
else:
@@ -892,6 +893,13 @@
elif batch_nos:
self.set("entries", batch_nos)
+ def delete_serial_batch_entries(self):
+ SBBE = frappe.qb.DocType("Serial and Batch Entry")
+
+ frappe.qb.from_(SBBE).delete().where(SBBE.parent == self.name).run()
+
+ self.set("entries", [])
+
@frappe.whitelist()
def download_blank_csv_template(content):
@@ -999,9 +1007,25 @@
make_serial_nos(item_code, serial_nos)
+ if kwargs.get("_has_serial_nos"):
+ return serial_nos
+
return serial_nos, batch_nos
+@frappe.whitelist()
+def create_serial_nos(item_code, serial_nos):
+ serial_nos = get_serial_batch_from_data(
+ item_code,
+ {
+ "serial_nos": serial_nos,
+ "_has_serial_nos": True,
+ },
+ )
+
+ return serial_nos
+
+
def make_serial_nos(item_code, serial_nos):
item = frappe.get_cached_value("Item", item_code, ["description", "item_code"], as_dict=1)
@@ -1093,7 +1117,7 @@
if isinstance(data, list):
return data
- return [s.strip() for s in cstr(data).strip().upper().replace(",", "\n").split("\n") if s.strip()]
+ return [s.strip() for s in cstr(data).strip().replace(",", "\n").split("\n") if s.strip()]
@frappe.whitelist()
@@ -1232,7 +1256,7 @@
def get_type_of_transaction(parent_doc, child_row):
- type_of_transaction = child_row.type_of_transaction
+ type_of_transaction = child_row.get("type_of_transaction")
if parent_doc.get("doctype") == "Stock Entry":
type_of_transaction = "Outward" if child_row.s_warehouse else "Inward"
@@ -1358,10 +1382,14 @@
elif kwargs.based_on == "Expiry":
order_by = "amc_expiry_date asc"
- filters = {"item_code": kwargs.item_code, "warehouse": ("is", "set")}
+ filters = {"item_code": kwargs.item_code}
- if kwargs.warehouse:
- filters["warehouse"] = kwargs.warehouse
+ # ignore_warehouse is used for backdated stock transactions
+ # There might be chances that the serial no not exists in the warehouse during backdated stock transactions
+ if not kwargs.get("ignore_warehouse"):
+ filters["warehouse"] = ("is", "set")
+ if kwargs.warehouse:
+ filters["warehouse"] = kwargs.warehouse
# Since SLEs are not present against Reserved Stock [POS invoices, SRE], need to ignore reserved serial nos.
ignore_serial_nos = get_reserved_serial_nos(kwargs)
@@ -1651,7 +1679,10 @@
query = query.where(sb_entry.batch_no == kwargs.batch_no)
if kwargs.warehouse:
- query = query.where(sre.warehouse == kwargs.warehouse)
+ if isinstance(kwargs.warehouse, list):
+ query = query.where(sre.warehouse.isin(kwargs.warehouse))
+ else:
+ query = query.where(sre.warehouse == kwargs.warehouse)
if kwargs.ignore_voucher_nos:
query = query.where(sre.name.notin(kwargs.ignore_voucher_nos))
@@ -2080,5 +2111,34 @@
@frappe.whitelist()
+def is_serial_batch_no_exists(item_code, type_of_transaction, serial_no=None, batch_no=None):
+ if serial_no and not frappe.db.exists("Serial No", serial_no):
+ if type_of_transaction != "Inward":
+ frappe.throw(_("Serial No {0} does not exists").format(serial_no))
+
+ make_serial_no(serial_no, item_code)
+
+ if batch_no and frappe.db.exists("Batch", batch_no):
+ if type_of_transaction != "Inward":
+ frappe.throw(_("Batch No {0} does not exists").format(batch_no))
+
+ make_batch_no(batch_no, item_code)
+
+
+def make_serial_no(serial_no, item_code):
+ serial_no_doc = frappe.new_doc("Serial No")
+ serial_no_doc.serial_no = serial_no
+ serial_no_doc.item_code = item_code
+ serial_no_doc.save(ignore_permissions=True)
+
+
+def make_batch_no(batch_no, item_code):
+ batch_doc = frappe.new_doc("Batch")
+ batch_doc.batch_id = batch_no
+ batch_doc.item = item_code
+ batch_doc.save(ignore_permissions=True)
+
+
+@frappe.whitelist()
def is_duplicate_serial_no(bundle_id, serial_no):
return frappe.db.exists("Serial and Batch Entry", {"parent": bundle_id, "serial_no": serial_no})
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
index 0d453fb..f430943 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py
@@ -136,6 +136,7 @@
def test_old_batch_valuation(self):
frappe.flags.ignore_serial_batch_bundle_validation = True
+ frappe.flags.use_serial_and_batch_fields = True
batch_item_code = "Old Batch Item Valuation 1"
make_item(
batch_item_code,
@@ -240,6 +241,7 @@
bundle_doc.submit()
frappe.flags.ignore_serial_batch_bundle_validation = False
+ frappe.flags.use_serial_and_batch_fields = False
def test_old_serial_no_valuation(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
@@ -259,6 +261,7 @@
)
frappe.flags.ignore_serial_batch_bundle_validation = True
+ frappe.flags.use_serial_and_batch_fields = True
serial_no_id = "Old Serial No 1"
if not frappe.db.exists("Serial No", serial_no_id):
@@ -320,6 +323,9 @@
for row in bundle_doc.entries:
self.assertEqual(flt(row.stock_value_difference, 2), -100.00)
+ frappe.flags.ignore_serial_batch_bundle_validation = False
+ frappe.flags.use_serial_and_batch_fields = False
+
def test_batch_not_belong_to_serial_no(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 122664c..5f4f393 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -151,9 +151,7 @@
if isinstance(serial_no, list):
return serial_no
- return [
- s.strip() for s in cstr(serial_no).strip().upper().replace(",", "\n").split("\n") if s.strip()
- ]
+ return [s.strip() for s in cstr(serial_no).strip().replace(",", "\n").split("\n") if s.strip()]
def clean_serial_no_string(serial_no: str) -> str:
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 96c249f..10e3522 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -228,7 +228,6 @@
self.fg_completed_qty = 0.0
self.validate_serialized_batch()
- self.set_actual_qty()
self.calculate_rate_and_amount()
self.validate_putaway_capacity()
@@ -275,6 +274,7 @@
def on_submit(self):
self.validate_closed_subcontracting_order()
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
self.update_work_order()
self.validate_subcontract_order()
@@ -640,7 +640,7 @@
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
if not (d.s_warehouse or d.t_warehouse):
- frappe.throw(_("Atleast one warehouse is mandatory"))
+ frappe.throw(_("At least one warehouse is mandatory"))
def validate_work_order(self):
if self.purpose in (
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index 83bfaa0..0f67e47 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -92,6 +92,9 @@
else:
args.qty = cint(args.qty)
+ if args.serial_no or args.batch_no:
+ args.use_serial_batch_fields = True
+
# purpose
if not args.purpose:
if args.source and args.target:
@@ -162,6 +165,7 @@
)
args.serial_no = serial_number
+
s.append(
"items",
{
@@ -177,6 +181,7 @@
"batch_no": args.batch_no,
"cost_center": args.cost_center,
"expense_account": args.expense_account,
+ "use_serial_batch_fields": args.use_serial_batch_fields,
},
)
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 23dacc8..af91536 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -680,6 +680,7 @@
def test_serial_move(self):
se = make_serialized_item()
serial_no = get_serial_nos_from_bundle(se.get("items")[0].serial_and_batch_bundle)[0]
+ frappe.flags.use_serial_and_batch_fields = True
se = frappe.copy_doc(test_records[0])
se.purpose = "Material Transfer"
@@ -700,6 +701,7 @@
self.assertTrue(
frappe.db.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse - _TC"
)
+ frappe.flags.use_serial_and_batch_fields = False
def test_serial_cancel(self):
se, serial_nos = self.test_serial_by_series()
@@ -999,6 +1001,8 @@
do_not_save=True,
)
+ frappe.flags.use_serial_and_batch_fields = True
+
cls_obj = SerialBatchCreation(
{
"type_of_transaction": "Inward",
@@ -1035,84 +1039,7 @@
s2.submit()
s2.cancel()
-
- # def test_retain_sample(self):
- # from erpnext.stock.doctype.batch.batch import get_batch_qty
- # from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
-
- # create_warehouse("Test Warehouse for Sample Retention")
- # frappe.db.set_value(
- # "Stock Settings",
- # None,
- # "sample_retention_warehouse",
- # "Test Warehouse for Sample Retention - _TC",
- # )
-
- # test_item_code = "Retain Sample Item"
- # if not frappe.db.exists("Item", test_item_code):
- # item = frappe.new_doc("Item")
- # item.item_code = test_item_code
- # item.item_name = "Retain Sample Item"
- # item.description = "Retain Sample Item"
- # item.item_group = "All Item Groups"
- # item.is_stock_item = 1
- # item.has_batch_no = 1
- # item.create_new_batch = 1
- # item.retain_sample = 1
- # item.sample_quantity = 4
- # item.save()
-
- # receipt_entry = frappe.new_doc("Stock Entry")
- # receipt_entry.company = "_Test Company"
- # receipt_entry.purpose = "Material Receipt"
- # receipt_entry.append(
- # "items",
- # {
- # "item_code": test_item_code,
- # "t_warehouse": "_Test Warehouse - _TC",
- # "qty": 40,
- # "basic_rate": 12,
- # "cost_center": "_Test Cost Center - _TC",
- # "sample_quantity": 4,
- # },
- # )
- # receipt_entry.set_stock_entry_type()
- # receipt_entry.insert()
- # receipt_entry.submit()
-
- # retention_data = move_sample_to_retention_warehouse(
- # receipt_entry.company, receipt_entry.get("items")
- # )
- # retention_entry = frappe.new_doc("Stock Entry")
- # retention_entry.company = retention_data.company
- # retention_entry.purpose = retention_data.purpose
- # retention_entry.append(
- # "items",
- # {
- # "item_code": test_item_code,
- # "t_warehouse": "Test Warehouse for Sample Retention - _TC",
- # "s_warehouse": "_Test Warehouse - _TC",
- # "qty": 4,
- # "basic_rate": 12,
- # "cost_center": "_Test Cost Center - _TC",
- # "batch_no": get_batch_from_bundle(receipt_entry.get("items")[0].serial_and_batch_bundle),
- # },
- # )
- # retention_entry.set_stock_entry_type()
- # retention_entry.insert()
- # retention_entry.submit()
-
- # qty_in_usable_warehouse = get_batch_qty(
- # get_batch_from_bundle(receipt_entry.get("items")[0].serial_and_batch_bundle), "_Test Warehouse - _TC", "_Test Item"
- # )
- # qty_in_retention_warehouse = get_batch_qty(
- # get_batch_from_bundle(receipt_entry.get("items")[0].serial_and_batch_bundle),
- # "Test Warehouse for Sample Retention - _TC",
- # "_Test Item",
- # )
-
- # self.assertEqual(qty_in_usable_warehouse, 36)
- # self.assertEqual(qty_in_retention_warehouse, 4)
+ frappe.flags.use_serial_and_batch_fields = False
def test_quality_check(self):
item_code = "_Test Item For QC"
@@ -1785,6 +1712,48 @@
self.assertRaises(frappe.ValidationError, se1.cancel)
+ def test_auto_reorder_level(self):
+ from erpnext.stock.reorder_item import reorder_item
+
+ item_doc = make_item(
+ "Test Auto Reorder Item - 001",
+ properties={"stock_uom": "Kg", "purchase_uom": "Nos", "is_stock_item": 1},
+ uoms=[{"uom": "Nos", "conversion_factor": 5}],
+ )
+
+ if not frappe.db.exists("Item Reorder", {"parent": item_doc.name}):
+ item_doc.append(
+ "reorder_levels",
+ {
+ "warehouse_reorder_level": 0,
+ "warehouse_reorder_qty": 10,
+ "warehouse": "_Test Warehouse - _TC",
+ "material_request_type": "Purchase",
+ },
+ )
+
+ item_doc.save(ignore_permissions=True)
+
+ frappe.db.set_single_value("Stock Settings", "auto_indent", 1)
+
+ mr_list = reorder_item()
+
+ frappe.db.set_single_value("Stock Settings", "auto_indent", 0)
+ mrs = frappe.get_all(
+ "Material Request Item",
+ fields=["qty", "stock_uom", "stock_qty"],
+ filters={"item_code": item_doc.name, "uom": "Nos"},
+ )
+
+ for mri in mrs:
+ self.assertEqual(mri.stock_uom, "Kg")
+ self.assertEqual(mri.stock_qty, 10)
+ self.assertEqual(mri.qty, 2)
+
+ for mr in mr_list:
+ mr.cancel()
+ mr.delete()
+
def make_serialized_item(**args):
args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index bd84a2b..c7b3daa 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -47,9 +47,12 @@
"amount",
"serial_no_batch",
"add_serial_batch_bundle",
- "serial_and_batch_bundle",
+ "use_serial_batch_fields",
"col_break4",
+ "serial_and_batch_bundle",
+ "section_break_rdtg",
"serial_no",
+ "column_break_prps",
"batch_no",
"accounting",
"expense_account",
@@ -289,27 +292,27 @@
"no_copy": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"label": "Serial No",
"no_copy": 1,
"oldfieldname": "serial_no",
- "oldfieldtype": "Text",
- "read_only": 1
+ "oldfieldtype": "Text"
},
{
"fieldname": "col_break4",
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"no_copy": 1,
"oldfieldname": "batch_no",
"oldfieldtype": "Link",
- "options": "Batch",
- "read_only": 1
+ "options": "Batch"
},
{
"depends_on": "eval:parent.inspection_required && doc.t_warehouse",
@@ -573,24 +576,41 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0",
"fieldname": "add_serial_batch_bundle",
"fieldtype": "Button",
"label": "Add Serial / Batch No"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
"no_copy": 1,
"options": "Serial and Batch Bundle",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_rdtg",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_prps",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2024-01-12 11:56:04.626103",
+ "modified": "2024-02-04 16:16:47.606270",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry Detail",
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
index a6dd0fa..47c443c 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py
@@ -63,6 +63,7 @@
transfer_qty: DF.Float
transferred_qty: DF.Float
uom: DF.Link
+ use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency
# end: auto-generated types
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index d8a3f2e..c099953 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -482,6 +482,8 @@
(item, warehouses[0], batches[1], 1, 200),
(item, warehouses[0], batches[0], 1, 200),
]
+
+ frappe.flags.use_serial_and_batch_fields = True
dns = create_delivery_note_entries_for_batchwise_item_valuation_test(dn_entry_list)
sle_details = fetch_sle_details_for_doc_list(dns, ["stock_value_difference"])
svd_list = [-1 * d["stock_value_difference"] for d in sle_details]
@@ -494,6 +496,8 @@
"Incorrect 'Incoming Rate' values fetched for DN items",
)
+ frappe.flags.use_serial_and_batch_fields = False
+
def test_batchwise_item_valuation_stock_reco(self):
item, warehouses, batches = setup_item_valuation_test()
state = {"stock_value": 0.0, "qty": 0.0}
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index 8e9dcb0..ba7f9c5 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -198,6 +198,7 @@
frappe.model.set_value(cdt, cdn, "current_amount", r.message.rate * r.message.qty);
frappe.model.set_value(cdt, cdn, "amount", row.qty * row.valuation_rate);
frappe.model.set_value(cdt, cdn, "current_serial_no", r.message.serial_nos);
+ frappe.model.set_value(cdt, cdn, "use_serial_batch_fields", r.message.use_serial_batch_fields);
if (frm.doc.purpose == "Stock Reconciliation" && !frm.doc.scan_mode) {
frappe.model.set_value(cdt, cdn, "serial_no", r.message.serial_nos);
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 6819968..ce08615 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -99,6 +99,8 @@
)
def on_submit(self):
+ self.make_bundle_for_current_qty()
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
self.make_gl_entries()
self.repost_future_sle_and_gle()
@@ -116,9 +118,52 @@
self.repost_future_sle_and_gle()
self.delete_auto_created_batches()
+ def make_bundle_for_current_qty(self):
+ from erpnext.stock.serial_batch_bundle import SerialBatchCreation
+
+ for row in self.items:
+ if not row.use_serial_batch_fields:
+ continue
+
+ if row.current_serial_and_batch_bundle:
+ continue
+
+ if row.current_qty and (row.current_serial_no or row.batch_no):
+ sn_doc = SerialBatchCreation(
+ {
+ "item_code": row.item_code,
+ "warehouse": row.warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "voucher_detail_no": row.name,
+ "qty": row.qty,
+ "type_of_transaction": "Outward",
+ "company": self.company,
+ "is_rejected": 0,
+ "serial_nos": get_serial_nos(row.current_serial_no) if row.current_serial_no else None,
+ "batches": frappe._dict({row.batch_no: row.qty}) if row.batch_no else None,
+ "batch_no": row.batch_no,
+ "do_not_submit": True,
+ }
+ ).make_serial_and_batch_bundle()
+
+ row.current_serial_and_batch_bundle = sn_doc.name
+ row.db_set(
+ {
+ "current_serial_and_batch_bundle": sn_doc.name,
+ "current_serial_no": "",
+ "batch_no": "",
+ }
+ )
+
def set_current_serial_and_batch_bundle(self, voucher_detail_no=None, save=False) -> None:
"""Set Serial and Batch Bundle for each item"""
for item in self.items:
+ if not save and item.use_serial_batch_fields:
+ continue
+
if voucher_detail_no and voucher_detail_no != item.name:
continue
@@ -156,6 +201,7 @@
"warehouse": item.warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
+ "ignore_warehouse": 1,
}
)
)
@@ -228,6 +274,9 @@
def set_new_serial_and_batch_bundle(self):
for item in self.items:
+ if item.use_serial_batch_fields:
+ continue
+
if not item.qty:
continue
@@ -290,8 +339,10 @@
inventory_dimensions_dict=inventory_dimensions_dict,
)
- if (item.qty is None or item.qty == item_dict.get("qty")) and (
- item.valuation_rate is None or item.valuation_rate == item_dict.get("rate")
+ if (
+ (item.qty is None or item.qty == item_dict.get("qty"))
+ and (item.valuation_rate is None or item.valuation_rate == item_dict.get("rate"))
+ and (not item.serial_no or (item.serial_no == item_dict.get("serial_nos")))
):
return False
else:
@@ -302,6 +353,11 @@
if item.valuation_rate is None:
item.valuation_rate = item_dict.get("rate")
+ if item_dict.get("serial_nos"):
+ item.current_serial_no = item_dict.get("serial_nos")
+ if self.purpose == "Stock Reconciliation" and not item.serial_no and item.qty:
+ item.serial_no = item.current_serial_no
+
item.current_qty = item_dict.get("qty")
item.current_valuation_rate = item_dict.get("rate")
self.calculate_difference_amount(item, item_dict)
@@ -780,7 +836,20 @@
current_qty = 0.0
if row.current_serial_and_batch_bundle:
- current_qty = self.get_qty_for_serial_and_batch_bundle(row)
+ current_qty = self.get_current_qty_for_serial_or_batch(row)
+ elif row.serial_no:
+ item_dict = get_stock_balance_for(
+ row.item_code,
+ row.warehouse,
+ self.posting_date,
+ self.posting_time,
+ voucher_no=self.name,
+ )
+
+ current_qty = item_dict.get("qty")
+ row.current_serial_no = item_dict.get("serial_nos")
+ row.current_valuation_rate = item_dict.get("rate")
+ val_rate = item_dict.get("rate")
elif row.batch_no:
current_qty = get_batch_qty_for_stock_reco(
row.item_code, row.warehouse, row.batch_no, self.posting_date, self.posting_time, self.name
@@ -788,15 +857,16 @@
precesion = row.precision("current_qty")
if flt(current_qty, precesion) != flt(row.current_qty, precesion):
- val_rate = get_valuation_rate(
- row.item_code,
- row.warehouse,
- self.doctype,
- self.name,
- company=self.company,
- batch_no=row.batch_no,
- serial_and_batch_bundle=row.current_serial_and_batch_bundle,
- )
+ if not row.serial_no:
+ val_rate = get_valuation_rate(
+ row.item_code,
+ row.warehouse,
+ self.doctype,
+ self.name,
+ company=self.company,
+ batch_no=row.batch_no,
+ serial_and_batch_bundle=row.current_serial_and_batch_bundle,
+ )
row.current_valuation_rate = val_rate
row.current_qty = current_qty
@@ -842,11 +912,56 @@
return allow_negative_stock
- def get_qty_for_serial_and_batch_bundle(self, row):
+ def get_current_qty_for_serial_or_batch(self, row):
doc = frappe.get_doc("Serial and Batch Bundle", row.current_serial_and_batch_bundle)
- precision = doc.entries[0].precision("qty")
+ current_qty = 0.0
+ if doc.has_serial_no:
+ current_qty = self.get_current_qty_for_serial_nos(doc)
+ elif doc.has_batch_no:
+ current_qty = self.get_current_qty_for_batch_nos(doc)
- current_qty = 0
+ return abs(current_qty)
+
+ def get_current_qty_for_serial_nos(self, doc):
+ serial_nos_details = get_available_serial_nos(
+ frappe._dict(
+ {
+ "item_code": doc.item_code,
+ "warehouse": doc.warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "voucher_no": self.name,
+ "ignore_warehouse": 1,
+ }
+ )
+ )
+
+ if not serial_nos_details:
+ return 0.0
+
+ doc.delete_serial_batch_entries()
+ current_qty = 0.0
+ for serial_no_row in serial_nos_details:
+ current_qty += 1
+ doc.append(
+ "entries",
+ {
+ "serial_no": serial_no_row.serial_no,
+ "qty": -1,
+ "warehouse": doc.warehouse,
+ "batch_no": serial_no_row.batch_no,
+ },
+ )
+
+ doc.set_incoming_rate(save=True)
+ doc.calculate_qty_and_amount(save=True)
+ doc.db_update_all()
+
+ return current_qty
+
+ def get_current_qty_for_batch_nos(self, doc):
+ current_qty = 0.0
+ precision = doc.entries[0].precision("qty")
for d in doc.entries:
qty = (
get_batch_qty(
@@ -864,7 +979,7 @@
current_qty += qty
- return abs(current_qty)
+ return current_qty
def get_batch_qty_for_stock_reco(
@@ -1075,9 +1190,16 @@
has_serial_no = bool(item_dict.get("has_serial_no"))
has_batch_no = bool(item_dict.get("has_batch_no"))
+ use_serial_batch_fields = frappe.db.get_single_value("Stock Settings", "use_serial_batch_fields")
+
if not batch_no and has_batch_no:
# Not enough information to fetch data
- return {"qty": 0, "rate": 0, "serial_nos": None}
+ return {
+ "qty": 0,
+ "rate": 0,
+ "serial_nos": None,
+ "use_serial_batch_fields": use_serial_batch_fields,
+ }
# TODO: fetch only selected batch's values
data = get_stock_balance(
@@ -1100,7 +1222,12 @@
get_batch_qty(batch_no, warehouse, posting_date=posting_date, posting_time=posting_time) or 0
)
- return {"qty": qty, "rate": rate, "serial_nos": serial_nos}
+ return {
+ "qty": qty,
+ "rate": rate,
+ "serial_nos": serial_nos,
+ "use_serial_batch_fields": use_serial_batch_fields,
+ }
@frappe.whitelist()
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 70e9fb2..479a74a 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -925,6 +925,74 @@
self.assertEqual(len(serial_batch_bundle), 0)
+ def test_backdated_purchase_receipt_with_stock_reco(self):
+ item_code = self.make_item(
+ properties={
+ "is_stock_item": 1,
+ "has_serial_no": 1,
+ "serial_no_series": "TEST-SERIAL-.###",
+ }
+ ).name
+
+ warehouse = "_Test Warehouse - _TC"
+
+ # Step - 1: Create a Backdated Purchase Receipt
+
+ pr1 = make_purchase_receipt(
+ item_code=item_code, warehouse=warehouse, qty=10, rate=100, posting_date=add_days(nowdate(), -3)
+ )
+ pr1.reload()
+
+ serial_nos = sorted(get_serial_nos_from_bundle(pr1.items[0].serial_and_batch_bundle))[:5]
+
+ # Step - 2: Create a Stock Reconciliation
+ sr1 = create_stock_reconciliation(
+ item_code=item_code,
+ warehouse=warehouse,
+ qty=5,
+ serial_no=serial_nos,
+ )
+
+ data = frappe.get_all(
+ "Stock Ledger Entry",
+ fields=["serial_no", "actual_qty", "stock_value_difference"],
+ filters={"voucher_no": sr1.name, "is_cancelled": 0},
+ order_by="creation",
+ )
+
+ for d in data:
+ if d.actual_qty < 0:
+ self.assertEqual(d.actual_qty, -10.0)
+ self.assertAlmostEqual(d.stock_value_difference, -1000.0)
+ else:
+ self.assertEqual(d.actual_qty, 5.0)
+ self.assertAlmostEqual(d.stock_value_difference, 500.0)
+
+ # Step - 3: Create a Purchase Receipt before the first Purchase Receipt
+ make_purchase_receipt(
+ item_code=item_code, warehouse=warehouse, qty=10, rate=200, posting_date=add_days(nowdate(), -5)
+ )
+
+ data = frappe.get_all(
+ "Stock Ledger Entry",
+ fields=["serial_no", "actual_qty", "stock_value_difference"],
+ filters={"voucher_no": sr1.name, "is_cancelled": 0},
+ order_by="creation",
+ )
+
+ for d in data:
+ if d.actual_qty < 0:
+ self.assertEqual(d.actual_qty, -20.0)
+ self.assertAlmostEqual(d.stock_value_difference, -3000.0)
+ else:
+ self.assertEqual(d.actual_qty, 5.0)
+ self.assertAlmostEqual(d.stock_value_difference, 500.0)
+
+ active_serial_no = frappe.get_all(
+ "Serial No", filters={"status": "Active", "item_code": item_code}
+ )
+ self.assertEqual(len(active_serial_no), 5)
+
def create_batch_item_with_batch(item_name, batch_id):
batch_item_doc = create_item(item_name, is_stock_item=1)
@@ -1026,7 +1094,7 @@
)
bundle_id = None
- if args.batch_no or args.serial_no:
+ if not args.use_serial_batch_fields and (args.batch_no or args.serial_no):
batches = frappe._dict({})
if args.batch_no:
batches[args.batch_no] = args.qty
@@ -1057,7 +1125,10 @@
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty,
"valuation_rate": args.rate,
+ "serial_no": args.serial_no if args.use_serial_batch_fields else None,
+ "batch_no": args.batch_no if args.use_serial_batch_fields else None,
"serial_and_batch_bundle": bundle_id,
+ "use_serial_batch_fields": args.use_serial_batch_fields,
},
)
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
index fc4ae6a..7342259 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
@@ -19,11 +19,14 @@
"allow_zero_valuation_rate",
"serial_no_and_batch_section",
"add_serial_batch_bundle",
- "serial_and_batch_bundle",
- "batch_no",
+ "use_serial_batch_fields",
"column_break_11",
+ "serial_and_batch_bundle",
"current_serial_and_batch_bundle",
+ "section_break_lypk",
"serial_no",
+ "column_break_eefq",
+ "batch_no",
"section_break_3",
"current_qty",
"current_amount",
@@ -103,10 +106,10 @@
"label": "Serial No and Batch"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Long Text",
- "label": "Serial No",
- "read_only": 1
+ "label": "Serial No"
},
{
"fieldname": "column_break_11",
@@ -171,11 +174,11 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch",
- "read_only": 1,
"search_index": 1
},
{
@@ -195,6 +198,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial / Batch Bundle",
@@ -204,6 +208,7 @@
"search_index": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "current_serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Current Serial / Batch Bundle",
@@ -212,6 +217,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "add_serial_batch_bundle",
"fieldtype": "Button",
"label": "Add Serial / Batch No"
@@ -222,11 +228,26 @@
"fieldtype": "Link",
"label": "Item Group",
"options": "Item Group"
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_lypk",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_eefq",
+ "fieldtype": "Column Break"
}
],
"istable": 1,
"links": [],
- "modified": "2024-01-14 10:04:23.599951",
+ "modified": "2024-02-04 16:19:44.576022",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reconciliation Item",
diff --git a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
index c82cdf5..1938fec 100644
--- a/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
+++ b/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.py
@@ -26,6 +26,7 @@
current_valuation_rate: DF.Currency
has_item_scanned: DF.Data | None
item_code: DF.Link
+ item_group: DF.Link | None
item_name: DF.Data | None
parent: DF.Data
parentfield: DF.Data
@@ -34,6 +35,7 @@
quantity_difference: DF.ReadOnly | None
serial_and_batch_bundle: DF.Link | None
serial_no: DF.LongText | None
+ use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency
warehouse: DF.Link
# end: auto-generated types
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 1228290..c698283 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -1,7 +1,7 @@
{
"actions": [],
"creation": "2013-06-24 16:37:54",
- "description": "Settings",
+ "description": "Default settings for your stock-related transactions",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
@@ -50,6 +50,7 @@
"disable_serial_no_and_batch_selector",
"use_naming_series",
"naming_series_prefix",
+ "use_serial_batch_fields",
"stock_planning_tab",
"auto_material_request",
"auto_indent",
@@ -176,7 +177,7 @@
"description": "No stock transactions can be created or modified before this date.",
"fieldname": "stock_frozen_upto",
"fieldtype": "Date",
- "label": "Stock Frozen Upto"
+ "label": "Stock Frozen Up To"
},
{
"description": "Stock transactions that are older than the mentioned days cannot be modified.",
@@ -420,6 +421,12 @@
"fieldname": "auto_reserve_stock_for_sales_order_on_purchase",
"fieldtype": "Check",
"label": "Auto Reserve Stock for Sales Order on Purchase"
+ },
+ {
+ "default": "1",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial / Batch Fields"
}
],
"icon": "icon-cog",
@@ -427,7 +434,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2023-10-18 12:35:30.068799",
+ "modified": "2024-02-04 12:01:31.931864",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index 088c7cd..c4960aa 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -57,6 +57,7 @@
stock_uom: DF.Link | None
update_existing_price_list_rate: DF.Check
use_naming_series: DF.Check
+ use_serial_batch_fields: DF.Check
valuation_method: DF.Literal["FIFO", "Moving Average", "LIFO"]
# end: auto-generated types
@@ -68,6 +69,7 @@
"allow_negative_stock",
"default_warehouse",
"set_qty_in_transactions_based_on_serial_no_input",
+ "use_serial_batch_fields",
]:
frappe.db.set_default(key, self.get(key, ""))
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index ebcdd11..1cb1057 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -86,7 +86,8 @@
get_party_item_code(args, item, out)
- set_valuation_rate(out, args)
+ if args.get("doctype") in ["Sales Order", "Quotation"]:
+ set_valuation_rate(out, args)
update_party_blanket_order(args, out)
@@ -269,7 +270,9 @@
if not item:
item = frappe.get_doc("Item", args.get("item_code"))
- if item.variant_of and not item.taxes:
+ if (
+ item.variant_of and not item.taxes and frappe.db.exists("Item Tax", {"parent": item.variant_of})
+ ):
item.update_template_tables()
item_defaults = get_item_defaults(item.name, args.company)
@@ -543,7 +546,7 @@
args = {
"company": company,
"tax_category": tax_category,
- "net_rate": item_rates.get(item_code[1]),
+ "base_net_rate": item_rates.get(item_code[1]),
}
if item_tax_templates:
@@ -635,7 +638,7 @@
if not flt(tax.maximum_net_rate):
# No range specified, just ignore
return True
- elif flt(tax.minimum_net_rate) <= flt(args.get("net_rate")) <= flt(tax.maximum_net_rate):
+ elif flt(tax.minimum_net_rate) <= flt(args.get("base_net_rate")) <= flt(tax.maximum_net_rate):
return True
return False
diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py
index 4cd9cbb..59f8b20 100644
--- a/erpnext/stock/reorder_item.py
+++ b/erpnext/stock/reorder_item.py
@@ -34,73 +34,157 @@
erpnext.get_default_company() or frappe.db.sql("""select name from tabCompany limit 1""")[0][0]
)
- items_to_consider = frappe.db.sql_list(
- """select name from `tabItem` item
- where is_stock_item=1 and has_variants=0
- and disabled=0
- and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
- and (exists (select name from `tabItem Reorder` ir where ir.parent=item.name)
- or (variant_of is not null and variant_of != ''
- and exists (select name from `tabItem Reorder` ir where ir.parent=item.variant_of))
- )""",
- {"today": nowdate()},
- )
+ items_to_consider = get_items_for_reorder()
if not items_to_consider:
return
item_warehouse_projected_qty = get_item_warehouse_projected_qty(items_to_consider)
- def add_to_material_request(
- item_code, warehouse, reorder_level, reorder_qty, material_request_type, warehouse_group=None
- ):
- if warehouse not in warehouse_company:
+ def add_to_material_request(**kwargs):
+ if isinstance(kwargs, dict):
+ kwargs = frappe._dict(kwargs)
+
+ if kwargs.warehouse not in warehouse_company:
# a disabled warehouse
return
- reorder_level = flt(reorder_level)
- reorder_qty = flt(reorder_qty)
+ reorder_level = flt(kwargs.reorder_level)
+ reorder_qty = flt(kwargs.reorder_qty)
# projected_qty will be 0 if Bin does not exist
- if warehouse_group:
- projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse_group))
+ if kwargs.warehouse_group:
+ projected_qty = flt(
+ item_warehouse_projected_qty.get(kwargs.item_code, {}).get(kwargs.warehouse_group)
+ )
else:
- projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse))
+ projected_qty = flt(
+ item_warehouse_projected_qty.get(kwargs.item_code, {}).get(kwargs.warehouse)
+ )
if (reorder_level or reorder_qty) and projected_qty <= reorder_level:
deficiency = reorder_level - projected_qty
if deficiency > reorder_qty:
reorder_qty = deficiency
- company = warehouse_company.get(warehouse) or default_company
+ company = warehouse_company.get(kwargs.warehouse) or default_company
- material_requests[material_request_type].setdefault(company, []).append(
- {"item_code": item_code, "warehouse": warehouse, "reorder_qty": reorder_qty}
+ material_requests[kwargs.material_request_type].setdefault(company, []).append(
+ {
+ "item_code": kwargs.item_code,
+ "warehouse": kwargs.warehouse,
+ "reorder_qty": reorder_qty,
+ "item_details": kwargs.item_details,
+ }
)
- for item_code in items_to_consider:
- item = frappe.get_doc("Item", item_code)
+ for item_code, reorder_levels in items_to_consider.items():
+ for d in reorder_levels:
+ if d.has_variants:
+ continue
- if item.variant_of and not item.get("reorder_levels"):
- item.update_template_tables()
-
- if item.get("reorder_levels"):
- for d in item.get("reorder_levels"):
- add_to_material_request(
- item_code,
- d.warehouse,
- d.warehouse_reorder_level,
- d.warehouse_reorder_qty,
- d.material_request_type,
- warehouse_group=d.warehouse_group,
- )
+ add_to_material_request(
+ item_code=item_code,
+ warehouse=d.warehouse,
+ reorder_level=d.warehouse_reorder_level,
+ reorder_qty=d.warehouse_reorder_qty,
+ material_request_type=d.material_request_type,
+ warehouse_group=d.warehouse_group,
+ item_details=frappe._dict(
+ {
+ "item_code": item_code,
+ "name": item_code,
+ "item_name": d.item_name,
+ "item_group": d.item_group,
+ "brand": d.brand,
+ "description": d.description,
+ "stock_uom": d.stock_uom,
+ "purchase_uom": d.purchase_uom,
+ }
+ ),
+ )
if material_requests:
return create_material_request(material_requests)
+def get_items_for_reorder() -> dict[str, list]:
+ reorder_table = frappe.qb.DocType("Item Reorder")
+ item_table = frappe.qb.DocType("Item")
+
+ query = (
+ frappe.qb.from_(reorder_table)
+ .inner_join(item_table)
+ .on(reorder_table.parent == item_table.name)
+ .select(
+ reorder_table.warehouse,
+ reorder_table.warehouse_group,
+ reorder_table.material_request_type,
+ reorder_table.warehouse_reorder_level,
+ reorder_table.warehouse_reorder_qty,
+ item_table.name,
+ item_table.stock_uom,
+ item_table.purchase_uom,
+ item_table.description,
+ item_table.item_name,
+ item_table.item_group,
+ item_table.brand,
+ item_table.variant_of,
+ item_table.has_variants,
+ )
+ .where(
+ (item_table.disabled == 0)
+ & (item_table.is_stock_item == 1)
+ & (
+ (item_table.end_of_life.isnull())
+ | (item_table.end_of_life > nowdate())
+ | (item_table.end_of_life == "0000-00-00")
+ )
+ )
+ )
+
+ data = query.run(as_dict=True)
+ itemwise_reorder = frappe._dict({})
+ for d in data:
+ itemwise_reorder.setdefault(d.name, []).append(d)
+
+ itemwise_reorder = get_reorder_levels_for_variants(itemwise_reorder)
+
+ return itemwise_reorder
+
+
+def get_reorder_levels_for_variants(itemwise_reorder):
+ item_table = frappe.qb.DocType("Item")
+
+ query = (
+ frappe.qb.from_(item_table)
+ .select(
+ item_table.name,
+ item_table.variant_of,
+ )
+ .where(
+ (item_table.disabled == 0)
+ & (item_table.is_stock_item == 1)
+ & (
+ (item_table.end_of_life.isnull())
+ | (item_table.end_of_life > nowdate())
+ | (item_table.end_of_life == "0000-00-00")
+ )
+ & (item_table.variant_of.notnull())
+ )
+ )
+
+ variants_item = query.run(as_dict=True)
+ for row in variants_item:
+ if not itemwise_reorder.get(row.name) and itemwise_reorder.get(row.variant_of):
+ itemwise_reorder.setdefault(row.name, []).extend(itemwise_reorder.get(row.variant_of, []))
+
+ return itemwise_reorder
+
+
def get_item_warehouse_projected_qty(items_to_consider):
item_warehouse_projected_qty = {}
+ items_to_consider = list(items_to_consider.keys())
for item_code, warehouse, projected_qty in frappe.db.sql(
"""select item_code, warehouse, projected_qty
@@ -145,6 +229,7 @@
mr.log_error("Unable to create material request")
+ company_wise_mr = frappe._dict({})
for request_type in material_requests:
for company in material_requests[request_type]:
try:
@@ -163,7 +248,7 @@
for d in items:
d = frappe._dict(d)
- item = frappe.get_doc("Item", d.item_code)
+ item = d.get("item_details")
uom = item.stock_uom
conversion_factor = 1.0
@@ -189,6 +274,7 @@
"item_code": d.item_code,
"schedule_date": add_days(nowdate(), cint(item.lead_time_days)),
"qty": qty,
+ "conversion_factor": conversion_factor,
"uom": uom,
"stock_uom": item.stock_uom,
"warehouse": d.warehouse,
@@ -206,17 +292,19 @@
mr.submit()
mr_list.append(mr)
+ company_wise_mr.setdefault(company, []).append(mr)
+
except Exception:
_log_exception(mr)
- if mr_list:
+ if company_wise_mr:
if getattr(frappe.local, "reorder_email_notify", None) is None:
frappe.local.reorder_email_notify = cint(
frappe.db.get_single_value("Stock Settings", "reorder_email_notify")
)
if frappe.local.reorder_email_notify:
- send_email_notification(mr_list)
+ send_email_notification(company_wise_mr)
if exceptions_list:
notify_errors(exceptions_list)
@@ -224,20 +312,56 @@
return mr_list
-def send_email_notification(mr_list):
+def send_email_notification(company_wise_mr):
"""Notify user about auto creation of indent"""
- email_list = frappe.db.sql_list(
- """select distinct r.parent
- from `tabHas Role` r, tabUser p
- where p.name = r.parent and p.enabled = 1 and p.docstatus < 2
- and r.role in ('Purchase Manager','Stock Manager')
- and p.name not in ('Administrator', 'All', 'Guest')"""
+ for company, mr_list in company_wise_mr.items():
+ email_list = get_email_list(company)
+
+ if not email_list:
+ continue
+
+ msg = frappe.render_template("templates/emails/reorder_item.html", {"mr_list": mr_list})
+
+ frappe.sendmail(
+ recipients=email_list, subject=_("Auto Material Requests Generated"), message=msg
+ )
+
+
+def get_email_list(company):
+ users = get_comapny_wise_users(company)
+ user_table = frappe.qb.DocType("User")
+ role_table = frappe.qb.DocType("Has Role")
+
+ query = (
+ frappe.qb.from_(user_table)
+ .inner_join(role_table)
+ .on(user_table.name == role_table.parent)
+ .select(user_table.email)
+ .where(
+ (role_table.role.isin(["Purchase Manager", "Stock Manager"]))
+ & (user_table.name.notin(["Administrator", "All", "Guest"]))
+ & (user_table.enabled == 1)
+ & (user_table.docstatus < 2)
+ )
)
- msg = frappe.render_template("templates/emails/reorder_item.html", {"mr_list": mr_list})
+ if users:
+ query = query.where(user_table.name.isin(users))
- frappe.sendmail(recipients=email_list, subject=_("Auto Material Requests Generated"), message=msg)
+ emails = query.run(as_dict=True)
+
+ return list(set([email.email for email in emails]))
+
+
+def get_comapny_wise_users(company):
+ users = frappe.get_all(
+ "User Permission",
+ filters={"allow": "Company", "for_value": company, "apply_to_all_doctypes": 1},
+ fields=["user"],
+ )
+
+ return [user.user for user in users]
def notify_errors(exceptions_list):
@@ -246,7 +370,7 @@
_("Dear System Manager,")
+ "<br>"
+ _(
- "An error occured for certain Items while creating Material Requests based on Re-order level. Please rectify these issues :"
+ "An error occurred for certain Items while creating Material Requests based on Re-order level. Please rectify these issues :"
)
+ "<br>"
)
diff --git a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
index 810dc46..3f5216b 100644
--- a/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
+++ b/erpnext/stock/report/serial_no_ledger/serial_no_ledger.py
@@ -22,9 +22,8 @@
{"label": _("Posting Time"), "fieldtype": "Time", "fieldname": "posting_time", "width": 90},
{
"label": _("Voucher Type"),
- "fieldtype": "Link",
+ "fieldtype": "Data",
"fieldname": "voucher_type",
- "options": "DocType",
"width": 160,
},
{
diff --git a/erpnext/stock/report/stock_balance/stock_balance.js b/erpnext/stock/report/stock_balance/stock_balance.js
index 6de5f00..fe6e83e 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.js
+++ b/erpnext/stock/report/stock_balance/stock_balance.js
@@ -99,7 +99,7 @@
"fieldname": 'ignore_closing_balance',
"label": __('Ignore Closing Balance'),
"fieldtype": 'Check',
- "default": 1
+ "default": 0
},
],
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index ed84a5c..2693238 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -90,8 +90,7 @@
self.opening_data.setdefault(group_by_key, entry)
def prepare_new_data(self):
- if not self.sle_entries:
- return
+ self.item_warehouse_map = self.get_item_warehouse_map()
if self.filters.get("show_stock_ageing_data"):
self.filters["show_warehouse_wise_stock"] = True
@@ -99,7 +98,8 @@
_func = itemgetter(1)
- self.item_warehouse_map = self.get_item_warehouse_map()
+ del self.sle_entries
+
sre_details = self.get_sre_reserved_qty_details()
variant_values = {}
@@ -143,15 +143,22 @@
item_warehouse_map = {}
self.opening_vouchers = self.get_opening_vouchers()
- for entry in self.sle_entries:
- group_by_key = self.get_group_by_key(entry)
- if group_by_key not in item_warehouse_map:
- self.initialize_data(item_warehouse_map, group_by_key, entry)
+ if self.filters.get("show_stock_ageing_data"):
+ self.sle_entries = self.sle_query.run(as_dict=True)
- self.prepare_item_warehouse_map(item_warehouse_map, entry, group_by_key)
+ with frappe.db.unbuffered_cursor():
+ if not self.filters.get("show_stock_ageing_data"):
+ self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True)
- if self.opening_data.get(group_by_key):
- del self.opening_data[group_by_key]
+ for entry in self.sle_entries:
+ group_by_key = self.get_group_by_key(entry)
+ if group_by_key not in item_warehouse_map:
+ self.initialize_data(item_warehouse_map, group_by_key, entry)
+
+ self.prepare_item_warehouse_map(item_warehouse_map, entry, group_by_key)
+
+ if self.opening_data.get(group_by_key):
+ del self.opening_data[group_by_key]
for group_by_key, entry in self.opening_data.items():
if group_by_key not in item_warehouse_map:
@@ -252,7 +259,8 @@
.where(
(table.docstatus == 1)
& (table.company == self.filters.company)
- & ((table.to_date <= self.from_date))
+ & (table.to_date <= self.from_date)
+ & (table.status == "Completed")
)
.orderby(table.to_date, order=Order.desc)
.limit(1)
@@ -305,7 +313,7 @@
if self.filters.get("company"):
query = query.where(sle.company == self.filters.get("company"))
- self.sle_entries = query.run(as_dict=True)
+ self.sle_query = query
def apply_inventory_dimensions_filters(self, query, sle) -> str:
inventory_dimension_fields = self.get_inventory_dimension_fields()
diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py
index 4cfe5d8..d8b5b34 100644
--- a/erpnext/stock/serial_batch_bundle.py
+++ b/erpnext/stock/serial_batch_bundle.py
@@ -283,6 +283,7 @@
if (sn_table.purchase_document_no != self.sle.voucher_no and self.sle.is_cancelled != 1)
else "Inactive",
)
+ .set(sn_table.company, self.sle.company)
.where(sn_table.name.isin(serial_nos))
).run()
@@ -793,6 +794,9 @@
setattr(self, "actual_qty", qty)
self.__dict__["actual_qty"] = self.actual_qty
+ if not hasattr(self, "use_serial_batch_fields"):
+ setattr(self, "use_serial_batch_fields", 0)
+
def duplicate_package(self):
if not self.serial_and_batch_bundle:
return
@@ -901,9 +905,14 @@
self.batches = get_available_batches(kwargs)
def set_auto_serial_batch_entries_for_inward(self):
+ print(self.get("serial_nos"))
+
if (self.get("batches") and self.has_batch_no) or (
self.get("serial_nos") and self.has_serial_no
):
+ if self.use_serial_batch_fields and self.get("serial_nos"):
+ self.make_serial_no_if_not_exists()
+
return
self.batch_no = None
@@ -915,6 +924,59 @@
else:
self.batches = frappe._dict({self.batch_no: abs(self.actual_qty)})
+ def make_serial_no_if_not_exists(self):
+ non_exists_serial_nos = []
+ for row in self.serial_nos:
+ if not frappe.db.exists("Serial No", row):
+ non_exists_serial_nos.append(row)
+
+ if non_exists_serial_nos:
+ self.make_serial_nos(non_exists_serial_nos)
+
+ def make_serial_nos(self, serial_nos):
+ serial_nos_details = []
+ batch_no = None
+ if self.batches:
+ batch_no = list(self.batches.keys())[0]
+
+ for serial_no in serial_nos:
+ serial_nos_details.append(
+ (
+ serial_no,
+ serial_no,
+ now(),
+ now(),
+ frappe.session.user,
+ frappe.session.user,
+ self.warehouse,
+ self.company,
+ self.item_code,
+ self.item_name,
+ self.description,
+ "Active",
+ batch_no,
+ )
+ )
+
+ if serial_nos_details:
+ fields = [
+ "name",
+ "serial_no",
+ "creation",
+ "modified",
+ "owner",
+ "modified_by",
+ "warehouse",
+ "company",
+ "item_code",
+ "item_name",
+ "description",
+ "status",
+ "batch_no",
+ ]
+
+ frappe.db.bulk_insert("Serial No", fields=fields, values=set(serial_nos_details))
+
def set_serial_batch_entries(self, doc):
if self.get("serial_nos"):
serial_no_wise_batch = frappe._dict({})
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 0370666..e88b192 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -9,9 +9,18 @@
import frappe
from frappe import _, scrub
from frappe.model.meta import get_field_precision
-from frappe.query_builder import Case
from frappe.query_builder.functions import CombineDatetime, Sum
-from frappe.utils import cint, flt, get_link_to_form, getdate, now, nowdate, nowtime, parse_json
+from frappe.utils import (
+ cint,
+ cstr,
+ flt,
+ get_link_to_form,
+ getdate,
+ now,
+ nowdate,
+ nowtime,
+ parse_json,
+)
import erpnext
from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty
@@ -712,11 +721,10 @@
if (
sle.voucher_type == "Stock Reconciliation"
- and (
- sle.batch_no or (sle.has_batch_no and sle.serial_and_batch_bundle and not sle.has_serial_no)
- )
+ and (sle.batch_no or sle.serial_no or sle.serial_and_batch_bundle)
and sle.voucher_detail_no
and not self.args.get("sle_id")
+ and sle.is_cancelled == 0
):
self.reset_actual_qty_for_stock_reco(sle)
@@ -737,6 +745,23 @@
if sle.serial_and_batch_bundle:
self.calculate_valuation_for_serial_batch_bundle(sle)
+ elif sle.serial_no and not self.args.get("sle_id"):
+ # Only run in reposting
+ self.get_serialized_values(sle)
+ self.wh_data.qty_after_transaction += flt(sle.actual_qty)
+ if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no:
+ self.wh_data.qty_after_transaction = sle.qty_after_transaction
+
+ self.wh_data.stock_value = flt(self.wh_data.qty_after_transaction) * flt(
+ self.wh_data.valuation_rate
+ )
+ elif (
+ sle.batch_no
+ and frappe.db.get_value("Batch", sle.batch_no, "use_batchwise_valuation", cache=True)
+ and not self.args.get("sle_id")
+ ):
+ # Only run in reposting
+ self.update_batched_values(sle)
else:
if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no and not has_dimensions:
# assert
@@ -782,6 +807,45 @@
):
self.update_outgoing_rate_on_transaction(sle)
+ def get_serialized_values(self, sle):
+ incoming_rate = flt(sle.incoming_rate)
+ actual_qty = flt(sle.actual_qty)
+ serial_nos = cstr(sle.serial_no).split("\n")
+
+ if incoming_rate < 0:
+ # wrong incoming rate
+ incoming_rate = self.wh_data.valuation_rate
+
+ stock_value_change = 0
+ if actual_qty > 0:
+ stock_value_change = actual_qty * incoming_rate
+ else:
+ # In case of delivery/stock issue, get average purchase rate
+ # of serial nos of current entry
+ if not sle.is_cancelled:
+ outgoing_value = self.get_incoming_value_for_serial_nos(sle, serial_nos)
+ stock_value_change = -1 * outgoing_value
+ else:
+ stock_value_change = actual_qty * sle.outgoing_rate
+
+ new_stock_qty = self.wh_data.qty_after_transaction + actual_qty
+
+ if new_stock_qty > 0:
+ new_stock_value = (
+ self.wh_data.qty_after_transaction * self.wh_data.valuation_rate
+ ) + stock_value_change
+ if new_stock_value >= 0:
+ # calculate new valuation rate only if stock value is positive
+ # else it remains the same as that of previous entry
+ self.wh_data.valuation_rate = new_stock_value / new_stock_qty
+
+ if not self.wh_data.valuation_rate and sle.voucher_detail_no:
+ allow_zero_rate = self.check_if_allow_zero_valuation_rate(
+ sle.voucher_type, sle.voucher_detail_no
+ )
+ if not allow_zero_rate:
+ self.wh_data.valuation_rate = self.get_fallback_rate(sle)
+
def reset_actual_qty_for_stock_reco(self, sle):
doc = frappe.get_cached_doc("Stock Reconciliation", sle.voucher_no)
doc.recalculate_current_qty(sle.voucher_detail_no, sle.creation, sle.actual_qty > 0)
@@ -795,6 +859,36 @@
if abs(sle.actual_qty) == 0.0:
sle.is_cancelled = 1
+ if sle.serial_and_batch_bundle and frappe.get_cached_value(
+ "Item", sle.item_code, "has_serial_no"
+ ):
+ self.update_serial_no_status(sle)
+
+ def update_serial_no_status(self, sle):
+ from erpnext.stock.serial_batch_bundle import get_serial_nos
+
+ serial_nos = get_serial_nos(sle.serial_and_batch_bundle)
+ if not serial_nos:
+ return
+
+ warehouse = None
+ status = "Inactive"
+
+ if sle.actual_qty > 0:
+ warehouse = sle.warehouse
+ status = "Active"
+
+ sn_table = frappe.qb.DocType("Serial No")
+
+ query = (
+ frappe.qb.update(sn_table)
+ .set(sn_table.warehouse, warehouse)
+ .set(sn_table.status, status)
+ .where(sn_table.name.isin(serial_nos))
+ )
+
+ query.run()
+
def calculate_valuation_for_serial_batch_bundle(self, sle):
doc = frappe.get_cached_doc("Serial and Batch Bundle", sle.serial_and_batch_bundle)
@@ -803,9 +897,12 @@
self.wh_data.stock_value = round_off_if_near_zero(self.wh_data.stock_value + doc.total_amount)
- self.wh_data.qty_after_transaction += doc.total_qty
+ precision = doc.precision("total_qty")
+ self.wh_data.qty_after_transaction += flt(doc.total_qty, precision)
if self.wh_data.qty_after_transaction:
- self.wh_data.valuation_rate = self.wh_data.stock_value / self.wh_data.qty_after_transaction
+ self.wh_data.valuation_rate = flt(self.wh_data.stock_value, precision) / flt(
+ self.wh_data.qty_after_transaction, precision
+ )
def validate_negative_stock(self, sle):
"""
@@ -1171,11 +1268,12 @@
outgoing_rate = get_batch_incoming_rate(
item_code=sle.item_code,
warehouse=sle.warehouse,
- serial_and_batch_bundle=sle.serial_and_batch_bundle,
+ batch_no=sle.batch_no,
posting_date=sle.posting_date,
posting_time=sle.posting_time,
creation=sle.creation,
)
+
if outgoing_rate is None:
# This can *only* happen if qty available for the batch is zero.
# in such case fall back various other rates.
@@ -1449,11 +1547,10 @@
def get_batch_incoming_rate(
- item_code, warehouse, serial_and_batch_bundle, posting_date, posting_time, creation=None
+ item_code, warehouse, batch_no, posting_date, posting_time, creation=None
):
sle = frappe.qb.DocType("Stock Ledger Entry")
- batch_ledger = frappe.qb.DocType("Serial and Batch Entry")
timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime(
posting_date, posting_time
@@ -1464,28 +1561,13 @@
== CombineDatetime(posting_date, posting_time)
) & (sle.creation < creation)
- batches = frappe.get_all(
- "Serial and Batch Entry", fields=["batch_no"], filters={"parent": serial_and_batch_bundle}
- )
-
batch_details = (
frappe.qb.from_(sle)
- .inner_join(batch_ledger)
- .on(sle.serial_and_batch_bundle == batch_ledger.parent)
- .select(
- Sum(
- Case()
- .when(sle.actual_qty > 0, batch_ledger.qty * batch_ledger.incoming_rate)
- .else_(batch_ledger.qty * batch_ledger.outgoing_rate * -1)
- ).as_("batch_value"),
- Sum(Case().when(sle.actual_qty > 0, batch_ledger.qty).else_(batch_ledger.qty * -1)).as_(
- "batch_qty"
- ),
- )
+ .select(Sum(sle.stock_value_difference).as_("batch_value"), Sum(sle.actual_qty).as_("batch_qty"))
.where(
(sle.item_code == item_code)
& (sle.warehouse == warehouse)
- & (batch_ledger.batch_no.isin([row.batch_no for row in batches]))
+ & (sle.batch_no == batch_no)
& (sle.is_cancelled == 0)
)
.where(timestamp_condition)
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index f29e7ea..9eac172 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -11,6 +11,9 @@
from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime
import erpnext
+from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
+ get_available_serial_nos,
+)
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.serial_batch_bundle import BatchNoValuation, SerialNoValuation
from erpnext.stock.valuation import FIFOValuation, LIFOValuation
@@ -125,7 +128,21 @@
if with_valuation_rate:
if with_serial_no:
- serial_nos = get_serial_nos_data_after_transactions(args)
+ serial_no_details = get_available_serial_nos(
+ frappe._dict(
+ {
+ "item_code": item_code,
+ "warehouse": warehouse,
+ "posting_date": posting_date,
+ "posting_time": posting_time,
+ "ignore_warehouse": 1,
+ }
+ )
+ )
+
+ serial_nos = ""
+ if serial_no_details:
+ serial_nos = "\n".join(d.serial_no for d in serial_no_details)
return (
(last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
@@ -140,38 +157,6 @@
return last_entry.qty_after_transaction if last_entry else 0.0
-def get_serial_nos_data_after_transactions(args):
-
- serial_nos = set()
- args = frappe._dict(args)
- sle = frappe.qb.DocType("Stock Ledger Entry")
-
- stock_ledger_entries = (
- frappe.qb.from_(sle)
- .select("serial_no", "actual_qty")
- .where(
- (sle.item_code == args.item_code)
- & (sle.warehouse == args.warehouse)
- & (
- CombineDatetime(sle.posting_date, sle.posting_time)
- < CombineDatetime(args.posting_date, args.posting_time)
- )
- & (sle.is_cancelled == 0)
- )
- .orderby(sle.posting_date, sle.posting_time, sle.creation)
- .run(as_dict=1)
- )
-
- for stock_ledger_entry in stock_ledger_entries:
- changed_serial_no = get_serial_nos_data(stock_ledger_entry.serial_no)
- if stock_ledger_entry.actual_qty > 0:
- serial_nos.update(changed_serial_no)
- else:
- serial_nos.difference_update(changed_serial_no)
-
- return "\n".join(serial_nos)
-
-
def get_serial_nos_data(serial_nos):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -289,6 +274,21 @@
in_rate = batch_obj.get_incoming_rate()
+ elif (args.get("serial_no") or "").strip() and not args.get("serial_and_batch_bundle"):
+ in_rate = get_avg_purchase_rate(args.get("serial_no"))
+ elif (
+ args.get("batch_no")
+ and frappe.db.get_value("Batch", args.get("batch_no"), "use_batchwise_valuation", cache=True)
+ and not args.get("serial_and_batch_bundle")
+ ):
+ in_rate = get_batch_incoming_rate(
+ item_code=args.get("item_code"),
+ warehouse=args.get("warehouse"),
+ batch_no=args.get("batch_no"),
+ posting_date=args.get("posting_date"),
+ posting_time=args.get("posting_time"),
+ )
+
else:
valuation_method = get_valuation_method(args.get("item_code"))
previous_sle = get_previous_sle(args)
@@ -319,6 +319,38 @@
return flt(in_rate)
+def get_batch_incoming_rate(
+ item_code, warehouse, batch_no, posting_date, posting_time, creation=None
+):
+
+ sle = frappe.qb.DocType("Stock Ledger Entry")
+
+ timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime(
+ posting_date, posting_time
+ )
+ if creation:
+ timestamp_condition |= (
+ CombineDatetime(sle.posting_date, sle.posting_time)
+ == CombineDatetime(posting_date, posting_time)
+ ) & (sle.creation < creation)
+
+ batch_details = (
+ frappe.qb.from_(sle)
+ .select(Sum(sle.stock_value_difference).as_("batch_value"), Sum(sle.actual_qty).as_("batch_qty"))
+ .where(
+ (sle.item_code == item_code)
+ & (sle.warehouse == warehouse)
+ & (sle.batch_no == batch_no)
+ & (sle.serial_and_batch_bundle.isnull())
+ & (sle.is_cancelled == 0)
+ )
+ .where(timestamp_condition)
+ ).run(as_dict=True)
+
+ if batch_details and batch_details[0].batch_qty:
+ return batch_details[0].batch_value / batch_details[0].batch_qty
+
+
def get_avg_purchase_rate(serial_nos):
"""get average value of serial numbers"""
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 7c2a1f1..3467b82 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -149,6 +149,7 @@
self.update_prevdoc_status()
self.set_subcontracting_order_status()
self.set_consumed_qty_in_subcontract_order()
+ self.make_bundle_using_old_serial_batch_fields()
self.update_stock_ledger()
self.make_gl_entries()
self.repost_future_sle_and_gle()
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
index 9bfc2fd..f9e0a0b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -48,11 +48,14 @@
"reference_name",
"section_break_45",
"serial_and_batch_bundle",
- "serial_no",
+ "use_serial_batch_fields",
"col_break5",
"rejected_serial_and_batch_bundle",
- "batch_no",
+ "section_break_jshh",
+ "serial_no",
"rejected_serial_no",
+ "column_break_henr",
+ "batch_no",
"manufacture_details",
"manufacturer",
"column_break_16",
@@ -311,22 +314,20 @@
"label": "Serial and Batch Details"
},
{
- "depends_on": "eval:!doc.is_fixed_asset",
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"label": "Serial No",
- "no_copy": 1,
- "read_only": 1
+ "no_copy": 1
},
{
- "depends_on": "eval:!doc.is_fixed_asset",
+ "depends_on": "eval:!doc.is_fixed_asset && doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"no_copy": 1,
"options": "Batch",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"depends_on": "eval: !parent.is_return",
@@ -478,6 +479,7 @@
"label": "Accounting Details"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Serial and Batch Bundle",
@@ -486,6 +488,7 @@
"print_hide": 1
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "rejected_serial_and_batch_bundle",
"fieldtype": "Link",
"label": "Rejected Serial and Batch Bundle",
@@ -546,12 +549,27 @@
"fieldtype": "Check",
"label": "Include Exploded Items",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_jshh",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_henr",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-30 12:05:51.920705",
+ "modified": "2024-02-04 16:23:30.374865",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Receipt Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py
index d02160e..1a4ce5b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py
@@ -58,6 +58,7 @@
subcontracting_order: DF.Link | None
subcontracting_order_item: DF.Data | None
subcontracting_receipt_item: DF.Data | None
+ use_serial_batch_fields: DF.Check
warehouse: DF.Link | None
# end: auto-generated types
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
index 90bcf4e..957b6a2 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.json
@@ -26,10 +26,13 @@
"current_stock",
"secbreak_3",
"serial_and_batch_bundle",
- "batch_no",
+ "use_serial_batch_fields",
"col_break4",
+ "subcontracting_order",
+ "section_break_zwnh",
"serial_no",
- "subcontracting_order"
+ "column_break_qibi",
+ "batch_no"
],
"fields": [
{
@@ -60,19 +63,19 @@
"width": "300px"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"no_copy": 1,
- "options": "Batch",
- "read_only": 1
+ "options": "Batch"
},
{
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
"fieldname": "serial_no",
"fieldtype": "Text",
"label": "Serial No",
- "no_copy": 1,
- "read_only": 1
+ "no_copy": 1
},
{
"fieldname": "col_break1",
@@ -198,6 +201,7 @@
},
{
"columns": 2,
+ "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1",
"fieldname": "serial_and_batch_bundle",
"fieldtype": "Link",
"in_list_view": 1,
@@ -205,12 +209,27 @@
"no_copy": 1,
"options": "Serial and Batch Bundle",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "use_serial_batch_fields",
+ "fieldtype": "Check",
+ "label": "Use Serial No / Batch Fields"
+ },
+ {
+ "depends_on": "eval:doc.use_serial_batch_fields === 1",
+ "fieldname": "section_break_zwnh",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_qibi",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-03-15 13:55:08.132626",
+ "modified": "2024-02-04 16:32:17.534162",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Receipt Supplied Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py
index 2ee5551..8f09197a 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_supplied_item/subcontracting_receipt_supplied_item.py
@@ -35,6 +35,7 @@
serial_no: DF.Text | None
stock_uom: DF.Link | None
subcontracting_order: DF.Link | None
+ use_serial_batch_fields: DF.Check
# end: auto-generated types
pass
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 97bf487..6c59a96 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -34,6 +34,18 @@
</a>
</ul>
</div>
+ {% if show_pay_button %}
+ <div class="form-column col-sm-6">
+ <div class="page-header-actions-block" data-html-block="header-actions">
+ <p>
+ <a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
+ class="btn btn-primary btn-sm" id="pay-for-order">
+ {{ _("Pay") }} {{doc.get_formatted("grand_total") }}
+ </a>
+ </p>
+ </div>
+ </div>
+ {% endif %}
</div>
{% endblock %}
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index d0968bf..21d4b86 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -48,7 +48,10 @@
)
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
- context.show_pay_button = frappe.db.get_single_value("Buying Settings", "show_pay_button")
+ context.show_pay_button = (
+ "payments" in frappe.get_installed_apps()
+ and frappe.db.get_single_value("Buying Settings", "show_pay_button")
+ )
context.show_make_pi_button = False
if context.doc.get("supplier"):
# show Make Purchase Invoice button based on permission
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index 4c8379e..581b53d 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -124,7 +124,7 @@
doctype="Timesheet",
title=_("Add Timesheets"),
description=_(
- "Timesheets help keep track of time, cost and billing for activites done by your team"
+ "Timesheets help keep track of time, cost and billing for activities done by your team"
),
action=_("Create Timesheet"),
route="List/Timesheet",
diff --git a/erpnext/utilities/web_form/addresses/addresses.json b/erpnext/utilities/web_form/addresses/addresses.json
index 2f5e180..4e2d8e3 100644
--- a/erpnext/utilities/web_form/addresses/addresses.json
+++ b/erpnext/utilities/web_form/addresses/addresses.json
@@ -8,26 +8,29 @@
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
+ "anonymous": 0,
+ "apply_document_permissions": 1,
+ "condition_json": "[]",
"creation": "2016-06-24 15:50:33.196990",
"doc_type": "Address",
"docstatus": 0,
"doctype": "Web Form",
"idx": 0,
"is_standard": 1,
+ "list_columns": [],
+ "list_title": "",
"login_required": 1,
"max_attachment_size": 0,
- "modified": "2019-10-15 06:55:30.405119",
- "modified_by": "Administrator",
+ "modified": "2024-01-24 10:28:35.026064",
+ "modified_by": "rohitw1991@gmail.com",
"module": "Utilities",
"name": "addresses",
"owner": "Administrator",
"published": 1,
"route": "address",
- "route_to_success_link": 0,
"show_attachments": 0,
- "show_in_grid": 0,
+ "show_list": 1,
"show_sidebar": 0,
- "sidebar_items": [],
"success_url": "/addresses",
"title": "Address",
"web_form_fields": [