mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-28 17:34:47 +00:00
Merge pull request #48979 from frappe/version-15-hotfix
chore: release v15
This commit is contained in:
4
.github/workflows/patch_faux.yml
vendored
4
.github/workflows/patch_faux.yml
vendored
@@ -1,7 +1,6 @@
|
|||||||
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
|
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
|
||||||
|
|
||||||
name: Skipped Patch Test
|
name: Skipped Patch Test
|
||||||
permissions: none
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -12,6 +11,9 @@ on:
|
|||||||
- "**.html"
|
- "**.html"
|
||||||
- "**.csv"
|
- "**.csv"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Entire Repository
|
- name: Checkout Entire Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
|
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
|
||||||
|
|
||||||
name: Skipped Tests
|
name: Skipped Tests
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -11,6 +10,9 @@ on:
|
|||||||
- "**.md"
|
- "**.md"
|
||||||
- "**.html"
|
- "**.html"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
25
CODEOWNERS
25
CODEOWNERS
@@ -3,22 +3,21 @@
|
|||||||
# These owners will be the default owners for everything in
|
# These owners will be the default owners for everything in
|
||||||
# the repo. Unless a later match takes precedence,
|
# the repo. Unless a later match takes precedence,
|
||||||
|
|
||||||
erpnext/accounts/ @deepeshgarg007 @ruthra-kumar
|
erpnext/accounts/ @ruthra-kumar
|
||||||
erpnext/assets/ @khushi8112 @deepeshgarg007
|
erpnext/assets/ @khushi8112
|
||||||
erpnext/regional @deepeshgarg007 @ruthra-kumar
|
erpnext/regional @ruthra-kumar
|
||||||
erpnext/selling @deepeshgarg007 @ruthra-kumar
|
erpnext/selling @ruthra-kumar
|
||||||
erpnext/support/ @deepeshgarg007
|
erpnext/support/ @ruthra-kumar
|
||||||
pos*
|
|
||||||
|
|
||||||
erpnext/buying/ @rohitwaghchaure
|
erpnext/buying/ @rohitwaghchaure @mihir-kandoi
|
||||||
erpnext/maintenance/ @rohitwaghchaure
|
erpnext/maintenance/ @rohitwaghchaure
|
||||||
erpnext/manufacturing/ @rohitwaghchaure
|
erpnext/manufacturing/ @rohitwaghchaure @mihir-kandoi
|
||||||
erpnext/quality_management/ @rohitwaghchaure
|
erpnext/quality_management/ @rohitwaghchaure
|
||||||
erpnext/stock/ @rohitwaghchaure
|
erpnext/stock/ @rohitwaghchaure @mihir-kandoi
|
||||||
erpnext/subcontracting @rohitwaghchaure
|
erpnext/subcontracting @mihir-kandoi
|
||||||
|
|
||||||
erpnext/controllers/ @deepeshgarg007 @rohitwaghchaure
|
erpnext/controllers/ @ruthra-kumar @rohitwaghchaure @mihir-kandoi
|
||||||
erpnext/patches/ @deepeshgarg007
|
erpnext/patches/ @ruthra-kumar
|
||||||
|
|
||||||
.github/ @deepeshgarg007
|
.github/ @ruthra-kumar
|
||||||
pyproject.toml @akhilnarang
|
pyproject.toml @akhilnarang
|
||||||
|
|||||||
@@ -304,7 +304,9 @@ class Account(NestedSet):
|
|||||||
self.account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
self.account_currency = frappe.get_cached_value("Company", self.company, "default_currency")
|
||||||
self.currency_explicitly_specified = False
|
self.currency_explicitly_specified = False
|
||||||
|
|
||||||
gl_currency = frappe.db.get_value("GL Entry", {"account": self.name}, "account_currency")
|
gl_currency = frappe.db.get_value(
|
||||||
|
"GL Entry", {"account": self.name, "is_cancelled": 0}, "account_currency"
|
||||||
|
)
|
||||||
|
|
||||||
if gl_currency and self.account_currency != gl_currency:
|
if gl_currency and self.account_currency != gl_currency:
|
||||||
if frappe.db.get_value("GL Entry", {"account": self.name}):
|
if frappe.db.get_value("GL Entry", {"account": self.name}):
|
||||||
|
|||||||
@@ -111,17 +111,15 @@ class AccountingDimension(Document):
|
|||||||
def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
def make_dimension_in_accounting_doctypes(doc, doclist=None):
|
||||||
if not doclist:
|
if not doclist:
|
||||||
doclist = get_doctypes_with_dimensions()
|
doclist = get_doctypes_with_dimensions()
|
||||||
|
|
||||||
doc_count = len(get_accounting_dimensions())
|
doc_count = len(get_accounting_dimensions())
|
||||||
count = 0
|
count = 0
|
||||||
repostable_doctypes = get_allowed_types_from_settings()
|
repostable_doctypes = get_allowed_types_from_settings(child_doc=True)
|
||||||
|
|
||||||
for doctype in doclist:
|
for doctype in doclist:
|
||||||
if (doc_count + 1) % 2 == 0:
|
if (doc_count + 1) % 2 == 0:
|
||||||
insert_after_field = "dimension_col_break"
|
insert_after_field = "dimension_col_break"
|
||||||
else:
|
else:
|
||||||
insert_after_field = "accounting_dimensions_section"
|
insert_after_field = "accounting_dimensions_section"
|
||||||
|
|
||||||
df = {
|
df = {
|
||||||
"fieldname": doc.fieldname,
|
"fieldname": doc.fieldname,
|
||||||
"label": doc.label,
|
"label": doc.label,
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class BankAccount(Document):
|
|||||||
"party_type": self.party_type,
|
"party_type": self.party_type,
|
||||||
"party": self.party,
|
"party": self.party,
|
||||||
"is_company_account": self.is_company_account,
|
"is_company_account": self.is_company_account,
|
||||||
|
"company": self.company,
|
||||||
"is_default": 1,
|
"is_default": 1,
|
||||||
"disabled": 0,
|
"disabled": 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.query_builder.custom import ConstantColumn
|
from frappe.query_builder.custom import ConstantColumn
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import cint, flt
|
from frappe.utils import cint, create_batch, flt
|
||||||
|
|
||||||
from erpnext import get_default_cost_center
|
from erpnext import get_default_cost_center
|
||||||
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
|
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
|
||||||
@@ -377,16 +377,17 @@ def auto_reconcile_vouchers(
|
|||||||
bank_transactions = get_bank_transactions(bank_account)
|
bank_transactions = get_bank_transactions(bank_account)
|
||||||
|
|
||||||
if len(bank_transactions) > 10:
|
if len(bank_transactions) > 10:
|
||||||
frappe.enqueue(
|
for bank_transaction_batch in create_batch(bank_transactions, 1000):
|
||||||
method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
|
frappe.enqueue(
|
||||||
queue="long",
|
method="erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.start_auto_reconcile",
|
||||||
bank_transactions=bank_transactions,
|
queue="long",
|
||||||
from_date=from_date,
|
bank_transactions=bank_transaction_batch,
|
||||||
to_date=to_date,
|
from_date=from_date,
|
||||||
filter_by_reference_date=filter_by_reference_date,
|
to_date=to_date,
|
||||||
from_reference_date=from_reference_date,
|
filter_by_reference_date=filter_by_reference_date,
|
||||||
to_reference_date=to_reference_date,
|
from_reference_date=from_reference_date,
|
||||||
)
|
to_reference_date=to_reference_date,
|
||||||
|
)
|
||||||
frappe.msgprint(_("Auto Reconciliation has started in the background"))
|
frappe.msgprint(_("Auto Reconciliation has started in the background"))
|
||||||
else:
|
else:
|
||||||
start_auto_reconcile(
|
start_auto_reconcile(
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.query_builder.functions import Sum
|
||||||
|
from frappe.tests.utils import change_settings
|
||||||
from frappe.utils import add_days, today
|
from frappe.utils import add_days, today
|
||||||
|
|
||||||
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
|
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
|
||||||
@@ -190,6 +192,31 @@ class TestCostCenterAllocation(unittest.TestCase):
|
|||||||
coa2.cancel()
|
coa2.cancel()
|
||||||
jv.cancel()
|
jv.cancel()
|
||||||
|
|
||||||
|
@change_settings("System Settings", {"rounding_method": "Commercial Rounding"})
|
||||||
|
def test_debit_credit_on_cost_center_allocation_for_commercial_rounding(self):
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
cca = create_cost_center_allocation(
|
||||||
|
"_Test Company",
|
||||||
|
"Main Cost Center 1 - _TC",
|
||||||
|
{"Sub Cost Center 2 - _TC": 50, "Sub Cost Center 3 - _TC": 50},
|
||||||
|
)
|
||||||
|
|
||||||
|
si = create_sales_invoice(rate=145.65, cost_center="Main Cost Center 1 - _TC")
|
||||||
|
|
||||||
|
gl_entry = frappe.qb.DocType("GL Entry")
|
||||||
|
gl_entries = (
|
||||||
|
frappe.qb.from_(gl_entry)
|
||||||
|
.select(Sum(gl_entry.credit).as_("cr"), Sum(gl_entry.debit).as_("dr"))
|
||||||
|
.where(gl_entry.voucher_type == "Sales Invoice")
|
||||||
|
.where(gl_entry.voucher_no == si.name)
|
||||||
|
).run(as_dict=1)
|
||||||
|
|
||||||
|
self.assertEqual(gl_entries[0].cr, gl_entries[0].dr)
|
||||||
|
|
||||||
|
si.cancel()
|
||||||
|
cca.cancel()
|
||||||
|
|
||||||
|
|
||||||
def create_cost_center_allocation(
|
def create_cost_center_allocation(
|
||||||
company,
|
company,
|
||||||
|
|||||||
@@ -8,4 +8,14 @@ frappe.ui.form.on("Payment Gateway Account", {
|
|||||||
frm.set_df_property("payment_gateway", "read_only", 1);
|
frm.set_df_property("payment_gateway", "read_only", 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup(frm) {
|
||||||
|
frm.set_query("payment_account", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: frm.doc.company,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"payment_gateway",
|
"payment_gateway",
|
||||||
"payment_channel",
|
"payment_channel",
|
||||||
|
"company",
|
||||||
"is_default",
|
"is_default",
|
||||||
"column_break_4",
|
"column_break_4",
|
||||||
"payment_account",
|
"payment_account",
|
||||||
@@ -70,11 +71,21 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Payment Channel",
|
"label": "Payment Channel",
|
||||||
"options": "\nEmail\nPhone"
|
"options": "\nEmail\nPhone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Company",
|
||||||
|
"options": "Company",
|
||||||
|
"print_hide": 1,
|
||||||
|
"remember_last_selected_value": 1,
|
||||||
|
"reqd": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-20 13:30:27.722852",
|
"modified": "2025-07-14 16:49:55.210352",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Gateway Account",
|
"name": "Payment Gateway Account",
|
||||||
@@ -95,4 +106,4 @@
|
|||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC"
|
"sort_order": "DESC"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class PaymentGatewayAccount(Document):
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from frappe.types import DF
|
from frappe.types import DF
|
||||||
|
|
||||||
|
company: DF.Link
|
||||||
currency: DF.ReadOnly | None
|
currency: DF.ReadOnly | None
|
||||||
is_default: DF.Check
|
is_default: DF.Check
|
||||||
message: DF.SmallText | None
|
message: DF.SmallText | None
|
||||||
@@ -24,7 +25,8 @@ class PaymentGatewayAccount(Document):
|
|||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
self.name = self.payment_gateway + " - " + self.currency
|
abbr = frappe.db.get_value("Company", self.company, "abbr")
|
||||||
|
self.name = self.payment_gateway + " - " + self.currency + " - " + abbr
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.currency = frappe.get_cached_value("Account", self.payment_account, "account_currency")
|
self.currency = frappe.get_cached_value("Account", self.payment_account, "account_currency")
|
||||||
@@ -34,13 +36,15 @@ class PaymentGatewayAccount(Document):
|
|||||||
|
|
||||||
def update_default_payment_gateway(self):
|
def update_default_payment_gateway(self):
|
||||||
if self.is_default:
|
if self.is_default:
|
||||||
frappe.db.sql(
|
frappe.db.set_value(
|
||||||
"""update `tabPayment Gateway Account` set is_default = 0
|
"Payment Gateway Account",
|
||||||
where is_default = 1 """
|
{"is_default": 1, "name": ["!=", self.name], "company": self.company},
|
||||||
|
"is_default",
|
||||||
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_as_default_if_not_set(self):
|
def set_as_default_if_not_set(self):
|
||||||
if not frappe.db.get_value(
|
if not frappe.db.exists(
|
||||||
"Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name)}, "name"
|
"Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name), "company": self.company}
|
||||||
):
|
):
|
||||||
self.is_default = 1
|
self.is_default = 1
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ frappe.ui.form.on("Payment Request", {
|
|||||||
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
|
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("payment_gateway_account", function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
company: frm.doc.company,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -539,7 +539,9 @@ def make_payment_request(**args):
|
|||||||
if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST:
|
if args.dt not in ALLOWED_DOCTYPES_FOR_PAYMENT_REQUEST:
|
||||||
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
|
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
|
||||||
|
|
||||||
ref_doc = frappe.get_doc(args.dt, args.dn)
|
ref_doc = args.ref_doc or frappe.get_doc(args.dt, args.dn)
|
||||||
|
if not args.get("company"):
|
||||||
|
args.company = ref_doc.company
|
||||||
gateway_account = get_gateway_details(args) or frappe._dict()
|
gateway_account = get_gateway_details(args) or frappe._dict()
|
||||||
|
|
||||||
grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
|
grand_total = get_amount(ref_doc, gateway_account.get("payment_account"))
|
||||||
@@ -782,7 +784,7 @@ def get_gateway_details(args): # nosemgrep
|
|||||||
"""
|
"""
|
||||||
Return gateway and payment account of default payment gateway
|
Return gateway and payment account of default payment gateway
|
||||||
"""
|
"""
|
||||||
gateway_account = args.get("payment_gateway_account", {"is_default": 1})
|
gateway_account = args.get("payment_gateway_account", {"is_default": 1, "company": args.company})
|
||||||
if gateway_account:
|
if gateway_account:
|
||||||
return get_payment_gateway_account(gateway_account)
|
return get_payment_gateway_account(gateway_account)
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ payment_method = [
|
|||||||
"payment_gateway": "_Test Gateway",
|
"payment_gateway": "_Test Gateway",
|
||||||
"payment_account": "_Test Bank - _TC",
|
"payment_account": "_Test Bank - _TC",
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
|
"company": "_Test Company",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Payment Gateway Account",
|
"doctype": "Payment Gateway Account",
|
||||||
"payment_gateway": "_Test Gateway",
|
"payment_gateway": "_Test Gateway",
|
||||||
"payment_account": "_Test Bank USD - _TC",
|
"payment_account": "_Test Bank USD - _TC",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
|
"company": "_Test Company",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -46,7 +48,11 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
for method in payment_method:
|
for method in payment_method:
|
||||||
if not frappe.db.get_value(
|
if not frappe.db.get_value(
|
||||||
"Payment Gateway Account",
|
"Payment Gateway Account",
|
||||||
{"payment_gateway": method["payment_gateway"], "currency": method["currency"]},
|
{
|
||||||
|
"payment_gateway": method["payment_gateway"],
|
||||||
|
"currency": method["currency"],
|
||||||
|
"company": method["company"],
|
||||||
|
},
|
||||||
"name",
|
"name",
|
||||||
):
|
):
|
||||||
frappe.get_doc(method).insert(ignore_permissions=True)
|
frappe.get_doc(method).insert(ignore_permissions=True)
|
||||||
@@ -60,7 +66,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dt="Sales Order",
|
dt="Sales Order",
|
||||||
dn=so_inr.name,
|
dn=so_inr.name,
|
||||||
recipient_id="saurabh@erpnext.com",
|
recipient_id="saurabh@erpnext.com",
|
||||||
payment_gateway_account="_Test Gateway - INR",
|
payment_gateway_account="_Test Gateway - INR - _TC",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pr.reference_doctype, "Sales Order")
|
self.assertEqual(pr.reference_doctype, "Sales Order")
|
||||||
@@ -74,7 +80,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dt="Sales Invoice",
|
dt="Sales Invoice",
|
||||||
dn=si_usd.name,
|
dn=si_usd.name,
|
||||||
recipient_id="saurabh@erpnext.com",
|
recipient_id="saurabh@erpnext.com",
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pr.reference_doctype, "Sales Invoice")
|
self.assertEqual(pr.reference_doctype, "Sales Invoice")
|
||||||
@@ -95,7 +101,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
party="_Test Supplier USD",
|
party="_Test Supplier USD",
|
||||||
recipient_id="user@example.com",
|
recipient_id="user@example.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
submit_doc=1,
|
submit_doc=1,
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
@@ -119,7 +125,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dn=purchase_invoice.name,
|
dn=purchase_invoice.name,
|
||||||
recipient_id="user@example.com",
|
recipient_id="user@example.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -138,7 +144,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dn=purchase_invoice.name,
|
dn=purchase_invoice.name,
|
||||||
recipient_id="user@example.com",
|
recipient_id="user@example.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -162,7 +168,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dn=so_inr.name,
|
dn=so_inr.name,
|
||||||
recipient_id="saurabh@erpnext.com",
|
recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - INR",
|
payment_gateway_account="_Test Gateway - INR - _TC",
|
||||||
submit_doc=1,
|
submit_doc=1,
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
@@ -184,7 +190,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dn=si_usd.name,
|
dn=si_usd.name,
|
||||||
recipient_id="saurabh@erpnext.com",
|
recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
submit_doc=1,
|
submit_doc=1,
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
@@ -228,7 +234,7 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
dn=si_usd.name,
|
dn=si_usd.name,
|
||||||
recipient_id="saurabh@erpnext.com",
|
recipient_id="saurabh@erpnext.com",
|
||||||
mute_email=1,
|
mute_email=1,
|
||||||
payment_gateway_account="_Test Gateway - USD",
|
payment_gateway_account="_Test Gateway - USD - _TC",
|
||||||
submit_doc=1,
|
submit_doc=1,
|
||||||
return_doc=1,
|
return_doc=1,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -301,6 +301,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Posting Time",
|
"label": "Posting Time",
|
||||||
@@ -1573,7 +1574,7 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-07-17 16:51:40.886083",
|
"modified": "2025-08-04 22:22:31.471752",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice",
|
"name": "POS Invoice",
|
||||||
|
|||||||
@@ -78,18 +78,18 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:(doc.enable_auto_email == 0 && doc.report == 'General Ledger');",
|
"depends_on": "eval:(!doc.enable_auto_email && doc.report == 'General Ledger');",
|
||||||
"fieldname": "from_date",
|
"fieldname": "from_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "From Date",
|
"label": "From Date",
|
||||||
"mandatory_depends_on": "eval:doc.frequency == '';"
|
"mandatory_depends_on": "eval:(!doc.enable_auto_email && doc.report == \"General Ledger\") "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:(doc.enable_auto_email == 0 && doc.report == 'General Ledger');",
|
"depends_on": "eval:(!doc.enable_auto_email && doc.report == 'General Ledger');",
|
||||||
"fieldname": "to_date",
|
"fieldname": "to_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "To Date",
|
"label": "To Date",
|
||||||
"mandatory_depends_on": "eval:doc.frequency == '';"
|
"mandatory_depends_on": "eval:(!doc.enable_auto_email && doc.report == \"General Ledger\") "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
@@ -330,7 +330,8 @@
|
|||||||
"depends_on": "eval:(doc.report == 'Accounts Receivable');",
|
"depends_on": "eval:(doc.report == 'Accounts Receivable');",
|
||||||
"fieldname": "posting_date",
|
"fieldname": "posting_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Posting Date"
|
"label": "Posting Date",
|
||||||
|
"mandatory_depends_on": "eval:(doc.report == 'Accounts Receivable');"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval: (doc.report == 'Accounts Receivable');",
|
"depends_on": "eval: (doc.report == 'Accounts Receivable');",
|
||||||
@@ -400,7 +401,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-07-08 16:52:12.602384",
|
"modified": "2025-08-04 18:21:12.603623",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Process Statement Of Accounts",
|
"name": "Process Statement Of Accounts",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import getdate
|
from frappe.utils import create_batch, getdate
|
||||||
|
|
||||||
from erpnext.accounts.doctype.subscription.subscription import DateTimeLikeObject, process_all
|
from erpnext.accounts.doctype.subscription.subscription import DateTimeLikeObject, process_all
|
||||||
|
|
||||||
@@ -23,7 +23,23 @@ class ProcessSubscription(Document):
|
|||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
process_all(subscription=self.subscription, posting_date=self.posting_date)
|
self.process_all_subscription()
|
||||||
|
|
||||||
|
def process_all_subscription(self):
|
||||||
|
filters = {"status": ("!=", "Cancelled")}
|
||||||
|
|
||||||
|
if self.subscription:
|
||||||
|
filters["name"] = self.subscription
|
||||||
|
|
||||||
|
subscriptions = frappe.get_all("Subscription", filters, pluck="name")
|
||||||
|
|
||||||
|
for subscription in create_batch(subscriptions, 500):
|
||||||
|
frappe.enqueue(
|
||||||
|
method="erpnext.accounts.doctype.subscription.subscription.process_all",
|
||||||
|
queue="long",
|
||||||
|
subscription=subscription,
|
||||||
|
posting_date=self.posting_date,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_subscription_process(
|
def create_subscription_process(
|
||||||
|
|||||||
@@ -319,6 +319,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Posting Time",
|
"label": "Posting Time",
|
||||||
@@ -1650,7 +1651,7 @@
|
|||||||
"idx": 204,
|
"idx": 204,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-04-09 16:49:22.175081",
|
"modified": "2025-08-04 19:19:11.380664",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import inspect
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, qb
|
from frappe import _, qb
|
||||||
|
from frappe.desk.form.linked_with import get_child_tables_of_doctypes
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils.data import comma_and
|
from frappe.utils.data import comma_and
|
||||||
|
|
||||||
@@ -208,13 +209,29 @@ def start_repost(account_repost_doc=str) -> None:
|
|||||||
doc.make_gl_entries()
|
doc.make_gl_entries()
|
||||||
|
|
||||||
|
|
||||||
def get_allowed_types_from_settings():
|
def get_allowed_types_from_settings(child_doc: bool = False):
|
||||||
return [
|
repost_docs = [
|
||||||
x.document_type
|
x.document_type
|
||||||
for x in frappe.db.get_all(
|
for x in frappe.db.get_all(
|
||||||
"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"]
|
"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
result = repost_docs
|
||||||
|
|
||||||
|
if repost_docs and child_doc:
|
||||||
|
result.extend(get_child_docs(repost_docs))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_child_docs(doc: list) -> list:
|
||||||
|
child_doc = []
|
||||||
|
doc = get_child_tables_of_doctypes(doc)
|
||||||
|
for child_list in doc.values():
|
||||||
|
for child in child_list:
|
||||||
|
if child.get("child_table"):
|
||||||
|
child_doc.append(child["child_table"])
|
||||||
|
return child_doc
|
||||||
|
|
||||||
|
|
||||||
def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):
|
def validate_docs_for_deferred_accounting(sales_docs, purchase_docs):
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
# import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||||
|
get_accounting_dimensions,
|
||||||
|
)
|
||||||
|
from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger import get_child_docs
|
||||||
|
|
||||||
|
|
||||||
class RepostAccountingLedgerSettings(Document):
|
class RepostAccountingLedgerSettings(Document):
|
||||||
# begin: auto-generated types
|
# begin: auto-generated types
|
||||||
@@ -17,6 +22,24 @@ class RepostAccountingLedgerSettings(Document):
|
|||||||
from erpnext.accounts.doctype.repost_allowed_types.repost_allowed_types import RepostAllowedTypes
|
from erpnext.accounts.doctype.repost_allowed_types.repost_allowed_types import RepostAllowedTypes
|
||||||
|
|
||||||
allowed_types: DF.Table[RepostAllowedTypes]
|
allowed_types: DF.Table[RepostAllowedTypes]
|
||||||
# end: auto-generated types
|
|
||||||
|
|
||||||
pass
|
# end: auto-generated types
|
||||||
|
def validate(self):
|
||||||
|
self.update_property_for_accounting_dimension()
|
||||||
|
|
||||||
|
def update_property_for_accounting_dimension(self):
|
||||||
|
doctypes = [entry.document_type for entry in self.allowed_types if entry.allowed]
|
||||||
|
if not doctypes:
|
||||||
|
return
|
||||||
|
doctypes += get_child_docs(doctypes)
|
||||||
|
|
||||||
|
set_allow_on_submit_for_dimension_fields(doctypes)
|
||||||
|
|
||||||
|
|
||||||
|
def set_allow_on_submit_for_dimension_fields(doctypes):
|
||||||
|
for dt in doctypes:
|
||||||
|
meta = frappe.get_meta(dt)
|
||||||
|
for dimension in get_accounting_dimensions():
|
||||||
|
df = meta.get_field(dimension)
|
||||||
|
if df and not df.allow_on_submit:
|
||||||
|
frappe.db.set_value("Custom Field", dt + "-" + dimension, "allow_on_submit", 1)
|
||||||
|
|||||||
@@ -379,6 +379,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"hide_days": 1,
|
"hide_days": 1,
|
||||||
@@ -2189,7 +2190,7 @@
|
|||||||
"link_fieldname": "consolidated_invoice"
|
"link_fieldname": "consolidated_invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2025-06-26 14:06:56.773552",
|
"modified": "2025-08-04 19:20:28.732039",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
|||||||
@@ -1370,8 +1370,9 @@ class SalesInvoice(SellingController):
|
|||||||
)
|
)
|
||||||
asset.db_set("disposal_date", None)
|
asset.db_set("disposal_date", None)
|
||||||
add_asset_activity(asset.name, _("Asset returned"))
|
add_asset_activity(asset.name, _("Asset returned"))
|
||||||
|
asset_status = asset.get_status()
|
||||||
|
|
||||||
if asset.calculate_depreciation:
|
if asset.calculate_depreciation and not asset_status == "Fully Depreciated":
|
||||||
posting_date = (
|
posting_date = (
|
||||||
frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
|
frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
|
||||||
if self.is_return
|
if self.is_return
|
||||||
|
|||||||
@@ -756,18 +756,14 @@ def get_prorata_factor(
|
|||||||
return diff / plan_days
|
return diff / plan_days
|
||||||
|
|
||||||
|
|
||||||
def process_all(subscription: str | None = None, posting_date: DateTimeLikeObject | None = None) -> None:
|
def process_all(subscription: list, posting_date: DateTimeLikeObject | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
Task to updates the status of all `Subscription` apart from those that are cancelled
|
Task to updates the status of all `Subscription` apart from those that are cancelled
|
||||||
"""
|
"""
|
||||||
filters = {"status": ("!=", "Cancelled")}
|
|
||||||
|
|
||||||
if subscription:
|
for subscription_name in subscription:
|
||||||
filters["name"] = subscription
|
|
||||||
|
|
||||||
for subscription in frappe.get_all("Subscription", filters, pluck="name"):
|
|
||||||
try:
|
try:
|
||||||
subscription = frappe.get_doc("Subscription", subscription)
|
subscription = frappe.get_doc("Subscription", subscription_name)
|
||||||
subscription.process(posting_date)
|
subscription.process(posting_date)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
except frappe.ValidationError:
|
except frappe.ValidationError:
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
|
"description": "Only payment entries with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
|
||||||
"fieldname": "consider_party_ledger_amount",
|
"fieldname": "consider_party_ledger_amount",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Consider Entire Party Ledger Amount",
|
"label": "Consider Entire Party Ledger Amount",
|
||||||
@@ -102,10 +102,11 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-07-27 21:47:34.396071",
|
"modified": "2025-07-30 07:13:51.785735",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Tax Withholding Category",
|
"name": "Tax Withholding Category",
|
||||||
|
"naming_rule": "Set by user",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@@ -148,4 +149,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,6 +186,15 @@ def process_gl_map(gl_map, merge_entries=True, precision=None, from_repost=False
|
|||||||
|
|
||||||
|
|
||||||
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_repost=False):
|
def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_repost=False):
|
||||||
|
round_off_account, default_currency = frappe.get_cached_value(
|
||||||
|
"Company", gl_map[0].company, ["round_off_account", "default_currency"]
|
||||||
|
)
|
||||||
|
if not precision:
|
||||||
|
precision = get_field_precision(
|
||||||
|
frappe.get_meta("GL Entry").get_field("debit"),
|
||||||
|
currency=default_currency,
|
||||||
|
)
|
||||||
|
|
||||||
new_gl_map = []
|
new_gl_map = []
|
||||||
for d in gl_map:
|
for d in gl_map:
|
||||||
cost_center = d.get("cost_center")
|
cost_center = d.get("cost_center")
|
||||||
@@ -203,6 +212,11 @@ def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None, from_r
|
|||||||
new_gl_map.append(d)
|
new_gl_map.append(d)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if d.account == round_off_account:
|
||||||
|
d.cost_center = cost_center_allocation[0][0]
|
||||||
|
new_gl_map.append(d)
|
||||||
|
continue
|
||||||
|
|
||||||
for sub_cost_center, percentage in cost_center_allocation:
|
for sub_cost_center, percentage in cost_center_allocation:
|
||||||
gle = copy.deepcopy(d)
|
gle = copy.deepcopy(d)
|
||||||
gle.cost_center = sub_cost_center
|
gle.cost_center = sub_cost_center
|
||||||
|
|||||||
@@ -197,6 +197,11 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
label: __("Show Net Values in Party Account"),
|
label: __("Show Net Values in Party Account"),
|
||||||
fieldtype: "Check",
|
fieldtype: "Check",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: "show_amount_in_company_currency",
|
||||||
|
label: __("Show Credit / Debit in Company Currency"),
|
||||||
|
fieldtype: "Check",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: "add_values_in_transaction_currency",
|
fieldname: "add_values_in_transaction_currency",
|
||||||
label: __("Add Columns in Transaction Currency"),
|
label: __("Add Columns in Transaction Currency"),
|
||||||
|
|||||||
@@ -605,6 +605,18 @@ def get_columns(filters):
|
|||||||
company = filters.get("company") or get_default_company()
|
company = filters.get("company") or get_default_company()
|
||||||
filters["presentation_currency"] = currency = get_company_currency(company)
|
filters["presentation_currency"] = currency = get_company_currency(company)
|
||||||
|
|
||||||
|
company_currency = get_company_currency(filters.get("company") or get_default_company())
|
||||||
|
|
||||||
|
if (
|
||||||
|
filters.get("show_amount_in_company_currency")
|
||||||
|
and filters["presentation_currency"] != company_currency
|
||||||
|
):
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
f'Presentation Currency cannot be {frappe.bold(filters["presentation_currency"])} , When {frappe.bold("Show Credit / Debit in Company Currency")} is enabled.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
columns = [
|
columns = [
|
||||||
{
|
{
|
||||||
"label": _("GL Entry"),
|
"label": _("GL Entry"),
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ def get_ordered_to_be_billed_data(args, filters=None):
|
|||||||
child_doctype.item_name,
|
child_doctype.item_name,
|
||||||
child_doctype.description,
|
child_doctype.description,
|
||||||
project_field,
|
project_field,
|
||||||
|
doctype.company,
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(doctype.docstatus == 1)
|
(doctype.docstatus == 1)
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class PaymentLedger:
|
|||||||
against_voucher_no=ple.against_voucher_no,
|
against_voucher_no=ple.against_voucher_no,
|
||||||
amount=ple.amount,
|
amount=ple.amount,
|
||||||
currency=ple.account_currency,
|
currency=ple.account_currency,
|
||||||
|
company=ple.company,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.filters.include_account_currency:
|
if self.filters.include_account_currency:
|
||||||
@@ -77,6 +78,7 @@ class PaymentLedger:
|
|||||||
against_voucher_no="Outstanding:",
|
against_voucher_no="Outstanding:",
|
||||||
amount=total,
|
amount=total,
|
||||||
currency=voucher_data[0].currency,
|
currency=voucher_data[0].currency,
|
||||||
|
company=voucher_data[0].company,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.filters.include_account_currency:
|
if self.filters.include_account_currency:
|
||||||
@@ -85,7 +87,12 @@ class PaymentLedger:
|
|||||||
voucher_data.append(entry)
|
voucher_data.append(entry)
|
||||||
|
|
||||||
# empty row
|
# empty row
|
||||||
voucher_data.append(frappe._dict())
|
voucher_data.append(
|
||||||
|
frappe._dict(
|
||||||
|
currency=voucher_data[0].currency,
|
||||||
|
company=voucher_data[0].company,
|
||||||
|
)
|
||||||
|
)
|
||||||
self.data.extend(voucher_data)
|
self.data.extend(voucher_data)
|
||||||
|
|
||||||
def build_conditions(self):
|
def build_conditions(self):
|
||||||
@@ -130,7 +137,6 @@ class PaymentLedger:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_columns(self):
|
def get_columns(self):
|
||||||
company_currency = frappe.get_cached_value("Company", self.filters.get("company"), "default_currency")
|
|
||||||
options = None
|
options = None
|
||||||
self.columns.append(
|
self.columns.append(
|
||||||
dict(
|
dict(
|
||||||
@@ -195,7 +201,7 @@ class PaymentLedger:
|
|||||||
label=_("Amount"),
|
label=_("Amount"),
|
||||||
fieldname="amount",
|
fieldname="amount",
|
||||||
fieldtype="Currency",
|
fieldtype="Currency",
|
||||||
options=company_currency,
|
options="Company:company:default_currency",
|
||||||
width="100",
|
width="100",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
|
|||||||
gle_map = get_gle_map(tds_docs)
|
gle_map = get_gle_map(tds_docs)
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
|
entries = {}
|
||||||
for name, details in gle_map.items():
|
for name, details in gle_map.items():
|
||||||
for entry in details:
|
for entry in details:
|
||||||
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
|
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
|
||||||
@@ -119,8 +120,13 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_
|
|||||||
"supplier_invoice_date": bill_date,
|
"supplier_invoice_date": bill_date,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
out.append(row)
|
|
||||||
|
|
||||||
|
key = entry.voucher_no
|
||||||
|
if key in entries:
|
||||||
|
entries[key]["tax_amount"] += tax_amount
|
||||||
|
else:
|
||||||
|
entries[key] = row
|
||||||
|
out = list(entries.values())
|
||||||
out.sort(key=lambda x: (x["section_code"], x["transaction_date"]))
|
out.sort(key=lambda x: (x["section_code"], x["transaction_date"]))
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ def convert_to_presentation_currency(gl_entries, currency_info, filters=None):
|
|||||||
len(account_currencies) == 1
|
len(account_currencies) == 1
|
||||||
and account_currency == presentation_currency
|
and account_currency == presentation_currency
|
||||||
and not exchange_gain_or_loss
|
and not exchange_gain_or_loss
|
||||||
):
|
) and not filters.get("show_amount_in_company_currency"):
|
||||||
entry["debit"] = debit_in_account_currency
|
entry["debit"] = debit_in_account_currency
|
||||||
entry["credit"] = credit_in_account_currency
|
entry["credit"] = credit_in_account_currency
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
from json import loads
|
from json import loads
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
@@ -1339,6 +1340,7 @@ def create_payment_gateway_account(gateway, payment_channel="Email"):
|
|||||||
"payment_account": bank_account.name,
|
"payment_account": bank_account.name,
|
||||||
"currency": bank_account.account_currency,
|
"currency": bank_account.account_currency,
|
||||||
"payment_channel": payment_channel,
|
"payment_channel": payment_channel,
|
||||||
|
"company": company,
|
||||||
}
|
}
|
||||||
).insert(ignore_permissions=True, ignore_if_duplicate=True)
|
).insert(ignore_permissions=True, ignore_if_duplicate=True)
|
||||||
|
|
||||||
@@ -2419,25 +2421,37 @@ def sync_auto_reconcile_config(auto_reconciliation_job_trigger: int = 15):
|
|||||||
).save()
|
).save()
|
||||||
|
|
||||||
|
|
||||||
|
def get_link_fields_grouped_by_option(doctype):
|
||||||
|
meta = frappe.get_meta(doctype)
|
||||||
|
link_fields_map = defaultdict(list)
|
||||||
|
|
||||||
|
for df in meta.fields:
|
||||||
|
if df.fieldtype == "Link" and df.options and not df.ignore_user_permissions:
|
||||||
|
link_fields_map[df.options].append(df.fieldname)
|
||||||
|
|
||||||
|
return link_fields_map
|
||||||
|
|
||||||
|
|
||||||
def build_qb_match_conditions(doctype, user=None) -> list:
|
def build_qb_match_conditions(doctype, user=None) -> list:
|
||||||
match_filters = build_match_conditions(doctype, user, False)
|
match_filters = build_match_conditions(doctype, user, False)
|
||||||
|
link_fields_map = get_link_fields_grouped_by_option(doctype)
|
||||||
criterion = []
|
criterion = []
|
||||||
apply_strict_user_permissions = frappe.get_system_settings("apply_strict_user_permissions")
|
apply_strict_user_permissions = frappe.get_system_settings("apply_strict_user_permissions")
|
||||||
|
|
||||||
if match_filters:
|
if match_filters:
|
||||||
from frappe import qb
|
|
||||||
|
|
||||||
_dt = qb.DocType(doctype)
|
_dt = qb.DocType(doctype)
|
||||||
|
|
||||||
for filter in match_filters:
|
for filter in match_filters:
|
||||||
for d, names in filter.items():
|
for link_option, allowed_values in filter.items():
|
||||||
fieldname = d.lower().replace(" ", "_")
|
fieldnames = link_fields_map.get(link_option, [])
|
||||||
field = _dt[fieldname]
|
|
||||||
|
|
||||||
cond = field.isin(names)
|
for fieldname in fieldnames:
|
||||||
if not apply_strict_user_permissions:
|
field = _dt[fieldname]
|
||||||
cond = (Coalesce(field, "") == "") | field.isin(names)
|
cond = field.isin(allowed_values)
|
||||||
|
|
||||||
criterion.append(cond)
|
if not apply_strict_user_permissions:
|
||||||
|
cond = (Coalesce(field, "") == "") | cond
|
||||||
|
|
||||||
|
criterion.append(cond)
|
||||||
|
|
||||||
return criterion
|
return criterion
|
||||||
|
|||||||
@@ -1097,7 +1097,7 @@ def make_journal_entry(asset_name):
|
|||||||
je.voucher_type = "Depreciation Entry"
|
je.voucher_type = "Depreciation Entry"
|
||||||
je.naming_series = depreciation_series
|
je.naming_series = depreciation_series
|
||||||
je.company = asset.company
|
je.company = asset.company
|
||||||
je.remark = f"Depreciation Entry against asset {asset_name}"
|
je.remark = _("Depreciation Entry against asset {0}").format(asset_name)
|
||||||
|
|
||||||
je.append(
|
je.append(
|
||||||
"accounts",
|
"accounts",
|
||||||
|
|||||||
@@ -277,7 +277,9 @@ def _make_journal_entry_for_depreciation(
|
|||||||
je.posting_date = depr_schedule.schedule_date
|
je.posting_date = depr_schedule.schedule_date
|
||||||
je.company = asset.company
|
je.company = asset.company
|
||||||
je.finance_book = asset_depr_schedule_doc.finance_book
|
je.finance_book = asset_depr_schedule_doc.finance_book
|
||||||
je.remark = f"Depreciation Entry against {asset.name} worth {depr_schedule.depreciation_amount}"
|
je.remark = _("Depreciation Entry against {0} worth {1}").format(
|
||||||
|
asset.name, depr_schedule.depreciation_amount
|
||||||
|
)
|
||||||
|
|
||||||
credit_entry = {
|
credit_entry = {
|
||||||
"account": credit_account,
|
"account": credit_account,
|
||||||
|
|||||||
@@ -346,6 +346,33 @@ class TestAsset(AssetSetup):
|
|||||||
si.cancel()
|
si.cancel()
|
||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||||
|
|
||||||
|
def test_asset_status_after_sales_invoice_cancel(self):
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
asset = create_asset(
|
||||||
|
calculate_depreciation=1,
|
||||||
|
available_for_use_date="2020-04-01",
|
||||||
|
purchase_date="2020-04-01",
|
||||||
|
expected_value_after_useful_life=0,
|
||||||
|
total_number_of_depreciations=5,
|
||||||
|
opening_number_of_booked_depreciations=2,
|
||||||
|
frequency_of_depreciation=12,
|
||||||
|
depreciation_start_date="2023-03-31",
|
||||||
|
opening_accumulated_depreciation=24000,
|
||||||
|
gross_purchase_amount=60000,
|
||||||
|
submit=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
si = create_sales_invoice(
|
||||||
|
item_code="Macbook Pro", asset=asset.name, qty=1, rate=40000, posting_date=getdate("2023-05-23")
|
||||||
|
)
|
||||||
|
asset.load_from_db()
|
||||||
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
|
||||||
|
|
||||||
|
si.cancel()
|
||||||
|
asset.load_from_db()
|
||||||
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||||
|
|
||||||
def test_gle_made_by_asset_sale_for_existing_asset(self):
|
def test_gle_made_by_asset_sale_for_existing_asset(self):
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
|||||||
@@ -98,20 +98,41 @@ class AssetDepreciationSchedule(Document):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
|
self.validate_asset()
|
||||||
self.db_set("status", "Active")
|
self.db_set("status", "Active")
|
||||||
|
|
||||||
def before_cancel(self):
|
def validate_asset(self):
|
||||||
|
asset = frappe.get_doc("Asset", self.asset)
|
||||||
|
if not asset.calculate_depreciation:
|
||||||
|
frappe.throw(
|
||||||
|
_("Asset {0} is not set to calculate depreciation.").format(
|
||||||
|
get_link_to_form("Asset", self.asset)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if asset.docstatus != 1:
|
||||||
|
frappe.throw(
|
||||||
|
_("Asset {0} is not submitted. Please submit the asset before proceeding.").format(
|
||||||
|
get_link_to_form("Asset", self.asset)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
self.db_set("status", "Cancelled")
|
||||||
if not self.flags.should_not_cancel_depreciation_entries:
|
if not self.flags.should_not_cancel_depreciation_entries:
|
||||||
self.cancel_depreciation_entries()
|
self.cancel_depreciation_entries()
|
||||||
|
|
||||||
def cancel_depreciation_entries(self):
|
def cancel_depreciation_entries(self):
|
||||||
for d in self.get("depreciation_schedule"):
|
for d in self.get("depreciation_schedule"):
|
||||||
if d.journal_entry:
|
if d.journal_entry:
|
||||||
|
je_status = frappe.db.get_value("Journal Entry", d.journal_entry, "docstatus")
|
||||||
|
if je_status == 0:
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Cannot cancel Asset Depreciation Schedule {0} as it has a draft journal entry {1}."
|
||||||
|
).format(self.name, d.journal_entry)
|
||||||
|
)
|
||||||
frappe.get_doc("Journal Entry", d.journal_entry).cancel()
|
frappe.get_doc("Journal Entry", d.journal_entry).cancel()
|
||||||
|
|
||||||
def on_cancel(self):
|
|
||||||
self.db_set("status", "Cancelled")
|
|
||||||
|
|
||||||
def update_shift_depr_schedule(self):
|
def update_shift_depr_schedule(self):
|
||||||
if not self.shift_based or self.docstatus != 0:
|
if not self.shift_based or self.docstatus != 0:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ frappe.listview_settings["Asset Maintenance Log"] = {
|
|||||||
has_indicator_for_draft: 1,
|
has_indicator_for_draft: 1,
|
||||||
get_indicator: function (doc) {
|
get_indicator: function (doc) {
|
||||||
if (doc.maintenance_status == "Planned") {
|
if (doc.maintenance_status == "Planned") {
|
||||||
return [__(doc.maintenance_status), "orange", "status,=," + doc.maintenance_status];
|
return [__(doc.maintenance_status), "orange", "maintenance_status,=," + doc.maintenance_status];
|
||||||
} else if (doc.maintenance_status == "Completed") {
|
} else if (doc.maintenance_status == "Completed") {
|
||||||
return [__(doc.maintenance_status), "green", "status,=," + doc.maintenance_status];
|
return [__(doc.maintenance_status), "green", "maintenance_status,=," + doc.maintenance_status];
|
||||||
} else if (doc.maintenance_status == "Cancelled") {
|
} else if (doc.maintenance_status == "Cancelled") {
|
||||||
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
|
return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
|
||||||
} else if (doc.maintenance_status == "Overdue") {
|
} else if (doc.maintenance_status == "Overdue") {
|
||||||
return [__(doc.maintenance_status), "red", "status,=," + doc.maintenance_status];
|
return [__(doc.maintenance_status), "red", "maintenance_status,=," + doc.maintenance_status];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -720,6 +720,7 @@ def close_or_unclose_purchase_orders(names, status):
|
|||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
target.run_method("set_missing_values")
|
target.run_method("set_missing_values")
|
||||||
target.run_method("calculate_taxes_and_totals")
|
target.run_method("calculate_taxes_and_totals")
|
||||||
|
target.run_method("set_use_serial_batch_fields")
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ def get_columns(filters):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Requestor"),
|
"label": _("Requestor"),
|
||||||
"options": "Employee",
|
"options": "User",
|
||||||
"fieldname": "requestor",
|
"fieldname": "requestor",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"width": 140,
|
"width": 140,
|
||||||
|
|||||||
@@ -153,7 +153,12 @@ class OpportunitySummaryBySalesStage:
|
|||||||
}[self.filters.get("based_on")]
|
}[self.filters.get("based_on")]
|
||||||
|
|
||||||
if self.filters.get("based_on") == "Opportunity Owner":
|
if self.filters.get("based_on") == "Opportunity Owner":
|
||||||
if d.get(based_on) == "[]" or d.get(based_on) is None or d.get(based_on) == "Not Assigned":
|
if (
|
||||||
|
d.get(based_on) == "[]"
|
||||||
|
or d.get(based_on) is None
|
||||||
|
or d.get(based_on) == "Not Assigned"
|
||||||
|
or d.get(based_on) == ""
|
||||||
|
):
|
||||||
assignments = ["Not Assigned"]
|
assignments = ["Not Assigned"]
|
||||||
else:
|
else:
|
||||||
assignments = json.loads(d.get(based_on))
|
assignments = json.loads(d.get(based_on))
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def import_genericode():
|
|||||||
"doctype": "File",
|
"doctype": "File",
|
||||||
"attached_to_doctype": "Code List",
|
"attached_to_doctype": "Code List",
|
||||||
"attached_to_name": code_list.name,
|
"attached_to_name": code_list.name,
|
||||||
"folder": "Home/Attachments",
|
"folder": frappe.db.get_value("File", {"is_attachments_folder": 1}),
|
||||||
"file_name": frappe.local.uploaded_filename,
|
"file_name": frappe.local.uploaded_filename,
|
||||||
"file_url": frappe.local.uploaded_file_url,
|
"file_url": frappe.local.uploaded_file_url,
|
||||||
"is_private": 1,
|
"is_private": 1,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
"fieldname": "hour_rate",
|
"fieldname": "hour_rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Hour Rate",
|
"label": "Hour Rate",
|
||||||
|
"non_negative": 1,
|
||||||
"oldfieldname": "hour_rate",
|
"oldfieldname": "hour_rate",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
@@ -78,6 +79,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Operation Time",
|
"label": "Operation Time",
|
||||||
|
"non_negative": 1,
|
||||||
"oldfieldname": "time_in_mins",
|
"oldfieldname": "time_in_mins",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
@@ -194,7 +196,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-11-04 17:17:16.986941",
|
"modified": "2025-07-31 16:17:47.287117",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM Operation",
|
"name": "BOM Operation",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Qty",
|
"label": "Qty",
|
||||||
|
"non_negative": 1,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -49,6 +50,7 @@
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Rate",
|
"label": "Rate",
|
||||||
|
"non_negative": 1,
|
||||||
"options": "currency"
|
"options": "currency"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -92,7 +94,7 @@
|
|||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-01-03 14:19:28.460965",
|
"modified": "2025-07-31 16:21:44.047007",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM Scrap Item",
|
"name": "BOM Scrap Item",
|
||||||
@@ -103,4 +105,4 @@
|
|||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": [],
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@
|
|||||||
"fieldname": "total_completed_qty",
|
"fieldname": "total_completed_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Total Completed Qty",
|
"label": "Total Completed Qty",
|
||||||
|
"non_negative": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -510,7 +511,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-03-17 15:55:11.143456",
|
"modified": "2025-08-04 15:47:54.514290",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Job Card",
|
"name": "Job Card",
|
||||||
@@ -568,4 +569,4 @@
|
|||||||
"states": [],
|
"states": [],
|
||||||
"title_field": "operation",
|
"title_field": "operation",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-14 01:20:48.588052",
|
"modified": "2025-07-29 13:09:57.323835",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Job Card Scrap Item",
|
"name": "Job Card Scrap Item",
|
||||||
@@ -80,4 +80,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,8 @@
|
|||||||
"fieldname": "completed_qty",
|
"fieldname": "completed_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Completed Qty"
|
"label": "Completed Qty",
|
||||||
|
"non_negative": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-05-21 12:40:55.765860",
|
"modified": "2025-08-04 15:47:11.748937",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Job Card Time Log",
|
"name": "Job Card Time Log",
|
||||||
|
|||||||
@@ -70,7 +70,8 @@
|
|||||||
"fieldname": "batch_size",
|
"fieldname": "batch_size",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Batch Size",
|
"label": "Batch Size",
|
||||||
"mandatory_depends_on": "create_job_card_based_on_batch_size"
|
"mandatory_depends_on": "create_job_card_based_on_batch_size",
|
||||||
|
"non_negative": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
"icon": "fa fa-wrench",
|
"icon": "fa fa-wrench",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-11-24 19:15:24.357187",
|
"modified": "2025-08-04 16:14:57.659318",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Operation",
|
"name": "Operation",
|
||||||
@@ -137,4 +138,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
"fieldname": "time_in_mins",
|
"fieldname": "time_in_mins",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Operation Time"
|
"label": "Operation Time",
|
||||||
|
"non_negative": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_5",
|
"fieldname": "column_break_5",
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-07-15 16:39:41.635362",
|
"modified": "2025-08-04 16:15:11.425349",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Sub Operation",
|
"name": "Sub Operation",
|
||||||
@@ -49,4 +50,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,8 +356,8 @@ erpnext.patches.v14_0.create_accounting_dimensions_in_supplier_quotation
|
|||||||
erpnext.patches.v14_0.update_zero_asset_quantity_field
|
erpnext.patches.v14_0.update_zero_asset_quantity_field
|
||||||
execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction")
|
execute:frappe.db.set_single_value("Buying Settings", "project_update_frequency", "Each Transaction")
|
||||||
erpnext.patches.v14_0.update_total_asset_cost_field
|
erpnext.patches.v14_0.update_total_asset_cost_field
|
||||||
|
erpnext.patches.v15_0.allow_on_submit_dimensions_for_repostable_doctypes #2025-06-19
|
||||||
erpnext.patches.v14_0.create_accounting_dimensions_in_reconciliation_tool
|
erpnext.patches.v14_0.create_accounting_dimensions_in_reconciliation_tool
|
||||||
erpnext.patches.v15_0.allow_on_submit_dimensions_for_repostable_doctypes
|
|
||||||
erpnext.patches.v14_0.update_flag_for_return_invoices #2024-03-22
|
erpnext.patches.v14_0.update_flag_for_return_invoices #2024-03-22
|
||||||
erpnext.patches.v15_0.create_accounting_dimensions_in_payment_request
|
erpnext.patches.v15_0.create_accounting_dimensions_in_payment_request
|
||||||
erpnext.patches.v14_0.update_pos_return_ledger_entries #2024-08-16
|
erpnext.patches.v14_0.update_pos_return_ledger_entries #2024-08-16
|
||||||
@@ -416,5 +416,6 @@ erpnext.patches.v15_0.update_payment_ledger_entries_against_advance_doctypes
|
|||||||
erpnext.patches.v15_0.rename_price_list_to_buying_price_list
|
erpnext.patches.v15_0.rename_price_list_to_buying_price_list
|
||||||
erpnext.patches.v15_0.patch_missing_buying_price_list_in_material_request
|
erpnext.patches.v15_0.patch_missing_buying_price_list_in_material_request
|
||||||
erpnext.patches.v15_0.remove_sales_partner_from_consolidated_sales_invoice
|
erpnext.patches.v15_0.remove_sales_partner_from_consolidated_sales_invoice
|
||||||
erpnext.patches.v15_0.repost_gl_entries_with_no_account_subcontracting #2025-07-31
|
erpnext.patches.v15_0.repost_gl_entries_with_no_account_subcontracting #2025-08-04
|
||||||
execute:frappe.db.set_single_value("Accounts Settings", "fetch_valuation_rate_for_internal_transaction", 1)
|
execute:frappe.db.set_single_value("Accounts Settings", "fetch_valuation_rate_for_internal_transaction", 1)
|
||||||
|
erpnext.patches.v15_0.add_company_payment_gateway_account
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
for gateway_account in frappe.get_list("Payment Gateway Account", fields=["name", "payment_account"]):
|
||||||
|
company = frappe.db.get_value("Account", gateway_account.payment_account, "company")
|
||||||
|
frappe.db.set_value("Payment Gateway Account", gateway_account.name, "company", company)
|
||||||
@@ -9,6 +9,6 @@ from erpnext.accounts.doctype.repost_accounting_ledger.repost_accounting_ledger
|
|||||||
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
for dt in get_allowed_types_from_settings():
|
for dt in get_allowed_types_from_settings(child_doc=True):
|
||||||
for dimension in get_accounting_dimensions():
|
for dimension in get_accounting_dimensions():
|
||||||
frappe.db.set_value("Custom Field", dt + "-" + dimension, "allow_on_submit", 1)
|
frappe.db.set_value("Custom Field", dt + "-" + dimension, "allow_on_submit", 1)
|
||||||
|
|||||||
@@ -2,24 +2,31 @@ import frappe
|
|||||||
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
def cancel_incorrect_gl_entries(gl_entries):
|
||||||
|
table = frappe.qb.DocType("GL Entry")
|
||||||
|
frappe.qb.update(table).set(table.is_cancelled, 1).where(table.name.isin(gl_entries)).run()
|
||||||
|
|
||||||
|
def recreate_gl_entries(voucher_nos):
|
||||||
|
for doc in voucher_nos:
|
||||||
|
doc = frappe.get_doc("Subcontracting Receipt", doc)
|
||||||
|
for item in doc.supplied_items:
|
||||||
|
account, cost_center = frappe.db.get_values(
|
||||||
|
"Subcontracting Receipt Item", item.reference_name, ["expense_account", "cost_center"]
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
if not item.expense_account:
|
||||||
|
item.db_set("expense_account", account)
|
||||||
|
if not item.cost_center:
|
||||||
|
item.db_set("cost_center", cost_center)
|
||||||
|
|
||||||
|
doc.make_gl_entries()
|
||||||
|
|
||||||
docs = frappe.get_all(
|
docs = frappe.get_all(
|
||||||
"GL Entry",
|
"GL Entry",
|
||||||
|
fields=["name", "voucher_no"],
|
||||||
filters={"voucher_type": "Subcontracting Receipt", "account": ["is", "not set"], "is_cancelled": 0},
|
filters={"voucher_type": "Subcontracting Receipt", "account": ["is", "not set"], "is_cancelled": 0},
|
||||||
pluck="voucher_no",
|
|
||||||
)
|
)
|
||||||
for doc in docs:
|
|
||||||
doc = frappe.get_doc("Subcontracting Receipt", doc)
|
|
||||||
for item in doc.supplied_items:
|
|
||||||
account, cost_center = frappe.db.get_values(
|
|
||||||
"Subcontracting Receipt Item", item.reference_name, ["expense_account", "cost_center"]
|
|
||||||
)[0]
|
|
||||||
|
|
||||||
if not item.expense_account:
|
if docs:
|
||||||
item.db_set("expense_account", account)
|
cancel_incorrect_gl_entries([d.name for d in docs])
|
||||||
if not item.cost_center:
|
recreate_gl_entries([d.voucher_no for d in docs])
|
||||||
item.db_set("cost_center", cost_center)
|
|
||||||
|
|
||||||
doc.docstatus = 2
|
|
||||||
doc.make_gl_entries_on_cancel()
|
|
||||||
doc.docstatus = 1
|
|
||||||
doc.make_gl_entries()
|
|
||||||
@@ -14,5 +14,6 @@ def get_data():
|
|||||||
{"label": _("Material"), "items": ["Material Request", "BOM", "Stock Entry"]},
|
{"label": _("Material"), "items": ["Material Request", "BOM", "Stock Entry"]},
|
||||||
{"label": _("Sales"), "items": ["Sales Order", "Delivery Note", "Sales Invoice"]},
|
{"label": _("Sales"), "items": ["Sales Order", "Delivery Note", "Sales Invoice"]},
|
||||||
{"label": _("Purchase"), "items": ["Purchase Order", "Purchase Receipt", "Purchase Invoice"]},
|
{"label": _("Purchase"), "items": ["Purchase Order", "Purchase Receipt", "Purchase Invoice"]},
|
||||||
|
{"label": _("Manufacture"), "items": ["Work Order"]},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -928,15 +928,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
async set_default_payment(total_amount_to_pay, update_paid_amount) {
|
set_default_payment(total_amount_to_pay, update_paid_amount) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var payment_status = true;
|
var payment_status = true;
|
||||||
if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) {
|
if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) {
|
||||||
let r = await frappe.db.get_value("POS Profile", this.frm.doc.pos_profile, "disable_grand_total_to_default_mop");
|
|
||||||
|
|
||||||
if (r.message.disable_grand_total_to_default_mop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.each(this.frm.doc['payments'] || [], function(index, data) {
|
$.each(this.frm.doc['payments'] || [], function(index, data) {
|
||||||
if(data.default && payment_status && total_amount_to_pay > 0) {
|
if(data.default && payment_status && total_amount_to_pay > 0) {
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
init_payments() {
|
init_payments() {
|
||||||
this.payment = new erpnext.PointOfSale.Payment({
|
this.payment = new erpnext.PointOfSale.Payment({
|
||||||
wrapper: this.$components_wrapper,
|
wrapper: this.$components_wrapper,
|
||||||
|
settings: this.settings,
|
||||||
events: {
|
events: {
|
||||||
get_frm: () => this.frm || {},
|
get_frm: () => this.frm || {},
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
erpnext.PointOfSale.Payment = class {
|
erpnext.PointOfSale.Payment = class {
|
||||||
constructor({ events, wrapper }) {
|
constructor({ events, settings, wrapper }) {
|
||||||
this.wrapper = wrapper;
|
this.wrapper = wrapper;
|
||||||
this.events = events;
|
this.events = events;
|
||||||
|
this.disable_grand_total_to_default_mop = settings.disable_grand_total_to_default_mop;
|
||||||
|
|
||||||
this.init_component();
|
this.init_component();
|
||||||
}
|
}
|
||||||
@@ -341,10 +342,11 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render_payment_section() {
|
render_payment_section() {
|
||||||
|
this.remove_grand_total_from_default_mop();
|
||||||
this.render_payment_mode_dom();
|
this.render_payment_mode_dom();
|
||||||
this.make_invoice_fields_control();
|
this.make_invoice_fields_control();
|
||||||
this.update_totals_section();
|
this.update_totals_section();
|
||||||
this.unset_grand_total_to_default_mop();
|
this.focus_on_default_mop();
|
||||||
}
|
}
|
||||||
|
|
||||||
after_render() {
|
after_render() {
|
||||||
@@ -446,7 +448,19 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
this.attach_cash_shortcuts(doc);
|
this.attach_cash_shortcuts(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove_grand_total_from_default_mop() {
|
||||||
|
if (!this.disable_grand_total_to_default_mop) return;
|
||||||
|
const doc = this.events.get_frm().doc;
|
||||||
|
const payments = doc.payments;
|
||||||
|
payments.forEach((p) => {
|
||||||
|
if (p.default) {
|
||||||
|
frappe.model.set_value(p.doctype, p.name, "amount", 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
focus_on_default_mop() {
|
focus_on_default_mop() {
|
||||||
|
if (this.disable_grand_total_to_default_mop) return;
|
||||||
const doc = this.events.get_frm().doc;
|
const doc = this.events.get_frm().doc;
|
||||||
const payments = doc.payments;
|
const payments = doc.payments;
|
||||||
payments.forEach((p) => {
|
payments.forEach((p) => {
|
||||||
@@ -629,19 +643,6 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
async unset_grand_total_to_default_mop() {
|
|
||||||
const doc = this.events.get_frm().doc;
|
|
||||||
let r = await frappe.db.get_value(
|
|
||||||
"POS Profile",
|
|
||||||
doc.pos_profile,
|
|
||||||
"disable_grand_total_to_default_mop"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!r.message.disable_grand_total_to_default_mop) {
|
|
||||||
this.focus_on_default_mop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_reqd_invoice_fields() {
|
validate_reqd_invoice_fields() {
|
||||||
const doc = this.events.get_frm().doc;
|
const doc = this.events.get_frm().doc;
|
||||||
let validation_flag = true;
|
let validation_flag = true;
|
||||||
|
|||||||
@@ -258,6 +258,7 @@
|
|||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Posting Time",
|
"label": "Posting Time",
|
||||||
@@ -1395,7 +1396,7 @@
|
|||||||
"idx": 146,
|
"idx": 146,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-11-26 12:44:28.258215",
|
"modified": "2025-08-04 19:20:47.724218",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note",
|
"name": "Delivery Note",
|
||||||
@@ -1486,6 +1487,7 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "status,customer,customer_name, territory,base_grand_total",
|
"search_fields": "status,customer,customer_name, territory,base_grand_total",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
@@ -1495,4 +1497,4 @@
|
|||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 1
|
"track_seen": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ class DeliveryNote(SellingController):
|
|||||||
per_billed: DF.Percent
|
per_billed: DF.Percent
|
||||||
per_installed: DF.Percent
|
per_installed: DF.Percent
|
||||||
per_returned: DF.Percent
|
per_returned: DF.Percent
|
||||||
pick_list: DF.Link | None
|
|
||||||
plc_conversion_rate: DF.Float
|
plc_conversion_rate: DF.Float
|
||||||
po_date: DF.Date | None
|
po_date: DF.Date | None
|
||||||
po_no: DF.SmallText | None
|
po_no: DF.SmallText | None
|
||||||
|
|||||||
@@ -243,6 +243,7 @@
|
|||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Posting Time",
|
"label": "Posting Time",
|
||||||
@@ -1290,7 +1291,7 @@
|
|||||||
"idx": 261,
|
"idx": 261,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-04-09 16:52:19.323878",
|
"modified": "2025-08-04 19:18:47.754957",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt",
|
"name": "Purchase Receipt",
|
||||||
@@ -1360,4 +1361,4 @@
|
|||||||
"timeline_field": "supplier",
|
"timeline_field": "supplier",
|
||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class SerialandBatchBundle(Document):
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif not frappe.db.exists("Stock Ledger Entry", {"voucher_detail_no": self.voucher_detail_no}):
|
elif not frappe.db.exists("Stock Ledger Entry", {"voucher_detail_no": self.voucher_detail_no}):
|
||||||
if self.voucher_type == "Delivery Note" and frappe.db.exists(
|
if self.voucher_type in ["Delivery Note", "Sales Invoice"] and frappe.db.exists(
|
||||||
"Packed Item", self.voucher_detail_no
|
"Packed Item", self.voucher_detail_no
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -218,6 +218,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Posting Time",
|
"label": "Posting Time",
|
||||||
@@ -697,7 +698,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-08-13 19:05:42.386955",
|
"modified": "2025-08-04 19:21:03.338958",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Entry",
|
"name": "Stock Entry",
|
||||||
@@ -763,6 +764,7 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "posting_date, from_warehouse, to_warehouse, purpose, remarks",
|
"search_fields": "posting_date, from_warehouse, to_warehouse, purpose, remarks",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
@@ -770,4 +772,4 @@
|
|||||||
"states": [],
|
"states": [],
|
||||||
"title_field": "stock_entry_type",
|
"title_field": "stock_entry_type",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "Now",
|
||||||
"fieldname": "posting_time",
|
"fieldname": "posting_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@@ -183,7 +184,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-05-11 09:10:26.327652",
|
"modified": "2025-08-04 19:21:20.179658",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Reconciliation",
|
"name": "Stock Reconciliation",
|
||||||
@@ -203,9 +204,10 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "posting_date",
|
"search_fields": "posting_date",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": []
|
"states": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1287,12 +1287,12 @@ def get_conversion_factor(item_code, uom):
|
|||||||
|
|
||||||
if variant_of:
|
if variant_of:
|
||||||
filters["parent"] = ("in", (item_code, variant_of))
|
filters["parent"] = ("in", (item_code, variant_of))
|
||||||
conversion_factor = frappe.db.get_value("UOM Conversion Detail", filters, "conversion_factor")
|
conversion_factor = frappe.get_all("UOM Conversion Detail", filters, pluck="conversion_factor")
|
||||||
if not conversion_factor:
|
if not conversion_factor:
|
||||||
stock_uom = frappe.db.get_value("Item", item_code, "stock_uom")
|
stock_uom = frappe.db.get_value("Item", item_code, "stock_uom")
|
||||||
conversion_factor = get_uom_conv_factor(uom, stock_uom)
|
conversion_factor = [get_uom_conv_factor(uom, stock_uom) or 1]
|
||||||
|
|
||||||
return {"conversion_factor": conversion_factor or 1.0}
|
return {"conversion_factor": conversion_factor[-1]}
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
Reference in New Issue
Block a user