Merge pull request #25109 from ankush/po_to_pr_fixes
fix: incorrect status creating PR from PO after creating PI
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 054afe5..6d388c4 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -12,6 +12,10 @@
from erpnext.stock.doctype.item.test_item import make_item
class TestPOSInvoice(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ frappe.db.sql("delete from `tabTax Rule`")
+
def tearDown(self):
if frappe.session.user != "Administrator":
frappe.set_user("Administrator")
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_records.json b/erpnext/accounts/doctype/purchase_invoice/test_records.json
index e7166c5..9f9e90d 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_records.json
+++ b/erpnext/accounts/doctype/purchase_invoice/test_records.json
@@ -43,7 +43,7 @@
}
],
"grand_total": 0,
- "naming_series": "_T-BILL",
+ "naming_series": "T-PINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",
@@ -167,7 +167,7 @@
}
],
"grand_total": 0,
- "naming_series": "_T-Purchase Invoice-",
+ "naming_series": "T-PINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_records.json b/erpnext/accounts/doctype/sales_invoice/test_records.json
index e00a58f..3781f8c 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_records.json
+++ b/erpnext/accounts/doctype/sales_invoice/test_records.json
@@ -31,7 +31,7 @@
"base_grand_total": 561.8,
"grand_total": 561.8,
"is_pos": 0,
- "naming_series": "_T-Sales Invoice-",
+ "naming_series": "T-SINV-",
"base_net_total": 500.0,
"taxes": [
{
@@ -104,7 +104,7 @@
"base_grand_total": 630.0,
"grand_total": 630.0,
"is_pos": 0,
- "naming_series": "_T-Sales Invoice-",
+ "naming_series": "T-SINV-",
"base_net_total": 500.0,
"taxes": [
{
@@ -175,7 +175,7 @@
],
"grand_total": 0,
"is_pos": 0,
- "naming_series": "_T-Sales Invoice-",
+ "naming_series": "T-SINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",
@@ -301,7 +301,7 @@
],
"grand_total": 0,
"is_pos": 0,
- "naming_series": "_T-Sales Invoice-",
+ "naming_series": "T-SINV-",
"taxes": [
{
"account_head": "_Test Account Excise Duty - _TC",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 90e2144..f09cc5a 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -2115,6 +2115,7 @@
si.return_against = args.return_against
si.currency=args.currency or "INR"
si.conversion_rate = args.conversion_rate or 1
+ si.naming_series = args.naming_series or "T-SINV-"
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
index 6e6eaed..2528240 100644
--- a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
+++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py
@@ -9,9 +9,7 @@
class TestSupplierScorecard(unittest.TestCase):
def test_create_scorecard(self):
- delete_test_scorecards()
- my_doc = make_supplier_scorecard()
- doc = my_doc.insert()
+ doc = make_supplier_scorecard().insert()
self.assertEqual(doc.name, valid_scorecard[0].get("supplier"))
def test_criteria_weight(self):
@@ -121,7 +119,8 @@
{
"weight":100.0,
"doctype":"Supplier Scorecard Scoring Criteria",
- "criteria_name":"Delivery"
+ "criteria_name":"Delivery",
+ "formula": "100"
}
],
"supplier":"_Test Supplier",
diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
index a21caca..21776d2 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py
@@ -81,15 +81,8 @@
self.ip_record.reload()
discharge_patient(self.ip_record)
- for entry in frappe.get_all('Inpatient Medication Entry'):
- doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
- doc.cancel()
- doc.delete()
-
- for entry in frappe.get_all('Inpatient Medication Order'):
- doc = frappe.get_doc('Inpatient Medication Order', entry.name)
- doc.cancel()
- doc.delete()
+ for doctype in ["Inpatient Medication Entry", "Inpatient Medication Order"]:
+ frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
def create_dosage_form():
if not frappe.db.exists('Dosage Form', 'Tablet'):
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js
index d527839..3e8a213 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.js
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js
@@ -216,7 +216,7 @@
});
var set_totals = function(frm) {
- if (frm.doc.docstatus === 0) {
+ if (frm.doc.docstatus === 0 && frm.doc.doctype === "Salary Slip") {
if (frm.doc.earnings || frm.doc.deductions) {
frappe.call({
method: "set_totals",
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 9abe57c..aa9acd8 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -618,13 +618,16 @@
component_row = self.append(component_type)
for attr in (
- 'depends_on_payment_days', 'salary_component', 'abbr'
+ 'depends_on_payment_days', 'salary_component',
'do_not_include_in_total', 'is_tax_applicable',
'is_flexible_benefit', 'variable_based_on_taxable_salary',
'exempted_from_income_tax'
):
component_row.set(attr, component_data.get(attr))
+ abbr = component_data.get('abbr') or component_data.get('salary_component_abbr')
+ component_row.set('abbr', abbr)
+
if additional_salary:
component_row.default_amount = 0
component_row.additional_amount = amount
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py
index 1712081..352c180 100644
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.py
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py
@@ -100,7 +100,7 @@
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
assign_salary_structure_for_employees(employees, self,
- payroll_payable_account=payroll_payable_account,
+ payroll_payable_account=payroll_payable_account,
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
frappe.msgprint(_("No Employee Found"))
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 077011a..c5265e2 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -18,8 +18,8 @@
};
},
onload: function (frm) {
- var so = frappe.meta.get_docfield("Project", "sales_order");
- so.get_route_options_for_new_doc = function (field) {
+ const so = frm.get_docfield("sales_order");
+ so.get_route_options_for_new_doc = () => {
if (frm.is_new()) return;
return {
"customer": frm.doc.customer,
diff --git a/erpnext/regional/india/e_invoice/einv_validation.json b/erpnext/regional/india/e_invoice/einv_validation.json
index 86290cf..f4a3542 100644
--- a/erpnext/regional/india/e_invoice/einv_validation.json
+++ b/erpnext/regional/india/e_invoice/einv_validation.json
@@ -919,7 +919,8 @@
"minLength": 1,
"maxLength": 15,
"pattern": "^([0-9A-Z/-]){1,15}$",
- "description": "Tranport Document Number"
+ "description": "Tranport Document Number",
+ "validationMsg": "Transport Receipt No is invalid"
},
"TransDocDt": {
"type": "string",
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 96f7f1b..8eccc3f 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -87,10 +87,10 @@
invoice_date=invoice_date
))
-def get_party_details(address_name):
+def get_party_details(address_name, company_address=None, billing_address=None, shipping_address=None):
d = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0]
- if (not d.gstin
+ if ((not d.gstin and not shipping_address)
or not d.city
or not d.pincode
or not d.address_title
@@ -108,8 +108,7 @@
# according to einvoice standard
pincode = 999999
- return frappe._dict(dict(
- gstin=d.gstin,
+ party_address_details = frappe._dict(dict(
legal_name=sanitize_for_json(d.address_title),
location=sanitize_for_json(d.city),
pincode=d.pincode,
@@ -117,6 +116,9 @@
address_line1=sanitize_for_json(d.address_line1),
address_line2=sanitize_for_json(d.address_line2)
))
+ if d.gstin:
+ party_address_details.gstin = d.gstin
+ return party_address_details
def get_gstin_details(gstin):
if not hasattr(frappe.local, 'gstin_cache'):
@@ -328,14 +330,17 @@
item_list = get_item_list(invoice)
doc_details = get_doc_details(invoice)
invoice_value_details = get_invoice_value_details(invoice)
- seller_details = get_party_details(invoice.company_address)
+ seller_details = get_party_details(invoice.company_address, company_address=1)
if invoice.gst_category == 'Overseas':
buyer_details = get_overseas_address_details(invoice.customer_address)
else:
- buyer_details = get_party_details(invoice.customer_address)
- place_of_supply = get_place_of_supply(invoice, invoice.doctype) or sanitize_for_json(invoice.billing_address_gstin)
- place_of_supply = place_of_supply[:2]
+ buyer_details = get_party_details(invoice.customer_address, billing_address=1)
+ place_of_supply = get_place_of_supply(invoice, invoice.doctype)
+ if place_of_supply:
+ place_of_supply = place_of_supply.split('-')[0]
+ else:
+ place_of_supply = sanitize_for_json(invoice.billing_address_gstin)[:2]
buyer_details.update(dict(place_of_supply=place_of_supply))
shipping_details = payment_details = prev_doc_details = eway_bill_details = frappe._dict({})
@@ -343,7 +348,7 @@
if invoice.gst_category == 'Overseas':
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
else:
- shipping_details = get_party_details(invoice.shipping_address_name)
+ shipping_details = get_party_details(invoice.shipping_address_name, shipping_address=1)
if invoice.is_pos and invoice.base_paid_amount:
payment_details = get_payment_details(invoice)
@@ -391,7 +396,9 @@
snippet = json_string[start:end]
frappe.throw(_("Error in input data. Please check for any special characters near following input: <br> {}").format(snippet))
-def validate_einvoice(validations, einvoice, errors=[]):
+def validate_einvoice(validations, einvoice, errors=None):
+ if errors is None:
+ errors = []
for fieldname, field_validation in validations.items():
value = einvoice.get(fieldname, None)
if not value or value == "None":
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index ee49aae..f7689cf 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -5,6 +5,7 @@
import frappe, os, json
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.permissions import add_permission, update_permission_property
from erpnext.regional.india import states
from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
@@ -18,6 +19,7 @@
# TODO: for all countries
def setup_company_independent_fixtures():
make_custom_fields()
+ make_property_setters()
add_permissions()
add_custom_roles_for_reports()
frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test)
@@ -110,6 +112,11 @@
frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0)
frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0)
+def make_property_setters():
+ # GST rules do not allow for an invoice no. bigger than 16 characters
+ make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '')
+ make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '')
+
def make_custom_fields(update=True):
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description',
@@ -860,4 +867,4 @@
})
rule.flags.ignore_mandatory = True
- rule.save()
\ No newline at end of file
+ rule.save()
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index c452594..96b3fa4 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -230,13 +230,20 @@
frappe.db.set(self, "customer_name", newdn)
def set_loyalty_program(self):
- if self.loyalty_program: return
+ if self.loyalty_program:
+ return
+
loyalty_program = get_loyalty_programs(self)
- if not loyalty_program: return
+ if not loyalty_program:
+ return
+
if len(loyalty_program) == 1:
self.loyalty_program = loyalty_program[0]
else:
- frappe.msgprint(_("Multiple Loyalty Program found for the Customer. Please select manually."))
+ frappe.msgprint(
+ _("Multiple Loyalty Programs found for Customer {}. Please select manually.")
+ .format(frappe.bold(self.customer_name))
+ )
def create_onboarding_docs(self, args):
defaults = frappe.defaults.get_defaults()
@@ -340,7 +347,6 @@
@frappe.whitelist()
def get_loyalty_programs(doc):
''' returns applicable loyalty programs for a customer '''
- from frappe.desk.treeview import get_children
lp_details = []
loyalty_programs = frappe.get_all("Loyalty Program",
@@ -349,15 +355,33 @@
"ifnull(to_date, '2500-01-01')": [">=", today()]})
for loyalty_program in loyalty_programs:
- customer_groups = [d.value for d in get_children("Customer Group", loyalty_program.customer_group)] + [loyalty_program.customer_group]
- customer_territories = [d.value for d in get_children("Territory", loyalty_program.customer_territory)] + [loyalty_program.customer_territory]
-
- if (not loyalty_program.customer_group or doc.customer_group in customer_groups)\
- and (not loyalty_program.customer_territory or doc.territory in customer_territories):
+ if (
+ (not loyalty_program.customer_group
+ or doc.customer_group in get_nested_links(
+ "Customer Group",
+ loyalty_program.customer_group,
+ doc.flags.ignore_permissions
+ ))
+ and (not loyalty_program.customer_territory
+ or doc.territory in get_nested_links(
+ "Territory",
+ loyalty_program.customer_territory,
+ doc.flags.ignore_permissions
+ ))
+ ):
lp_details.append(loyalty_program.name)
return lp_details
+def get_nested_links(link_doctype, link_name, ignore_permissions=False):
+ from frappe.desk.treeview import _get_children
+
+ links = [link_name]
+ for d in _get_children(link_doctype, link_name, ignore_permissions):
+ links.append(d.value)
+
+ return links
+
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None):
@@ -572,4 +596,4 @@
""", {
'customer': customer,
'txt': '%%%s%%' % txt
- })
\ No newline at end of file
+ })
diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json
index 909c4ee..c1f20a4 100644
--- a/erpnext/stock/doctype/item/test_records.json
+++ b/erpnext/stock/doctype/item/test_records.json
@@ -12,6 +12,7 @@
"item_name": "_Test Item",
"apply_warehouse_wise_reorder_level": 1,
"gst_hsn_code": "999800",
+ "opening_stock": 10,
"valuation_rate": 100,
"item_defaults": [{
"company": "_Test Company",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 05819ab..469511a 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -64,17 +64,21 @@
(quality_inspection, self.modified, self.reference_name, self.item_code))
else:
+ args = [quality_inspection, self.modified, self.reference_name, self.item_code]
doctype = self.reference_type + ' Item'
+
if self.reference_type == 'Stock Entry':
doctype = 'Stock Entry Detail'
if self.reference_type and self.reference_name:
conditions = ""
if self.batch_no and self.docstatus == 1:
- conditions += " and t1.batch_no = '%s'"%(self.batch_no)
+ conditions += " and t1.batch_no = %s"
+ args.append(self.batch_no)
if self.docstatus == 2: # if cancel, then remove qi link wherever same name
- conditions += " and t1.quality_inspection = '%s'"%(self.name)
+ conditions += " and t1.quality_inspection = %s"
+ args.append(self.name)
frappe.db.sql("""
UPDATE
@@ -87,7 +91,7 @@
and t1.parent = t2.name
{conditions}
""".format(parent_doc=self.reference_type, child_doc=doctype, conditions=conditions),
- (quality_inspection, self.modified, self.reference_name, self.item_code))
+ args)
def inspect_and_set_status(self):
for reading in self.readings: