Merge pull request #32494 from frappe/version-13-hotfix

chore: release v13
This commit is contained in:
Deepesh Garg
2022-10-04 17:41:06 +05:30
committed by GitHub
15 changed files with 151 additions and 24 deletions

View File

@@ -12,17 +12,13 @@ erpnext/selling @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
erpnext/support/ @nextchamp-saqib @deepeshgarg007 erpnext/support/ @nextchamp-saqib @deepeshgarg007
pos* @nextchamp-saqib pos* @nextchamp-saqib
erpnext/buying/ @marination @rohitwaghchaure @s-aga-r erpnext/buying/ @rohitwaghchaure @s-aga-r
erpnext/e_commerce/ @marination erpnext/maintenance/ @rohitwaghchaure @s-aga-r
erpnext/maintenance/ @marination @rohitwaghchaure @s-aga-r erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
erpnext/manufacturing/ @marination @rohitwaghchaure @s-aga-r erpnext/quality_management/ @rohitwaghchaure @s-aga-r
erpnext/portal/ @marination erpnext/stock/ @rohitwaghchaure @s-aga-r
erpnext/quality_management/ @marination @rohitwaghchaure @s-aga-r
erpnext/shopping_cart/ @marination
erpnext/stock/ @marination @rohitwaghchaure @s-aga-r
erpnext/crm/ @NagariaHussain
erpnext/education/ @rutwikhdev
erpnext/healthcare/ @chillaranand erpnext/healthcare/ @chillaranand
erpnext/hr/ @ruchamahabal erpnext/hr/ @ruchamahabal
erpnext/non_profit/ @ruchamahabal erpnext/non_profit/ @ruchamahabal
@@ -30,7 +26,7 @@ erpnext/payroll @ruchamahabal
erpnext/projects/ @ruchamahabal erpnext/projects/ @ruchamahabal
erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
erpnext/patches/ @deepeshgarg007 @nextchamp-saqib @marination rohitwaghchaure erpnext/patches/ @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure
erpnext/public/ @nextchamp-saqib @marination erpnext/public/ @nextchamp-saqib @marination
.github/ @ankush .github/ @ankush

View File

@@ -357,7 +357,7 @@ 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") and (get_invoices or get_payments or get_return_invoices): if self.get("cost_center"):
condition = " and cost_center = '{0}' ".format(self.cost_center) condition = " and cost_center = '{0}' ".format(self.cost_center)
if get_invoices: if get_invoices:

View File

@@ -186,8 +186,10 @@
{ {
"fetch_from": "bank_account.bank", "fetch_from": "bank_account.bank",
"fieldname": "bank", "fieldname": "bank",
"fieldtype": "Read Only", "fieldtype": "Link",
"label": "Bank" "label": "Bank",
"options": "Bank",
"read_only": 1
}, },
{ {
"fetch_from": "bank_account.bank_account_no", "fetch_from": "bank_account.bank_account_no",
@@ -366,10 +368,11 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-09-18 12:24:14.178853", "modified": "2022-09-30 16:19:43.680025",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Request", "name": "Payment Request",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
@@ -401,5 +404,6 @@
} }
], ],
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC" "sort_order": "DESC",
"states": []
} }

View File

@@ -7,7 +7,7 @@ import unittest
import frappe import frappe
from frappe.model.dynamic_links import get_dynamic_link_map from frappe.model.dynamic_links import get_dynamic_link_map
from frappe.model.naming import make_autoname from frappe.model.naming import make_autoname
from frappe.utils import add_days, flt, getdate, nowdate from frappe.utils import add_days, flt, getdate, nowdate, today
from six import iteritems from six import iteritems
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
@@ -3396,6 +3396,37 @@ class TestSalesInvoice(unittest.TestCase):
"Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled "Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
) )
def test_batch_expiry_for_sales_invoice_return(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.item.test_item import make_item
item = make_item(
"_Test Batch Item For Return Check",
{
"is_purchase_item": 1,
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TBIRC.#####",
},
)
pr = make_purchase_receipt(qty=1, item_code=item.name)
batch_no = pr.items[0].batch_no
si = create_sales_invoice(qty=1, item_code=item.name, update_stock=1, batch_no=batch_no)
si.load_from_db()
batch_no = si.items[0].batch_no
self.assertTrue(batch_no)
frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1))
return_si = make_return_doc(si.doctype, si.name)
return_si.save().submit()
self.assertTrue(return_si.docstatus == 1)
def get_sales_invoice_for_e_invoice(): def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill() si = make_sales_invoice_for_ewaybill()
@@ -3666,6 +3697,7 @@ def create_sales_invoice(**args):
"serial_no": args.serial_no, "serial_no": args.serial_no,
"conversion_factor": 1, "conversion_factor": 1,
"incoming_rate": args.incoming_rate or 0, "incoming_rate": args.incoming_rate or 0,
"batch_no": args.batch_no or None,
}, },
) )

View File

