mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-09 08:11:19 +00:00
Merge branch 'develop' into version-15-beta
This commit is contained in:
8
.github/workflows/server-tests-mariadb.yml
vendored
8
.github/workflows/server-tests-mariadb.yml
vendored
@@ -7,11 +7,9 @@ on:
|
||||
- '**.css'
|
||||
- '**.md'
|
||||
- '**.html'
|
||||
push:
|
||||
branches: [ develop ]
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
- '**.md'
|
||||
schedule:
|
||||
# Run everday at midnight UTC / 5:30 IST
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
user:
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
"creation": "2020-07-17 11:25:34.593061",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"to_fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"erpnext.utils.get_fiscal_year()\",\"to_fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"period\":\"Monthly\",\"budget_against\":\"Cost Center\",\"show_cumulative\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:24:49.144210",
|
||||
"modified": "2023-07-19 13:13:13.307073",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Budget Variance",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Budget Variance Report",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
"creation": "2020-07-17 11:25:34.448572",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"frappe.sys_defaults.fiscal_year\",\"to_fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_fiscal_year\":\"erpnext.utils.get_fiscal_year()\",\"to_fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"filter_based_on\":\"Fiscal Year\",\"period_start_date\":\"2020-04-01\",\"period_end_date\":\"2021-03-31\",\"periodicity\":\"Yearly\",\"include_default_book_entries\":1}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:33:48.888943",
|
||||
"modified": "2023-07-19 13:08:56.470390",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Profit and Loss",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Profit and Loss Statement",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -14,10 +14,8 @@ class AccountClosingBalance(Document):
|
||||
pass
|
||||
|
||||
|
||||
def make_closing_entries(closing_entries, voucher_name):
|
||||
def make_closing_entries(closing_entries, voucher_name, company, closing_date):
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
company = closing_entries[0].get("company")
|
||||
closing_date = closing_entries[0].get("closing_date")
|
||||
|
||||
previous_closing_entries = get_previous_closing_entries(
|
||||
company, closing_date, accounting_dimensions
|
||||
|
||||
@@ -20,5 +20,11 @@ frappe.ui.form.on('Accounting Period', {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
frm.set_query("document_type", "closed_documents", () => {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_doctypes_for_closing",
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,6 +11,10 @@ class OverlapError(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class ClosedAccountingPeriod(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class AccountingPeriod(Document):
|
||||
def validate(self):
|
||||
self.validate_overlap()
|
||||
@@ -65,3 +69,42 @@ class AccountingPeriod(Document):
|
||||
"closed_documents",
|
||||
{"document_type": doctype_for_closing.document_type, "closed": doctype_for_closing.closed},
|
||||
)
|
||||
|
||||
|
||||
def validate_accounting_period_on_doc_save(doc, method=None):
|
||||
if doc.doctype == "Bank Clearance":
|
||||
return
|
||||
elif doc.doctype == "Asset":
|
||||
if doc.is_existing_asset:
|
||||
return
|
||||
else:
|
||||
date = doc.available_for_use_date
|
||||
elif doc.doctype == "Asset Repair":
|
||||
date = doc.completion_date
|
||||
else:
|
||||
date = doc.posting_date
|
||||
|
||||
ap = frappe.qb.DocType("Accounting Period")
|
||||
cd = frappe.qb.DocType("Closed Document")
|
||||
|
||||
accounting_period = (
|
||||
frappe.qb.from_(ap)
|
||||
.from_(cd)
|
||||
.select(ap.name)
|
||||
.where(
|
||||
(ap.name == cd.parent)
|
||||
& (ap.company == doc.company)
|
||||
& (cd.closed == 1)
|
||||
& (cd.document_type == doc.doctype)
|
||||
& (date >= ap.start_date)
|
||||
& (date <= ap.end_date)
|
||||
)
|
||||
).run(as_dict=1)
|
||||
|
||||
if accounting_period:
|
||||
frappe.throw(
|
||||
_("You cannot create a {0} within the closed Accounting Period {1}").format(
|
||||
doc.doctype, frappe.bold(accounting_period[0]["name"])
|
||||
),
|
||||
ClosedAccountingPeriod,
|
||||
)
|
||||
|
||||
@@ -6,9 +6,11 @@ import unittest
|
||||
import frappe
|
||||
from frappe.utils import add_months, nowdate
|
||||
|
||||
from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
|
||||
from erpnext.accounts.doctype.accounting_period.accounting_period import (
|
||||
ClosedAccountingPeriod,
|
||||
OverlapError,
|
||||
)
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
from erpnext.accounts.general_ledger import ClosedAccountingPeriod
|
||||
|
||||
test_dependencies = ["Item"]
|
||||
|
||||
@@ -33,9 +35,9 @@ class TestAccountingPeriod(unittest.TestCase):
|
||||
ap1.save()
|
||||
|
||||
doc = create_sales_invoice(
|
||||
do_not_submit=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC"
|
||||
do_not_save=1, cost_center="_Test Company - _TC", warehouse="Stores - _TC"
|
||||
)
|
||||
self.assertRaises(ClosedAccountingPeriod, doc.submit)
|
||||
self.assertRaises(ClosedAccountingPeriod, doc.save)
|
||||
|
||||
def tearDown(self):
|
||||
for d in frappe.get_all("Accounting Period"):
|
||||
|
||||
@@ -8,17 +8,6 @@ frappe.ui.form.on('Fiscal Year', {
|
||||
frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1));
|
||||
}
|
||||
},
|
||||
refresh: function (frm) {
|
||||
if (!frm.doc.__islocal && (frm.doc.name != frappe.sys_defaults.fiscal_year)) {
|
||||
frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
|
||||
frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
|
||||
} else {
|
||||
frm.set_intro("");
|
||||
}
|
||||
},
|
||||
set_as_default: function(frm) {
|
||||
return frm.call('set_as_default');
|
||||
},
|
||||
year_start_date: function(frm) {
|
||||
if (!frm.doc.is_short_year) {
|
||||
let year_end_date =
|
||||
|
||||
@@ -4,28 +4,12 @@
|
||||
|
||||
import frappe
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from frappe import _, msgprint
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import add_days, add_years, cstr, getdate
|
||||
|
||||
|
||||
class FiscalYear(Document):
|
||||
@frappe.whitelist()
|
||||
def set_as_default(self):
|
||||
frappe.db.set_single_value("Global Defaults", "current_fiscal_year", self.name)
|
||||
global_defaults = frappe.get_doc("Global Defaults")
|
||||
global_defaults.check_permission("write")
|
||||
global_defaults.on_update()
|
||||
|
||||
# clear cache
|
||||
frappe.clear_cache()
|
||||
|
||||
msgprint(
|
||||
_(
|
||||
"{0} is now the default Fiscal Year. Please refresh your browser for the change to take effect."
|
||||
).format(self.name)
|
||||
)
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
self.validate_overlap()
|
||||
@@ -68,13 +52,6 @@ class FiscalYear(Document):
|
||||
frappe.cache().delete_value("fiscal_years")
|
||||
|
||||
def on_trash(self):
|
||||
global_defaults = frappe.get_doc("Global Defaults")
|
||||
if global_defaults.current_fiscal_year == self.name:
|
||||
frappe.throw(
|
||||
_(
|
||||
"You cannot delete Fiscal Year {0}. Fiscal Year {0} is set as default in Global Settings"
|
||||
).format(self.name)
|
||||
)
|
||||
frappe.cache().delete_value("fiscal_years")
|
||||
|
||||
def validate_overlap(self):
|
||||
|
||||
@@ -408,6 +408,15 @@ class JournalEntry(AccountsController):
|
||||
d.idx, d.account
|
||||
)
|
||||
)
|
||||
elif (
|
||||
d.party_type
|
||||
and frappe.db.get_value("Party Type", d.party_type, "account_type") != account_type
|
||||
):
|
||||
frappe.throw(
|
||||
_("Row {0}: Account {1} and Party Type {2} have different account types").format(
|
||||
d.idx, d.account, d.party_type
|
||||
)
|
||||
)
|
||||
|
||||
def check_credit_limit(self):
|
||||
customers = list(
|
||||
|
||||
@@ -226,10 +226,12 @@ class PaymentEntry(AccountsController):
|
||||
latest_lookup = {}
|
||||
for d in latest_references:
|
||||
d = frappe._dict(d)
|
||||
latest_lookup.update({(d.voucher_type, d.voucher_no): d})
|
||||
latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
|
||||
|
||||
for d in self.get("references"):
|
||||
latest = latest_lookup.get((d.reference_doctype, d.reference_name))
|
||||
latest = (latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()).get(
|
||||
d.payment_term
|
||||
)
|
||||
|
||||
# The reference has already been fully paid
|
||||
if not latest:
|
||||
@@ -251,6 +253,18 @@ class PaymentEntry(AccountsController):
|
||||
if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
|
||||
frappe.throw(fail_message.format(d.idx))
|
||||
|
||||
if d.payment_term and (
|
||||
(flt(d.allocated_amount)) > 0
|
||||
and flt(d.allocated_amount) > flt(latest.payment_term_outstanding)
|
||||
):
|
||||
frappe.throw(
|
||||
_(
|
||||
"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
|
||||
).format(
|
||||
d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
|
||||
)
|
||||
)
|
||||
|
||||
# Check for negative outstanding invoices as well
|
||||
if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
|
||||
frappe.throw(fail_message.format(d.idx))
|
||||
@@ -1500,7 +1514,9 @@ def get_outstanding_reference_documents(args, validate=False):
|
||||
accounting_dimensions=accounting_dimensions_filter,
|
||||
)
|
||||
|
||||
outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices)
|
||||
outstanding_invoices = split_invoices_based_on_payment_terms(
|
||||
outstanding_invoices, args.get("company")
|
||||
)
|
||||
|
||||
for d in outstanding_invoices:
|
||||
d["exchange_rate"] = 1
|
||||
@@ -1560,8 +1576,27 @@ def get_outstanding_reference_documents(args, validate=False):
|
||||
return data
|
||||
|
||||
|
||||
def split_invoices_based_on_payment_terms(outstanding_invoices):
|
||||
def split_invoices_based_on_payment_terms(outstanding_invoices, company):
|
||||
invoice_ref_based_on_payment_terms = {}
|
||||
|
||||
company_currency = (
|
||||
frappe.db.get_value("Company", company, "default_currency") if company else None
|
||||
)
|
||||
exc_rates = frappe._dict()
|
||||
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||
invoices = [x.voucher_no for x in outstanding_invoices if x.voucher_type == doctype]
|
||||
for x in frappe.db.get_all(
|
||||
doctype,
|
||||
filters={"name": ["in", invoices]},
|
||||
fields=["name", "currency", "conversion_rate", "party_account_currency"],
|
||||
):
|
||||
exc_rates[x.name] = frappe._dict(
|
||||
conversion_rate=x.conversion_rate,
|
||||
currency=x.currency,
|
||||
party_account_currency=x.party_account_currency,
|
||||
company_currency=company_currency,
|
||||
)
|
||||
|
||||
for idx, d in enumerate(outstanding_invoices):
|
||||
if d.voucher_type in ["Sales Invoice", "Purchase Invoice"]:
|
||||
payment_term_template = frappe.db.get_value(
|
||||
@@ -1578,6 +1613,14 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
|
||||
|
||||
for payment_term in payment_schedule:
|
||||
if payment_term.outstanding > 0.1:
|
||||
doc_details = exc_rates.get(payment_term.parent, None)
|
||||
is_multi_currency_acc = (doc_details.currency != doc_details.company_currency) and (
|
||||
doc_details.party_account_currency != doc_details.company_currency
|
||||
)
|
||||
payment_term_outstanding = flt(payment_term.outstanding)
|
||||
if not is_multi_currency_acc:
|
||||
payment_term_outstanding = doc_details.conversion_rate * flt(payment_term.outstanding)
|
||||
|
||||
invoice_ref_based_on_payment_terms.setdefault(idx, [])
|
||||
invoice_ref_based_on_payment_terms[idx].append(
|
||||
frappe._dict(
|
||||
@@ -1589,6 +1632,7 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
|
||||
"posting_date": d.posting_date,
|
||||
"invoice_amount": flt(d.invoice_amount),
|
||||
"outstanding_amount": flt(d.outstanding_amount),
|
||||
"payment_term_outstanding": payment_term_outstanding,
|
||||
"payment_amount": payment_term.payment_amount,
|
||||
"payment_term": payment_term.payment_term,
|
||||
"account": d.account,
|
||||
@@ -2371,6 +2415,7 @@ def get_reference_as_per_payment_terms(
|
||||
"due_date": doc.get("due_date"),
|
||||
"total_amount": grand_total,
|
||||
"outstanding_amount": outstanding_amount,
|
||||
"payment_term_outstanding": payment_term_outstanding,
|
||||
"payment_term": payment_term.payment_term,
|
||||
"allocated_amount": payment_term_outstanding,
|
||||
}
|
||||
|
||||
@@ -133,6 +133,8 @@ class PeriodClosingVoucher(AccountsController):
|
||||
gl_entries=gl_entries,
|
||||
closing_entries=closing_entries,
|
||||
voucher_name=self.name,
|
||||
company=self.company,
|
||||
closing_date=self.posting_date,
|
||||
queue="long",
|
||||
)
|
||||
frappe.msgprint(
|
||||
@@ -140,7 +142,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
alert=True,
|
||||
)
|
||||
else:
|
||||
process_gl_entries(gl_entries, closing_entries, voucher_name=self.name)
|
||||
process_gl_entries(gl_entries, closing_entries, self.name, self.company, self.posting_date)
|
||||
|
||||
def get_grouped_gl_entries(self, get_opening_entries=False):
|
||||
closing_entries = []
|
||||
@@ -321,7 +323,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
return query.run(as_dict=1)
|
||||
|
||||
|
||||
def process_gl_entries(gl_entries, closing_entries, voucher_name=None):
|
||||
def process_gl_entries(gl_entries, closing_entries, voucher_name, company, closing_date):
|
||||
from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
|
||||
make_closing_entries,
|
||||
)
|
||||
@@ -329,7 +331,7 @@ def process_gl_entries(gl_entries, closing_entries, voucher_name=None):
|
||||
|
||||
try:
|
||||
make_gl_entries(gl_entries, merge_entries=False)
|
||||
make_closing_entries(gl_entries + closing_entries, voucher_name=voucher_name)
|
||||
make_closing_entries(gl_entries + closing_entries, voucher_name, company, closing_date)
|
||||
frappe.db.set_value(
|
||||
"Period Closing Voucher", gl_entries[0].get("voucher_no"), "gle_processing_status", "Completed"
|
||||
)
|
||||
|
||||
@@ -13,14 +13,11 @@ import erpnext
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_accounting_dimensions,
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
class ClosedAccountingPeriod(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
def make_gl_entries(
|
||||
gl_map,
|
||||
cancel=False,
|
||||
|
||||
@@ -49,7 +49,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"label": __("Start Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
on_change: () => {
|
||||
frappe.model.with_doc("Fiscal Year", frappe.query_report.get_filter_value('from_fiscal_year'), function(r) {
|
||||
@@ -65,7 +65,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"label": __("End Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
on_change: () => {
|
||||
frappe.model.with_doc("Fiscal Year", frappe.query_report.get_filter_value('to_fiscal_year'), function(r) {
|
||||
@@ -139,7 +139,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
return value;
|
||||
},
|
||||
onload: function() {
|
||||
let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
|
||||
let fiscal_year = erpnext.utils.get_fiscal_year(frappe.datetime.get_today());
|
||||
|
||||
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
|
||||
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
|
||||
|
||||
@@ -48,7 +48,7 @@ function get_filters() {
|
||||
"label": __("Start Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -56,7 +56,7 @@ function get_filters() {
|
||||
"label": __("End Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -100,7 +100,7 @@ frappe.query_reports["Deferred Revenue and Expense"] = {
|
||||
return default_formatter(value, row, column, data);
|
||||
},
|
||||
onload: function(report){
|
||||
let fiscal_year = frappe.defaults.get_user_default("fiscal_year");
|
||||
let fiscal_year = erpnext.utils.get_fiscal_year(frappe.datetime.get_today());
|
||||
|
||||
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
|
||||
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
import frappe
|
||||
from frappe import _, qb
|
||||
from frappe.query_builder import Column, functions
|
||||
from frappe.utils import add_days, date_diff, flt, get_first_day, get_last_day, rounded
|
||||
from frappe.utils import add_days, date_diff, flt, get_first_day, get_last_day, getdate, rounded
|
||||
|
||||
from erpnext.accounts.report.financial_statements import get_period_list
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
|
||||
class Deferred_Item(object):
|
||||
@@ -226,7 +227,7 @@ class Deferred_Revenue_and_Expense_Report(object):
|
||||
|
||||
# If no filters are provided, get user defaults
|
||||
if not filters:
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", frappe.defaults.get_user_default("fiscal_year"))
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date=getdate()))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
|
||||
@@ -10,6 +10,7 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
|
||||
from erpnext.accounts.report.deferred_revenue_and_expense.deferred_revenue_and_expense import (
|
||||
Deferred_Revenue_and_Expense_Report,
|
||||
)
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
|
||||
@@ -116,7 +117,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
pda.submit()
|
||||
|
||||
# execute report
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", frappe.defaults.get_user_default("fiscal_year"))
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
@@ -209,7 +210,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
pda.submit()
|
||||
|
||||
# execute report
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", frappe.defaults.get_user_default("fiscal_year"))
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
@@ -297,7 +298,7 @@ class TestDeferredRevenueAndExpense(unittest.TestCase):
|
||||
pda.submit()
|
||||
|
||||
# execute report
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", frappe.defaults.get_user_default("fiscal_year"))
|
||||
fiscal_year = frappe.get_doc("Fiscal Year", get_fiscal_year(date="2021-05-01"))
|
||||
self.filters = frappe._dict(
|
||||
{
|
||||
"company": frappe.defaults.get_user_default("Company"),
|
||||
|
||||
@@ -18,7 +18,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"on_change": function(query_report) {
|
||||
var fiscal_year = query_report.get_values().fiscal_year;
|
||||
|
||||
@@ -25,7 +25,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"on_change": function(query_report) {
|
||||
var fiscal_year = query_report.get_values().fiscal_year;
|
||||
|
||||
@@ -17,7 +17,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"on_change": function(query_report) {
|
||||
var fiscal_year = query_report.get_values().fiscal_year;
|
||||
|
||||
@@ -221,7 +221,10 @@ def get_opening_balance(
|
||||
)
|
||||
else:
|
||||
if start_date:
|
||||
opening_balance = opening_balance.where(closing_balance.posting_date >= start_date)
|
||||
opening_balance = opening_balance.where(
|
||||
(closing_balance.posting_date >= start_date)
|
||||
& (closing_balance.posting_date < filters.from_date)
|
||||
)
|
||||
opening_balance = opening_balance.where(closing_balance.is_opening == "No")
|
||||
else:
|
||||
opening_balance = opening_balance.where(
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Trial Balance for Party"] = {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"on_change": function(query_report) {
|
||||
var fiscal_year = query_report.get_values().fiscal_year;
|
||||
|
||||
@@ -1110,6 +1110,11 @@ def get_autoname_with_number(number_value, doc_title, company):
|
||||
return " - ".join(parts)
|
||||
|
||||
|
||||
def parse_naming_series_variable(doc, variable):
|
||||
if variable == "FY":
|
||||
return get_fiscal_year(date=doc.get("posting_date"), company=doc.get("company"))[0]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_coa(doctype, parent, is_root, chart=None):
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import (
|
||||
|
||||
@@ -82,7 +82,7 @@ frappe.query_reports["Fixed Asset Register"] = {
|
||||
"label": __("Start Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
|
||||
},
|
||||
{
|
||||
@@ -90,7 +90,7 @@ frappe.query_reports["Fixed Asset Register"] = {
|
||||
"label": __("End Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
"custom_options": "{\"type\": \"line\", \"axisOptions\": {\"shortenYAxisNumbers\": 1}, \"tooltipOptions\": {}, \"lineOptions\": {\"regionFill\": 1}}",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"period\":\"Monthly\",\"period_based_on\":\"posting_date\",\"based_on\":\"Item\"}",
|
||||
"idx": 0,
|
||||
"idx": 1,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-21 16:13:25.092287",
|
||||
"modified": "2023-07-19 13:06:42.937941",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Trends",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Purchase Order Trends",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Line",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
"creation": "2020-07-20 21:01:02.329519",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"period\":\"Monthly\",\"period_based_on\":\"posting_date\",\"based_on\":\"Supplier\"}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 12:43:40.829652",
|
||||
"modified": "2023-07-19 13:07:41.753556",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Top Suppliers",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Purchase Receipt Trends",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -822,6 +822,15 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql(query, filters)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_doctypes_for_closing(doctype, txt, searchfield, start, page_len, filters):
|
||||
doctypes = frappe.get_hooks("period_closing_doctypes")
|
||||
if txt:
|
||||
doctypes = [d for d in doctypes if txt.lower() in d.lower()]
|
||||
return [(d,) for d in set(doctypes)]
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
@@ -83,7 +83,7 @@ update_website_context = [
|
||||
my_account_context = "erpnext.e_commerce.shopping_cart.utils.update_my_account_context"
|
||||
webform_list_context = "erpnext.controllers.website_list_for_contact.get_webform_list_context"
|
||||
|
||||
calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday List", "ToDo"]
|
||||
calendars = ["Task", "Work Order", "Sales Order", "Holiday List", "ToDo"]
|
||||
|
||||
website_generators = ["Item Group", "Website Item", "BOM", "Sales Partner"]
|
||||
|
||||
@@ -285,10 +285,34 @@ standard_queries = {
|
||||
"Customer": "erpnext.controllers.queries.customer_query",
|
||||
}
|
||||
|
||||
period_closing_doctypes = [
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Journal Entry",
|
||||
"Bank Clearance",
|
||||
"Stock Entry",
|
||||
"Dunning",
|
||||
"Invoice Discounting",
|
||||
"Payment Entry",
|
||||
"Period Closing Voucher",
|
||||
"Process Deferred Accounting",
|
||||
"Asset",
|
||||
"Asset Capitalization",
|
||||
"Asset Repair",
|
||||
"Delivery Note",
|
||||
"Landed Cost Voucher",
|
||||
"Purchase Receipt",
|
||||
"Stock Reconciliation",
|
||||
"Subcontracting Receipt",
|
||||
]
|
||||
|
||||
doc_events = {
|
||||
"*": {
|
||||
"validate": "erpnext.support.doctype.service_level_agreement.service_level_agreement.apply",
|
||||
},
|
||||
tuple(period_closing_doctypes): {
|
||||
"validate": "erpnext.accounts.doctype.accounting_period.accounting_period.validate_accounting_period_on_doc_save",
|
||||
},
|
||||
"Stock Entry": {
|
||||
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
|
||||
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
|
||||
@@ -354,6 +378,11 @@ doc_events = {
|
||||
},
|
||||
}
|
||||
|
||||
# function should expect the variable and doc as arguments
|
||||
naming_series_variables = {
|
||||
"FY": "erpnext.accounts.utils.parse_naming_series_variable",
|
||||
}
|
||||
|
||||
# On cancel event Payment Entry will be exempted and all linked submittable doctype will get cancelled.
|
||||
# to maintain data integrity we exempted payment entry. it will un-link when sales invoice get cancelled.
|
||||
# if payment entry not in auto cancel exempted doctypes it will cancel payment entry.
|
||||
@@ -459,15 +488,6 @@ advance_payment_doctypes = ["Sales Order", "Purchase Order"]
|
||||
|
||||
invoice_doctypes = ["Sales Invoice", "Purchase Invoice"]
|
||||
|
||||
period_closing_doctypes = [
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Journal Entry",
|
||||
"Bank Clearance",
|
||||
"Asset",
|
||||
"Stock Entry",
|
||||
]
|
||||
|
||||
bank_reconciliation_doctypes = [
|
||||
"Payment Entry",
|
||||
"Journal Entry",
|
||||
|
||||
@@ -1539,7 +1539,7 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
|
||||
frappe.qb.from_(table)
|
||||
.inner_join(child)
|
||||
.on(table.name == child.parent)
|
||||
.select(Sum(child.required_bom_qty * IfNull(child.conversion_factor, 1.0)))
|
||||
.select(Sum(child.quantity * IfNull(child.conversion_factor, 1.0)))
|
||||
.where(
|
||||
(table.docstatus == 1)
|
||||
& (child.item_code == item_code)
|
||||
|
||||
@@ -933,6 +933,54 @@ class TestProductionPlan(FrappeTestCase):
|
||||
|
||||
self.assertEqual(after_qty, before_qty)
|
||||
|
||||
def test_resered_qty_for_production_plan_for_material_requests_with_multi_UOM(self):
|
||||
from erpnext.stock.utils import get_or_make_bin
|
||||
|
||||
fg_item = make_item(properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1"}).name
|
||||
bom_item = make_item(
|
||||
properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1", "purchase_uom": "Nos"}
|
||||
).name
|
||||
|
||||
if not frappe.db.exists("UOM Conversion Detail", {"parent": bom_item, "uom": "Nos"}):
|
||||
doc = frappe.get_doc("Item", bom_item)
|
||||
doc.append("uoms", {"uom": "Nos", "conversion_factor": 25})
|
||||
doc.save()
|
||||
|
||||
make_bom(item=fg_item, raw_materials=[bom_item], source_warehouse="_Test Warehouse - _TC")
|
||||
|
||||
bin_name = get_or_make_bin(bom_item, "_Test Warehouse - _TC")
|
||||
before_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
|
||||
|
||||
pln = create_production_plan(
|
||||
item_code=fg_item, planned_qty=100, ignore_existing_ordered_qty=1, stock_uom="_Test UOM 1"
|
||||
)
|
||||
|
||||
for row in pln.mr_items:
|
||||
self.assertEqual(row.uom, "Nos")
|
||||
self.assertEqual(row.quantity, 4)
|
||||
|
||||
reserved_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan"))
|
||||
self.assertEqual(reserved_qty - before_qty, 100.0)
|
||||
|
||||
pln.submit_material_request = 1
|
||||
pln.make_work_order()
|
||||
|
||||
for work_order in frappe.get_all(
|
||||
"Work Order",
|
||||
fields=["name"],
|
||||
filters={"production_plan": pln.name},
|
||||
):
|
||||
wo_doc = frappe.get_doc("Work Order", work_order.name)
|
||||
wo_doc.source_warehouse = "_Test Warehouse - _TC"
|
||||
wo_doc.wip_warehouse = "_Test Warehouse 1 - _TC"
|
||||
wo_doc.fg_warehouse = "_Test Warehouse - _TC"
|
||||
wo_doc.submit()
|
||||
|
||||
reserved_qty_after_mr = flt(
|
||||
frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan")
|
||||
)
|
||||
self.assertEqual(reserved_qty_after_mr, before_qty)
|
||||
|
||||
def test_skip_available_qty_for_sub_assembly_items(self):
|
||||
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ frappe.query_reports["Job Card Summary"] = {
|
||||
label: __("Fiscal Year"),
|
||||
fieldtype: "Link",
|
||||
options: "Fiscal Year",
|
||||
default: frappe.defaults.get_user_default("fiscal_year"),
|
||||
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
reqd: 1,
|
||||
on_change: function(query_report) {
|
||||
var fiscal_year = query_report.get_values().fiscal_year;
|
||||
|
||||
@@ -334,4 +334,5 @@ erpnext.patches.v14_0.cleanup_workspaces
|
||||
erpnext.patches.v15_0.remove_loan_management_module #2023-07-03
|
||||
erpnext.patches.v14_0.set_report_in_process_SOA
|
||||
erpnext.buying.doctype.supplier.patches.migrate_supplier_portal_users
|
||||
execute:frappe.defaults.clear_default("fiscal_year")
|
||||
erpnext.patches.v15_0.remove_exotel_integration
|
||||
|
||||
@@ -69,7 +69,6 @@ def execute():
|
||||
|
||||
entries = gl_entries + closing_entries
|
||||
|
||||
if entries:
|
||||
make_closing_entries(entries, voucher_name=pcv.name)
|
||||
i += 1
|
||||
company_wise_order[pcv.company].append(pcv.posting_date)
|
||||
make_closing_entries(entries, pcv.name, pcv.company, pcv.posting_date)
|
||||
company_wise_order[pcv.company].append(pcv.posting_date)
|
||||
i += 1
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from contextlib import suppress
|
||||
|
||||
import click
|
||||
import frappe
|
||||
from frappe import _
|
||||
@@ -13,12 +11,14 @@ def execute():
|
||||
if "exotel_integration" in frappe.get_installed_apps():
|
||||
return
|
||||
|
||||
with suppress(Exception):
|
||||
try:
|
||||
exotel = frappe.get_doc(SETTINGS_DOCTYPE)
|
||||
if exotel.enabled:
|
||||
notify_existing_users()
|
||||
|
||||
frappe.delete_doc("DocType", SETTINGS_DOCTYPE)
|
||||
except Exception:
|
||||
frappe.log_error("Failed to remove Exotel Integration.")
|
||||
|
||||
|
||||
def notify_existing_users():
|
||||
|
||||
@@ -358,12 +358,14 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
||||
}
|
||||
|
||||
refresh() {
|
||||
|
||||
erpnext.toggle_naming_series();
|
||||
erpnext.hide_company();
|
||||
this.set_dynamic_labels();
|
||||
this.setup_sms();
|
||||
this.setup_quality_inspection();
|
||||
this.validate_has_items();
|
||||
erpnext.utils.view_serial_batch_nos(this.frm);
|
||||
}
|
||||
|
||||
scan_barcode() {
|
||||
|
||||
@@ -56,7 +56,7 @@ erpnext.financial_statements = {
|
||||
// dropdown for links to other financial statements
|
||||
erpnext.financial_statements.filters = get_filters()
|
||||
|
||||
let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
|
||||
let fiscal_year = erpnext.utils.get_fiscal_year(frappe.datetime.get_today());
|
||||
|
||||
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
|
||||
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
|
||||
@@ -137,7 +137,7 @@ function get_filters() {
|
||||
"label": __("Start Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
|
||||
},
|
||||
@@ -146,7 +146,7 @@ function get_filters() {
|
||||
"label": __("End Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
|
||||
},
|
||||
|
||||
@@ -113,6 +113,23 @@ $.extend(erpnext.utils, {
|
||||
}
|
||||
},
|
||||
|
||||
view_serial_batch_nos: function(frm) {
|
||||
let bundle_ids = frm.doc.items.filter(d => d.serial_and_batch_bundle);
|
||||
|
||||
if (bundle_ids?.length) {
|
||||
frm.add_custom_button(__('Serial / Batch Nos'), () => {
|
||||
frappe.route_options = {
|
||||
"voucher_no": frm.doc.name,
|
||||
"voucher_type": frm.doc.doctype,
|
||||
"from_date": frm.doc.posting_date || frm.doc.transaction_date,
|
||||
"to_date": frm.doc.posting_date || frm.doc.transaction_date,
|
||||
"company": frm.doc.company,
|
||||
};
|
||||
frappe.set_route("query-report", "Serial and Batch Summary");
|
||||
}, __('View'));
|
||||
}
|
||||
},
|
||||
|
||||
add_indicator_for_multicompany: function(frm, info) {
|
||||
frm.dashboard.stats_area.show();
|
||||
frm.dashboard.stats_area_row.addClass('flex');
|
||||
@@ -381,6 +398,27 @@ $.extend(erpnext.utils, {
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get_fiscal_year: function(date) {
|
||||
if(!date) {
|
||||
date = frappe.datetime.get_today();
|
||||
}
|
||||
|
||||
let fiscal_year = '';
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.utils.get_fiscal_year",
|
||||
args: {
|
||||
date: date
|
||||
},
|
||||
async: false,
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
fiscal_year = r.message[0];
|
||||
}
|
||||
}
|
||||
});
|
||||
return fiscal_year;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1003,4 +1041,4 @@ function attach_selector_button(inner_text, append_loction, context, grid_row) {
|
||||
$btn.on("click", function() {
|
||||
context.show_serial_batch_selector(grid_row.frm, grid_row.doc, "", "", true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ frappe.query_reports["Fichier des Ecritures Comptables [FEC]"] = {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -17,7 +17,7 @@ frappe.query_reports["IRS 1099"] = {
|
||||
"label": __("Fiscal Year"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
|
||||
"reqd": 1,
|
||||
"width": 80,
|
||||
},
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
"custom_options": "{\"type\": \"line\", \"axisOptions\": {\"shortenYAxisNumbers\": 1}, \"tooltipOptions\": {}, \"lineOptions\": {\"regionFill\": 1}}",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"period\":\"Monthly\",\"based_on\":\"Item\"}",
|
||||
"idx": 0,
|
||||
"idx": 1,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 16:24:45.726270",
|
||||
"modified": "2023-07-19 13:09:45.341791",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Trends",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Sales Order Trends",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Line",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"frappe.sys_defaults.fiscal_year\"}",
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"fiscal_year\":\"erpnext.utils.get_fiscal_year()\"}",
|
||||
"filters_json": "{\"period\":\"Yearly\",\"based_on\":\"Customer\"}",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 17:03:10.320147",
|
||||
"modified": "2023-07-19 13:14:20.151502",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Top Customers",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Delivery Note Trends",
|
||||
"roles": [],
|
||||
"timeseries": 0,
|
||||
"type": "Bar",
|
||||
"use_report_chart": 1,
|
||||
|
||||
@@ -1904,12 +1904,11 @@ class TestSalesOrder(FrappeTestCase):
|
||||
"voucher_no": so.name,
|
||||
"voucher_detail_no": item.name,
|
||||
},
|
||||
fields=["status", "reserved_qty", "delivered_qty"],
|
||||
fields=["reserved_qty", "delivered_qty"],
|
||||
)
|
||||
|
||||
for sre_detail in sre_details:
|
||||
self.assertEqual(sre_detail.reserved_qty, sre_detail.delivered_qty)
|
||||
self.assertEqual(sre_detail.status, "Delivered")
|
||||
|
||||
def test_delivered_item_material_request(self):
|
||||
"SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."
|
||||
|
||||
@@ -1,352 +1,99 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2013-05-02 17:53:24",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 0,
|
||||
"actions": [],
|
||||
"allow_copy": 1,
|
||||
"creation": "2013-05-02 17:53:24",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"default_company",
|
||||
"country",
|
||||
"default_distance_unit",
|
||||
"column_break_8",
|
||||
"default_currency",
|
||||
"hide_currency_symbol",
|
||||
"disable_rounded_total",
|
||||
"disable_in_words"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"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
|
||||
},
|
||||
"fieldname": "default_company",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "current_fiscal_year",
|
||||
"fieldtype": "Link",
|
||||
"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": "Current Fiscal Year",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "country",
|
||||
"fieldtype": "Link",
|
||||
"label": "Country",
|
||||
"options": "Country"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "country",
|
||||
"fieldtype": "Link",
|
||||
"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": "Country",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Country",
|
||||
"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
|
||||
},
|
||||
"fieldname": "default_distance_unit",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Distance Unit",
|
||||
"options": "UOM"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "default_distance_unit",
|
||||
"fieldtype": "Link",
|
||||
"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": "Default Distance Unit",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "UOM",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_8",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_8",
|
||||
"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,
|
||||
"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
|
||||
},
|
||||
"default": "INR",
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Default Currency",
|
||||
"options": "Currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "INR",
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default 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
|
||||
},
|
||||
"description": "Do not show any symbol like $ etc next to currencies.",
|
||||
"fieldname": "hide_currency_symbol",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Hide Currency Symbol",
|
||||
"options": "\nNo\nYes"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Do not show any symbol like $ etc next to currencies.",
|
||||
"fieldname": "hide_currency_symbol",
|
||||
"fieldtype": "Select",
|
||||
"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": "Hide Currency Symbol",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nNo\nYes",
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"description": "If disable, 'Rounded Total' field will not be visible in any transaction",
|
||||
"fieldname": "disable_rounded_total",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Disable Rounded Total"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "If disable, 'Rounded Total' field will not be visible in any transaction",
|
||||
"fieldname": "disable_rounded_total",
|
||||
"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": "Disable Rounded Total",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "If disable, 'In Words' field will not be visible in any transaction",
|
||||
"fieldname": "disable_in_words",
|
||||
"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": "Disable In Words",
|
||||
"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
|
||||
"default": "0",
|
||||
"description": "If disable, 'In Words' field will not be visible in any transaction",
|
||||
"fieldname": "disable_in_words",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Disable In Words"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-cog",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 1,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-10-15 03:08:19.886212",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Global Defaults",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2023-07-01 19:45:00.323953",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Global Defaults",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"read_only": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -10,7 +10,6 @@ from frappe.utils import cint
|
||||
|
||||
keydict = {
|
||||
# "key in defaults": "key in Global Defaults"
|
||||
"fiscal_year": "current_fiscal_year",
|
||||
"company": "default_company",
|
||||
"currency": "default_currency",
|
||||
"country": "country",
|
||||
@@ -29,22 +28,6 @@ class GlobalDefaults(Document):
|
||||
for key in keydict:
|
||||
frappe.db.set_default(key, self.get(keydict[key], ""))
|
||||
|
||||
# update year start date and year end date from fiscal_year
|
||||
if self.current_fiscal_year:
|
||||
if fiscal_year := frappe.get_all(
|
||||
"Fiscal Year",
|
||||
filters={"name": self.current_fiscal_year},
|
||||
fields=["year_start_date", "year_end_date"],
|
||||
limit=1,
|
||||
order_by=None,
|
||||
):
|
||||
ysd = fiscal_year[0].year_start_date or ""
|
||||
yed = fiscal_year[0].year_end_date or ""
|
||||
|
||||
if ysd and yed:
|
||||
frappe.db.set_default("year_start_date", ysd.strftime("%Y-%m-%d"))
|
||||
frappe.db.set_default("year_end_date", yed.strftime("%Y-%m-%d"))
|
||||
|
||||
# enable default currency
|
||||
if self.default_currency:
|
||||
frappe.db.set_value("Currency", self.default_currency, "enabled", 1)
|
||||
|
||||
@@ -462,11 +462,9 @@ def install_defaults(args=None): # nosemgrep
|
||||
|
||||
def set_global_defaults(args):
|
||||
global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
|
||||
current_fiscal_year = frappe.get_all("Fiscal Year")[0]
|
||||
|
||||
global_defaults.update(
|
||||
{
|
||||
"current_fiscal_year": current_fiscal_year.name,
|
||||
"default_currency": args.get("currency"),
|
||||
"default_company": args.get("company_name"),
|
||||
"country": args.get("country"),
|
||||
|
||||
@@ -118,8 +118,8 @@ class MaterialRequest(BuyingController):
|
||||
self.title = _("{0} Request for {1}").format(_(self.material_request_type), items)[:100]
|
||||
|
||||
def on_submit(self):
|
||||
self.update_requested_qty()
|
||||
self.update_requested_qty_in_production_plan()
|
||||
self.update_requested_qty()
|
||||
if self.material_request_type == "Purchase":
|
||||
self.validate_budget()
|
||||
|
||||
@@ -178,8 +178,8 @@ class MaterialRequest(BuyingController):
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_requested_qty()
|
||||
self.update_requested_qty_in_production_plan()
|
||||
self.update_requested_qty()
|
||||
|
||||
def get_mr_items_ordered_qty(self, mr_items):
|
||||
mr_items_ordered_qty = {}
|
||||
@@ -270,7 +270,13 @@ class MaterialRequest(BuyingController):
|
||||
item_wh_list.append([d.item_code, d.warehouse])
|
||||
|
||||
for item_code, warehouse in item_wh_list:
|
||||
update_bin_qty(item_code, warehouse, {"indented_qty": get_indented_qty(item_code, warehouse)})
|
||||
update_bin_qty(
|
||||
item_code,
|
||||
warehouse,
|
||||
{
|
||||
"indented_qty": get_indented_qty(item_code, warehouse),
|
||||
},
|
||||
)
|
||||
|
||||
def update_requested_qty_in_production_plan(self):
|
||||
production_plans = []
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Naming Series",
|
||||
"options": "SBB-.####"
|
||||
"options": "SABB-.########"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -244,7 +244,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-04-10 20:02:42.964309",
|
||||
"modified": "2023-07-16 10:53:04.045605",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Bundle",
|
||||
|
||||
@@ -889,13 +889,16 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_serial_batch_ledgers(item_code, docstatus=None, voucher_no=None, name=None):
|
||||
filters = get_filters_for_bundle(item_code, docstatus=docstatus, voucher_no=voucher_no, name=name)
|
||||
def get_serial_batch_ledgers(item_code=None, docstatus=None, voucher_no=None, name=None):
|
||||
filters = get_filters_for_bundle(
|
||||
item_code=item_code, docstatus=docstatus, voucher_no=voucher_no, name=name
|
||||
)
|
||||
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
fields=[
|
||||
"`tabSerial and Batch Bundle`.`name`",
|
||||
"`tabSerial and Batch Bundle`.`item_code`",
|
||||
"`tabSerial and Batch Entry`.`qty`",
|
||||
"`tabSerial and Batch Entry`.`warehouse`",
|
||||
"`tabSerial and Batch Entry`.`batch_no`",
|
||||
@@ -906,12 +909,14 @@ def get_serial_batch_ledgers(item_code, docstatus=None, voucher_no=None, name=No
|
||||
)
|
||||
|
||||
|
||||
def get_filters_for_bundle(item_code, docstatus=None, voucher_no=None, name=None):
|
||||
def get_filters_for_bundle(item_code=None, docstatus=None, voucher_no=None, name=None):
|
||||
filters = [
|
||||
["Serial and Batch Bundle", "item_code", "=", item_code],
|
||||
["Serial and Batch Bundle", "is_cancelled", "=", 0],
|
||||
]
|
||||
|
||||
if item_code:
|
||||
filters.append(["Serial and Batch Bundle", "item_code", "=", item_code])
|
||||
|
||||
if not docstatus:
|
||||
docstatus = [0, 1]
|
||||
|
||||
|
||||
@@ -925,6 +925,7 @@ erpnext.stock.StockEntry = class StockEntry extends erpnext.stock.StockControlle
|
||||
this.toggle_related_fields(this.frm.doc);
|
||||
this.toggle_enable_bom();
|
||||
this.show_stock_ledger();
|
||||
erpnext.utils.view_serial_batch_nos(this.frm);
|
||||
if (this.frm.doc.docstatus===1 && erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
|
||||
this.show_general_ledger();
|
||||
}
|
||||
|
||||
@@ -337,6 +337,7 @@ erpnext.stock.StockReconciliation = class StockReconciliation extends erpnext.st
|
||||
refresh() {
|
||||
if(this.frm.doc.docstatus > 0) {
|
||||
this.show_stock_ledger();
|
||||
erpnext.utils.view_serial_batch_nos(this.frm);
|
||||
if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
|
||||
this.show_general_ledger();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Serial and Batch Summary"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname":"company",
|
||||
"label": __("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"default": frappe.defaults.get_user_default("Company"),
|
||||
},
|
||||
{
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
|
||||
},
|
||||
{
|
||||
"fieldname":"to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.datetime.get_today()
|
||||
},
|
||||
{
|
||||
"fieldname":"item_code",
|
||||
"label": __("Item"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
},
|
||||
{
|
||||
"fieldname":"warehouse",
|
||||
"label": __("Warehouse"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_type",
|
||||
"label": __("Voucher Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
get_query: function() {
|
||||
return {
|
||||
query: "erpnext.stock.report.serial_and_batch_summary.serial_and_batch_summary.get_voucher_type",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_no",
|
||||
"label": __("Voucher No"),
|
||||
"fieldtype": "MultiSelectList",
|
||||
get_data: function(txt) {
|
||||
if (!frappe.query_report.filters) return;
|
||||
|
||||
let voucher_type = frappe.query_report.get_filter_value('voucher_type');
|
||||
if (!voucher_type) return;
|
||||
|
||||
return frappe.db.get_link_options(voucher_type, txt);
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname":"serial_no",
|
||||
"label": __("Serial No"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Serial No",
|
||||
get_query: function() {
|
||||
return {
|
||||
query: "erpnext.stock.report.serial_and_batch_summary.serial_and_batch_summary.get_serial_nos",
|
||||
filters: {
|
||||
"item_code": frappe.query_report.get_filter_value('item_code'),
|
||||
"voucher_type": frappe.query_report.get_filter_value('voucher_type'),
|
||||
"voucher_no": frappe.query_report.get_filter_value('voucher_no'),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname":"batch_no",
|
||||
"label": __("Batch No"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Batch",
|
||||
get_query: function() {
|
||||
return {
|
||||
query: "erpnext.stock.report.serial_and_batch_summary.serial_and_batch_summary.get_batch_nos",
|
||||
filters: {
|
||||
"item_code": frappe.query_report.get_filter_value('item_code'),
|
||||
"voucher_type": frappe.query_report.get_filter_value('voucher_type'),
|
||||
"voucher_no": frappe.query_report.get_filter_value('voucher_no'),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"columns": [],
|
||||
"creation": "2023-07-13 16:53:27.735091",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"filters": [],
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"json": "{}",
|
||||
"modified": "2023-07-13 16:53:33.204591",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Summary",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Serial and Batch Bundle",
|
||||
"report_name": "Serial and Batch Summary",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "System Manager"
|
||||
},
|
||||
{
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"role": "Purchase User"
|
||||
},
|
||||
{
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
data = get_data(filters)
|
||||
columns = get_columns(filters, data)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
filter_conditions = get_filter_conditions(filters)
|
||||
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
fields=[
|
||||
"`tabSerial and Batch Bundle`.`voucher_type`",
|
||||
"`tabSerial and Batch Bundle`.`posting_date`",
|
||||
"`tabSerial and Batch Bundle`.`name`",
|
||||
"`tabSerial and Batch Bundle`.`company`",
|
||||
"`tabSerial and Batch Bundle`.`voucher_no`",
|
||||
"`tabSerial and Batch Bundle`.`item_code`",
|
||||
"`tabSerial and Batch Bundle`.`item_name`",
|
||||
"`tabSerial and Batch Entry`.`serial_no`",
|
||||
"`tabSerial and Batch Entry`.`batch_no`",
|
||||
"`tabSerial and Batch Entry`.`warehouse`",
|
||||
"`tabSerial and Batch Entry`.`incoming_rate`",
|
||||
"`tabSerial and Batch Entry`.`stock_value_difference`",
|
||||
"`tabSerial and Batch Entry`.`qty`",
|
||||
],
|
||||
filters=filter_conditions,
|
||||
order_by="posting_date",
|
||||
)
|
||||
|
||||
|
||||
def get_filter_conditions(filters):
|
||||
filter_conditions = [
|
||||
["Serial and Batch Bundle", "docstatus", "=", 1],
|
||||
["Serial and Batch Bundle", "is_cancelled", "=", 0],
|
||||
]
|
||||
|
||||
for field in ["voucher_type", "voucher_no", "item_code", "warehouse", "company"]:
|
||||
if filters.get(field):
|
||||
if field == "voucher_no":
|
||||
filter_conditions.append(["Serial and Batch Bundle", field, "in", filters.get(field)])
|
||||
else:
|
||||
filter_conditions.append(["Serial and Batch Bundle", field, "=", filters.get(field)])
|
||||
|
||||
if filters.get("from_date") and filters.get("to_date"):
|
||||
filter_conditions.append(
|
||||
[
|
||||
"Serial and Batch Bundle",
|
||||
"posting_date",
|
||||
"between",
|
||||
[filters.get("from_date"), filters.get("to_date")],
|
||||
]
|
||||
)
|
||||
|
||||
for field in ["serial_no", "batch_no"]:
|
||||
if filters.get(field):
|
||||
filter_conditions.append(["Serial and Batch Entry", field, "=", filters.get(field)])
|
||||
|
||||
return filter_conditions
|
||||
|
||||
|
||||
def get_columns(filters, data):
|
||||
columns = [
|
||||
{
|
||||
"label": _("Company"),
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"width": 120,
|
||||
},
|
||||
{
|
||||
"label": _("Serial and Batch Bundle"),
|
||||
"fieldname": "name",
|
||||
"fieldtype": "Link",
|
||||
"options": "Serial and Batch Bundle",
|
||||
"width": 110,
|
||||
},
|
||||
{"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100},
|
||||
]
|
||||
|
||||
item_details = {}
|
||||
|
||||
item_codes = []
|
||||
if filters.get("voucher_type"):
|
||||
item_codes = [d.item_code for d in data]
|
||||
|
||||
if filters.get("item_code") or (item_codes and len(list(set(item_codes))) == 1):
|
||||
item_details = frappe.get_cached_value(
|
||||
"Item",
|
||||
filters.get("item_code") or item_codes[0],
|
||||
["has_serial_no", "has_batch_no"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not filters.get("voucher_no"):
|
||||
columns.extend(
|
||||
[
|
||||
{
|
||||
"label": _("Voucher Type"),
|
||||
"fieldname": "voucher_type",
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"width": 120,
|
||||
},
|
||||
{
|
||||
"label": _("Voucher No"),
|
||||
"fieldname": "voucher_no",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"options": "voucher_type",
|
||||
"width": 160,
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
if not filters.get("item_code"):
|
||||
columns.extend(
|
||||
[
|
||||
{
|
||||
"label": _("Item Code"),
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"width": 120,
|
||||
},
|
||||
{"label": _("Item Name"), "fieldname": "item_name", "fieldtype": "Data", "width": 120},
|
||||
]
|
||||
)
|
||||
|
||||
if not filters.get("warehouse"):
|
||||
columns.append(
|
||||
{
|
||||
"label": _("Warehouse"),
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"width": 120,
|
||||
}
|
||||
)
|
||||
|
||||
if not item_details or item_details.get("has_serial_no"):
|
||||
columns.append(
|
||||
{"label": _("Serial No"), "fieldname": "serial_no", "fieldtype": "Data", "width": 120}
|
||||
)
|
||||
|
||||
if not item_details or item_details.get("has_batch_no"):
|
||||
columns.extend(
|
||||
[
|
||||
{"label": _("Batch No"), "fieldname": "batch_no", "fieldtype": "Data", "width": 120},
|
||||
{"label": _("Batch Qty"), "fieldname": "qty", "fieldtype": "Float", "width": 120},
|
||||
]
|
||||
)
|
||||
|
||||
columns.extend(
|
||||
[
|
||||
{"label": _("Incoming Rate"), "fieldname": "incoming_rate", "fieldtype": "Float", "width": 120},
|
||||
{
|
||||
"label": _("Change in Stock Value"),
|
||||
"fieldname": "stock_value_difference",
|
||||
"fieldtype": "Float",
|
||||
"width": 120,
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
return columns
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_voucher_type(doctype, txt, searchfield, start, page_len, filters):
|
||||
child_doctypes = frappe.get_all(
|
||||
"DocField",
|
||||
filters={"fieldname": "serial_and_batch_bundle"},
|
||||
fields=["distinct parent as parent"],
|
||||
)
|
||||
|
||||
query_filters = {"options": ["in", [d.parent for d in child_doctypes]]}
|
||||
if txt:
|
||||
query_filters["parent"] = ["like", "%{}%".format(txt)]
|
||||
|
||||
return frappe.get_all("DocField", filters=query_filters, fields=["distinct parent"], as_list=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_serial_nos(doctype, txt, searchfield, start, page_len, filters):
|
||||
query_filters = {}
|
||||
|
||||
if txt:
|
||||
query_filters["serial_no"] = ["like", f"%{txt}%"]
|
||||
|
||||
if filters.get("voucher_no"):
|
||||
serial_batch_bundle = frappe.get_cached_value(
|
||||
"Serial and Batch Bundle",
|
||||
{"voucher_no": ("in", filters.get("voucher_no")), "docstatus": 1, "is_cancelled": 0},
|
||||
"name",
|
||||
)
|
||||
|
||||
query_filters["parent"] = serial_batch_bundle
|
||||
if not txt:
|
||||
query_filters["serial_no"] = ("is", "set")
|
||||
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Entry", filters=query_filters, fields=["serial_no"], as_list=True
|
||||
)
|
||||
|
||||
else:
|
||||
query_filters["item_code"] = filters.get("item_code")
|
||||
return frappe.get_all("Serial No", filters=query_filters, as_list=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def get_batch_nos(doctype, txt, searchfield, start, page_len, filters):
|
||||
query_filters = {}
|
||||
|
||||
if txt:
|
||||
query_filters["batch_no"] = ["like", f"%{txt}%"]
|
||||
|
||||
if filters.get("voucher_no"):
|
||||
serial_batch_bundle = frappe.get_cached_value(
|
||||
"Serial and Batch Bundle",
|
||||
{"voucher_no": ("in", filters.get("voucher_no")), "docstatus": 1, "is_cancelled": 0},
|
||||
"name",
|
||||
)
|
||||
|
||||
query_filters["parent"] = serial_batch_bundle
|
||||
if not txt:
|
||||
query_filters["batch_no"] = ("is", "set")
|
||||
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Entry", filters=query_filters, fields=["batch_no"], as_list=True
|
||||
)
|
||||
|
||||
else:
|
||||
query_filters["item"] = filters.get("item_code")
|
||||
return frappe.get_all("Batch", filters=query_filters, as_list=True)
|
||||
@@ -15,7 +15,7 @@
|
||||
{% for item, taxes in itemised_tax.items() %}
|
||||
<tr>
|
||||
<td>{{ item }}</td>
|
||||
<td class='text-right'>
|
||||
<td class="text-right">
|
||||
{% if doc.get('is_return') %}
|
||||
{{ frappe.utils.fmt_money((itemised_taxable_amount.get(item, 0))|abs, None, doc.currency) }}
|
||||
{% else %}
|
||||
@@ -25,7 +25,7 @@
|
||||
{% for tax_account in tax_accounts %}
|
||||
{% set tax_details = taxes.get(tax_account) %}
|
||||
{% if tax_details %}
|
||||
<td class='text-right'>
|
||||
<td class="text-right">
|
||||
{% if tax_details.tax_rate or not tax_details.tax_amount %}
|
||||
({{ tax_details.tax_rate }}%)
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user