From 7cd7bf7f968ddb24ef2e71a96948f9e1bc3e373b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 13 Jan 2021 00:05:29 +0530 Subject: [PATCH 01/10] fix: incorrect key --- erpnext/controllers/buying_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 6edc020701..4dee375e5a 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -336,7 +336,7 @@ class BuyingController(StockController): raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {}) consumed_qty = raw_material_data.get('qty', 0) - consumed_serial_nos = raw_material_data.get('serial_nos', '') + consumed_serial_nos = raw_material_data.get('serial_no', '') consumed_batch_nos = raw_material_data.get('batch_nos', '') transferred_qty = raw_material.qty From fdad94f98314ee2e4c603f044e4682e3c43dfd69 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 14 Jan 2021 00:40:58 +0530 Subject: [PATCH 02/10] feat(Payroll): compute Year to Date for Salary Slip components --- .../doctype/salary_detail/salary_detail.json | 11 +++- .../doctype/salary_slip/salary_slip.js | 8 +-- .../doctype/salary_slip/salary_slip.py | 53 +++++++++++++++---- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json index 5c1eb61281..9bc25a6710 100644 --- a/erpnext/payroll/doctype/salary_detail/salary_detail.json +++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json @@ -9,6 +9,7 @@ "abbr", "column_break_3", "amount", + "year_to_date", "section_break_5", "additional_salary", "statistical_component", @@ -226,11 +227,19 @@ { "fieldname": "column_break_24", "fieldtype": "Column Break" + }, + { + "description": "Total amount spent on this salary component from the beginning of the year (payroll or fiscal) to the current payroll date.", + "fieldname": "year_to_date", + "fieldtype": "Currency", + "label": "Year To Date", + "options": "currency", + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2020-11-25 13:12:41.081106", + "modified": "2021-01-13 17:33:19.184195", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Detail", diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js index 51fb3596e9..945bd45275 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.js +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js @@ -138,11 +138,11 @@ frappe.ui.form.on("Salary Slip", { }, change_grid_labels: function(frm) { - frm.set_currency_labels(["amount", "default_amount", "additional_amount", "tax_on_flexible_benefit", - "tax_on_additional_salary"], frm.doc.currency, "earnings"); + let fields = ["amount", "year_to_date", "default_amount", "additional_amount", "tax_on_flexible_benefit", + "tax_on_additional_salary"]; - frm.set_currency_labels(["amount", "default_amount", "additional_amount", "tax_on_flexible_benefit", - "tax_on_additional_salary"], frm.doc.currency, "deductions"); + frm.set_currency_labels(fields, frm.doc.currency, "earnings"); + frm.set_currency_labels(fields, frm.doc.currency, "deductions"); }, refresh: function(frm) { diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 183ad13411..2d3bc57900 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -52,6 +52,7 @@ class SalarySlip(TransactionBase): self.calculate_net_pay() self.compute_year_to_date() self.compute_month_to_date() + self.compute_component_wise_year_to_date() if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"): max_working_hours = frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet") @@ -1138,16 +1139,7 @@ class SalarySlip(TransactionBase): def compute_year_to_date(self): year_to_date = 0 - payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) - - if payroll_period: - period_start_date = payroll_period.start_date - period_end_date = payroll_period.end_date - else: - # get dates based on fiscal year if no payroll period exists - fiscal_year = get_fiscal_year(date=self.start_date, company=self.company, as_dict=1) - period_start_date = fiscal_year.year_start_date - period_end_date = fiscal_year.year_end_date + period_start_date, period_end_date = self.get_year_to_date_period() salary_slip_sum = frappe.get_list('Salary Slip', fields = ['sum(net_pay) as sum'], @@ -1180,6 +1172,47 @@ class SalarySlip(TransactionBase): month_to_date += self.net_pay self.month_to_date = month_to_date + def compute_component_wise_year_to_date(self): + period_start_date, period_end_date = self.get_year_to_date_period() + + for key in ('earnings', 'deductions'): + for component in self.get(key): + year_to_date = 0 + component_sum = frappe.db.sql(""" + SELECT sum(detail.amount) as sum + FROM `tabSalary Detail` as detail + INNER JOIN `tabSalary Slip` as salary_slip + ON detail.parent = salary_slip.name + WHERE + salary_slip.employee_name = %(employee_name)s + AND detail.salary_component = %(component)s + AND salary_slip.start_date >= %(period_start_date)s + AND salary_slip.end_date < %(period_end_date)s + AND salary_slip.name != %(docname)s + AND salary_slip.docstatus = 1""", + {'employee_name': self.employee_name, 'component': component.salary_component, 'period_start_date': period_start_date, + 'period_end_date': period_end_date, 'docname': self.name} + ) + + year_to_date = flt(component_sum[0][0]) if component_sum else 0.0 + year_to_date += component.amount + component.year_to_date = year_to_date + + def get_year_to_date_period(self): + payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) + + if payroll_period: + period_start_date = payroll_period.start_date + period_end_date = payroll_period.end_date + else: + # get dates based on fiscal year if no payroll period exists + fiscal_year = get_fiscal_year(date=self.start_date, company=self.company, as_dict=1) + period_start_date = fiscal_year.year_start_date + period_end_date = fiscal_year.year_end_date + + return period_start_date, period_end_date + + def unlink_ref_doc_from_salary_slip(ref_no): linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip` where journal_entry=%s and docstatus < 2""", (ref_no)) From 2c315a738eb99e1a04735f257573b21f9de0fc18 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 14 Jan 2021 10:06:24 +0530 Subject: [PATCH 03/10] feat: Salary Slip with Year to Date Print Format --- erpnext/payroll/print_format/__init__.py | 0 .../salary_slip_with_year_to_date/__init__.py | 0 .../salary_slip_with_year_to_date.json | 25 +++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 erpnext/payroll/print_format/__init__.py create mode 100644 erpnext/payroll/print_format/salary_slip_with_year_to_date/__init__.py create mode 100644 erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json diff --git a/erpnext/payroll/print_format/__init__.py b/erpnext/payroll/print_format/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/payroll/print_format/salary_slip_with_year_to_date/__init__.py b/erpnext/payroll/print_format/salary_slip_with_year_to_date/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json b/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json new file mode 100644 index 0000000000..71ba37f6ed --- /dev/null +++ b/erpnext/payroll/print_format/salary_slip_with_year_to_date/salary_slip_with_year_to_date.json @@ -0,0 +1,25 @@ +{ + "absolute_value": 0, + "align_labels_right": 0, + "creation": "2021-01-14 09:56:42.393623", + "custom_format": 0, + "default_print_language": "en", + "disabled": 0, + "doc_type": "Salary Slip", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"

{{doc.name}}

\\n
\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"employee\", \"print_hide\": 0, \"label\": \"Employee\"}, {\"fieldname\": \"company\", \"print_hide\": 0, \"label\": \"Company\"}, {\"fieldname\": \"employee_name\", \"print_hide\": 0, \"label\": \"Employee Name\"}, {\"fieldname\": \"department\", \"print_hide\": 0, \"label\": \"Department\"}, {\"fieldname\": \"designation\", \"print_hide\": 0, \"label\": \"Designation\"}, {\"fieldname\": \"branch\", \"print_hide\": 0, \"label\": \"Branch\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"start_date\", \"print_hide\": 0, \"label\": \"Start Date\"}, {\"fieldname\": \"end_date\", \"print_hide\": 0, \"label\": \"End Date\"}, {\"fieldname\": \"total_working_days\", \"print_hide\": 0, \"label\": \"Working Days\"}, {\"fieldname\": \"leave_without_pay\", \"print_hide\": 0, \"label\": \"Leave Without Pay\"}, {\"fieldname\": \"payment_days\", \"print_hide\": 0, \"label\": \"Payment Days\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"earnings\", \"print_hide\": 0, \"label\": \"Earnings\", \"visible_columns\": [{\"fieldname\": \"salary_component\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"amount\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"year_to_date\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"deductions\", \"print_hide\": 0, \"label\": \"Deductions\", \"visible_columns\": [{\"fieldname\": \"salary_component\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"amount\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"year_to_date\", \"print_width\": \"\", \"print_hide\": 0}, {\"fieldname\": \"depends_on_payment_days\", \"print_width\": \"\", \"print_hide\": 0}]}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"gross_pay\", \"print_hide\": 0, \"label\": \"Gross Pay\"}, {\"fieldname\": \"total_deduction\", \"print_hide\": 0, \"label\": \"Total Deduction\"}, {\"fieldname\": \"net_pay\", \"print_hide\": 0, \"label\": \"Net Pay\"}, {\"fieldname\": \"rounded_total\", \"print_hide\": 0, \"label\": \"Rounded Total\"}, {\"fieldname\": \"total_in_words\", \"print_hide\": 0, \"label\": \"Total in words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"net pay info\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"year_to_date\", \"print_hide\": 0, \"label\": \"Year To Date\"}, {\"fieldname\": \"month_to_date\", \"print_hide\": 0, \"label\": \"Month To Date\"}]", + "idx": 0, + "line_breaks": 0, + "modified": "2021-01-14 10:03:45.283725", + "modified_by": "Administrator", + "module": "Payroll", + "name": "Salary Slip with Year to Date", + "owner": "Administrator", + "print_format_builder": 0, + "print_format_type": "Jinja", + "raw_printing": 0, + "show_section_headings": 0, + "standard": "Yes" +} \ No newline at end of file From 49702c1487f7b597b78ff7396e652860cee9ad28 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 14 Jan 2021 11:57:24 +0530 Subject: [PATCH 04/10] test: year to date computation for salary slip components --- .../doctype/salary_slip/salary_slip.js | 2 +- .../doctype/salary_slip/test_salary_slip.py | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js index 945bd45275..b50c774fbe 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.js +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js @@ -139,7 +139,7 @@ frappe.ui.form.on("Salary Slip", { change_grid_labels: function(frm) { let fields = ["amount", "year_to_date", "default_amount", "additional_amount", "tax_on_flexible_benefit", - "tax_on_additional_salary"]; + "tax_on_additional_salary"]; frm.set_currency_labels(fields, frm.doc.currency, "earnings"); frm.set_currency_labels(fields, frm.doc.currency, "deductions"); diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 4368c03c2a..f58a8e58c2 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -321,6 +321,38 @@ class TestSalarySlip(unittest.TestCase): year_to_date += flt(slip.net_pay) self.assertEqual(slip.year_to_date, year_to_date) + def test_component_wise_year_to_date_computation(self): + from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + + applicant = make_employee("test_ytd@salary.com", company="_Test Company") + + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") + + create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01"), + company="_Test Company") + + salary_structure = make_salary_structure("Monthly Salary Structure Test for Salary Slip YTD", + "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period) + + # clear salary slip for this employee + frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'") + + create_salary_slips_for_payroll_period(applicant, salary_structure.name, + payroll_period, deduct_random=False, num=3) + + salary_slips = frappe.get_all("Salary Slip", fields=["name"], filters={"employee_name": + "test_ytd@salary.com"}, order_by = "posting_date") + + year_to_date = dict() + for slip in salary_slips: + doc = frappe.get_doc("Salary Slip", slip.name) + for entry in doc.get("earnings"): + if not year_to_date.get(entry.salary_component): + year_to_date[entry.salary_component] = 0 + + year_to_date[entry.salary_component] += entry.amount + self.assertEqual(year_to_date[entry.salary_component], entry.year_to_date) + def test_tax_for_payroll_period(self): data = {} # test the impact of tax exemption declaration, tax exemption proof submission @@ -714,10 +746,10 @@ def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = else: return income_tax_slab_name -def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True): +def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True, num=12): deducted_dates = [] i = 0 - while i < 12: + while i < num: slip = frappe.get_doc({"doctype": "Salary Slip", "employee": employee, "salary_structure": salary_structure, "frequency": "Monthly"}) if i == 0: From 6c90e269829d35c0e3b0e11b84507d08c76a8f5e Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 14 Jan 2021 13:42:40 +0530 Subject: [PATCH 05/10] feat: add descriptions for YTD and MTD fields --- erpnext/payroll/doctype/salary_detail/salary_detail.json | 4 ++-- erpnext/payroll/doctype/salary_slip/salary_slip.json | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json index 9bc25a6710..393f647cc8 100644 --- a/erpnext/payroll/doctype/salary_detail/salary_detail.json +++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json @@ -229,7 +229,7 @@ "fieldtype": "Column Break" }, { - "description": "Total amount spent on this salary component from the beginning of the year (payroll or fiscal) to the current payroll date.", + "description": "Total salary booked against this component for this employee from the beginning of the year (payroll period or fiscal year) up to the current salary slip's end date.", "fieldname": "year_to_date", "fieldtype": "Currency", "label": "Year To Date", @@ -239,7 +239,7 @@ ], "istable": 1, "links": [], - "modified": "2021-01-13 17:33:19.184195", + "modified": "2021-01-14 13:39:15.847158", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Detail", diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index 43deee43aa..9f9691b59d 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -584,6 +584,7 @@ "fieldtype": "Column Break" }, { + "description": "Total salary booked for this employee from the beginning of the year (payroll period or fiscal year) up to the current salary slip's end date.", "fieldname": "year_to_date", "fieldtype": "Currency", "label": "Year To Date", @@ -591,6 +592,7 @@ "read_only": 1 }, { + "description": "Total salary booked for this employee from the beginning of the month up to the current salary slip's end date.", "fieldname": "month_to_date", "fieldtype": "Currency", "label": "Month To Date", @@ -616,7 +618,7 @@ "idx": 9, "is_submittable": 1, "links": [], - "modified": "2020-12-21 23:43:44.959840", + "modified": "2021-01-14 13:37:38.180920", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", From c69ab6d184f2927bb8a148d2e3d20fc32ee0eba5 Mon Sep 17 00:00:00 2001 From: Afshan Date: Tue, 19 Jan 2021 19:29:31 +0530 Subject: [PATCH 06/10] fix: select sal comp while making sal struct --- erpnext/payroll/doctype/salary_structure/salary_structure.js | 4 ++++ erpnext/payroll/doctype/salary_structure/salary_structure.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.js b/erpnext/payroll/doctype/salary_structure/salary_structure.js index ba824c5d6f..6c7b382264 100755 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.js +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.js @@ -70,6 +70,9 @@ frappe.ui.form.on('Salary Structure', { }); }, + company: function(frm) { + frm.trigger('set_earning_deduction_component'); + }, currency: function(frm) { calculate_totals(frm.doc); @@ -117,6 +120,7 @@ frappe.ui.form.on('Salary Structure', { fields_read_only.forEach(function(field) { frappe.meta.get_docfield("Salary Detail", field, frm.doc.name).read_only = 1; }); + frm.trigger('set_earning_deduction_component'); }, assign_to_employees:function (frm) { diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py index 77914bb531..340f4e8569 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py @@ -216,7 +216,7 @@ def get_earning_deduction_components(doctype, txt, searchfield, start, page_len, return frappe.db.sql(""" select t1.salary_component from `tabSalary Component` t1, `tabSalary Component Account` t2 - where t1.salary_component = t2.parent + where t1.name = t2.parent and t1.type = %s and t2.company = %s order by salary_component From e2ed2324c3eb50f6bb5a67e95f218db6153f8a5d Mon Sep 17 00:00:00 2001 From: Saqib Date: Wed, 20 Jan 2021 13:17:42 +0530 Subject: [PATCH 07/10] fix: (e-invoicing) qrcode image generation (#24395) * fix: invalid taxable value of item for e-invoice * fix: qrcode image duplicate error * fix: net total discount calculation * fix: auto fetch auth token --- erpnext/regional/india/e_invoice/utils.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index d0cac90e4d..83635a199e 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -161,9 +161,9 @@ def get_item_list(invoice): item.qty = abs(item.qty) item.discount_amount = abs(item.discount_amount * item.qty) - item.unit_rate = abs(item.base_amount / item.qty) - item.gross_amount = abs(item.base_amount) - item.taxable_value = abs(item.base_amount) + item.unit_rate = abs(item.base_net_amount / item.qty) + item.gross_amount = abs(item.base_net_amount) + item.taxable_value = abs(item.base_net_amount) item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None @@ -198,7 +198,7 @@ def update_item_taxes(invoice, item): if t.account_head in gst_accounts_list: item_tax_rate = item_tax_detail[0] # item tax amount excluding discount amount - item_tax_amount = (item_tax_rate / 100) * item.base_amount + item_tax_amount = (item_tax_rate / 100) * item.base_net_amount if t.account_head in gst_accounts.cess_account: item_tax_amount_after_discount = item_tax_detail[1] @@ -217,7 +217,10 @@ def update_item_taxes(invoice, item): def get_invoice_value_details(invoice): invoice_value_details = frappe._dict(dict()) - invoice_value_details.base_total = abs(invoice.base_total) + if invoice.apply_discount_on == 'Net Total' and invoice.discount_amount: + invoice_value_details.base_total = abs(invoice.base_total) + else: + invoice_value_details.base_total = abs(invoice.base_net_total) invoice_value_details.invoice_discount_amt = invoice.base_discount_amount invoice_value_details.round_off = invoice.base_rounding_adjustment invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total) @@ -473,7 +476,7 @@ class GSPConnector(): "data": json.dumps(data, indent=4) if isinstance(data, dict) else data, "response": json.dumps(res, indent=4) if res else None }) - request_log.insert(ignore_permissions=True) + request_log.save(ignore_permissions=True) frappe.db.commit() def fetch_auth_token(self): @@ -486,7 +489,8 @@ class GSPConnector(): res = self.make_request('post', self.authenticate_url, headers) self.e_invoice_settings.auth_token = "{} {}".format(res.get('token_type'), res.get('access_token')) self.e_invoice_settings.token_expiry = add_to_date(None, seconds=res.get('expires_in')) - self.e_invoice_settings.save() + self.e_invoice_settings.save(ignore_permissions=True) + self.e_invoice_settings.reload() except Exception: self.log_error(res) @@ -757,7 +761,7 @@ class GSPConnector(): 'label': _('IRN Generated') } self.update_invoice() - + def attach_qrcode_image(self): qrcode = self.invoice.signed_qr_code doctype = self.invoice.doctype @@ -768,7 +772,7 @@ class GSPConnector(): 'file_name': 'QRCode_{}.png'.format(docname.replace('/', '-')), 'attached_to_doctype': doctype, 'attached_to_name': docname, - 'content': 'qrcode', + 'content': str(base64.b64encode(os.urandom(64))), 'is_private': 1 }) _file.insert() From 912647f4f23f2b6a6a7c10290682e757fdf840f4 Mon Sep 17 00:00:00 2001 From: Afshan Date: Wed, 20 Jan 2021 13:58:32 +0530 Subject: [PATCH 08/10] fix: allow statistical component in salary structure. --- .../payroll/doctype/salary_structure/salary_structure.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py index 340f4e8569..bf1c746964 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py @@ -216,8 +216,9 @@ def get_earning_deduction_components(doctype, txt, searchfield, start, page_len, return frappe.db.sql(""" select t1.salary_component from `tabSalary Component` t1, `tabSalary Component Account` t2 - where t1.name = t2.parent + where (t1.name = t2.parent and t1.type = %s - and t2.company = %s + and t2.company = %s) + or (t1.statistical_component = 1) order by salary_component - """, (filters['type'], filters['company']) ) + """, (filters['type'], filters['company'])) From 36e3e05a0edcbe2736df77a9c57c7eae63f25f30 Mon Sep 17 00:00:00 2001 From: Afshan Date: Wed, 20 Jan 2021 16:48:42 +0530 Subject: [PATCH 09/10] fix: query for salary componet in salary structure --- .../doctype/salary_structure/salary_structure.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py index bf1c746964..e71803172c 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py @@ -217,8 +217,12 @@ def get_earning_deduction_components(doctype, txt, searchfield, start, page_len, select t1.salary_component from `tabSalary Component` t1, `tabSalary Component Account` t2 where (t1.name = t2.parent - and t1.type = %s - and t2.company = %s) - or (t1.statistical_component = 1) + and t1.type = %(type)s + and t2.company = %(company)s) + or (t1.type = %(type)s + and t1.statistical_component = 1) order by salary_component - """, (filters['type'], filters['company'])) + """,{ + "type": filters['type'], + "company": filters['company'] + }) From 577d2bed6ec0d919b89ff55bb442b629d5e1c5af Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 21 Jan 2021 18:43:55 +0530 Subject: [PATCH 10/10] fix: failing einvoice test (#24434) --- .../sales_invoice/test_sales_invoice.py | 27 ++++--------------- erpnext/regional/india/e_invoice/utils.py | 9 ++++--- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 5435d3b21e..3a6dbeb51c 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1861,23 +1861,6 @@ class TestSalesInvoice(unittest.TestCase): def test_einvoice_json(self): from erpnext.regional.india.e_invoice.utils import make_einvoice - customer_gstin = '27AACCM7806M1Z3' - customer_gstin_dtls = { - 'LegalName': '_Test Customer', 'TradeName': '_Test Customer', 'AddrLoc': '_Test City', - 'StateCode': '27', 'AddrPncd': '410038', 'AddrBno': '_Test Bldg', - 'AddrBnm': '100', 'AddrFlno': '200', 'AddrSt': '_Test Street' - } - company_gstin = '27AAECE4835E1ZR' - company_gstin_dtls = { - 'LegalName': '_Test Company', 'TradeName': '_Test Company', 'AddrLoc': '_Test City', - 'StateCode': '27', 'AddrPncd': '401108', 'AddrBno': '_Test Bldg', - 'AddrBnm': '100', 'AddrFlno': '200', 'AddrSt': '_Test Street' - } - # set cache gstin details to avoid fetching details which will require connection to GSP servers - frappe.local.gstin_cache = {} - frappe.local.gstin_cache[customer_gstin] = customer_gstin_dtls - frappe.local.gstin_cache[company_gstin] = company_gstin_dtls - si = make_sales_invoice_for_ewaybill() si.naming_series = 'INV-2020-.#####' si.items = [] @@ -1930,12 +1913,12 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(value_details['SgstVal'], total_item_sgst_value) self.assertEqual(value_details['IgstVal'], total_item_igst_value) - self.assertEqual( - value_details['TotInvVal'], - value_details['AssVal'] + value_details['CgstVal'] - + value_details['SgstVal'] + value_details['IgstVal'] + calculated_invoice_value = \ + value_details['AssVal'] + value_details['CgstVal'] \ + + value_details['SgstVal'] + value_details['IgstVal'] \ + value_details['OthChrg'] - value_details['Discount'] - ) + + self.assertTrue(value_details['TotInvVal'] - calculated_invoice_value < 0.1) self.assertEqual(value_details['TotInvVal'], si.base_grand_total) self.assertTrue(einvoice['EwbDtls']) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index 83635a199e..eb210be16a 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -217,11 +217,14 @@ def update_item_taxes(invoice, item): def get_invoice_value_details(invoice): invoice_value_details = frappe._dict(dict()) + if invoice.apply_discount_on == 'Net Total' and invoice.discount_amount: invoice_value_details.base_total = abs(invoice.base_total) else: invoice_value_details.base_total = abs(invoice.base_net_total) - invoice_value_details.invoice_discount_amt = invoice.base_discount_amount + + # since tax already considers discount amount + invoice_value_details.invoice_discount_amt = 0 # invoice.base_discount_amount invoice_value_details.round_off = invoice.base_rounding_adjustment invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total) invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total) @@ -247,9 +250,9 @@ def update_invoice_taxes(invoice, invoice_value_details): for tax_type in ['igst', 'cgst', 'sgst']: if t.account_head in gst_accounts[f'{tax_type}_account']: - invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount) + invoice_value_details[f'total_{tax_type}_amt'] += abs(t.base_tax_amount_after_discount_amount) else: - invoice_value_details.total_other_charges += abs(t.base_tax_amount) + invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount) return invoice_value_details