@@ -326,6 +326,9 @@ def get_advance_vouchers(
"party": ["in", parties], "party": ["in", parties],
} }
if party_type == "Customer":
filters.update({"against_voucher": ["is", "not set"]})
if company: if company:
filters["company"] = company filters["company"] = company
if from_date and to_date: if from_date and to_date:

View File

@@ -370,7 +370,7 @@ def get_conditions(filters):
where parent=`tabSales Invoice`.name where parent=`tabSales Invoice`.name
and ifnull(`tab{table}`.{field}, '') = %({field})s)""" and ifnull(`tab{table}`.{field}, '') = %({field})s)"""
conditions += get_sales_invoice_item_field_condition("mode_of_payments", "Sales Invoice Payment") conditions += get_sales_invoice_item_field_condition("mode_of_payment", "Sales Invoice Payment")
conditions += get_sales_invoice_item_field_condition("cost_center") conditions += get_sales_invoice_item_field_condition("cost_center")
conditions += get_sales_invoice_item_field_condition("warehouse") conditions += get_sales_invoice_item_field_condition("warehouse")
conditions += get_sales_invoice_item_field_condition("brand") conditions += get_sales_invoice_item_field_condition("brand")

View File

@@ -100,6 +100,7 @@ def execute():
"mode_of_payment": loan.mode_of_payment, "mode_of_payment": loan.mode_of_payment,
"loan_account": loan.loan_account, "loan_account": loan.loan_account,
"payment_account": loan.payment_account, "payment_account": loan.payment_account,
"disbursement_account": loan.payment_account,
"interest_income_account": loan.interest_income_account, "interest_income_account": loan.interest_income_account,
"penalty_income_account": loan.penalty_income_account, "penalty_income_account": loan.penalty_income_account,
}, },
@@ -190,6 +191,7 @@ def create_loan_type(loan, loan_type_name, penalty_account):
loan_type_doc.company = loan.company loan_type_doc.company = loan.company
loan_type_doc.mode_of_payment = loan.mode_of_payment loan_type_doc.mode_of_payment = loan.mode_of_payment
loan_type_doc.payment_account = loan.payment_account loan_type_doc.payment_account = loan.payment_account
loan_type_doc.disbursement_account = loan.payment_account
loan_type_doc.loan_account = loan.loan_account loan_type_doc.loan_account = loan.loan_account
loan_type_doc.interest_income_account = loan.interest_income_account loan_type_doc.interest_income_account = loan.interest_income_account
loan_type_doc.penalty_income_account = penalty_account loan_type_doc.penalty_income_account = penalty_account

View File

@@ -257,9 +257,16 @@ def get_regional_address_details(party_details, doctype, company):
update_party_details(party_details, doctype) update_party_details(party_details, doctype)
customer_gst_category = frappe.get_value(
"Customer", party_details.customer, ["gst_category", "export_type"]
)
party_details.place_of_supply = get_place_of_supply(party_details, doctype) party_details.place_of_supply = get_place_of_supply(party_details, doctype)
if is_internal_transfer(party_details, doctype): if is_internal_transfer(party_details, doctype) or customer_gst_category == (
"SEZ",
"Without Payment of Tax",
):
party_details.taxes_and_charges = "" party_details.taxes_and_charges = ""
party_details.taxes = [] party_details.taxes = []
return party_details return party_details
@@ -603,6 +610,10 @@ def get_ewb_data(dt, dn):
data = get_address_details(data, doc, company_address, billing_address, dispatch_address) data = get_address_details(data, doc, company_address, billing_address, dispatch_address)
if is_intrastate_transfer_eway_bill(data):
data.docType = "CHL"
data.subSupplyType = 8
data.itemList = [] data.itemList = []
data.totalValue = doc.total data.totalValue = doc.total
@@ -645,6 +656,10 @@ def get_ewb_data(dt, dn):
return data return data
def is_intrastate_transfer_eway_bill(data):
return data.fromGstin == data.toGstin
@frappe.whitelist() @frappe.whitelist()
def generate_ewb_json(dt, dn): def generate_ewb_json(dt, dn):
dn = json.loads(dn) dn = json.loads(dn)

View File

