Merge branch 'staging-fixes' into staging
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index f48b48b..6947c02 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -12,7 +12,7 @@
source_link = "https://github.com/frappe/erpnext"
develop_version = '12.x.x-develop'
-staging_version = '11.0.3-beta.21'
+staging_version = '11.0.3-beta.22'
error_report_email = "support@erpnext.com"
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 4a111e7..033938d 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -58,6 +58,9 @@
doc.company = frm.doc.company;
frappe.set_route('Form', 'Salary Structure Assignment', doc.name);
});
+ frm.add_custom_button(__("Assign to Employees"),function () {
+ frm.trigger('assign_to_employees')
+ })
}
let fields_read_only = ["is_tax_applicable", "is_flexible_benefit", "variable_based_on_taxable_salary"];
fields_read_only.forEach(function(field) {
@@ -65,6 +68,43 @@
});
},
+ assign_to_employees:function (frm) {
+ var d = new frappe.ui.Dialog({
+ title: __("Assign to Employees"),
+ fields: [
+ {fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")},
+ {fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")},
+ {fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')},
+ {fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')},
+ {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
+ {fieldname:'base_variable', fieldtype:'Section Break'},
+ {fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1},
+ {fieldname:'base_col_br', fieldtype:'Column Break'},
+ {fieldname:'base', fieldtype:'Currency', label: __('Base')},
+ {fieldname:'variable', fieldtype:'Currency', label: __('Variable')}
+ ],
+ primary_action: function() {
+ var data = d.get_values();
+
+ frappe.call({
+ doc: frm.doc,
+ method: "assign_salary_structure",
+ args: data,
+ callback: function(r) {
+ if(!r.exc) {
+ d.hide();
+ frm.reload_doc();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Assign')
+ });
+
+
+ d.show();
+ },
+
salary_slip_based_on_timesheet: function(frm) {
frm.trigger("toggle_fields")
},
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index a36d820..7ead140 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -65,6 +65,76 @@
if not have_a_flexi and flt(self.max_benefits) > 0:
frappe.throw(_("Salary Structure should have flexible benefit component(s) to dispense benefit amount"))
+ def get_employees(self, **kwargs):
+ conditions, values = [], []
+ for field, value in kwargs.items():
+ if value:
+ conditions.append("{0}=%s".format(field))
+ values.append(value)
+
+ condition_str = " and " + " and ".join(conditions) if conditions else ""
+
+ employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}"
+ .format(condition=condition_str), tuple(values))
+
+ return employees
+
+ @frappe.whitelist()
+ def assign_salary_structure(self, grade=None, department=None, designation=None,employee=None,
+ from_date=None, base=None,variable=None):
+ employees = self.get_employees(grade= grade,department= department,designation= designation,name=employee)
+
+ if employees:
+ if len(employees) > 20:
+ frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
+ employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable)
+ else:
+ assign_salary_structure_for_employees(employees, self,from_date=from_date, base=base,variable=variable)
+ else:
+ frappe.msgprint(_("No Employee Found"))
+
+
+
+def assign_salary_structure_for_employees(employees, salary_structure,from_date=None, base=None,variable=None):
+ salary_structures_assignments = []
+ existing_assignments_for = get_existing_assignments(employees, salary_structure.name,from_date)
+ count=0
+ for employee in employees:
+ if employee in existing_assignments_for:
+ continue
+ count +=1
+
+ salary_structures_assignment = create_salary_structures_assignment(employee, salary_structure, from_date, base, variable)
+ salary_structures_assignments.append(salary_structures_assignment)
+ frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures..."))
+
+ if salary_structures_assignments:
+ frappe.msgprint(_("Structures have been assigned successfully"))
+
+
+def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable):
+ assignment = frappe.new_doc("Salary Structure Assignment")
+ assignment.employee = employee
+ assignment.salary_structure = salary_structure.name
+ assignment.from_date = from_date
+ assignment.base = base
+ assignment.variable = variable
+ assignment.save(ignore_permissions = True)
+ assignment.submit()
+ return assignment.name
+
+
+def get_existing_assignments(employees, salary_structure,from_date):
+ salary_structures_assignments = frappe.db.sql_list("""
+ select distinct employee from `tabSalary Structure Assignment`
+ where salary_structure=%s and employee in (%s)
+ and from_date=%s and docstatus=1
+ """ % ('%s', ', '.join(['%s']*len(employees)),'%s'), [salary_structure] + employees+[from_date])
+ if salary_structures_assignments:
+ frappe.msgprint(_("Skipping Salary Structure Assignment for the following employees, as Salary Structure Assignment records already exists against them. {0}")
+ .format("\n".join(salary_structures_assignments)))
+ return salary_structures_assignments
+
@frappe.whitelist()
def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None):
def postprocess(source, target):
diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
index 1a16db7..1a660d9 100644
--- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
@@ -71,6 +71,19 @@
for row in salary_structure.deductions:
self.assertFalse(("\n" in row.formula) or ("\n" in row.condition))
+ def test_salary_structures_assignment(self):
+ salary_structure = make_salary_structure("Salary Structure Sample", "Monthly")
+ employee = "test_assign_stucture@salary.com"
+ employee_doc_name = make_employee(employee)
+ # clear the already assigned stuctures
+ frappe.db.sql('''delete from `tabSalary Structure Assignment` where employee=%s and salary_structure=%s ''',
+ ("test_assign_stucture@salary.com",salary_structure.name))
+ #test structure_assignment
+ salary_structure.assign_salary_structure(employee=employee_doc_name,from_date='2013-01-01',base=5000,variable=200)
+ salary_structure_assignment = frappe.get_doc("Salary Structure Assignment",{'employee':employee_doc_name, 'from_date':'2013-01-01'})
+ self.assertEqual(salary_structure_assignment.docstatus, 1)
+ self.assertEqual(salary_structure_assignment.base, 5000)
+ self.assertEqual(salary_structure_assignment.variable, 200)
def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None, test_tax=False):
if test_tax:
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 0eab982..d72f00a 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -108,7 +108,8 @@
"item_code": item.item_code,
"item_name": item.item_name,
"bom_no": item.bom_no,
- "stock_qty": item.stock_qty
+ "stock_qty": item.stock_qty,
+ "allow_transfer_for_manufacture": item.allow_transfer_for_manufacture
})
for r in ret:
if not item.get(r):
@@ -127,6 +128,8 @@
self.validate_rm_item(item)
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
+ args['transfer_for_manufacture'] = (cstr(args.get('allow_transfer_for_manufacture', '')) or
+ item and item[0].allow_transfer_for_manufacture or 0)
args.update(item[0])
rate = self.get_rm_rate(args)
@@ -142,7 +145,7 @@
'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate,
- 'allow_transfer_for_manufacture': item and args['allow_transfer_for_manufacture'] or 0
+ 'allow_transfer_for_manufacture': cint(args['transfer_for_manufacture']) or 0
}
return ret_item
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ca25667..f771181 100755
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -572,9 +572,10 @@
execute:frappe.delete_doc("Page", "Purchase Analytics")
execute:frappe.delete_doc("Page", "Stock Analytics")
execute:frappe.delete_doc("Page", "Production Analytics")
-erpnext.patches.v11_0.ewaybill_fields_gst_india
+erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13
erpnext.patches.v11_0.drop_column_max_days_allowed
erpnext.patches.v11_0.change_healthcare_desktop_icons
erpnext.patches.v10_0.update_user_image_in_employee
erpnext.patches.v11_0.update_delivery_trip_status
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
+erpnext.patches.v11_0.set_missing_gst_hsn_code
diff --git a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
new file mode 100644
index 0000000..9d28a4a
--- /dev/null
+++ b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py
@@ -0,0 +1,43 @@
+import frappe
+from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html
+
+def execute():
+ company = frappe.db.sql_list("select name from tabCompany where country = 'India'")
+ if not company:
+ return
+
+ doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice",
+ "Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"]
+
+ for dt in doctypes:
+ date_field = "posting_date"
+ if dt in ["Quotation", "Sales Order", "Supplier Quotation", "Purchase Order"]:
+ date_field = "transaction_date"
+
+ transactions = frappe.db.sql("""
+ select dt.name, dt_item.name as child_name
+ from `tab{dt}` dt, `tab{dt} Item` dt_item
+ where dt.name = dt_item.parent
+ and dt.`{date_field}` > '2018-06-01'
+ and dt.docstatus = 1
+ and ifnull(dt_item.gst_hsn_code, '') = ''
+ and ifnull(dt_item.item_code, '') != ''
+ and dt.company in ({company})
+ """.format(dt=dt, date_field=date_field, company=", ".join(['%s']*len(company))), tuple(company), as_dict=1)
+
+ if not transactions:
+ continue
+
+ transaction_rows_name = [d.child_name for d in transactions]
+
+ frappe.db.sql("""
+ update `tab{dt} Item` dt_item
+ set dt_item.gst_hsn_code = (select gst_hsn_code from tabItem where name=dt_item.item_code)
+ where dt_item.name in ({rows_name})
+ """.format(dt=dt, rows_name=", ".join(['%s']*len(transaction_rows_name))), tuple(transaction_rows_name))
+
+ for t in transactions:
+ print(t.name)
+ trans_doc = frappe.get_doc(dt, t.name)
+ hsnwise_tax = get_itemised_tax_breakup_html(trans_doc)
+ frappe.db.set_value(dt, t.name, "other_charges_calculation", hsnwise_tax, update_modified=False)
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index c754121..d282f5c 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -85,7 +85,7 @@
def make_custom_fields(update=True):
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
- fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description',
+ fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description',
allow_on_submit=1, print_hide=1)
invoice_gst_fields = [
dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break',