def get_payroll_period_days(start_date, end_date, employee): company = dataent.db.get_value("Employee", employee, "company") payroll_period = dataent.db.sql( """ select name, start_date, end_date from `tabPayroll Period` where company=%(company)s and %(start_date)s between start_date and end_date and %(end_date)s between start_date and end_date """, { 'company': company, 'start_date': start_date, 'end_date': end_date }) if len(payroll_period) > 0: actual_no_of_days = date_diff(getdate(payroll_period[0][2]), getdate(payroll_period[0][1])) + 1 working_days = actual_no_of_days if not cint( dataent.db.get_value( "HR Settings", None, "include_holidays_in_total_working_days")): holidays = get_holidays_for_employee(employee, getdate(payroll_period[0][1]), getdate(payroll_period[0][2])) working_days -= len(holidays) return payroll_period[0][0], working_days, actual_no_of_days return False, False, False
def get_item_warehouse_batch_map(filters, float_precision): sle = get_stock_ledger_entries(filters) iwb_map = {} from_date = getdate(filters["from_date"]) to_date = getdate(filters["to_date"]) for d in sle: iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, {})\ .setdefault(d.batch_no, dataent._dict({ "expires_on": None, "expiry_status": None})) qty_dict = iwb_map[d.item_code][d.warehouse][d.batch_no] expiry_date_unicode = dataent.db.get_value('Batch', d.batch_no, 'expiry_date') qty_dict.expires_on = expiry_date_unicode exp_date = dataent.utils.data.getdate(expiry_date_unicode) qty_dict.expires_on = exp_date expires_in_days = (exp_date - dataent.utils.datetime.date.today()).days if expires_in_days > 0: qty_dict.expiry_status = expires_in_days else: qty_dict.expiry_status = 0 return iwb_map
def execute(filters=None): if not filters: filters = {} float_preceision = dataent.db.get_default("float_preceision") condition = get_condition(filters) avg_daily_outgoing = 0 diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days) + 1 if diff <= 0: dataent.throw(_("'From Date' must be after 'To Date'")) columns = get_columns() items = get_item_info(filters) consumed_item_map = get_consumed_items(condition) delivered_item_map = get_delivered_items(condition) data = [] for item in items: total_outgoing = consumed_item_map.get( item.name, 0) + delivered_item_map.get(item.name, 0) avg_daily_outgoing = flt(total_outgoing / diff, float_preceision) reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt( item.safety_stock) data.append([ item.name, item.item_name, item.item_group, item.brand, item.description, item.safety_stock, item.lead_time_days, consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name, 0), total_outgoing, avg_daily_outgoing, reorder_level ]) return columns, data
def get_data(args): dates = get_dates(args) employees = get_active_employees() existing_attendance_records = get_existing_attendance_records(args) data = [] for date in dates: for employee in employees: if getdate(date) < getdate(employee.date_of_joining): continue if employee.relieving_date: if getdate(date) > getdate(employee.relieving_date): continue existing_attendance = {} if existing_attendance_records \ and tuple([getdate(date), employee.name]) in existing_attendance_records \ and getdate(employee.date_of_joining) >= getdate(date) \ and getdate(employee.relieving_date) <= getdate(date): existing_attendance = existing_attendance_records[tuple( [getdate(date), employee.name])] row = [ existing_attendance and existing_attendance.name or "", employee.name, employee.employee_name, date, existing_attendance and existing_attendance.status or "", existing_attendance and existing_attendance.leave_type or "", employee.company, existing_attendance and existing_attendance.naming_series or get_naming_series(), ] data.append(row) return data
def monthly_auto_repeat(self, doctype, docname, start_date, end_date): def get_months(start, end): diff = (12 * end.year + end.month) - (12 * start.year + start.month) return diff + 1 doc = make_auto_repeat(reference_doctype=doctype, frequency='Monthly', reference_document=docname, start_date=start_date, end_date=end_date) disable_auto_repeat(doc) for data in get_auto_repeat_entries(today()): create_repeated_entries(data) docnames = dataent.get_all(doc.reference_doctype, {'auto_repeat': doc.name}) self.assertEqual(len(docnames), 1) doc = dataent.get_doc('Auto Repeat', doc.name) doc.db_set('disabled', 0) months = get_months(getdate(start_date), getdate(today())) for data in get_auto_repeat_entries(today()): create_repeated_entries(data) docnames = dataent.get_all(doc.reference_doctype, {'auto_repeat': doc.name}) self.assertEqual(len(docnames), months)
def get_start_end_dates(payroll_frequency, start_date=None, company=None): '''Returns dict of start and end dates for given payroll frequency based on start_date''' if payroll_frequency == "Monthly" or payroll_frequency == "Bimonthly" or payroll_frequency == "": fiscal_year = get_fiscal_year(start_date, company=company)[0] month = "%02d" % getdate(start_date).month m = get_month_details(fiscal_year, month) if payroll_frequency == "Bimonthly": if getdate(start_date).day <= 15: start_date = m['month_start_date'] end_date = m['month_mid_end_date'] else: start_date = m['month_mid_start_date'] end_date = m['month_end_date'] else: start_date = m['month_start_date'] end_date = m['month_end_date'] if payroll_frequency == "Weekly": end_date = add_days(start_date, 6) if payroll_frequency == "Fortnightly": end_date = add_days(start_date, 13) if payroll_frequency == "Daily": end_date = start_date return dataent._dict({'start_date': start_date, 'end_date': end_date})
def validate_dates(self): date_of_joining, relieving_date = dataent.db.get_value( "Employee", self.employee, ["date_of_joining", "relieving_date"]) if date_of_joining and getdate( self.payroll_date) < getdate(date_of_joining): dataent.throw( _("Payroll date can not be less than employee's joining date"))
def get_period_date_ranges(self): from dateutil.relativedelta import relativedelta, MO from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date) increment = { "Monthly": 1, "Quarterly": 3, "Half-Yearly": 6, "Yearly": 12 }.get(self.filters.range, 1) if self.filters.range in ['Monthly', 'Quarterly']: from_date = from_date.replace(day = 1) elif self.filters.range == "Yearly": from_date = get_fiscal_year(from_date)[1] else: from_date = from_date + relativedelta(from_date, weekday=MO(-1)) self.periodic_daterange = [] for dummy in range(1, 53): if self.filters.range == "Weekly": period_end_date = add_days(from_date, 6) else: period_end_date = add_to_date(from_date, months=increment, days=-1) if period_end_date > to_date: period_end_date = to_date self.periodic_daterange.append(period_end_date) from_date = add_days(period_end_date, 1) if period_end_date == to_date: break
def validate_filters(filters): if not filters.fiscal_year: dataent.throw(_("Fiscal Year {0} is required").format(filters.fiscal_year)) fiscal_year = dataent.db.get_value("Fiscal Year", filters.fiscal_year, ["year_start_date", "year_end_date"], as_dict=True) if not fiscal_year: dataent.throw(_("Fiscal Year {0} does not exist").format(filters.fiscal_year)) else: filters.year_start_date = getdate(fiscal_year.year_start_date) filters.year_end_date = getdate(fiscal_year.year_end_date) if not filters.from_date: filters.from_date = filters.year_start_date if not filters.to_date: filters.to_date = filters.year_end_date filters.from_date = getdate(filters.from_date) filters.to_date = getdate(filters.to_date) if filters.from_date > filters.to_date: dataent.throw(_("From Date cannot be greater than To Date")) if (filters.from_date < filters.year_start_date) or (filters.from_date > filters.year_end_date): dataent.msgprint(_("From Date should be within the Fiscal Year. Assuming From Date = {0}")\ .format(formatdate(filters.year_start_date))) filters.from_date = filters.year_start_date if (filters.to_date < filters.year_start_date) or (filters.to_date > filters.year_end_date): dataent.msgprint(_("To Date should be within the Fiscal Year. Assuming To Date = {0}")\ .format(formatdate(filters.year_end_date))) filters.to_date = filters.year_end_date
def validate_delivery_date(self): if self.order_type == 'Sales': delivery_date_list = [ d.delivery_date for d in self.get("items") if d.delivery_date ] max_delivery_date = max( delivery_date_list) if delivery_date_list else None if not self.delivery_date: self.delivery_date = max_delivery_date if self.delivery_date: for d in self.get("items"): if not d.delivery_date: d.delivery_date = self.delivery_date if getdate(self.transaction_date) > getdate( d.delivery_date): dataent.msgprint(_( "Expected Delivery Date should be after Sales Order Date" ), indicator='orange', title=_('Warning')) if getdate(self.delivery_date) != getdate(max_delivery_date): self.delivery_date = max_delivery_date else: dataent.throw(_("Please enter Delivery Date")) self.validate_sales_mntc_quotation()
def test_reschedule_dependent_task(self): task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10)) task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name) task2.get("depends_on")[0].project = "_Test Project" task2.save() task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name) task3.get("depends_on")[0].project = "_Test Project" task3.save() task1.update({"exp_end_date": add_days(nowdate(), 20)}) task1.save() self.assertEqual( dataent.db.get_value("Task", task2.name, "exp_start_date"), getdate(add_days(nowdate(), 21))) self.assertEqual( dataent.db.get_value("Task", task2.name, "exp_end_date"), getdate(add_days(nowdate(), 25))) self.assertEqual( dataent.db.get_value("Task", task3.name, "exp_start_date"), getdate(add_days(nowdate(), 26))) self.assertEqual( dataent.db.get_value("Task", task3.name, "exp_end_date"), getdate(add_days(nowdate(), 30)))
def get_working_days(self, start_date, end_date): start_date, end_date = getdate(start_date), getdate(end_date) from datetime import timedelta date_list = [] employee_holiday_list = [] employee_holidays = dataent.db.sql( """select holiday_date from `tabHoliday` where parent in (select holiday_list from `tabEmployee` where name = %s)""", self.employee, as_dict=1) for d in employee_holidays: employee_holiday_list.append(d.holiday_date) reference_date = start_date while reference_date <= end_date: if reference_date not in employee_holiday_list: date_list.append(reference_date) reference_date += timedelta(days=1) return date_list
def get_period_date_ranges(period, fiscal_year=None, year_start_date=None): from dateutil.relativedelta import relativedelta if not year_start_date: year_start_date, year_end_date = dataent.db.get_value("Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) increment = { "Monthly": 1, "Quarterly": 3, "Half-Yearly": 6, "Yearly": 12 }.get(period) period_date_ranges = [] for i in range(1, 13, increment): period_end_date = getdate(year_start_date) + relativedelta(months=increment, days=-1) if period_end_date > getdate(year_end_date): period_end_date = year_end_date period_date_ranges.append([year_start_date, period_end_date]) year_start_date = period_end_date + relativedelta(days=1) if period_end_date == year_end_date: break return period_date_ranges
def get_period_factor(employee, start_date, end_date, payroll_frequency, payroll_period, depends_on_payment_days=0): # TODO if both deduct checked update the factor to make tax consistent period_start, period_end = payroll_period.start_date, payroll_period.end_date joining_date, relieving_date = dataent.db.get_value( "Employee", employee, ["date_of_joining", "relieving_date"]) if getdate(joining_date) > getdate(period_start): period_start = joining_date if relieving_date and getdate(relieving_date) < getdate(period_end): period_end = relieving_date total_sub_periods, remaining_sub_periods = 0.0, 0.0 if payroll_frequency == "Monthly" and not depends_on_payment_days: total_sub_periods = month_diff(payroll_period.end_date, payroll_period.start_date) remaining_sub_periods = month_diff(period_end, start_date) else: salary_days = date_diff(end_date, start_date) + 1 days_in_payroll_period = date_diff(payroll_period.end_date, payroll_period.start_date) + 1 total_sub_periods = flt(days_in_payroll_period) / flt(salary_days) remaining_days_in_payroll_period = date_diff(period_end, start_date) + 1 remaining_sub_periods = flt(remaining_days_in_payroll_period) / flt( salary_days) return total_sub_periods, remaining_sub_periods
def update_clearance_date(self): clearance_date_updated = False for d in self.get('payment_entries'): if d.clearance_date: if not d.payment_document: dataent.throw( _("Row #{0}: Payment document is required to complete the trasaction" )) if d.cheque_date and getdate(d.clearance_date) < getdate( d.cheque_date): dataent.throw( _("Row #{0}: Clearance date {1} cannot be before Cheque Date {2}" ).format(d.idx, d.clearance_date, d.cheque_date)) if d.clearance_date or self.include_reconciled_entries: if not d.clearance_date: d.clearance_date = None dataent.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date) dataent.db.sql( """update `tab{0}` set clearance_date = %s, modified = %s where name=%s""".format(d.payment_document), (d.clearance_date, nowdate(), d.payment_entry)) clearance_date_updated = True if clearance_date_updated: self.get_payment_entries() msgprint(_("Clearance Date updated")) else: msgprint(_("Clearance Date not mentioned"))
def set_indicator(self): if self.docstatus==1: self.indicator_color = 'blue' self.indicator_title = 'Submitted' if self.valid_till and getdate(self.valid_till) < getdate(nowdate()): self.indicator_color = 'darkgrey' self.indicator_title = 'Expired'
def get_amount_based_on_payment_days(self, row, joining_date, relieving_date): amount, additional_amount = row.amount, row.additional_amount if (self.salary_structure and cint(row.depends_on_payment_days) and cint(self.total_working_days) and (not self.salary_slip_based_on_timesheet or getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date)): additional_amount = flt( (flt(row.additional_amount) * flt(self.payment_days) / cint(self.total_working_days)), row.precision("additional_amount")) amount = flt((flt(row.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), row.precision("amount")) + additional_amount elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint( row.depends_on_payment_days): amount, additional_amount = 0, 0 elif not row.amount: amount = flt(row.default_amount) + flt(row.additional_amount) # apply rounding if dataent.get_cached_value("Salary Component", row.salary_component, "round_to_the_nearest_integer"): amount, additional_amount = rounded(amount), rounded( additional_amount) return amount, additional_amount
def get_item_warehouse_batch_map(filters, float_precision): sle = get_stock_ledger_entries(filters) iwb_map = {} from_date = getdate(filters["from_date"]) to_date = getdate(filters["to_date"]) for d in sle: iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, {})\ .setdefault(d.batch_no, dataent._dict({ "opening_qty": 0.0, "in_qty": 0.0, "out_qty": 0.0, "bal_qty": 0.0 })) qty_dict = iwb_map[d.item_code][d.warehouse][d.batch_no] if d.posting_date < from_date: qty_dict.opening_qty = flt(qty_dict.opening_qty, float_precision) \ + flt(d.actual_qty, float_precision) elif d.posting_date >= from_date and d.posting_date <= to_date: if flt(d.actual_qty) > 0: qty_dict.in_qty = flt(qty_dict.in_qty, float_precision) + flt( d.actual_qty, float_precision) else: qty_dict.out_qty = flt(qty_dict.out_qty, float_precision) \ + abs(flt(d.actual_qty, float_precision)) qty_dict.bal_qty = flt(qty_dict.bal_qty, float_precision) + flt( d.actual_qty, float_precision) return iwb_map
def test_overlapping_allocation(self): dataent.db.sql("delete from `tabLeave Allocation`") employee = dataent.get_doc( "Employee", dataent.db.sql_list("select name from tabEmployee limit 1")[0]) leaves = [{ "doctype": "Leave Allocation", "__islocal": 1, "employee": employee.name, "employee_name": employee.employee_name, "leave_type": "_Test Leave Type", "from_date": getdate("2015-10-01"), "to_date": getdate("2015-10-31"), "new_leaves_allocated": 5, "docstatus": 1 }, { "doctype": "Leave Allocation", "__islocal": 1, "employee": employee.name, "employee_name": employee.employee_name, "leave_type": "_Test Leave Type", "from_date": getdate("2015-09-01"), "to_date": getdate("2015-11-30"), "new_leaves_allocated": 5 }] dataent.get_doc(leaves[0]).save() self.assertRaises(dataent.ValidationError, dataent.get_doc(leaves[1]).save)
def validate_dates(self): joining_date, relieving_date = dataent.db.get_value( "Employee", self.employee, ["date_of_joining", "relieving_date"]) if self.from_date: if dataent.db.exists( "Salary Structure Assignment", { "employee": self.employee, "from_date": self.from_date, "docstatus": 1 }): dataent.throw( _("Salary Structure Assignment for Employee already exists" ), DuplicateAssignment) if joining_date and getdate(self.from_date) < joining_date: dataent.throw( _("From Date {0} cannot be before employee's joining Date {1}" ).format(self.from_date, joining_date)) # flag - old_employee is for migrating the old employees data via patch if relieving_date and getdate( self.from_date ) > relieving_date and not self.flags.old_employee: dataent.throw( _("From Date {0} cannot be after employee's relieving Date {1}" ).format(self.from_date, relieving_date))
def update_item(obj, target, source_parent): target.conversion_factor = obj.conversion_factor target.qty = flt(flt(obj.stock_qty) - flt(obj.ordered_qty)) / target.conversion_factor target.stock_qty = (target.qty * target.conversion_factor) if getdate(target.schedule_date) < getdate(nowdate()): target.schedule_date = None
def __init__(self, filters=None): self.filters = dataent._dict(filters or {}) self.filters.report_date = getdate(self.filters.report_date or nowdate()) self.age_as_on = getdate(nowdate()) \ if self.filters.report_date > getdate(nowdate()) \ else self.filters.report_date
def test_payroll_frequency(self): fiscal_year = get_fiscal_year(nowdate(), company=epaas.get_default_company())[0] month = "%02d" % getdate(nowdate()).month m = get_month_details(fiscal_year, month) for payroll_frequency in [ "Monthly", "Bimonthly", "Fortnightly", "Weekly", "Daily" ]: make_employee(payroll_frequency + "*****@*****.**") ss = make_employee_salary_slip( payroll_frequency + "*****@*****.**", payroll_frequency) if payroll_frequency == "Monthly": self.assertEqual(ss.end_date, m['month_end_date']) elif payroll_frequency == "Bimonthly": if getdate(ss.start_date).day <= 15: self.assertEqual(ss.end_date, m['month_mid_end_date']) else: self.assertEqual(ss.end_date, m['month_end_date']) elif payroll_frequency == "Fortnightly": self.assertEqual(ss.end_date, add_days(nowdate(), 13)) elif payroll_frequency == "Weekly": self.assertEqual(ss.end_date, add_days(nowdate(), 6)) elif payroll_frequency == "Daily": self.assertEqual(ss.end_date, nowdate())
def get_due_date(posting_date, party_type, party, company=None, bill_date=None): """Get due date from `Payment Terms Template`""" due_date = None if (bill_date or posting_date) and party: due_date = bill_date or posting_date template_name = get_pyt_term_template(party, party_type, company) if template_name: due_date = get_due_date_from_template( template_name, posting_date, bill_date).strftime("%Y-%m-%d") else: if party_type == "Supplier": supplier_group = dataent.get_cached_value( party_type, party, "supplier_group") template_name = dataent.get_cached_value( "Supplier Group", supplier_group, "payment_terms") if template_name: due_date = get_due_date_from_template( template_name, posting_date, bill_date).strftime("%Y-%m-%d") # If due date is calculated from bill_date, check this condition if getdate(due_date) < getdate(posting_date): due_date = posting_date return due_date
def validate_supplier_invoice(self): if self.bill_date: if getdate(self.bill_date) > getdate(self.posting_date): dataent.throw(_("Supplier Invoice Date cannot be greater than Posting Date")) if self.bill_no: if cint(dataent.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")): fiscal_year = get_fiscal_year(self.posting_date, company=self.company, as_dict=True) pi = dataent.db.sql('''select name from `tabPurchase Invoice` where bill_no = %(bill_no)s and supplier = %(supplier)s and name != %(name)s and docstatus < 2 and posting_date between %(year_start_date)s and %(year_end_date)s''', { "bill_no": self.bill_no, "supplier": self.supplier, "name": self.name, "year_start_date": fiscal_year.year_start_date, "year_end_date": fiscal_year.year_end_date }) if pi: pi = pi[0][0] dataent.throw(_("Supplier Invoice No exists in Purchase Invoice {0}".format(pi)))
def validate_due_date(posting_date, due_date, party_type, party, company=None, bill_date=None, template_name=None): if getdate(due_date) < getdate(posting_date): dataent.throw( _("Due Date cannot be before Posting / Supplier Invoice Date")) else: if not template_name: return default_due_date = get_due_date_from_template( template_name, posting_date, bill_date).strftime("%Y-%m-%d") if not default_due_date: return if default_due_date != posting_date and getdate(due_date) > getdate( default_due_date): is_credit_controller = dataent.db.get_single_value( "Accounts Settings", "credit_controller") in dataent.get_roles() if is_credit_controller: msgprint( _("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)" ).format(date_diff(due_date, default_due_date))) else: dataent.throw( _("Due / Reference Date cannot be after {0}").format( formatdate(default_due_date)))
def get_fy_details(fy_start_date, fy_end_date): start_year = getdate(fy_start_date).year if start_year == getdate(fy_end_date).year: fy = cstr(start_year) else: fy = cstr(start_year) + '-' + cstr(start_year + 1) return fy
def update_attendance(self): if self.status == "Approved": attendance = dataent.db.sql( """select name from `tabAttendance` where employee = %s\ and (attendance_date between %s and %s) and docstatus < 2""", (self.employee, self.from_date, self.to_date), as_dict=1) if attendance: for d in attendance: doc = dataent.get_doc("Attendance", d.name) if getdate(self.half_day_date) == doc.attendance_date: status = "Half Day" else: status = "On Leave" dataent.db.sql( """update `tabAttendance` set status = %s, leave_type = %s\ where name = %s""", (status, self.leave_type, d.name)) elif getdate(self.to_date) <= getdate(nowdate()): for dt in daterange(getdate(self.from_date), getdate(self.to_date)): date = dt.strftime("%Y-%m-%d") doc = dataent.new_doc("Attendance") doc.employee = self.employee doc.employee_name = self.employee_name doc.attendance_date = date doc.company = self.company doc.leave_type = self.leave_type doc.status = "Half Day" if date == self.half_day_date else "On Leave" doc.flags.ignore_validate = True doc.insert(ignore_permissions=True) doc.submit()
def validate_attendance_date(self): date_of_joining = dataent.db.get_value("Employee", self.employee, "date_of_joining") if getdate(self.attendance_date) > getdate(nowdate()): dataent.throw(_("Attendance can not be marked for future dates")) elif date_of_joining and getdate(self.attendance_date) < getdate(date_of_joining): dataent.throw(_("Attendance date can not be less than employee's joining date"))
def check_stock_frozen_date(self): stock_frozen_upto = dataent.db.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: stock_auth_role = dataent.db.get_value('Stock Settings', None, 'stock_auth_role') if getdate(self.posting_date) <= getdate( stock_frozen_upto ) and not stock_auth_role in dataent.get_roles(): dataent.throw( _("Stock transactions before {0} are frozen").format( formatdate(stock_frozen_upto)), StockFreezeError) stock_frozen_upto_days = int( dataent.db.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0) if stock_frozen_upto_days: stock_auth_role = dataent.db.get_value('Stock Settings', None, 'stock_auth_role') older_than_x_days_ago = (add_days(getdate( self.posting_date), stock_frozen_upto_days) <= date.today()) if older_than_x_days_ago and not stock_auth_role in dataent.get_roles( ): dataent.throw( _("Not allowed to update stock transactions older than {0}" ).format(stock_frozen_upto_days), StockFreezeError)