def calculate_totals(self): self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist else self.net_total, self.precision("grand_total")) self.grand_total_import = flt(self.grand_total / self.conversion_rate, self.precision("grand_total_import")) self.total_tax = flt(self.grand_total - self.net_total, self.precision("total_tax")) if self.meta.get_field("rounded_total"): self.rounded_total = rounded(self.grand_total) if self.meta.get_field("rounded_total_import"): self.rounded_total_import = rounded(self.grand_total_import) if self.meta.get_field("other_charges_added"): self.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]), self.precision("other_charges_added")) if self.meta.get_field("other_charges_deducted"): self.other_charges_deducted = flt(sum([flt(d.tax_amount) for d in self.tax_doclist if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]), self.precision("other_charges_deducted")) if self.meta.get_field("other_charges_added_import"): self.other_charges_added_import = flt(self.other_charges_added / self.conversion_rate, self.precision("other_charges_added_import")) if self.meta.get_field("other_charges_deducted_import"): self.other_charges_deducted_import = flt(self.other_charges_deducted / self.conversion_rate, self.precision("other_charges_deducted_import"))
def make_repayment_schedule(self): self.repayment_schedule = [] payment_date = self.disbursement_date balance_amount = self.loan_amount while(balance_amount > 0): interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100)) principal_amount = self.monthly_repayment_amount - interest_amount balance_amount = rounded(balance_amount + interest_amount - self.monthly_repayment_amount) if balance_amount < 0: principal_amount += balance_amount balance_amount = 0.0 total_payment = principal_amount + interest_amount self.append("repayment_schedule", { "payment_date": payment_date, "principal_amount": principal_amount, "interest_amount": interest_amount, "total_payment": total_payment, "balance_loan_amount": balance_amount }) next_payment_date = add_months(payment_date, 1) payment_date = next_payment_date
def calculate_totals(self): self.doc.grand_total = flt(self.doc.get("taxes")[-1].total if self.doc.get("taxes") else self.doc.net_total) self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total, self.doc.precision("total_taxes_and_charges")) self._set_in_company_currency(self.doc, ["total_taxes_and_charges"]) if self.doc.doctype in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]: self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate) \ if self.doc.total_taxes_and_charges else self.doc.base_net_total else: self.doc.taxes_and_charges_added = self.doc.taxes_and_charges_deducted = 0.0 for tax in self.doc.get("taxes"): if tax.category in ["Valuation and Total", "Total"]: if tax.add_deduct_tax == "Add": self.doc.taxes_and_charges_added += flt(tax.tax_amount_after_discount_amount) else: self.doc.taxes_and_charges_deducted += flt(tax.tax_amount_after_discount_amount) self.doc.round_floats_in(self.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"]) self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate) \ if (self.doc.taxes_and_charges_added or self.doc.taxes_and_charges_deducted) \ else self.doc.base_net_total self._set_in_company_currency(self.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"]) self.doc.round_floats_in(self.doc, ["grand_total", "base_grand_total"]) if self.doc.meta.get_field("rounded_total"): self.doc.rounded_total = rounded(self.doc.grand_total) if self.doc.meta.get_field("base_rounded_total"): self.doc.base_rounded_total = rounded(self.doc.base_grand_total)
def calculate_payable_amount(self): balance_amount = self.loan_amount self.total_payable_amount = 0 self.total_payable_interest = 0 while(balance_amount > 0): interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100)) balance_amount = rounded(balance_amount + interest_amount - self.repayment_amount) self.total_payable_interest += interest_amount self.total_payable_amount = self.loan_amount + self.total_payable_interest
def calculate_earning_total(self): self.gross_pay = flt(self.arrear_amount) salaryperday = 0 hourlyrate = 0 for d in self.get("earnings"): if d.e_type == "Salary": salaryperday = flt(d.e_amount) / 30 hourlyrate = flt(salaryperday) / 9 d.rate = hourlyrate break if salaryperday == 0: frappe.throw(_("No salary per day calculation for employee {0}").format(self.employee)) for d in self.get("earnings"): # if(d.rate_type == "Hourly Based On Salary"): # d.e_amount = flt(self.overtime_hours_weekdays) * flt(d.rate) * flt(hourlyrate) # elif(d.e_type == "Hourly"): if d.e_type == "Overtime Weekdays": d.rate = flt(frappe.db.get_single_value("Regulations", "overtime_weekdays_rate")) d.e_amount = flt(self.overtime_hours_weekdays) * flt(d.rate) * flt(hourlyrate) elif d.e_type == "Overtime Fridays": d.rate = flt(frappe.db.get_single_value("Regulations", "overtime_fridays_rate")) d.e_amount = flt(self.overtime_hours_fridays) * flt(d.rate) * flt(hourlyrate) elif d.e_type == "Overtime Holidays": d.rate = flt(frappe.db.get_single_value("Regulations", "overtime_holidays_rate")) d.e_amount = flt(self.overtime_hours_holidays) * flt(d.rate) * flt(hourlyrate) if cint(d.e_depends_on_lwp) == 1: d.e_modified_amount = rounded( (flt(d.e_amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("e_modified_amount", "earnings"), ) if d.e_type == "Salary": d.e_modified_amount = rounded( (flt(d.e_amount) - (flt(self.leave_without_pay) * flt(d.rate) * 9)), self.precision("e_modified_amount", "earnings"), ) d.e_modified_amount = d.e_modified_amount > 0 and d.e_modified_amount or 0 elif not self.payment_days: d.e_modified_amount = 0 elif not d.e_modified_amount: d.e_modified_amount = d.e_amount self.gross_pay += flt(d.e_modified_amount) self.calculate_leave_and_gratuity(salaryperday)
def calculate_totals(self): self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist else self.net_total) self.grand_total_export = flt(self.grand_total / self.conversion_rate) self.other_charges_total = flt(self.grand_total - self.net_total, self.precision("other_charges_total")) self.other_charges_total_export = flt(self.grand_total_export - self.net_total_export + flt(self.discount_amount), self.precision("other_charges_total_export")) self.grand_total = flt(self.grand_total, self.precision("grand_total")) self.grand_total_export = flt(self.grand_total_export, self.precision("grand_total_export")) self.rounded_total = rounded(self.grand_total) self.rounded_total_export = rounded(self.grand_total_export)
def validate_remaining_benefit_amount(self): # check salary structure earnings have flexi component (sum of max_benefit_amount) # without pro-rata which satisfy the remaining_benefit # else pro-rata component for the amount # again comes the same validation and satisfy or throw benefit_components = [] if self.employee_benefits: for employee_benefit in self.employee_benefits: benefit_components.append(employee_benefit.earning_component) salary_struct_name = get_assigned_salary_structure(self.employee, self.date) if salary_struct_name: non_pro_rata_amount = 0 pro_rata_amount = 0 salary_structure = frappe.get_doc("Salary Structure", salary_struct_name) if salary_structure.earnings: for earnings in salary_structure.earnings: if earnings.is_flexible_benefit == 1 and earnings.salary_component not in benefit_components: pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", earnings.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) if pay_against_benefit_claim != 1: pro_rata_amount += max_benefit_amount else: non_pro_rata_amount += max_benefit_amount if pro_rata_amount == 0 and non_pro_rata_amount == 0: frappe.throw(_("Please add the remaining benefits {0} to any of the existing component").format(self.remaining_benefit)) elif non_pro_rata_amount > 0 and non_pro_rata_amount < rounded(self.remaining_benefit): frappe.throw(_("You can claim only an amount of {0}, the rest amount {1} should be in the application \ as pro-rata component").format(non_pro_rata_amount, self.remaining_benefit - non_pro_rata_amount)) elif non_pro_rata_amount == 0: frappe.throw(_("Please add the remaining benefits {0} to the application as \ pro-rata component").format(self.remaining_benefit))
def calculate_net_pay(self): disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) self.calculate_earning_total() self.calculate_ded_total() self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) self.rounded_total = rounded(self.net_pay, self.precision("net_pay") if disable_rounded_total else 0)
def sum_components(self, component_type, total_field): joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) if not relieving_date: relieving_date = getdate(self.end_date) if not joining_date: frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name))) for d in self.get(component_type): if (self.salary_structure and cint(d.depends_on_lwp) and (not self.salary_slip_based_on_timesheet or getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date )): d.amount = rounded( (flt(d.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), self.precision("amount", component_type) ) elif not self.payment_days and not self.salary_slip_based_on_timesheet and \ cint(d.depends_on_lwp): d.amount = 0 elif not d.amount: d.amount = d.default_amount if not d.do_not_include_in_total: self.set(total_field, self.get(total_field) + flt(d.amount))
def calculate_tax(self, args): tax_amount, benefit_tax, additional_tax = 0, 0, 0 annual_taxable_earning = args.get("annual_taxable_earning") benefit_to_tax = args.get("unclaimed_benefit") additional_income = args.get("additional_income") # Get tax calc by period annual_tax = self.calculate_tax_by_tax_slab(args.get("payroll_period"), annual_taxable_earning) # Calc prorata tax tax_amount = annual_tax / args.get("period_factor") # Benefit is a part of Salary Structure, add the tax diff, update annual_tax if benefit_to_tax > 0: annual_taxable_earning += benefit_to_tax annual_tax_with_benefit_income = self.calculate_tax_by_tax_slab( args.get("payroll_period"), annual_taxable_earning) benefit_tax = annual_tax_with_benefit_income - annual_tax - args.get("benefit_tax_paid") tax_amount += benefit_tax annual_tax = annual_tax_with_benefit_income # find the annual tax diff caused by additional_income, add to tax_amount if additional_income > 0: annual_tax_with_additional_income = self.calculate_tax_by_tax_slab( args.get("payroll_period"), annual_taxable_earning + additional_income) additional_tax = annual_tax_with_additional_income - annual_tax - args.get("additional_tax_paid") tax_amount += additional_tax # less paid taxes if args.get("pro_rata_tax_paid"): tax_amount -= args.get("pro_rata_tax_paid") tax_amount = rounded(tax_amount) struct_row = self.get_salary_slip_row(args.get("tax_component")) return [struct_row, tax_amount, benefit_tax, additional_tax]
def validate_max_benefit(self, earning_component_name): max_benefit_amount = frappe.db.get_value("Salary Component", earning_component_name, "max_benefit_amount") benefit_amount = 0 for employee_benefit in self.employee_benefits: if employee_benefit.earning_component == earning_component_name: benefit_amount += employee_benefit.amount prev_sal_slip_flexi_amount = get_sal_slip_total_benefit_given(self.employee, frappe.get_doc("Payroll Period", self.payroll_period), earning_component_name) benefit_amount += prev_sal_slip_flexi_amount if rounded(benefit_amount, 2) > max_benefit_amount: frappe.throw(_("Maximum benefit amount of component {0} exceeds {1}").format(earning_component_name, max_benefit_amount))
def sum_components(self, component_type, total_field): for d in self.get(component_type): if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet: d.amount = rounded((flt(d.amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("amount", component_type)) elif not self.payment_days and not self.salary_slip_based_on_timesheet: d.amount = 0 elif not d.amount: d.amount = d.default_amount self.set(total_field, self.get(total_field) + flt(d.amount))
def calculate_earning_total(self): self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount) for d in self.get("earnings"): if cint(d.e_depends_on_lwp) == 1: d.e_modified_amount = rounded((flt(d.e_amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("e_modified_amount", "earnings")) elif not self.payment_days: d.e_modified_amount = 0 elif not d.e_modified_amount: d.e_modified_amount = d.e_amount self.gross_pay += flt(d.e_modified_amount)
def calculate_ded_total(self): self.total_deduction = 0 for d in self.get('deductions'): if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet: d.amount = rounded((flt(d.amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("amount", "deductions")) elif not self.payment_days and not self.salary_slip_based_on_timesheet: d.amount = 0 elif not d.amount: d.amount = d.default_amount self.total_deduction += flt(d.amount)
def calculate_earning_total(self): self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount) for d in self.get("earnings"): if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet: d.amount = rounded((flt(d.default_amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("amount", "earnings")) elif not self.payment_days and not self.salary_slip_based_on_timesheet: d.amount = 0 elif not d.amount: d.amount = d.default_amount self.gross_pay += flt(d.amount)
def merge_tailoring_items(doc,method): doc.set('entries', []) amt = amount = 0.0 for d in doc.get('sales_invoice_items_one'): e = doc.append('entries', {}) e.barcode=d.tailoring_barcode e.item_code=d.tailoring_item_code e.item_name=d.tailoring_item_name e.item_group = frappe.db.get_value('Item', d.tailoring_item_code, 'item_group') e.work_order=d.tailoring_work_order e.description=d.tailoring_description e.sales_invoice_branch = d.tailoring_branch e.warehouse= frappe.db.get_value('Branch', d.tailoring_branch, 'warehouse') e.income_account=d.tailoring_income_account e.cost_center=d.tailoring_cost_center e.batch_no=d.tailoring_batch_no e.item_tax_rate=d.tailoring_item_tax_rate e.stock_uom=d.tailoring_stock_uom e.price_list_rate=d.tailoring_price_list_rate e.trial_date = d.tailoring_trial_date e.discount_percentage=d.tailoring_discount_percentage e.amount= d.tailoring_amount e.base_amount= cstr(flt(e.amount)*flt(doc.conversion_rate)) e.base_rate= cstr(flt(d.tailoring_rate)*flt(doc.conversion_rate)) e.rate=d.tailoring_rate e.base_price_list_rate=d.tailoring_base_price_list_rate e.qty=d.tailoring_qty e.base_price_list_rate=d.tailoring_base_price_list_rate e.delivery_date = d.tailoring_delivery_date amt += flt(e.amount) amount = merge_merchandise_items(doc) doc.net_total_export = cstr(flt(amount) + flt(amt)) doc.grand_total_export = cstr(flt(amount) + flt(amt) + flt(doc.other_charges_total_export)) doc.rounded_total_export = cstr(rounded(flt(amount) + flt(amt) + flt(doc.other_charges_total_export))) doc.in_words_export = cstr(money_in_words(flt(amount) + flt(amt) + flt(doc.other_charges_total_export),doc.currency)) doc.net_total = cstr(flt(doc.net_total_export) * flt(doc.conversion_rate)) doc.grand_total = cstr(flt(doc.net_total) + flt(doc.other_charges_total)) doc.rounded_total = cstr(rounded(flt(doc.net_total) + flt(doc.other_charges_total))) doc.in_words = cstr(money_in_words(flt(doc.net_total) + flt(doc.other_charges_total))) doc.outstanding_amount = cstr(flt(doc.net_total) + flt(doc.other_charges_total) - flt(doc.total_advance)) return "Done"
def calculate_net_pay(self): disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) #self.calculate_ovetime_total() self.calculate_earning_total() self.calculate_ded_total() data = {'employee':self.employee,'month':self.month,'gross_pay':self.gross_pay,'company':self.company,'days':self.total_days_in_month} salary = calculate_salary(data) self.salary_payable = flt(salary.get('salary_payable')) self.payment_days = salary.get('payment_days') self.net_pay = flt(salary.get('salary_payable'))- flt(self.total_deduction) self.rounded_total = rounded(self.net_pay, self.precision("net_pay") if disable_rounded_total else 0)
def calculate_ded_total(self): self.total_deduction = 0 for d in self.get('deductions'): if cint(d.d_depends_on_lwp) == 1: d.d_modified_amount = rounded((flt(d.d_amount) * flt(self.payment_days) / cint(self.total_days_in_month)), self.precision("d_modified_amount", "deductions")) elif not self.payment_days: d.d_modified_amount = 0 elif not d.d_modified_amount: d.d_modified_amount = d.d_amount self.total_deduction += flt(d.d_modified_amount)
def calculate_ded_total(self): self.total_deduction = 0 for d in self.get('deduction_details'): if cint(d.d_depends_on_lwp) == 1: d.d_modified_amount = rounded(flt(d.d_amount) * flt(self.payment_days) / cint(self.total_days_in_month), 2) elif not self.payment_days: d.d_modified_amount = 0 else: d.d_modified_amount = d.d_amount self.total_deduction += flt(d.d_modified_amount)
def calculate_net_pay(self): if self.salary_structure: self.calculate_component_amounts() disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount) self.total_deduction = 0 self.sum_components('earnings', 'gross_pay') self.sum_components('deductions', 'total_deduction') self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) self.rounded_total = rounded(self.net_pay, self.precision("net_pay") if disable_rounded_total else 0)
def sum_components(self, component_type, total_field): joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) if not relieving_date: relieving_date = getdate(self.end_date) for d in self.get(component_type): if ((cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet) or\ getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date): d.amount = rounded((flt(d.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), self.precision("amount", component_type)) elif not self.payment_days and not self.salary_slip_based_on_timesheet: d.amount = 0 elif not d.amount: d.amount = d.default_amount self.set(total_field, self.get(total_field) + flt(d.amount))
def calculate_net_pay(self): if self.salary_structure: self.calculate_component_amounts() disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) precision = frappe.defaults.get_global_default("currency_precision") self.total_deduction = 0 self.gross_pay = 0 self.sum_components('earnings', 'gross_pay', precision) self.sum_components('deductions', 'total_deduction', precision) self.set_loan_repayment() self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment)) self.rounded_total = rounded(self.net_pay, self.precision("net_pay") if disable_rounded_total else 0) if self.net_pay < 0: frappe.throw(_("Net Pay cannnot be negative"))
def eval_condition_and_formula(self, d, data): try: condition = d.condition.strip() if d.condition else None if condition: if not frappe.safe_eval(condition, self.whitelisted_globals, data): return None amount = d.amount if d.amount_based_on_formula: formula = d.formula.strip() if d.formula else None if formula: amount = rounded(frappe.safe_eval(formula, self.whitelisted_globals, data)) if amount: data[d.abbr] = amount return amount except NameError as err: frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in formula or condition: {0}".format(err))) except Exception as e: frappe.throw(_("Error in formula or condition: {0}".format(e))) raise
def calculate_gratuity(self, salaryperday, joining_date, relieving_date): disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) # Relieving date is the last day of work payment_days = date_diff(relieving_date, joining_date) + 1 payment_years = flt(payment_days) / 365 payment_years = rounded(payment_years, self.precision("net_pay")) leavedaysdue = 0 if payment_years >= 1: leavedaysdue = flt(payment_days) / 365 * 30 leavedaysdue = ceil(leavedaysdue) from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period leave_type = "Vacation Leave" leavedaystaken = get_approved_leaves_for_period(self.employee, leave_type, joining_date, relieving_date) leave_type = "Encash Leave" leavedaystaken += flt(get_approved_leaves_for_period(self.employee, leave_type, joining_date, relieving_date)) leave_type = "Leave Without Pay" leavedaystaken += flt(get_approved_leaves_for_period(self.employee, leave_type, joining_date, relieving_date)) leavesbalance = leavedaysdue - leavedaystaken leaveadvance = 0 if leavesbalance < 0: payment_days += leavesbalance else: leaveadvance = flt(leavesbalance) * flt(salaryperday) leaveadvance = rounded(leaveadvance, self.precision("net_pay")) if payment_years < 1: gratuity_pay = 0 elif payment_years <= 5: gratuity_pay = flt(payment_years) * 21 * flt(salaryperday) else: gratuity_pay = (5 * 21 * flt(salaryperday)) + (payment_years - 5) * (30 * flt(salaryperday)) self.leave_encashment_amount = leaveadvance gratuity_pay = rounded(gratuity_pay, self.precision("net_pay")) joiningtext = ( "Joining Date: " + str(joining_date) + " - Relieving Date: " + str(relieving_date) + " - Total Working Days: " + str(payment_days) ) workingdaystext = ( "Total Leave Due: " + str(leavedaysdue) + " - Total Leave Taken: " + str(leavedaystaken) + " - Leave Balance: " + str(leavesbalance) ) networkingdaytext = "Net Working Days: " + str(payment_days) + " - Net Working Years: " + str(payment_years) gratuitytext = "Less than 1 year, no leave or gratuity<br>Between 1 and 5 years: No. of years worked * Basic Salary per day * 21<br>More than 5 years: (5 * Basic Salary per day * 21) + (No. of years worked - 5) * (Basic Salary per day * 30)" self.gratuity_calculation = ( joiningtext + "<br>" + workingdaystext + "<br>" + networkingdaytext + "<br>" + gratuitytext + "<br>" ) return gratuity_pay
def calculate_net_pay(self): self.calculate_earning_total() self.calculate_ded_total() self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) self.rounded_total = rounded(self.net_pay)
def get_healthcare_services_to_invoice(patient): patient = frappe.get_doc("Patient", patient) if patient: if patient.customer: item_to_invoice = [] patient_appointments = frappe.get_list("Patient Appointment", { 'patient': patient.name, 'invoiced': False }, order_by="appointment_date") if patient_appointments: fee_validity_details = [] valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") for patient_appointment in patient_appointments: patient_appointment_obj = frappe.get_doc( "Patient Appointment", patient_appointment['name']) if patient_appointment_obj.procedure_template: if frappe.db.get_value( "Clinical Procedure Template", patient_appointment_obj.procedure_template, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': patient_appointment_obj.procedure_template }) else: practitioner_exist_in_list = False skip_invoice = False if fee_validity_details: for validity in fee_validity_details: if validity[ 'practitioner'] == patient_appointment_obj.practitioner: practitioner_exist_in_list = True if validity[ 'valid_till'] >= patient_appointment_obj.appointment_date: validity[ 'visits'] = validity['visits'] + 1 if int(max_visit) > validity['visits']: skip_invoice = True if not skip_invoice: validity['visits'] = 1 validity[ 'valid_till'] = patient_appointment_obj.appointment_date + datetime.timedelta( days=int(valid_days)) if not practitioner_exist_in_list: valid_till = patient_appointment_obj.appointment_date + datetime.timedelta( days=int(valid_days)) visits = 0 validity_exist = validity_exists( patient_appointment_obj.practitioner, patient_appointment_obj.patient) if validity_exist: fee_validity = frappe.get_doc( "Fee Validity", validity_exist[0][0]) valid_till = fee_validity.valid_till visits = fee_validity.visited fee_validity_details.append({ 'practitioner': patient_appointment_obj.practitioner, 'valid_till': valid_till, 'visits': visits }) if not skip_invoice: practitioner_charge = 0 income_account = None service_item = None if patient_appointment_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge( patient_appointment_obj) income_account = get_income_account( patient_appointment_obj.practitioner, patient_appointment_obj.company) item_to_invoice.append({ 'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account }) encounters = frappe.get_list("Patient Encounter", { 'patient': patient.name, 'invoiced': False, 'docstatus': 1 }) if encounters: for encounter in encounters: encounter_obj = frappe.get_doc("Patient Encounter", encounter['name']) if not encounter_obj.appointment: practitioner_charge = 0 income_account = None service_item = None if encounter_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge( encounter_obj) income_account = get_income_account( encounter_obj.practitioner, encounter_obj.company) item_to_invoice.append({ 'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account }) lab_tests = frappe.get_list("Lab Test", { 'patient': patient.name, 'invoiced': False }) if lab_tests: for lab_test in lab_tests: lab_test_obj = frappe.get_doc("Lab Test", lab_test['name']) if frappe.db.get_value("Lab Test Template", lab_test_obj.template, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Lab Test', 'reference_name': lab_test_obj.name, 'service': frappe.db.get_value("Lab Test Template", lab_test_obj.template, "item") }) lab_rxs = frappe.db.sql( """select lp.name from `tabPatient Encounter` et, `tabLab Prescription` lp where et.patient=%s and lp.parent=et.name and lp.lab_test_created=0 and lp.invoiced=0""", (patient.name)) if lab_rxs: for lab_rx in lab_rxs: rx_obj = frappe.get_doc("Lab Prescription", lab_rx[0]) if rx_obj.lab_test_code and (frappe.db.get_value( "Lab Test Template", rx_obj.lab_test_code, "is_billable") == 1): item_to_invoice.append({ 'reference_type': 'Lab Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "item") }) procedures = frappe.get_list("Clinical Procedure", { 'patient': patient.name, 'invoiced': False }) if procedures: for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) if not procedure_obj.appointment: if procedure_obj.procedure_template and ( frappe.db.get_value( "Clinical Procedure Template", procedure_obj.procedure_template, "is_billable") == 1): item_to_invoice.append({ 'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': frappe.db.get_value( "Clinical Procedure Template", procedure_obj.procedure_template, "item") }) procedure_rxs = frappe.db.sql( """select pp.name from `tabPatient Encounter` et, `tabProcedure Prescription` pp where et.patient=%s and pp.parent=et.name and pp.procedure_created=0 and pp.invoiced=0 and pp.appointment_booked=0""", (patient.name)) if procedure_rxs: for procedure_rx in procedure_rxs: rx_obj = frappe.get_doc("Procedure Prescription", procedure_rx[0]) if frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Procedure Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "item") }) procedures = frappe.get_list( "Clinical Procedure", { 'patient': patient.name, 'invoice_separately_as_consumables': True, 'consumption_invoiced': False, 'consume_stock': True, 'status': 'Completed' }) if procedures: service_item = get_healthcare_service_item( 'clinical_procedure_consumable_item') if not service_item: msg = _(("Please Configure {0} in ").format("Clinical Procedure Consumable Item") \ + """<b><a href="#Form/Healthcare Settings">Healthcare Settings</a></b>""") frappe.throw(msg) for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) item_to_invoice.append({ 'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': service_item, 'rate': procedure_obj.consumable_total_amount, 'description': procedure_obj.consumption_details }) inpatient_services = frappe.db.sql( """select io.name, io.parent from `tabInpatient Record` ip, `tabInpatient Occupancy` io where ip.patient=%s and io.parent=ip.name and io.left=1 and io.invoiced=0""", (patient.name)) if inpatient_services: for inpatient_service in inpatient_services: inpatient_occupancy = frappe.get_doc( "Inpatient Occupancy", inpatient_service[0]) service_unit_type = frappe.get_doc( "Healthcare Service Unit Type", frappe.db.get_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "service_unit_type")) if service_unit_type and service_unit_type.is_billable == 1: hours_occupied = time_diff_in_hours( inpatient_occupancy.check_out, inpatient_occupancy.check_in) qty = 0.5 if hours_occupied > 0: if service_unit_type.no_of_hours and service_unit_type.no_of_hours > 0: actual_qty = hours_occupied / service_unit_type.no_of_hours else: # 24 hours = 1 Day actual_qty = hours_occupied / 24 floor = math.floor(actual_qty) decimal_part = actual_qty - floor if decimal_part > 0.5: qty = rounded(floor + 1, 1) elif decimal_part < 0.5 and decimal_part > 0: qty = rounded(floor + 0.5, 1) if qty <= 0: qty = 0.5 item_to_invoice.append({ 'reference_type': 'Inpatient Occupancy', 'reference_name': inpatient_occupancy.name, 'service': service_unit_type.item, 'qty': qty }) return item_to_invoice else: frappe.throw( _("The Patient {0} do not have customer refrence to invoice"). format(patient.name))
def get_healthcare_services_to_invoice(patient): patient = frappe.get_doc("Patient", patient) if patient: if patient.customer: item_to_invoice = [] patient_appointments = frappe.get_list("Patient Appointment",{'patient': patient.name, 'invoiced': False}, order_by="appointment_date") if patient_appointments: fee_validity_details = [] valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") for patient_appointment in patient_appointments: patient_appointment_obj = frappe.get_doc("Patient Appointment", patient_appointment['name']) if patient_appointment_obj.procedure_template: if frappe.db.get_value("Clinical Procedure Template", patient_appointment_obj.procedure_template, "is_billable") == 1: item_to_invoice.append({'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': patient_appointment_obj.procedure_template}) else: practitioner_exist_in_list = False skip_invoice = False if fee_validity_details: for validity in fee_validity_details: if validity['practitioner'] == patient_appointment_obj.practitioner: practitioner_exist_in_list = True if validity['valid_till'] >= patient_appointment_obj.appointment_date: validity['visits'] = validity['visits']+1 if int(max_visit) > validity['visits']: skip_invoice = True if not skip_invoice: validity['visits'] = 1 validity['valid_till'] = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days)) if not practitioner_exist_in_list: valid_till = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days)) visits = 0 validity_exist = validity_exists(patient_appointment_obj.practitioner, patient_appointment_obj.patient) if validity_exist: fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) valid_till = fee_validity.valid_till visits = fee_validity.visited fee_validity_details.append({'practitioner': patient_appointment_obj.practitioner, 'valid_till': valid_till, 'visits': visits}) if not skip_invoice: practitioner_charge = 0 income_account = None service_item = None if patient_appointment_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge(patient_appointment_obj) income_account = get_income_account(patient_appointment_obj.practitioner, patient_appointment_obj.company) item_to_invoice.append({'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account}) encounters = frappe.get_list("Patient Encounter", {'patient': patient.name, 'invoiced': False, 'docstatus': 1}) if encounters: for encounter in encounters: encounter_obj = frappe.get_doc("Patient Encounter", encounter['name']) if not encounter_obj.appointment: practitioner_charge = 0 income_account = None service_item = None if encounter_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge(encounter_obj) income_account = get_income_account(encounter_obj.practitioner, encounter_obj.company) item_to_invoice.append({'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account}) lab_tests = frappe.get_list("Lab Test", {'patient': patient.name, 'invoiced': False}) if lab_tests: for lab_test in lab_tests: lab_test_obj = frappe.get_doc("Lab Test", lab_test['name']) if frappe.db.get_value("Lab Test Template", lab_test_obj.template, "is_billable") == 1: item_to_invoice.append({'reference_type': 'Lab Test', 'reference_name': lab_test_obj.name, 'service': frappe.db.get_value("Lab Test Template", lab_test_obj.template, "item")}) lab_rxs = frappe.db.sql("""select lp.name from `tabPatient Encounter` et, `tabLab Prescription` lp where et.patient=%s and lp.parent=et.name and lp.lab_test_created=0 and lp.invoiced=0""", (patient.name)) if lab_rxs: for lab_rx in lab_rxs: rx_obj = frappe.get_doc("Lab Prescription", lab_rx[0]) if rx_obj.lab_test_code and (frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "is_billable") == 1): item_to_invoice.append({'reference_type': 'Lab Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "item")}) procedures = frappe.get_list("Clinical Procedure", {'patient': patient.name, 'invoiced': False}) if procedures: for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) if not procedure_obj.appointment: if procedure_obj.procedure_template and (frappe.db.get_value("Clinical Procedure Template", procedure_obj.procedure_template, "is_billable") == 1): item_to_invoice.append({'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': frappe.db.get_value("Clinical Procedure Template", procedure_obj.procedure_template, "item")}) procedure_rxs = frappe.db.sql("""select pp.name from `tabPatient Encounter` et, `tabProcedure Prescription` pp where et.patient=%s and pp.parent=et.name and pp.procedure_created=0 and pp.invoiced=0 and pp.appointment_booked=0""", (patient.name)) if procedure_rxs: for procedure_rx in procedure_rxs: rx_obj = frappe.get_doc("Procedure Prescription", procedure_rx[0]) if frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "is_billable") == 1: item_to_invoice.append({'reference_type': 'Procedure Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "item")}) procedures = frappe.get_list("Clinical Procedure", {'patient': patient.name, 'invoice_separately_as_consumables': True, 'consumption_invoiced': False, 'consume_stock': True, 'status': 'Completed'}) if procedures: service_item = get_healthcare_service_item('clinical_procedure_consumable_item') if not service_item: msg = _(("Please Configure {0} in ").format("Clinical Procedure Consumable Item") \ + """<b><a href="#Form/Healthcare Settings">Healthcare Settings</a></b>""") frappe.throw(msg) for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) item_to_invoice.append({'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': service_item, 'rate': procedure_obj.consumable_total_amount, 'description': procedure_obj.consumption_details}) inpatient_services = frappe.db.sql("""select io.name, io.parent from `tabInpatient Record` ip, `tabInpatient Occupancy` io where ip.patient=%s and io.parent=ip.name and io.left=1 and io.invoiced=0""", (patient.name)) if inpatient_services: for inpatient_service in inpatient_services: inpatient_occupancy = frappe.get_doc("Inpatient Occupancy", inpatient_service[0]) service_unit_type = frappe.get_doc("Healthcare Service Unit Type", frappe.db.get_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "service_unit_type")) if service_unit_type and service_unit_type.is_billable == 1: hours_occupied = time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in) qty = 0.5 if hours_occupied > 0: actual_qty = hours_occupied / service_unit_type.no_of_hours floor = math.floor(actual_qty) decimal_part = actual_qty - floor if decimal_part > 0.5: qty = rounded(floor + 1, 1) elif decimal_part < 0.5 and decimal_part > 0: qty = rounded(floor + 0.5, 1) if qty <= 0: qty = 0.5 item_to_invoice.append({'reference_type': 'Inpatient Occupancy', 'reference_name': inpatient_occupancy.name, 'service': service_unit_type.item, 'qty': qty}) return item_to_invoice else: frappe.throw(_("The Patient {0} do not have customer refrence to invoice").format(patient.name))
def make_deduction(doc_salary, doc_type, doc_struct, context, result_description, precision): tributavel_calcule = doc_type.tributavel_expression if not result_description.get("deductions"): result_description["deductions"] = [] if not doc_struct.d_modified_amt: doc_struct.d_modified_amt = 0 if not tributavel_calcule: tributavel_value = rounded(doc_struct.d_modified_amt, precision) res = {"idx": doc_struct.idx, "d_modified_amt": tributavel_value} result_description.get("deductions").append(res) return tributavel_value doc_type_dict = doc_type.as_dict() for attr in ("tributavel_calcule", "parent", "parenttype", "parentfield", "owner", "modified_by"): doc_type_dict.pop(attr, None) doc_struct.pop(attr, None) doc_salary.pop(attr, None) # context.update({doc_type_dict.short_name: doc_type_dict}) # context.update({doc_struct.short_name: doc_struct}) context.update(doc_struct) context.update(doc_type_dict) try: t = Template(tributavel_calcule, extensions=["jinja2.ext.do"], trim_blocks=True) set_functions_context(t) m = t.make_module(context) # try: # if (doc_type.deduction_type == "Table"): # print "table name %s date %s" % (doc_salary.earnings, doc_salary.from_date) # except: # print "there is no table_name %s" % frappe.utils.encode(doc_employee.estado_civil) try: value = m.tribut except AttributeError: value = 0 if value: tributavel_value = rounded(value, precision) else: tributavel_value = rounded(0, precision) res = {"idx": doc_struct.idx, "d_modified_amt": tributavel_value} context[doc_type_dict.short_name] = res result_description.get("deductions").append(res) print "short_name %s res %s idx %s tributavel_value %s" % ( doc_type_dict.short_name, context.get(doc_type_dict.short_name), doc_struct.idx, tributavel_value, ) return tributavel_value except TaxDependencyError: pass except: d_type = frappe.utils.encode(doc_struct.d_type) frappe.throw(_("Error in rule for Earning Type {}. Please check jinja2 syntax.".format(d_type)))
def get_tributavel_value(doc_salary, doc_type, doc_struct, precision): tributavel_calcule = doc_type.tributavel_calcule if not tributavel_calcule: tributavel_value = rounded(doc_struct.modified_value, precision) return tributavel_value is_diary = doc_type.diary_earning_ if is_diary: value = doc_struct.modified_value_diary else: value = doc_struct.modified_value context = {"value": value} doc_employee = frappe.get_doc("Employee", doc_salary.employee).as_dict() doc_type_dict = doc_type.as_dict() for attr in ( "tributavel_calcule", "parent", "parenttype", "parentfield", "owner", "modified_by", "short_name", "idx", ): doc_type_dict.pop(attr, None) doc_struct.pop(attr, None) doc_employee.pop(attr, None) context.update({doc_type_dict.short_name: doc_type_dict}) context.update({doc_struct.short_name: doc_struct}) context.update(doc_employee) context.update(doc_struct) context.update(doc_type_dict) try: t = Template(tributavel_calcule, extensions=["jinja2.ext.do"], trim_blocks=True) set_functions_context(t) m = t.make_module(context) try: value = m.tribut except AttributeError: value = 0 if value: tributavel_value = rounded(value, precision) if is_diary: tributavel_value = tributavel_value * 31 else: tributavel_value = rounded(0, precision) return tributavel_value except: e_type = frappe.utils.encode(doc_struct.e_type) frappe.throw(_("Error in rule for Earning Type {}. Please check jinja2 syntax.".format(e_type)))
def calculate_leaveadvance(self, salaryperday, joining_date, relieving_date): disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total")) if relieving_date: return else: m = get_month_details(self.fiscal_year, self.month) dt = add_days(cstr(m["month_start_date"]), m["month_days"] + 2) leave = frappe.db.sql( """ select from_date,to_date,leave_type from `tabLeave Application` t1 where (t1.leave_type = 'Vacation Leave' OR t1.leave_type = 'Encash Leave') and t1.docstatus < 2 and t1.status = 'Approved' and t1.employee = %s and t1.from_date <= %s ORDER BY to_date DESC LIMIT 2""", (self.employee, dt), as_dict=True, ) frappe.errprint(leave) if leave: if leave[0].leave_type == "Vacation Leave": relieving_date = leave[0].from_date # Relieving date should be decremented since leave applications include the first day relieving_date = relieving_date - timedelta(days=1) if relieving_date < m["month_start_date"]: self.encash_leave = 0 frappe.msgprint( _( "No leave applications found for this period. Please approve a leave application for this employee" ) ) return if date_diff(relieving_date, joining_date) < 365: frappe.msgprint(_("This employee has worked at the company for less than a year.")) if len(leave) > 1: joining_date = leave[1].to_date # Joining date should be incremented since leave applications include the last day joining_date = joining_date + timedelta(days=1) frappe.msgprint( _("Calculating Leave From Date {0} To Date {1}.").format(joining_date, relieving_date) ) else: frappe.msgprint( _("No previous application found for this employee. Using company joining date.") ) elif leave[0].leave_type == "Encash Leave": relieving_date = leave[0].to_date joining_date = leave[0].from_date frappe.msgprint(_("Special Case: Leave Encashment application dated {0}.").format(relieving_date)) else: self.encash_leave = 0 frappe.msgprint( _( "No VACATION/ENCASH leave applications found for this period. Change LEAVE WITHOUT PAY Applications to VACATION/ENCASH" ) ) return else: self.encash_leave = 0 frappe.msgprint( _( "No leave applications found for this period. Please approve a valid leave application for this employee" ) ) return payment_days = date_diff(relieving_date, joining_date) + 1 leavedaysdue = flt(payment_days) / 365 * 30 leavedaysdue = ceil(leavedaysdue) if leavedaysdue < 30 and leavedaysdue + 2 >= 30: leavedaysdue = 30 leaveadvance = flt(leavedaysdue) * flt(salaryperday) leaveadvance = rounded(leaveadvance, self.precision("net_pay")) joiningtext = ( "From Date: " + str(joining_date) + " - To Date: " + str(relieving_date) + " - Total Working Days: " + str(payment_days) ) workingdaystext = "Leave Days Due (Rounded): " + str(leavedaysdue) leavetext = "30 Days Leave Accumulated Every Year" self.leave_calculation = joiningtext + " - " + workingdaystext + "<br>" + leavetext + "<br>" return leaveadvance