Employee Benefits in Salary Slip - Application and Claim
diff --git a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py
index e1af430..1902b5d 100644
--- a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py
+++ b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py
@@ -110,8 +110,9 @@
 	if salary_structure:
 		return salary_structure
 
-def get_employee_benefit_application(employee, start_date, end_date):
-	employee_benefits = frappe.db.sql("""
+def get_benefit_component_amount(employee, start_date, end_date, struct_row, sal_struct):
+	# Considering there is only one application for an year
+	benefit_application_name = frappe.db.sql("""
 	select name from `tabEmployee Benefit Application`
 	where employee=%(employee)s
 	and docstatus = 1
@@ -122,41 +123,41 @@
 		'end_date': end_date
 	})
 
-	if employee_benefits:
-		for employee_benefit in employee_benefits:
-			employee_benefit_obj = frappe.get_doc("Employee Benefit Application", employee_benefit[0])
-			return get_benefit_components(employee_benefit_obj, employee, start_date, end_date)
-
-def get_benefit_components(employee_benefit_application, employee, start_date, end_date):
-	salary_components_array = []
-	group_component_amount = {}
 	payroll_period_days = get_payroll_period_days(start_date, end_date, frappe.db.get_value("Employee", employee, "company"))
-	for employee_benefit in employee_benefit_application.employee_benefits:
-		if employee_benefit.is_pro_rata_applicable == 1:
-			struct_row = {}
-			salary_components_dict = {}
-			amount = get_amount(payroll_period_days, start_date, end_date, employee_benefit.amount)
-			sc = frappe.get_doc("Salary Component", employee_benefit.earning_component)
-			salary_component = sc
-			if sc.earning_component_group and not sc.is_group and not sc.flexi_default:
-				salary_component = frappe.get_doc("Salary Component", sc.earning_component_group)
-				if group_component_amount and group_component_amount.has_key(sc.earning_component_group):
-					group_component_amount[sc.earning_component_group] += amount
-				else:
-					group_component_amount[sc.earning_component_group] = amount
-				amount = group_component_amount[sc.earning_component_group]
-			struct_row['depends_on_lwp'] = salary_component.depends_on_lwp
-			struct_row['salary_component'] = salary_component.name
-			struct_row['abbr'] = salary_component.salary_component_abbr
-			struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total
-			salary_components_dict['amount'] = amount
-			salary_components_dict['struct_row'] = struct_row
-			salary_components_array.append(salary_components_dict)
+	if payroll_period_days:
+		# If there is application for benefit claim then fetch the amount from it.
+		if benefit_application_name:
+			benefit_application = frappe.get_doc("Employee Benefit Application", benefit_application_name[0][0])
+			return get_benefit_amount(benefit_application, start_date, end_date, struct_row, payroll_period_days)
 
-	if len(salary_components_array) > 0:
-		return salary_components_array
+		# TODO: Check if there is benefit claim for employee then pro-rata devid the rest of amount
+		# else Split the max benefits to the pro-rata components with the ratio of thier max_benefit_amount
+		else:
+			component_max = frappe.db.get_value("Salary Component", struct_row.salary_component, "max_benefit_amount")
+			if component_max > 0:
+				return get_benefit_pro_rata_ratio_amount(sal_struct, component_max, payroll_period_days, start_date, end_date)
 	return False
 
+def get_benefit_pro_rata_ratio_amount(sal_struct, component_max, payroll_period_days, start_date, end_date):
+	total_pro_rata_max = 0
+	for sal_struct_row in sal_struct.get("earnings"):
+		is_pro_rata_applicable, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["is_pro_rata_applicable", "max_benefit_amount"])
+		if sal_struct_row.is_flexible_benefit == 1 and is_pro_rata_applicable == 1:
+			total_pro_rata_max += max_benefit_amount
+	if total_pro_rata_max > 0:
+		benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max
+		if benefit_amount > component_max:
+			benefit_amount = component_max
+		return get_amount(payroll_period_days, start_date, end_date, benefit_amount)
+	return False
+
+def get_benefit_amount(application, start_date, end_date, struct_row, payroll_period_days):
+	amount = 0
+	for employee_benefit in application.employee_benefits:
+		if employee_benefit.earning_component == struct_row.salary_component:
+			amount += get_amount(payroll_period_days, start_date, end_date, employee_benefit.amount)
+	return amount if amount > 0 else False
+
 def get_amount(payroll_period_days, start_date, end_date, amount):
 	salary_slip_days = date_diff(getdate(end_date), getdate(start_date)) + 1
 	amount_per_day = amount / payroll_period_days
diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
index cd9c07c..b8aef0c 100644
--- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
+++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
@@ -13,9 +13,9 @@
 class EmployeeBenefitClaim(Document):
 	def validate(self):
 		max_benefits = get_max_benefits(self.employee, self.claim_date)
-		self.validate_max_benefit_for_component()
-		self.validate_max_benefit_for_sal_struct(max_benefits)
 		payroll_period = get_payroll_period(self.claim_date, self.claim_date, frappe.db.get_value("Employee", self.employee, "company"))
+		self.validate_max_benefit_for_component(payroll_period)
+		self.validate_max_benefit_for_sal_struct(max_benefits)
 		self.validate_benefit_claim_amount(max_benefits, payroll_period)
 		if not self.is_pro_rata_applicable:
 			self.validate_non_pro_rata_benefit_claim(max_benefits, payroll_period)
@@ -31,20 +31,27 @@
 		if self.claimed_amount > max_benefits:
 			frappe.throw(_("Maximum benefit amount of employee {0} exceeds {1}").format(self.employee, max_benefits))
 
-	def validate_max_benefit_for_component(self):
-		if self.claimed_amount > self.max_amount_eligible:
+	def validate_max_benefit_for_component(self, payroll_period):
+		claimed_amount = self.claimed_amount
+		claimed_amount += self.get_previous_claimed_amount(payroll_period, self.earning_component)
+		if claimed_amount > self.max_amount_eligible:
 			frappe.throw(_("Maximum amount eligible for the component {0} exceeds {1}").format(self.earning_component, self.max_amount_eligible))
 
 	def validate_non_pro_rata_benefit_claim(self, max_benefits, payroll_period):
 		claimed_amount = self.claimed_amount
 		pro_rata_amount = self.get_pro_rata_amount_in_application(payroll_period.name)
+		if not pro_rata_amount:
+			pro_rata_amount = 0
+			# TODO: 
+			# Get pro_rata_amount if there is no application,
+			# get salary slip for the period and calculate pro-rata amount per day and mulitply with payroll_period_days
+
 		claimed_amount += self.get_previous_claimed_amount(payroll_period, True)
 		if max_benefits < pro_rata_amount + claimed_amount:
 			frappe.throw(_("Maximum benefit of employee {0} exceeds {1} by the sum {2} of benefit application pro-rata component\
 			amount and previous claimed amount").format(self.employee, max_benefits, pro_rata_amount+claimed_amount-max_benefits))
 
 	def get_pro_rata_amount_in_application(self, payroll_period):
-		pro_rata_dispensed_amount = 0
 		application = frappe.db.exists(
 			"Employee Benefit Application",
 			{
@@ -54,10 +61,10 @@
 			}
 		)
 		if application:
-			pro_rata_dispensed_amount = frappe.db.get_value("Employee Benefit Application", application, "pro_rata_dispensed_amount")
-		return pro_rata_dispensed_amount
+			return frappe.db.get_value("Employee Benefit Application", application, "pro_rata_dispensed_amount")
+		return False
 
-	def get_previous_claimed_amount(self, payroll_period, non_pro_rata=False):
+	def get_previous_claimed_amount(self, payroll_period, non_pro_rata=False, component=False):
 		total_claimed_amount = 0
 		query = """
 		select sum(claimed_amount) as 'total_amount'
@@ -68,56 +75,36 @@
 		"""
 		if non_pro_rata:
 			query += "and is_pro_rata_applicable = 0"
