mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-13 10:11:20 +00:00
Merge branch 'version-13-hotfix' into hsn-summary-report
This commit is contained in:
@@ -43,20 +43,13 @@ frappe.ui.form.on('Bank Guarantee', {
|
|||||||
|
|
||||||
reference_docname: function(frm) {
|
reference_docname: function(frm) {
|
||||||
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
|
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
|
||||||
let fields_to_fetch = ["grand_total"];
|
|
||||||
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
|
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
|
||||||
|
|
||||||
if (frm.doc.reference_doctype == "Sales Order") {
|
|
||||||
fields_to_fetch.push("project");
|
|
||||||
}
|
|
||||||
|
|
||||||
fields_to_fetch.push(party_field);
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_vouchar_detials",
|
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details",
|
||||||
args: {
|
args: {
|
||||||
"column_list": fields_to_fetch,
|
"bank_guarantee_type": frm.doc.bg_type,
|
||||||
"doctype": frm.doc.reference_doctype,
|
"reference_name": frm.doc.reference_docname
|
||||||
"docname": frm.doc.reference_docname
|
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.desk.search import sanitize_searchfield
|
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
@@ -25,14 +22,18 @@ class BankGuarantee(Document):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_vouchar_detials(column_list, doctype, docname):
|
def get_voucher_details(bank_guarantee_type: str, reference_name: str):
|
||||||
column_list = json.loads(column_list)
|
if not isinstance(reference_name, str):
|
||||||
for col in column_list:
|
raise TypeError("reference_name must be a string")
|
||||||
sanitize_searchfield(col)
|
|
||||||
return frappe.db.sql(
|
fields_to_fetch = ["grand_total"]
|
||||||
""" select {columns} from `tab{doctype}` where name=%s""".format(
|
|
||||||
columns=", ".join(column_list), doctype=doctype
|
if bank_guarantee_type == "Receiving":
|
||||||
),
|
doctype = "Sales Order"
|
||||||
docname,
|
fields_to_fetch.append("customer")
|
||||||
as_dict=1,
|
fields_to_fetch.append("project")
|
||||||
)[0]
|
else:
|
||||||
|
doctype = "Purchase Order"
|
||||||
|
fields_to_fetch.append("supplier")
|
||||||
|
|
||||||
|
return frappe.db.get_value(doctype, reference_name, fields_to_fetch, as_dict=True)
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ class PaymentReconciliation(Document):
|
|||||||
def get_payment_entries(self):
|
def get_payment_entries(self):
|
||||||
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
|
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
|
||||||
condition = self.get_conditions(get_payments=True)
|
condition = self.get_conditions(get_payments=True)
|
||||||
|
|
||||||
|
if self.get("cost_center"):
|
||||||
|
condition += " and cost_center = '{0}' ".format(self.cost_center)
|
||||||
|
|
||||||
payment_entries = get_advance_payment_entries(
|
payment_entries = get_advance_payment_entries(
|
||||||
self.party_type,
|
self.party_type,
|
||||||
self.party,
|
self.party,
|
||||||
@@ -61,6 +65,10 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
def get_jv_entries(self):
|
def get_jv_entries(self):
|
||||||
condition = self.get_conditions()
|
condition = self.get_conditions()
|
||||||
|
|
||||||
|
if self.get("cost_center"):
|
||||||
|
condition += " and t2.cost_center = '{0}' ".format(self.cost_center)
|
||||||
|
|
||||||
dr_or_cr = (
|
dr_or_cr = (
|
||||||
"credit_in_account_currency"
|
"credit_in_account_currency"
|
||||||
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
||||||
@@ -113,6 +121,10 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
def get_dr_or_cr_notes(self):
|
def get_dr_or_cr_notes(self):
|
||||||
condition = self.get_conditions(get_return_invoices=True)
|
condition = self.get_conditions(get_return_invoices=True)
|
||||||
|
|
||||||
|
if self.get("cost_center"):
|
||||||
|
condition += " and doc.cost_center = '{0}' ".format(self.cost_center)
|
||||||
|
|
||||||
dr_or_cr = (
|
dr_or_cr = (
|
||||||
"credit_in_account_currency"
|
"credit_in_account_currency"
|
||||||
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
||||||
@@ -172,6 +184,9 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
condition = self.get_conditions(get_invoices=True)
|
condition = self.get_conditions(get_invoices=True)
|
||||||
|
|
||||||
|
if self.get("cost_center"):
|
||||||
|
condition += " and cost_center = '{0}' ".format(self.cost_center)
|
||||||
|
|
||||||
non_reconciled_invoices = get_outstanding_invoices(
|
non_reconciled_invoices = get_outstanding_invoices(
|
||||||
self.party_type, self.party, self.receivable_payable_account, condition=condition
|
self.party_type, self.party, self.receivable_payable_account, condition=condition
|
||||||
)
|
)
|
||||||
@@ -357,9 +372,6 @@ class PaymentReconciliation(Document):
|
|||||||
def get_conditions(self, get_invoices=False, get_payments=False, get_return_invoices=False):
|
def get_conditions(self, get_invoices=False, get_payments=False, get_return_invoices=False):
|
||||||
condition = " and company = '{0}' ".format(self.company)
|
condition = " and company = '{0}' ".format(self.company)
|
||||||
|
|
||||||
if self.get("cost_center"):
|
|
||||||
condition = " and cost_center = '{0}' ".format(self.cost_center)
|
|
||||||
|
|
||||||
if get_invoices:
|
if get_invoices:
|
||||||
condition += (
|
condition += (
|
||||||
" and posting_date >= {0}".format(frappe.db.escape(self.from_invoice_date))
|
" and posting_date >= {0}".format(frappe.db.escape(self.from_invoice_date))
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ frappe.ui.form.on('Process Statement Of Accounts', {
|
|||||||
},
|
},
|
||||||
refresh: function(frm){
|
refresh: function(frm){
|
||||||
if(!frm.doc.__islocal) {
|
if(!frm.doc.__islocal) {
|
||||||
frm.add_custom_button('Send Emails',function(){
|
frm.add_custom_button(__('Send Emails'), function(){
|
||||||
|
if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails",
|
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails",
|
||||||
args: {
|
args: {
|
||||||
@@ -24,8 +25,9 @@ frappe.ui.form.on('Process Statement Of Accounts', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
frm.add_custom_button('Download',function(){
|
frm.add_custom_button(__('Download'), function(){
|
||||||
var url = frappe.urllib.get_full_url(
|
if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
|
||||||
|
let url = frappe.urllib.get_full_url(
|
||||||
'/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?'
|
'/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?'
|
||||||
+ 'document_name='+encodeURIComponent(frm.doc.name))
|
+ 'document_name='+encodeURIComponent(frm.doc.name))
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"customers",
|
"customers",
|
||||||
"preferences",
|
"preferences",
|
||||||
"orientation",
|
"orientation",
|
||||||
|
"include_break",
|
||||||
"include_ageing",
|
"include_ageing",
|
||||||
"ageing_based_on",
|
"ageing_based_on",
|
||||||
"section_break_14",
|
"section_break_14",
|
||||||
@@ -284,10 +285,16 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Terms and Conditions",
|
"label": "Terms and Conditions",
|
||||||
"options": "Terms and Conditions"
|
"options": "Terms and Conditions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "include_break",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Page Break After Each SoA"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-06 21:00:45.732505",
|
"modified": "2022-10-17 17:47:08.662475",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Process Statement Of Accounts",
|
"name": "Process Statement Of Accounts",
|
||||||
@@ -320,5 +327,6 @@
|
|||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import copy
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.desk.reportview import get_match_cond
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import add_days, add_months, format_date, getdate, today
|
from frappe.utils import add_days, add_months, format_date, getdate, today
|
||||||
from frappe.utils.jinja import validate_template
|
from frappe.utils.jinja import validate_template
|
||||||
@@ -128,7 +129,8 @@ def get_report_pdf(doc, consolidated=True):
|
|||||||
if not bool(statement_dict):
|
if not bool(statement_dict):
|
||||||
return False
|
return False
|
||||||
elif consolidated:
|
elif consolidated:
|
||||||
result = "".join(list(statement_dict.values()))
|
delimiter = '<div style="page-break-before: always;"></div>' if doc.include_break else ""
|
||||||
|
result = delimiter.join(list(statement_dict.values()))
|
||||||
return get_pdf(result, {"orientation": doc.orientation})
|
return get_pdf(result, {"orientation": doc.orientation})
|
||||||
else:
|
else:
|
||||||
for customer, statement_html in statement_dict.items():
|
for customer, statement_html in statement_dict.items():
|
||||||
@@ -240,8 +242,6 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
|
|||||||
if int(primary_mandatory):
|
if int(primary_mandatory):
|
||||||
if primary_email == "":
|
if primary_email == "":
|
||||||
continue
|
continue
|
||||||
elif (billing_email == "") and (primary_email == ""):
|
|
||||||
continue
|
|
||||||
|
|
||||||
customer_list.append(
|
customer_list.append(
|
||||||
{"name": customer.name, "primary_email": primary_email, "billing_email": billing_email}
|
{"name": customer.name, "primary_email": primary_email, "billing_email": billing_email}
|
||||||
@@ -273,8 +273,12 @@ def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=Tr
|
|||||||
link.link_doctype='Customer'
|
link.link_doctype='Customer'
|
||||||
and link.link_name=%s
|
and link.link_name=%s
|
||||||
and contact.is_billing_contact=1
|
and contact.is_billing_contact=1
|
||||||
|
{mcond}
|
||||||
ORDER BY
|
ORDER BY
|
||||||
contact.creation desc""",
|
contact.creation desc
|
||||||
|
""".format(
|
||||||
|
mcond=get_match_cond("Contact")
|
||||||
|
),
|
||||||
customer_name,
|
customer_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -313,6 +317,8 @@ def send_emails(document_name, from_scheduler=False):
|
|||||||
attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}]
|
attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}]
|
||||||
|
|
||||||
recipients, cc = get_recipients_and_cc(customer, doc)
|
recipients, cc = get_recipients_and_cc(customer, doc)
|
||||||
|
if not recipients:
|
||||||
|
continue
|
||||||
context = get_context(customer, doc)
|
context = get_context(customer, doc)
|
||||||
subject = frappe.render_template(doc.subject, context)
|
subject = frappe.render_template(doc.subject, context)
|
||||||
message = frappe.render_template(doc.body, context)
|
message = frappe.render_template(doc.body, context)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import frappe
|
|||||||
from frappe import _, bold
|
from frappe import _, bold
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe.query_builder import Criterion
|
||||||
|
from frappe.query_builder.functions import IfNull, Max, Min
|
||||||
from frappe.utils import (
|
from frappe.utils import (
|
||||||
add_days,
|
add_days,
|
||||||
add_to_date,
|
add_to_date,
|
||||||
@@ -112,43 +114,44 @@ class JobCard(Document):
|
|||||||
def get_overlap_for(self, args, check_next_available_slot=False):
|
def get_overlap_for(self, args, check_next_available_slot=False):
|
||||||
production_capacity = 1
|
production_capacity = 1
|
||||||
|
|
||||||
|
jc = frappe.qb.DocType("Job Card")
|
||||||
|
jctl = frappe.qb.DocType("Job Card Time Log")
|
||||||
|
|
||||||
|
time_conditions = [
|
||||||
|
((jctl.from_time < args.from_time) & (jctl.to_time > args.from_time)),
|
||||||
|
((jctl.from_time < args.to_time) & (jctl.to_time > args.to_time)),
|
||||||
|
((jctl.from_time >= args.from_time) & (jctl.to_time <= args.to_time)),
|
||||||
|
]
|
||||||
|
|
||||||
|
if check_next_available_slot:
|
||||||
|
time_conditions.append(((jctl.from_time >= args.from_time) & (jctl.to_time >= args.to_time)))
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(jctl)
|
||||||
|
.from_(jc)
|
||||||
|
.select(jc.name.as_("name"), jctl.to_time)
|
||||||
|
.where(
|
||||||
|
(jctl.parent == jc.name)
|
||||||
|
& (Criterion.any(time_conditions))
|
||||||
|
& (jctl.name != f"{args.name or 'No Name'}")
|
||||||
|
& (jc.name != f"{args.parent or 'No Name'}")
|
||||||
|
& (jc.docstatus < 2)
|
||||||
|
)
|
||||||
|
.orderby(jctl.to_time, order=frappe.qb.desc)
|
||||||
|
)
|
||||||
|
|
||||||
if self.workstation:
|
if self.workstation:
|
||||||
production_capacity = (
|
production_capacity = (
|
||||||
frappe.get_cached_value("Workstation", self.workstation, "production_capacity") or 1
|
frappe.get_cached_value("Workstation", self.workstation, "production_capacity") or 1
|
||||||
)
|
)
|
||||||
validate_overlap_for = " and jc.workstation = %(workstation)s "
|
query = query.where(jc.workstation == self.workstation)
|
||||||
|
|
||||||
if args.get("employee"):
|
if args.get("employee"):
|
||||||
# override capacity for employee
|
# override capacity for employee
|
||||||
production_capacity = 1
|
production_capacity = 1
|
||||||
validate_overlap_for = " and jctl.employee = %(employee)s "
|
query = query.where(jctl.employee == args.get("employee"))
|
||||||
|
|
||||||
extra_cond = ""
|
existing = query.run(as_dict=True)
|
||||||
if check_next_available_slot:
|
|
||||||
extra_cond = " or (%(from_time)s <= jctl.from_time and %(to_time)s <= jctl.to_time)"
|
|
||||||
|
|
||||||
existing = frappe.db.sql(
|
|
||||||
"""select jc.name as name, jctl.to_time from
|
|
||||||
`tabJob Card Time Log` jctl, `tabJob Card` jc where jctl.parent = jc.name and
|
|
||||||
(
|
|
||||||
(%(from_time)s > jctl.from_time and %(from_time)s < jctl.to_time) or
|
|
||||||
(%(to_time)s > jctl.from_time and %(to_time)s < jctl.to_time) or
|
|
||||||
(%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time) {0}
|
|
||||||
)
|
|
||||||
and jctl.name != %(name)s and jc.name != %(parent)s and jc.docstatus < 2 {1}
|
|
||||||
order by jctl.to_time desc""".format(
|
|
||||||
extra_cond, validate_overlap_for
|
|
||||||
),
|
|
||||||
{
|
|
||||||
"from_time": args.from_time,
|
|
||||||
"to_time": args.to_time,
|
|
||||||
"name": args.name or "No Name",
|
|
||||||
"parent": args.parent or "No Name",
|
|
||||||
"employee": args.get("employee"),
|
|
||||||
"workstation": self.workstation,
|
|
||||||
},
|
|
||||||
as_dict=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if existing and production_capacity > len(existing):
|
if existing and production_capacity > len(existing):
|
||||||
return
|
return
|
||||||
@@ -488,18 +491,21 @@ class JobCard(Document):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def update_work_order_data(self, for_quantity, time_in_mins, wo):
|
def update_work_order_data(self, for_quantity, time_in_mins, wo):
|
||||||
time_data = frappe.db.sql(
|
jc = frappe.qb.DocType("Job Card")
|
||||||
"""
|
jctl = frappe.qb.DocType("Job Card Time Log")
|
||||||
SELECT
|
|
||||||
min(from_time) as start_time, max(to_time) as end_time
|
time_data = (
|
||||||
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
|
frappe.qb.from_(jc)
|
||||||
WHERE
|
.from_(jctl)
|
||||||
jctl.parent = jc.name and jc.work_order = %s and jc.operation_id = %s
|
.select(Min(jctl.from_time).as_("start_time"), Max(jctl.to_time).as_("end_time"))
|
||||||
and jc.docstatus = 1 and IFNULL(jc.is_corrective_job_card, 0) = 0
|
.where(
|
||||||
""",
|
(jctl.parent == jc.name)
|
||||||
(self.work_order, self.operation_id),
|
& (jc.work_order == self.work_order)
|
||||||
as_dict=1,
|
& (jc.operation_id == self.operation_id)
|
||||||
)
|
& (jc.docstatus == 1)
|
||||||
|
& (IfNull(jc.is_corrective_job_card, 0) == 0)
|
||||||
|
)
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
for data in wo.operations:
|
for data in wo.operations:
|
||||||
if data.get("name") == self.operation_id:
|
if data.get("name") == self.operation_id:
|
||||||
|
|||||||
@@ -315,6 +315,9 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
else:
|
else:
|
||||||
args.uom = item.stock_uom
|
args.uom = item.stock_uom
|
||||||
|
|
||||||
|
# Set stock UOM in args, so that it can be used while fetching item price
|
||||||
|
args.stock_uom = item.stock_uom
|
||||||
|
|
||||||
if args.get("batch_no") and item.name != frappe.get_cached_value(
|
if args.get("batch_no") and item.name != frappe.get_cached_value(
|
||||||
"Batch", args.get("batch_no"), "item"
|
"Batch", args.get("batch_no"), "item"
|
||||||
):
|
):
|
||||||
|
|||||||
Reference in New Issue
Block a user