@@ -6,7 +6,7 @@ import json
import frappe import frappe
from frappe.tests.utils import FrappeTestCase from frappe.tests.utils import FrappeTestCase
from frappe.utils import cstr, flt, nowdate, nowtime from frappe.utils import add_days, cstr, flt, nowdate, nowtime, today
from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
@@ -1091,6 +1091,36 @@ class TestDeliveryNote(FrappeTestCase):
frappe.db.exists("GL Entry", {"voucher_no": dn.name, "voucher_type": dn.doctype}) frappe.db.exists("GL Entry", {"voucher_no": dn.name, "voucher_type": dn.doctype})
) )
def test_batch_expiry_for_delivery_note(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
item = make_item(
"_Test Batch Item For Return Check",
{
"is_purchase_item": 1,
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TBIRC.#####",
},
)
pi = make_purchase_receipt(qty=1, item_code=item.name)
dn = create_delivery_note(qty=1, item_code=item.name, batch_no=pi.items[0].batch_no)
dn.load_from_db()
batch_no = dn.items[0].batch_no
self.assertTrue(batch_no)
frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1))
return_dn = make_return_doc(dn.doctype, dn.name)
return_dn.save().submit()
self.assertTrue(return_dn.docstatus == 1)
def create_delivery_note(**args): def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note") dn = frappe.new_doc("Delivery Note")
@@ -1117,6 +1147,7 @@ def create_delivery_note(**args):
"expense_account": args.expense_account or "Cost of Goods Sold - _TC", "expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC", "cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no, "serial_no": args.serial_no,
"batch_no": args.batch_no or None,
"target_warehouse": args.target_warehouse, "target_warehouse": args.target_warehouse,
}, },
) )

View File

@@ -10,6 +10,31 @@ frappe.ui.form.on("Item", {
frm.add_fetch('attribute', 'to_range', 'to_range'); frm.add_fetch('attribute', 'to_range', 'to_range');
frm.add_fetch('attribute', 'increment', 'increment'); frm.add_fetch('attribute', 'increment', 'increment');
frm.add_fetch('tax_type', 'tax_rate', 'tax_rate'); frm.add_fetch('tax_type', 'tax_rate', 'tax_rate');
frm.make_methods = {
'Sales Order': () => {
open_form(frm, "Sales Order", "Sales Order Item", "items");
},
'Delivery Note': () => {
open_form(frm, "Delivery Note", "Delivery Note Item", "items");
},
'Sales Invoice': () => {
open_form(frm, "Sales Invoice", "Sales Invoice Item", "items");
},
'Purchase Order': () => {
open_form(frm, "Purchase Order", "Purchase Order Item", "items");
},
'Purchase Receipt': () => {
open_form(frm, "Purchase Receipt", "Purchase Receipt Item", "items");
},
'Purchase Invoice': () => {
open_form(frm, "Purchase Invoice", "Purchase Invoice Item", "items");
},
'Material Request': () => {
open_form(frm, "Material Request", "Material Request Item", "items");
},
};
}, },
onload: function(frm) { onload: function(frm) {
erpnext.item.setup_queries(frm); erpnext.item.setup_queries(frm);
@@ -813,3 +838,17 @@ frappe.ui.form.on("UOM Conversion Detail", {
} }
} }
}); });
function open_form(frm, doctype, child_doctype, parentfield) {
frappe.model.with_doctype(doctype, () => {
let new_doc = frappe.model.get_new_doc(doctype);
let new_child_doc = frappe.model.add_child(new_doc, child_doctype, parentfield);
new_child_doc.item_code = frm.doc.name;
new_child_doc.item_name = frm.doc.item_name;
new_child_doc.uom = frm.doc.stock_uom;
new_child_doc.description = frm.doc.description;
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
}

View File

@@ -174,7 +174,7 @@ class PickList(Document):
frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx)) frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx))
item_code = item.item_code item_code = item.item_code
reference = item.sales_order_item or item.material_request_item reference = item.sales_order_item or item.material_request_item
key = (item_code, item.uom, item.warehouse, reference) key = (item_code, item.uom, item.warehouse, item.batch_no, reference)
item.idx = None item.idx = None
item.name = None item.name = None

View File

@@ -153,7 +153,9 @@ class StockLedgerEntry(Document):
def validate_batch(self): def validate_batch(self):
if self.batch_no and self.voucher_type != "Stock Entry": if self.batch_no and self.voucher_type != "Stock Entry":
if self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0: if (self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0) or (
self.voucher_type in ["Delivery Note", "Sales Invoice"] and self.actual_qty > 0
):
return return
expiry_date = frappe.db.get_value("Batch", self.batch_no, "expiry_date") expiry_date = frappe.db.get_value("Batch", self.batch_no, "expiry_date")

View File

@@ -18,7 +18,7 @@
<b class="caret"></b> <b class="caret"></b>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right" role="menu"> <ul class="dropdown-menu dropdown-menu-right" role="menu">
{% if doc.doctype == 'Purchase Order' %} {% if doc.doctype == 'Purchase Order' and show_make_pi_button %}
<a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a> <a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a>
{% endif %} {% endif %}
<a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' <a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}'

View File

@@ -53,6 +53,9 @@ def get_context(context):
) )
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points")) context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
# show Make Purchase Invoice button based on permission
context.show_make_pi_button = frappe.has_permission("Purchase Invoice", "create")
def get_attachments(dt, dn): def get_attachments(dt, dn):
return frappe.get_all( return frappe.get_all(

View File

@@ -45,7 +45,7 @@
.time-slot.selected { .time-slot.selected {
color: white; color: white;
background: #5e64ff; background: var(--primary-color);
} }
.time-slot.selected .text-muted { .time-slot.selected .text-muted {