+		if component:
+			query += "and earning_component = %(component)s"
 
 		sum_of_claimed_amount = frappe.db.sql(query, {
 			'employee': self.employee,
 			'start_date': payroll_period.start_date,
-			'end_date': payroll_period.end_date
+			'end_date': payroll_period.end_date,
+			'component': component
 		}, as_dict=True)
-		if sum_of_claimed_amount:
+		if sum_of_claimed_amount and sum_of_claimed_amount[0].total_amount > 0:
 			total_claimed_amount = sum_of_claimed_amount[0].total_amount
 		return total_claimed_amount
 
-def get_employee_benefit_claim(employee, start_date, end_date):
-	employee_benefits = frappe.db.sql("""
-	select name from `tabEmployee Benefit Claim`
+def get_benefit_claim_amount(employee, start_date, end_date, struct_row):
+	benefit_claim_details = frappe.db.sql("""
+	select claimed_amount from `tabEmployee Benefit Claim`
 	where employee=%(employee)s
 	and docstatus = 1 and is_pro_rata_applicable = 0
+	and earning_component = %(earning_component)s
 	and (claim_date between %(start_date)s and %(end_date)s)
 	""", {
 		'employee': employee,
 		'start_date': start_date,
-		'end_date': end_date
-	})
+		'end_date': end_date,
+		'earning_component': struct_row.salary_component
+	}, as_dict = True)
 
-	if employee_benefits:
-		salary_components_array = []
-		for employee_benefit in employee_benefits:
-			struct_row = {}
-			salary_components_dict = {}
-			group_component_amount = {}
-
-			employee_benefit_claim = frappe.get_doc("Employee Benefit Claim", employee_benefit[0])
-			amount = employee_benefit_claim.claimed_amount
-			sc = frappe.get_doc("Salary Component", employee_benefit_claim.earning_component)
-
-			salary_component = sc
-			if sc.earning_component_group and not sc.is_group and not sc.flexi_default:
-				salary_component = frappe.get_doc("Salary Component", sc.earning_component_group)
-				if group_component_amount and group_component_amount.has_key(sc.earning_component_group):
-					group_component_amount[sc.earning_component_group] += amount
-				else:
-					group_component_amount[sc.earning_component_group] = amount
-				amount = group_component_amount[sc.earning_component_group]
-
-			struct_row['depends_on_lwp'] = salary_component.depends_on_lwp
-			struct_row['salary_component'] = salary_component.name
-			struct_row['abbr'] = salary_component.salary_component_abbr
-			struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total
-			salary_components_dict['amount'] = amount
-			salary_components_dict['struct_row'] = struct_row
-			salary_components_array.append(salary_components_dict)
-
-		if len(salary_components_array) > 0:
-			return salary_components_array
+	if benefit_claim_details:
+		claimed_amount = 0
+		for claim_detail in benefit_claim_details:
+			claimed_amount += claim_detail.claimed_amount
+		return claimed_amount
 	return False
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 6651e05..32fc4b9 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -14,9 +14,8 @@
 from frappe.utils.background_jobs import enqueue
 from erpnext.hr.doctype.additional_salary_component.additional_salary_component import get_additional_salary_component
 from erpnext.hr.utils import get_payroll_period
-from erpnext.hr.doctype.employee_benefit_application.employee_benefit_application import get_employee_benefit_application, get_amount
-from erpnext.hr.doctype.payroll_period.payroll_period import get_payroll_period_days
-from erpnext.hr.doctype.employee_benefit_claim.employee_benefit_claim import get_employee_benefit_claim
+from erpnext.hr.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
+from erpnext.hr.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount
 
 class SalarySlip(TransactionBase):
 	def autoname(self):
@@ -62,6 +61,10 @@
 				amount = self.eval_condition_and_formula(struct_row, data)
 				if amount and struct_row.statistical_component == 0:
 					self.update_component_row(struct_row, amount, key)
+
+				if key=="earnings" and struct_row.is_flexible_benefit == 1:
+					self.add_employee_flexi_benefits(struct_row)
+
 				if key=="deductions" and struct_row.variable_based_on_taxable_salary:
 					tax_row, amount = self.calculate_pro_rata_tax(struct_row.salary_component)
 					if tax_row and amount:
@@ -74,41 +77,15 @@
 				amount = additional_component.amount + self.get_amount_from_exisiting_component(frappe._dict(additional_component.struct_row).salary_component)
 				self.update_component_row(frappe._dict(additional_component.struct_row), amount, "earnings")
 
-		max_benefits = self._salary_structure_doc.get("max_benefits")
-		if max_benefits > 0:
-			self.add_employee_benefits(max_benefits)
-
-	def add_employee_benefits(self, max_benefits):
-		employee_benefits = get_employee_benefit_application(self.employee, self.start_date, self.end_date)
-		if employee_benefits:
-			for employee_benefit in employee_benefits:
-				benefit_component = frappe._dict(employee_benefit)
-				amount = benefit_component.amount + self.get_amount_from_exisiting_component(frappe._dict(benefit_component.struct_row).salary_component)
-				self.update_component_row(frappe._dict(benefit_component.struct_row), amount, "earnings")
+	def add_employee_flexi_benefits(self, struct_row):
+		if frappe.db.get_value("Salary Component", struct_row.salary_component, "is_pro_rata_applicable") == 1:
+			benefit_component_amount = get_benefit_component_amount(self.employee, self.start_date, self.end_date, struct_row, self._salary_structure_doc)
+			if benefit_component_amount:
+				self.update_component_row(struct_row, benefit_component_amount, "earnings")
 		else:
-			default_flexi_compenent = frappe.db.exists(
-				'Salary Component',
-				{
-					'is_flexible_benefit': 1,
-					'is_pro_rata_applicable': 1,
-					'flexi_default': 1
-				}
-			)
-			if default_flexi_compenent:
-				flexi_struct_row = self.create_flexi_struct_row(default_flexi_compenent)
-				payroll_period_days = get_payroll_period_days(self.start_date, self.end_date, self.company)
-				amount = get_amount(payroll_period_days, self.start_date, self.end_date, max_benefits)
-				amount += self.get_amount_from_exisiting_component(default_flexi_compenent)
-				self.update_component_row(flexi_struct_row, amount, "earnings")
-			else:
-				frappe.throw(_("Configure default flexible benefit salary component to apply pro-rata benefit"))
-
-		benefit_claims = get_employee_benefit_claim(self.employee, self.start_date, self.end_date)
-		if benefit_claims:
-			for benefit_claim in benefit_claims:
-				benefit_component = frappe._dict(benefit_claim)
-				amount = benefit_component.amount + self.get_amount_from_exisiting_component(frappe._dict(benefit_component.struct_row).salary_component)
-				self.update_component_row(frappe._dict(benefit_component.struct_row), amount, "earnings")
+			benefit_claim_amount = get_benefit_claim_amount(self.employee, self.start_date, self.end_date, struct_row)
+			if benefit_claim_amount:
+				self.update_component_row(struct_row, benefit_claim_amount, "earnings")
 
 	def get_amount_from_exisiting_component(self, salary_component):
 		amount = 0
@@ -117,15 +94,6 @@
 				amount = d.amount
 		return amount
 
-	def create_flexi_struct_row(self, default_flexi_compenent):
-		salary_component = frappe.get_doc("Salary Component", default_flexi_compenent)
-		flexi_struct_row = {}
-		flexi_struct_row['depends_on_lwp'] = salary_component.depends_on_lwp
-		flexi_struct_row['salary_component'] = salary_component.name
-		flexi_struct_row['abbr'] = salary_component.salary_component_abbr
-		flexi_struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total
-		return frappe._dict(flexi_struct_row)
-
 	def update_component_row(self, struct_row, amount, key):
 		component_row = None
 		for d in self.get(key):