def test_max_continuous_leaves(self): employee = get_employee() leave_period = get_leave_period() frappe.delete_doc_if_exists("Leave Type", "Test Leave Type", force=1) leave_type = frappe.get_doc(dict( leave_type_name = 'Test Leave Type', doctype = 'Leave Type', max_leaves_allowed = 15, max_continuous_days_allowed = 3 )).insert() date = add_days(nowdate(), -7) allocate_leaves(employee, leave_period, leave_type.name, 10) leave_application = frappe.get_doc(dict( doctype = 'Leave Application', employee = employee.name, leave_type = leave_type.name, from_date = date, to_date = add_days(date, 4), company = "_Test Company", docstatus = 1, status = "Approved" )) self.assertRaises(frappe.ValidationError, leave_application.insert)
def test_fee_validity(self): patient = get_random("Patient") physician = get_random("Physician") if not patient: patient = frappe.new_doc("Patient") patient.patient_name = "Test Patient" patient.sex = "Male" patient.save(ignore_permissions=True) patient = patient.name if not physician: physician = frappe.new_doc("Physician") physician.first_name = "Amit Jain" physician.save(ignore_permissions=True) physician = physician.name frappe.db.set_value("Healthcare Settings", None, "max_visit", 2) frappe.db.set_value("Healthcare Settings", None, "valid_days", 7) appointment = create_appointment(patient, physician, nowdate()) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None) create_invoice(frappe.defaults.get_global_default("company"), physician, patient, appointment.name, appointment.appointment_date) appointment = create_appointment(patient, physician, add_days(nowdate(), 4)) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertTrue(invoice) appointment = create_appointment(patient, physician, add_days(nowdate(), 5)) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None) appointment = create_appointment(patient, physician, add_days(nowdate(), 10)) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None)
def validate(self): member_name = frappe.get_value('Member', dict(email=frappe.session.user)) if not member_name: user = frappe.get_doc('User', frappe.session.user) member = frappe.get_doc(dict( doctype='Member', email=frappe.session.user, member_name=user.get_fullname() )).insert(ignore_permissions=True) member_name = member.name if self.get("__islocal"): self.member = member_name # get last membership (if active) last_membership = foundation.get_last_membership() # if person applied for offline membership if last_membership and not frappe.session.user == "Administrator": # if last membership does not expire in 30 days, then do not allow to renew if getdate(add_days(last_membership.to_date, -30)) > getdate(nowdate()) : frappe.throw(_('You can only renew if your membership expires within 30 days')) self.from_date = add_days(last_membership.to_date, 1) elif frappe.session.user == "Administrator": self.from_date = self.from_date else: self.from_date = nowdate() self.to_date = add_years(self.from_date, 1)
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 frappe._dict({ 'start_date': start_date, 'end_date': end_date })
def schedule_course(self): course_schedules= [] course_schedules_errors= [] rescheduled= [] reschedule_errors= [] self.validate_date() if self.rechedule: rescheduled, reschedule_errors = self.delete_course_schedule(rescheduled, reschedule_errors) date = self.course_start_date while(date < self.course_end_date): if self.day == calendar.day_name[getdate(date).weekday()]: course_schedule = self.make_course_schedule(date) try: course_schedule.save() except OverlapError: course_schedules_errors.append(date) else: course_schedules.append(course_schedule.name + " on " + date) date = add_days(date, 7) else: date = add_days(date, 1) frappe.local.message_log = [] if course_schedules: frappe.msgprint(_("Course Schedules created:") + "\n" + "\n".join(course_schedules)) if course_schedules_errors: frappe.msgprint(_("There were errors while scheduling course on :") + "\n" + "\n".join(course_schedules_errors)) if rescheduled: frappe.msgprint(_("Course Schedules deleted:") + "\n" + "\n".join(rescheduled)) if reschedule_errors: frappe.msgprint(_("There were errors while deleting following schedules:") + "\n" + "\n".join(reschedule_errors))
def create_purchase_order(**args): po = frappe.new_doc("Purchase Order") args = frappe._dict(args) if args.transaction_date: po.transaction_date = args.transaction_date po.schedule_date = add_days(nowdate(), 1) po.company = args.company or "_Test Company" po.supplier = args.customer or "_Test Supplier" po.is_subcontracted = args.is_subcontracted or "No" po.currency = args.currency or frappe.get_cached_value('Company', po.company, "default_currency") po.conversion_factor = args.conversion_factor or 1 po.supplier_warehouse = args.supplier_warehouse or None po.append("items", { "item_code": args.item or args.item_code or "_Test Item", "warehouse": args.warehouse or "_Test Warehouse - _TC", "qty": args.qty or 10, "rate": args.rate or 500, "schedule_date": add_days(nowdate(), 1), "include_exploded_items": args.get('include_exploded_items', 1) }) if not args.do_not_save: po.insert() if not args.do_not_submit: if po.is_subcontracted == "Yes": supp_items = po.get("supplied_items") for d in supp_items: d.reserve_warehouse = args.warehouse or "_Test Warehouse - _TC" po.submit() return po
def test_make_purchase_invoice_with_terms(self): po = create_purchase_order(do_not_save=True) self.assertRaises(frappe.ValidationError, make_purchase_invoice, po.name) po.update( {"payment_terms_template": "_Test Payment Term Template"} ) po.save() po.submit() self.assertEqual(po.payment_schedule[0].payment_amount, 2500.0) self.assertEqual(getdate(po.payment_schedule[0].due_date), getdate(po.transaction_date)) self.assertEqual(po.payment_schedule[1].payment_amount, 2500.0) self.assertEqual(getdate(po.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30)) pi = make_purchase_invoice(po.name) pi.save() self.assertEqual(pi.doctype, "Purchase Invoice") self.assertEqual(len(pi.get("items", [])), 1) self.assertEqual(pi.payment_schedule[0].payment_amount, 2500.0) self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date)) self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0) self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30))
def create_purchase_order(**args): po = frappe.new_doc("Purchase Order") args = frappe._dict(args) if args.transaction_date: po.transaction_date = args.transaction_date po.schedule_date = add_days(nowdate(), 1) po.company = args.company or "_Test Company" po.supplier = args.customer or "_Test Supplier" po.is_subcontracted = args.is_subcontracted or "No" po.currency = args.currency or frappe.db.get_value("Company", po.company, "default_currency") po.conversion_factor = args.conversion_factor or 1 po.append("items", { "item_code": args.item or args.item_code or "_Test Item", "warehouse": args.warehouse or "_Test Warehouse - _TC", "qty": args.qty or 10, "rate": args.rate or 500, "schedule_date": add_days(nowdate(), 1) }) if not args.do_not_save: po.insert() if not args.do_not_submit: po.submit() return po
def get_booking_dates(doc, item, posting_date=None): if not posting_date: posting_date = add_days(today(), -1) last_gl_entry = False deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account" prev_gl_entry = frappe.db.sql(''' select name, posting_date from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s order by posting_date desc limit 1 ''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) if prev_gl_entry: start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1)) else: start_date = item.service_start_date end_date = get_last_day(start_date) if end_date >= item.service_end_date: end_date = item.service_end_date last_gl_entry = True elif item.service_stop_date and end_date >= item.service_stop_date: end_date = item.service_stop_date last_gl_entry = True if end_date > getdate(posting_date): end_date = posting_date if getdate(start_date) <= getdate(end_date): return start_date, end_date, last_gl_entry else: return None, None, None
def test_overdue(self): task = create_task("Testing Overdue", add_days(nowdate(), -10), add_days(nowdate(), -5)) from erpnext.projects.doctype.task.task import set_tasks_as_overdue set_tasks_as_overdue() self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
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(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate(add_days(nowdate(), 21))) self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate(add_days(nowdate(), 25))) self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate(add_days(nowdate(), 26))) self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate(add_days(nowdate(), 30)))
def auto_status_update_ms(doc, method): new = add_years(doc.installation_date, doc.guarantee_period) validdate_amc1=add_days(new,-1) doc.amc_guarantee_valid_upto_date=validdate_amc1 new = add_days(new, days=-1) if doc.guarantee_period==0: doc.amc_guarantee_valid_upto_date="" doc.amc_status="N/A" frappe.throw("Enter The Guarantee Period") else: doc.amc_guarantee_valid_upto_date = new # if doc.transaction_date # doc.amc_status = "Untraceable" # if date_diff(doc.transaction_date,doc.installation_date)<=365*doc.contract_period: # doc.amc_status = "N/A" if doc.amc_guarantee_valid_upto_date>doc.transaction_date: doc.amc_status = "Guarantee" else: doc.amc_status="Expired" if doc.amc_start_month: guarntee=add_years(doc.amc_start_month,doc.contract_period) validdate_amc=add_days(guarntee,-1) doc.amc_guarantee_valid_upto_date=validdate_amc guarntee = add_days(guarntee, days=-1) doc.amc_guarantee_valid_upto_date=guarntee doc.amc_status = "AMC" if getdate(doc.transaction_date) > getdate(doc.installation_date): frappe.throw("Installation Date Should be Greater Than Equal To Transaction 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 test_future_inactive_signed_contract_status(self): self.contract_doc.is_signed = True self.contract_doc.start_date = add_days(nowdate(), 1) self.contract_doc.end_date = add_days(nowdate(), 2) self.contract_doc.insert() self.assertEqual(self.contract_doc.status, "Inactive")
def test_lapsed_contract_status(self): self.contract_doc.contract_term = "_Test Customer Contract with Requirements" self.contract_doc.start_date = add_days(nowdate(), -2) self.contract_doc.end_date = add_days(nowdate(), 1) self.contract_doc.requires_fulfilment = 1 self.contract_doc.fulfilment_deadline = add_days(nowdate(), -1) self.contract_doc.save() self.assertEqual(self.contract_doc.fulfilment_status, "Lapsed")
def get_due_date(posting_date, term): due_date = None if term.due_date_based_on == "Day(s) after invoice date": due_date = add_days(posting_date, term.credit_days) elif term.due_date_based_on == "Day(s) after the end of the invoice month": due_date = add_days(get_last_day(posting_date), term.credit_days) elif term.due_date_based_on == "Month(s) after the end of the invoice month": due_date = add_months(get_last_day(posting_date), term.credit_months) return due_date
def test_valid_till(self): from erpnext.selling.doctype.quotation.quotation import make_sales_order quotation = frappe.copy_doc(test_records[0]) quotation.valid_till = add_days(quotation.transaction_date, -1) self.assertRaises(frappe.ValidationError, quotation.validate) quotation.valid_till = add_days(nowdate(), -1) quotation.insert() quotation.submit() self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
def test_create_training_event(self): if not frappe.db.get_value("Training Event", "Basic Training Event"): frappe.get_doc({ "doctype": "Training Event", "event_name": "Basic Training Event", "training_program": "Basic Training", "location": "Union Square", "start_time": add_days(today(), 5), "end_time": add_days(today(), 6), "introduction": "Welcome to the Basic Training Event", "employees": get_attendees(self.employee, self.employee2) }).insert()
def reschedule_dependent_tasks(self): end_date = self.exp_end_date or self.act_end_date if end_date: for task_name in frappe.db.sql("select name from `tabTask` as parent where %s in \ (select task from `tabTask Depends On` as child where parent.name = child.parent )", self.name, as_dict=1): task = frappe.get_doc("Task", task_name.name) if task.exp_start_date and task.exp_end_date and task.exp_start_date < getdate(end_date) and task.status == "Open" : task_duration = date_diff(task.exp_end_date, task.exp_start_date) task.exp_start_date = add_days(end_date, 1) task.exp_end_date = add_days(task.exp_start_date, task_duration) task.flags.ignore_recursion_check = True task.save()
def setup_asset(): assets = json.loads(open(frappe.get_app_path('erpnext', 'demo', 'data', 'asset.json')).read()) for d in assets: asset = frappe.new_doc('Asset') asset.update(d) asset.purchase_date = add_days(nowdate(), -random.randint(20, 1500)) asset.next_depreciation_date = add_days(asset.purchase_date, 30) asset.warehouse = "Stores - WPL" asset.set_missing_values() asset.make_depreciation_schedule() asset.flags.ignore_validate = True asset.save() asset.submit()
def reschedule_dependent_tasks(self): end_date = self.exp_end_date or self.act_end_date if end_date: for task_name in frappe.db.sql("""select name from `tabTask` as parent where parent.project = %(project)s and parent.name in \ (select parent from `tabTask Depends On` as child where child.task = %(task)s and child.project = %(project)s)""", {'project': self.project, 'task':self.name }, as_dict=1): task = frappe.get_doc("Task", task_name.name) if task.exp_start_date and task.exp_end_date and task.exp_start_date < getdate(end_date) and task.status == "Open": task_duration = date_diff(task.exp_end_date, task.exp_start_date) task.exp_start_date = add_days(end_date, 1) task.exp_end_date = add_days(task.exp_start_date, task_duration) task.flags.ignore_recursion_check = True task.save()
def test_fee_validity(self): frappe.db.sql("""delete from `tabPatient Appointment`""") frappe.db.sql("""delete from `tabFee Validity`""") patient = get_random("Patient") practitioner = get_random("Healthcare Practitioner") department = get_random("Medical Department") if not patient: patient = frappe.new_doc("Patient") patient.patient_name = "_Test Patient" patient.sex = "Male" patient.save(ignore_permissions=True) patient = patient.name if not department: medical_department = frappe.new_doc("Medical Department") medical_department.department = "_Test Medical Department" medical_department.save(ignore_permissions=True) department = medical_department.name if not practitioner: practitioner = frappe.new_doc("Healthcare Practitioner") practitioner.first_name = "_Test Healthcare Practitioner" practitioner.department = department practitioner.save(ignore_permissions=True) practitioner = practitioner.name frappe.db.set_value("Healthcare Settings", None, "max_visit", 2) frappe.db.set_value("Healthcare Settings", None, "valid_days", 7) appointment = create_appointment(patient, practitioner, nowdate(), department) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertEqual(invoiced, 0) invoice_appointment(appointment) appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), department) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertTrue(invoiced) appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), department) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertEqual(invoiced, 0) appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), department) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertEqual(invoiced, 0)
def execute(): leave_app_list = frappe.db.sql("""SELECT name FROM `tabLeave Application` WHERE docstatus = 1 AND status = 'Approved' ORDER BY name ASC""", as_list=1) for leave_app in leave_app_list: print("Checking for Leave Application " + leave_app[0]) la_doc = frappe.get_doc("Leave Application", leave_app[0]) att_list = frappe.db.sql("""SELECT name FROM `tabAttendance` WHERE docstatus = 1 AND employee ='%s' AND attendance_date BETWEEN '%s' AND '%s'"""%(la_doc.employee, \ la_doc.from_date, la_doc.to_date), as_list=1) if att_list: for att in att_list: status = frappe.db.get_value("Attendance", att[0], "status") if status != 'On Leave': if status == 'Half Day': if la_doc.total_leave_days != 0.5: print('Half Day Error for ' + att[0] + ' and Leave App ' + leave_app[0]) else: print('Error for ' + att[0] + ' and Leave App ' + leave_app[0]) else: leave_days = la_doc.total_leave_days for lday in range(int(leave_days)): shift_request = frappe.db.sql("""SELECT name FROM `tabShift Assignment` WHERE employee = '%s' AND docstatus = 1 AND `date` = '%s'"""%\ (la_doc.employee, add_days(la_doc.from_date, lday)),as_list=1) if not shift_request: new_sr = frappe.new_doc("Shift Assignment") new_sr.employee = la_doc.employee new_sr.company = la_doc.company new_sr.shift_type = 'General Shift G-Shift With In and Out' new_sr.date = add_days(la_doc.from_date, lday) new_sr.docstatus = 1 new_sr.insert() print("Added Shift Request " + str(new_sr.name) + " for Employee " + \ la_doc.employee + " with Name: " + str(la_doc.employee_name)) frappe.db.commit() new_att = frappe.new_doc("Attendance") new_att.docstatus = 1 new_att.employee = la_doc.employee new_att.attendance_date = add_days(la_doc.from_date, lday) if la_doc.total_leave_days == int(la_doc.total_leave_days): new_att.status = 'On Leave' new_att.company = la_doc.company new_att.department = la_doc.department new_att.insert() print('Added Attendance for Employee ' + la_doc.employee + ' Name: ' + str(la_doc.employee_name) + ' for Leave Application ' + la_doc.name) frappe.db.commit()
def get_error_report(from_date=None, to_date=None, limit=10): from frappe.utils import get_url, now_datetime, add_days if not from_date: from_date = add_days(now_datetime().date(), -1) if not to_date: to_date = add_days(now_datetime().date(), -1) errors = get_errors(from_date, to_date, limit) if errors: return 1, _("""<h4>Scheduler Failed Events (max {limit}):</h4> <p>URL: <a href="{url}" target="_blank">{url}</a></p><hr>{errors}""").format( limit=limit, url=get_url(), errors="<hr>".join(errors)) else: return 0, _("<p>Scheduler didn't encounter any problems.</p>")
def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args) if args.transaction_date: so.transaction_date = args.transaction_date so.company = args.company or "_Test Company" so.customer = args.customer or "_Test Customer" so.delivery_date = add_days(so.transaction_date, 10) so.currency = args.currency or "INR" if args.selling_price_list: so.selling_price_list = args.selling_price_list if "warehouse" not in args: args.warehouse = "_Test Warehouse - _TC" if args.item_list: for item in args.item_list: so.append("items", item) else: so.append("items", { "item_code": args.item or args.item_code or "_Test Item", "warehouse": args.warehouse, "qty": args.qty or 10, "rate": args.rate or 100, "conversion_factor": 1.0, }) if not args.do_not_save: so.insert() if not args.do_not_submit: so.submit() return so
def get_next_dep_date(doc, dep_freq, tot_dep): #Next depreciation date shoud be last date of the purchase date if monthly or last date #of period of depreciation #if monthly depreciation then last day or month, if bi-monthly then last day of month+1 #if 3 monthly then last day of quarter and not 3 months #if 4 monthly then last day of third and not 4 months and so on and so forth fy_doc = get_fy_doc(doc) r = relativedelta.relativedelta(add_days(fy_doc.year_end_date,1), fy_doc.year_start_date) fy_months = r.years*12 + r.months dep_in_fy = cint(fy_months)/flt(dep_freq) booked_deps_months = (cint(doc.number_of_depreciations_booked)*cint(dep_freq)) last_day = add_months(get_last_day(doc.purchase_date), booked_deps_months) base_last_day = get_last_day(doc.purchase_date) base_dep_date = None if dep_in_fy >= 1 and dep_in_fy % 1 == 0: for i in range(0, cint(tot_dep)): dep_date = get_last_day(add_months(fy_doc.year_start_date, (i*dep_freq -1))) if base_last_day <= dep_date and base_dep_date is None: base_dep_date = dep_date if last_day <= dep_date: doc.next_depreciation_date = dep_date break else: doc.next_depreciation_date = fy_doc.year_end_date elif dep_in_fy % 1 != 0: frappe.throw('Frequency Causing Depreciations not to be posted equally in FY, \ please change the frequency of depreciation') else: frappe.throw('Months between depreciation cannot be less than 1') return base_dep_date
def make_leave_application(): allocated_leaves = frappe.get_all("Leave Allocation", fields=['employee', 'leave_type']) for allocated_leave in allocated_leaves: leave_balance = get_leave_balance_on(allocated_leave.employee, allocated_leave.leave_type, frappe.flags.current_date, consider_all_leaves_in_the_allocation_period=True) if leave_balance != 0: if leave_balance == 1: to_date = frappe.flags.current_date else: to_date = add_days(frappe.flags.current_date, random.randint(0, leave_balance-1)) leave_application = frappe.get_doc({ "doctype": "Leave Application", "employee": allocated_leave.employee, "from_date": frappe.flags.current_date, "to_date": to_date, "leave_type": allocated_leave.leave_type, "status": "Approved" }) try: leave_application.insert() leave_application.submit() frappe.db.commit() except (OverlapError): frappe.db.rollback()
def validate_schedule_date_for_holiday_list(self, schedule_date, sales_person): from erpnext.accounts.utils import get_fiscal_year validated = False fy_details = "" try: fy_details = get_fiscal_year(date=schedule_date, verbose=0) except Exception: pass if fy_details and fy_details[0]: # check holiday list in employee master holiday_list = frappe.db.sql_list("""select h.holiday_date from `tabEmployee` emp, `tabSales Person` sp, `tabHoliday` h, `tabHoliday List` hl where sp.name=%s and emp.name=sp.employee and hl.name=emp.holiday_list and h.parent=hl.name and hl.fiscal_year=%s""", (sales_person, fy_details[0])) if not holiday_list: # check global holiday list holiday_list = frappe.db.sql("""select h.holiday_date from `tabHoliday` h, `tabHoliday List` hl where h.parent=hl.name and ifnull(hl.is_default, 0) = 1 and hl.fiscal_year=%s""", fy_details[0]) if not validated and holiday_list: if schedule_date in holiday_list: schedule_date = add_days(schedule_date, -1) else: validated = True return schedule_date
def test_make_sales_invoice_with_terms(self): so = make_sales_order(do_not_submit=True) self.assertRaises(frappe.ValidationError, make_sales_invoice, so.name) so.update({"payment_terms_template": "_Test Payment Term Template"}) so.save() so.submit() si = make_sales_invoice(so.name) self.assertEquals(len(si.get("items")), len(so.get("items"))) self.assertEquals(len(si.get("items")), 1) si.insert() self.assertEqual(si.payment_schedule[0].payment_amount, 500.0) self.assertEqual(si.payment_schedule[0].due_date, so.transaction_date) self.assertEqual(si.payment_schedule[1].payment_amount, 500.0) self.assertEqual(si.payment_schedule[1].due_date, add_days(so.transaction_date, 30)) si.submit() si1 = make_sales_invoice(so.name) self.assertEquals(len(si1.get("items")), 0)
def get_item_details(args): """ args = { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "plc_conversion_rate": 1.0, "parenttype": "", "parent": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "transaction_type": "selling", "ignore_pricing_rule": 0/1 "project_name": "" } """ args = process_args(args) item_doc = frappe.get_doc("Item", args.item_code) item = item_doc validate_item_details(args, item) out = get_basic_details(args, item) get_party_item_code(args, item_doc, out) if out.get("warehouse"): out.update(get_available_qty(args.item_code, out.warehouse)) out.update(get_projected_qty(item.name, out.warehouse)) get_price_list_rate(args, item_doc, out) if args.transaction_type == "selling" and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args)) # update args with out, if key or value not exists for key, value in out.iteritems(): if args.get(key) is None: args[key] = value out.update(get_pricing_rule_for_item(args)) if args.get("parenttype") in ("Sales Invoice", "Delivery Note"): if item_doc.has_serial_no == 1 and not args.serial_no: out.serial_no = get_serial_nos_by_fifo(args, item_doc) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days(args.transaction_date, item.lead_time_days) if args.get("is_subcontracted") == "Yes": out.bom = get_default_bom(args.item_code) return out
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False, company=None, reset_period_on_fy_change=True): """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year) validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year) # start with first day, so as to avoid year to_dates like 2-April if ever they occur] year_start_date = getdate(fiscal_year.year_start_date) year_end_date = getdate(fiscal_year.year_end_date) months_to_add = { "Yearly": 12, "Half-Yearly": 6, "Quarterly": 3, "Monthly": 1 }[periodicity] period_list = [] start_date = year_start_date months = get_months(year_start_date, year_end_date) for i in range(cint(math.ceil(months / months_to_add))): period = frappe._dict({"from_date": start_date}) to_date = add_months(start_date, months_to_add) start_date = to_date # Subtract one day from to_date, as it may be first day in next fiscal year or month to_date = add_days(to_date, -1) if to_date <= year_end_date: # the normal case period.to_date = to_date else: # if a fiscal year ends before a 12 month period period.to_date = year_end_date period.to_date_fiscal_year = get_fiscal_year(period.to_date, company=company)[0] period.from_date_fiscal_year_start_date = get_fiscal_year( period.from_date, company=company)[1] period_list.append(period) if period.to_date == year_end_date: break # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() if periodicity == "Monthly" and not accumulated_values: label = formatdate(opts["to_date"], "MMM YYYY") else: if not accumulated_values: label = get_label(periodicity, opts["from_date"], opts["to_date"]) else: if reset_period_on_fy_change: label = get_label(periodicity, opts.from_date_fiscal_year_start_date, opts["to_date"]) else: label = get_label(periodicity, period_list[0].from_date, opts["to_date"]) opts.update({ "key": key.replace(" ", "_").replace("-", "_"), "label": label, "year_start_date": year_start_date, "year_end_date": year_end_date }) return period_list
def get_dates(args): """get list of dates in between from date and to date""" no_of_days = date_diff(add_days(args["to_date"], 1), args["from_date"]) dates = [add_days(args["from_date"], i) for i in range(0, no_of_days)] return dates
def create_ts(): day = add_days(today(), -1) # days = ["2018-07-30"] # for day in days: attendance = frappe.get_all("Attendance", fields=[ 'name', 'employee', 'attendance_date', 'out_date', 'in_time', 'out_time', 'total_working_hours' ], filters={'attendance_date': day}) for doc in attendance: if doc.attendance_date and doc.out_date and doc.in_time and doc.out_time: employee = frappe.get_doc("Employee", doc.employee) if employee.employment_type == 'Operator': ot_hours = calculate_hours(doc.attendance_date, doc.out_date, doc.in_time, doc.out_time, doc.employee) if ot_hours: from_date = doc.attendance_date to_date = doc.out_date from_time = str(from_date) + " " + doc.in_time from_time_f = datetime.strptime( from_time, '%Y-%m-%d %H:%M:%S') + timedelta(hours=( (employee.working_hours).seconds // 3600)) to_time = str(to_date) + " " + doc.out_time to_time_f = datetime.strptime(to_time, '%Y-%m-%d %H:%M:%S') ts_id = frappe.db.get_value( "Timesheet", { "employee": doc.employee, "start_date": from_date, "end_date": to_date }) if ts_id: ts = frappe.get_doc("Timesheet", ts_id) ts.update({ "company": doc.company, "employee": doc.employee, "start_date": from_date, "end_date": to_date, }) ts.time_logs[0].activity_type = "OT" ts.time_logs[0].hours = round(flt(ot_hours / 3600.00)) ts.time_logs[0].from_time = from_time_f ts.time_logs[0].to_time = to_time_f ts.save(ignore_permissions=True) frappe.db.commit() else: ts = frappe.new_doc("Timesheet") ts.company = doc.company ts.employee = doc.employee ts.start_date = from_date ts.end_date = to_date ts.append( "time_logs", { "activity_type": "OT", "hours": round(flt(ot_hours / 3600.00)), "from_time": from_time_f, "to_time": to_time_f }) ts.insert() ts.save(ignore_permissions=True) frappe.db.commit()
def test_is_dormant(self): self.assertTrue(is_dormant(check_time= get_datetime('2100-01-01 00:00:00'))) self.assertTrue(is_dormant(check_time = add_days(frappe.db.get_last_created('Activity Log'), 5))) self.assertFalse(is_dormant(check_time = frappe.db.get_last_created('Activity Log')))
def test_backdated_stock_reco_qty_reposting(self): """ Test if a backdated stock reco recalculates future qty until next reco. ------------------------------------------- Var | Doc | Qty | Balance ------------------------------------------- PR5 | PR | 10 | 10 (posting date: today-4) [backdated] SR5 | Reco | 0 | 8 (posting date: today-4) [backdated] PR1 | PR | 10 | 18 (posting date: today-3) PR2 | PR | 1 | 19 (posting date: today-2) SR4 | Reco | 0 | 6 (posting date: today-1) [backdated] PR3 | PR | 1 | 7 (posting date: today) # can't post future PR """ item_code = make_item().name warehouse = "_Test Warehouse - _TC" frappe.flags.dont_execute_stock_reposts = True def assertBalance(doc, qty_after_transaction): sle_balance = frappe.db.get_value("Stock Ledger Entry", { "voucher_no": doc.name, "is_cancelled": 0 }, "qty_after_transaction") self.assertEqual(sle_balance, qty_after_transaction) pr1 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=10, rate=100, posting_date=add_days(nowdate(), -3)) pr2 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=1, rate=100, posting_date=add_days(nowdate(), -2)) pr3 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=1, rate=100, posting_date=nowdate()) assertBalance(pr1, 10) assertBalance(pr3, 12) # post backdated stock reco in between sr4 = create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=6, rate=100, posting_date=add_days(nowdate(), -1)) assertBalance(pr3, 7) # post backdated stock reco at the start sr5 = create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=8, rate=100, posting_date=add_days(nowdate(), -4)) assertBalance(pr1, 18) assertBalance(pr2, 19) assertBalance(sr4, 6) # check if future stock reco is unaffected # Make a backdated receipt and check only entries till first SR are affected pr5 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=10, rate=100, posting_date=add_days(nowdate(), -5)) assertBalance(pr5, 10) # check if future stock reco is unaffected assertBalance(sr4, 6) assertBalance(sr5, 8) # cancel backdated stock reco and check future impact sr5.cancel() assertBalance(pr1, 10) assertBalance(pr2, 11) assertBalance(sr4, 6) # check if future stock reco is unaffected
def create_material_request(material_requests): """ Create indent on reaching reorder level """ mr_list = [] exceptions_list = [] def _log_exception(): if frappe.local.message_log: exceptions_list.extend(frappe.local.message_log) frappe.local.message_log = [] else: exceptions_list.append(frappe.get_traceback()) frappe.log_error(frappe.get_traceback()) for request_type in material_requests: for company in material_requests[request_type]: try: items = material_requests[request_type][company] if not items: continue mr = frappe.new_doc("Material Request") mr.update({ "company": company, "transaction_date": nowdate(), "material_request_type": "Material Transfer" if request_type == "Transfer" else request_type }) for d in items: d = frappe._dict(d) item = frappe.get_doc("Item", d.item_code) uom = item.stock_uom conversion_factor = 1.0 if request_type == 'Purchase': uom = item.purchase_uom or item.stock_uom if uom != item.stock_uom: conversion_factor = frappe.db.get_value( "UOM Conversion Detail", { 'parent': item.name, 'uom': uom }, 'conversion_factor') or 1.0 mr.append( "items", { "doctype": "Material Request Item", "item_code": d.item_code, "schedule_date": add_days(nowdate(), cint(item.lead_time_days)), "qty": d.reorder_qty / conversion_factor, "uom": uom, "stock_uom": item.stock_uom, "warehouse": d.warehouse, "item_name": item.item_name, "description": item.description, "item_group": item.item_group, "brand": item.brand, }) schedule_dates = [d.schedule_date for d in mr.items] mr.schedule_date = max(schedule_dates or [nowdate()]) mr.flags.ignore_mandatory = True mr.insert() mr.submit() mr_list.append(mr) except: _log_exception() if mr_list: if getattr(frappe.local, "reorder_email_notify", None) is None: frappe.local.reorder_email_notify = cint( frappe.db.get_value('Stock Settings', None, 'reorder_email_notify')) if (frappe.local.reorder_email_notify): send_email_notification(mr_list) if exceptions_list: notify_errors(exceptions_list) return mr_list
def test_supplied_qty_against_subcontracted_po(self): item_code = "_Test Subcontracted FG Item 5" make_item('Sub Contracted Raw Material 4', { 'is_stock_item': 1, 'is_sub_contracted_item': 1 }) make_subcontracted_item( item_code=item_code, raw_materials=["Sub Contracted Raw Material 4"]) update_backflush_based_on("Material Transferred for Subcontract") order_qty = 250 po = create_purchase_order( item_code=item_code, qty=order_qty, is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC", do_not_save=True) # Add same subcontracted items multiple times po.append( "items", { "item_code": item_code, "qty": order_qty, "schedule_date": add_days(nowdate(), 1), "warehouse": "_Test Warehouse - _TC" }) po.set_missing_values() po.submit() # Material receipt entry for the raw materials which will be send to supplier make_stock_entry(target="_Test Warehouse - _TC", item_code="Sub Contracted Raw Material 4", qty=500, basic_rate=100) rm_items = [ { "item_code": item_code, "rm_item_code": "Sub Contracted Raw Material 4", "item_name": "_Test Item", "qty": 250, "warehouse": "_Test Warehouse - _TC", "stock_uom": "Nos", "name": po.supplied_items[0].name }, { "item_code": item_code, "rm_item_code": "Sub Contracted Raw Material 4", "item_name": "_Test Item", "qty": 250, "warehouse": "_Test Warehouse - _TC", "stock_uom": "Nos" }, ] # Raw Materials transfer entry from stores to supplier's warehouse rm_item_string = json.dumps(rm_items) se = frappe.get_doc( make_subcontract_transfer_entry(po.name, rm_item_string)) se.submit() # Test po_detail field has value or not for item_row in se.items: self.assertEqual(item_row.po_detail, po.supplied_items[item_row.idx - 1].name) po_doc = frappe.get_doc("Purchase Order", po.name) for row in po_doc.supplied_items: # Valid that whether transferred quantity is matching with supplied qty or not in the purchase order self.assertEqual(row.supplied_qty, 250.0) update_backflush_based_on("BOM")
def get_item_details(args): """ args = { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "plc_conversion_rate": 1.0, "doctype": "", "name": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "" } """ args = process_args(args) item_doc = frappe.get_doc("Item", args.item_code) item = item_doc validate_item_details(args, item) out = get_basic_details(args, item) get_party_item_code(args, item_doc, out) if frappe.db.exists("Product Bundle", args.item_code): valuation_rate = 0.0 bundled_items = frappe.get_doc("Product Bundle", args.item_code) for bundle_item in bundled_items.items: valuation_rate += \ flt(get_valuation_rate(bundle_item.item_code, out.get("warehouse")).get("valuation_rate") \ * bundle_item.qty) out.update({"valuation_rate": valuation_rate}) else: out.update(get_valuation_rate(args.item_code, out.get("warehouse"))) get_price_list_rate(args, item_doc, out) if args.customer and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args)) if out.get("warehouse"): out.update(get_bin_details(args.item_code, out.warehouse)) # update args with out, if key or value not exists for key, value in out.iteritems(): if args.get(key) is None: args[key] = value out.update(get_pricing_rule_for_item(args)) if (args.get("doctype") == "Delivery Note" or (args.get("doctype") == "Sales Invoice" and args.get('update_stock'))) \ and out.warehouse and out.stock_qty > 0: if out.has_serial_no: out.serial_no = get_serial_no(out, args.serial_no) if out.has_batch_no and not args.get("batch_no"): out.batch_no = get_batch_no(out.item_code, out.warehouse, out.qty) actual_batch_qty = get_batch_qty(out.batch_no, out.warehouse, out.item_code) if actual_batch_qty: out.update(actual_batch_qty) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days( args.transaction_date, item.lead_time_days) if args.get("is_subcontracted") == "Yes": out.bom = args.get('bom') or get_default_bom(args.item_code) get_gross_profit(out) return out
def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=True): """ args = { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "plc_conversion_rate": 1.0, "doctype": "", "name": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "" "set_warehouse": "" } """ args = process_args(args) item = frappe.get_cached_doc("Item", args.item_code) validate_item_details(args, item) out = get_basic_details(args, item, overwrite_warehouse) if isinstance(doc, string_types): doc = json.loads(doc) if doc and doc.get('doctype') == 'Purchase Invoice': args['bill_date'] = doc.get('bill_date') if doc: args['posting_date'] = doc.get('posting_date') args['transaction_date'] = doc.get('transaction_date') get_item_tax_template(args, item, out) out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \ else out.get("item_tax_template"), as_json=True) get_party_item_code(args, item, out) set_valuation_rate(out, args) update_party_blanket_order(args, out) get_price_list_rate(args, item, out) if args.customer and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args)) if out.get("warehouse"): out.update(get_bin_details(args.item_code, out.warehouse)) # update args with out, if key or value not exists for key, value in iteritems(out): if args.get(key) is None: args[key] = value data = get_pricing_rule_for_item(args, out.price_list_rate, doc, for_validate=for_validate) out.update(data) update_stock(args, out) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days( args.transaction_date, item.lead_time_days) if args.get("is_subcontracted") == "Yes": out.bom = args.get('bom') or get_default_bom(args.item_code) get_gross_profit(out) if args.doctype == 'Material Request': out.rate = args.rate or out.price_list_rate out.amount = flt(args.qty * out.rate) return out
def send(recipients=None, sender=None, subject=None, message=None, text_content=None, reference_doctype=None, reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, attachments=None, reply_to=None, cc=[], bcc=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, send_priority=1, communication=None, now=False, read_receipt=None, queue_separately=False, is_notification=False, add_unsubscribe_link=1, inline_images=None, header=None, print_letterhead=False): """Add email to sending queue (Email Queue) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param text_content: Text version of email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :param send_priority: Priority for Email Queue, default 1. :param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.queue.unsubscribe`. :param unsubscribe_params: additional params for unsubscribed links. default are name, doctype, email :param attachments: Attachments to be sent. :param reply_to: Reply to be captured here (default inbox) :param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To. :param send_after: Send this email after the given datetime. If value is in integer, then `send_after` will be the automatically set to no of days from current date. :param communication: Communication link to be set in Email Queue record :param now: Send immediately (don't send in the background) :param queue_separately: Queue each email separately :param is_notification: Marks email as notification so will not trigger notifications from system :param add_unsubscribe_link: Send unsubscribe link in the footer of the Email, default 1. :param inline_images: List of inline images as {"filename", "filecontent"}. All src properties will be replaced with random Content-Id :param header: Append header in email (boolean) """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" if not recipients and not cc: return if isinstance(recipients, string_types): recipients = split_emails(recipients) if isinstance(cc, string_types): cc = split_emails(cc) if isinstance(bcc, string_types): bcc = split_emails(bcc) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) email_account = get_outgoing_email_account(True, append_to=reference_doctype, sender=sender) if not sender or sender == "Administrator": sender = email_account.default_sender if not text_content: try: text_content = html2text(message) except HTMLParser.HTMLParseError: text_content = "See html attachment" recipients = list(set(recipients)) cc = list(set(cc)) all_ids = tuple(recipients + cc) unsubscribed = frappe.db.sql_list( ''' SELECT distinct email from `tabEmail Unsubscribe` where email in %(all_ids)s and ( ( reference_doctype = %(reference_doctype)s and reference_name = %(reference_name)s ) or global_unsubscribe = 1 ) ''', { 'all_ids': all_ids, 'reference_doctype': reference_doctype, 'reference_name': reference_name, }) recipients = [r for r in recipients if r and r not in unsubscribed] if cc: cc = [r for r in cc if r and r not in unsubscribed] if not recipients and not cc: # Recipients may have been unsubscribed, exit quietly return email_text_context = text_content should_append_unsubscribe = (add_unsubscribe_link and reference_doctype and (unsubscribe_message or reference_doctype == "Newsletter") and add_unsubscribe_link == 1) unsubscribe_link = None if should_append_unsubscribe: unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_text_context += unsubscribe_link.text email_content = get_formatted_html(subject, message, email_account=email_account, header=header, unsubscribe_link=unsubscribe_link) # add to queue add(recipients, sender, subject, formatted=email_content, text_content=email_text_context, reference_doctype=reference_doctype, reference_name=reference_name, attachments=attachments, reply_to=reply_to, cc=cc, bcc=bcc, message_id=message_id, in_reply_to=in_reply_to, send_after=send_after, send_priority=send_priority, email_account=email_account, communication=communication, add_unsubscribe_link=add_unsubscribe_link, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, expose_recipients=expose_recipients, read_receipt=read_receipt, queue_separately=queue_separately, is_notification=is_notification, inline_images=inline_images, header=header, now=now, print_letterhead=print_letterhead)
def test_payment_days_based_on_attendance(self): from erpnext.hr.doctype.attendance.attendance import mark_attendance no_of_days = self.get_no_of_days() # Payroll based on attendance frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance") frappe.db.set_value("Payroll Settings", None, "daily_wages_fraction_for_half_day", 0.75) emp_id = make_employee( "*****@*****.**") frappe.db.set_value("Employee", emp_id, { "relieving_date": None, "status": "Active" }) frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0) month_start_date = get_first_day(nowdate()) month_end_date = get_last_day(nowdate()) first_sunday = frappe.db.sql( """ select holiday_date from `tabHoliday` where parent = 'Salary Slip Test Holiday List' and holiday_date between %s and %s order by holiday_date """, (month_start_date, month_end_date))[0][0] mark_attendance(emp_id, first_sunday, 'Absent', ignore_validate=True) # invalid lwp mark_attendance(emp_id, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # counted as absent mark_attendance(emp_id, add_days(first_sunday, 2), 'Half Day', leave_type='Leave Without Pay', ignore_validate=True) # valid 0.75 lwp mark_attendance(emp_id, add_days(first_sunday, 3), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # valid lwp mark_attendance(emp_id, add_days(first_sunday, 4), 'On Leave', leave_type='Casual Leave', ignore_validate=True) # invalid lwp mark_attendance(emp_id, add_days(first_sunday, 7), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # invalid lwp ss = make_employee_salary_slip( "*****@*****.**", "Monthly", "Test Payment Based On Attendence") self.assertEqual(ss.leave_without_pay, 1.25) self.assertEqual(ss.absent_days, 1) days_in_month = no_of_days[0] no_of_holidays = no_of_days[1] self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 2.25) #Gross pay calculation based on attendances gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay + ss.absent_days)) self.assertEqual(ss.gross_pay, gross_pay) frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
def test_payment_days(self): no_of_days = self.get_no_of_days() # Holidays not included in working days frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1) # set joinng date in the same month make_employee("*****@*****.**") if getdate(nowdate()).day >= 15: relieving_date = getdate(add_days(nowdate(), -10)) date_of_joining = getdate(add_days(nowdate(), -10)) elif getdate(nowdate()).day < 15 and getdate(nowdate()).day >= 5: date_of_joining = getdate(add_days(nowdate(), -3)) relieving_date = getdate(add_days(nowdate(), -3)) elif getdate(nowdate()).day < 5 and not getdate(nowdate()).day == 1: date_of_joining = getdate(add_days(nowdate(), -1)) relieving_date = getdate(add_days(nowdate(), -1)) elif getdate(nowdate()).day == 1: date_of_joining = getdate(nowdate()) relieving_date = getdate(nowdate()) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "date_of_joining", date_of_joining) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "relieving_date", None) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "status", "Active") ss = make_employee_salary_slip("*****@*****.**", "Monthly", "Test Payment Days") self.assertEqual(ss.total_working_days, no_of_days[0]) self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1)) # set relieving date in the same month frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "date_of_joining", (add_days(nowdate(), -60))) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "relieving_date", relieving_date) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "status", "Left") ss.save() self.assertEqual(ss.total_working_days, no_of_days[0]) self.assertEqual(ss.payment_days, getdate(relieving_date).day) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "relieving_date", None) frappe.db.set_value( "Employee", frappe.get_value("Employee", {"employee_name": "*****@*****.**"}, "name"), "status", "Active")
def fetch_transactions(self, from_date=None): def update_transactions(transactions, after_date, bank_account): trans_ids = frappe.get_all( "Bank Transaction", filters=[ ["creation", ">", add_days(after_date, -1)], ["bank_account", "=", bank_account], ], fields="transaction_id", ) existing_transactions = [ item["transaction_id"] for item in trans_ids ] count = 0 for transaction in transactions: for key in ("Withdrawal", "Deposit", "Closing Balance"): if transaction.get(key): transaction[key] = flt(transaction[key]) transaction["Cheque/Ref. No."] = str( transaction["Cheque/Ref. No."]).replace('.0', '') transaction_id = hashlib.sha224( str(transaction).encode()).hexdigest() if transaction_id in existing_transactions: continue bank_transaction = frappe.get_doc( {"doctype": "Bank Transaction"}) bank_transaction.update({ "transaction_id": transaction_id, "date": getdate(transaction["Date"]), "description": transaction["Narration"], "debit": flt(transaction["Withdrawal"]), "credit": flt(transaction["Deposit"]), "reference_number": transaction["Cheque/Ref. No."], "closing_balance": flt(transaction["Closing Balance"]), "bank_account": bank_account, "unallocated_amount": abs( flt(transaction["Deposit"]) - flt(transaction["Withdrawal"])), }) bank_transaction.submit() count += 1 frappe.publish_realtime( "sync_transactions", { "uid": self.uid, "count": count, "after_date": add_days(after_date, -1), }, user=frappe.session.user, ) self.switch_to_frame("main_part") self.switch_to_frame("left_menu") self.get_element("enquiryatag", selector_type="id", now=True).click() self.get_element("SIN_nohref", selector_type="id", now=True).click() self.switch_to_frame("main_part") self.get_element("selectselAccttype0", "id") self.click_option( self.get_element("selAccttype", now=True), "SCA", "Unable to select Account Type", ) self.click_option( self.get_element("selAcct", now=True), self.data.from_account_no, "Please verify account number in Bank Integration Settings", ) prev_valid_date = add_months(add_days(today(), -getdate().day + 1), -1) if not frappe.db.count( "Bank Transaction", filters={ "bank_account": self.data.bank_account, "date": [">", prev_valid_date], }, ): from_date = prev_valid_date else: from_date = frappe.get_all( "Bank Transaction", filters={"bank_account": self.data.bank_account}, fields="date", order_by="creation desc", limit=1, )[0]["date"] if getdate(from_date) <= getdate(prev_valid_date): from_date = prev_valid_date from_date = add_days(from_date, -1) self.br.find_elements_by_class_name("radio")[1].click() self.get_element("frmDatePicker", selector_type="id", now=True).send_keys( getdate(from_date).strftime("%d/%m/%Y")) self.get_element("toDatePicker", selector_type="id", now=True).send_keys(getdate().strftime("%d/%m/%Y")) self.br.execute_script("return formSubmitbytype()") transactions = [] self.br.execute_script("$('.datatable').show()") transaction_tables = self.br.find_elements_by_class_name("datatable") if not transaction_tables: self.throw("No New Transactions found") self.logout() return for transaction_table in transaction_tables: transactions += pd.read_html( transaction_table.get_attribute("outerHTML")) self.logout() transactions = pd.concat(transactions) transactions = transactions.where(pd.notnull(transactions), None) transactions = transactions.to_dict("records") transactions.reverse() update_transactions(transactions, from_date, self.data.bank_account)
def get_items(date1): object_list=[] # item_list=frappe.db.sql("""select distinct si.item_code,si.item_name from `tabSales Order` so inner join `tabSales Order Item` si on so.name=si.parent where si.qty>0 and so.transaction_date between %s and %s""",(date1,add_days(date1,5))) # for row in item_list: # balance_qty = frappe.db.sql("""select sum(qty_after_transaction) from `tabStock Ledger Entry` # where item_code=%s and is_cancelled='No' limit 1""", (row[0])) # if not len(balance_qty): # b_qty=0 # else: # b_qty=balance_qty[0][0] # infinity_sale_qty=frappe.db.sql("""select sum(qty) from `tabSales Order Item` where item_code=%s and delivery_date>=%s""",(row[0],today())) # if not len(infinity_sale_qty): # inf_s_qty=0 # else: # inf_s_qty=infinity_sale_qty[0][0] # infinity_purchase_qty=frappe.db.sql("""select sum(qty) from `tabPurchase Order Item` where item_code=%s and schedule_date>=%s""",(row[0],today())) # if not len(infinity_purchase_qty): # inf_p_qty=0 # else: # inf_p_qty=infinity_purchase_qty[0][0] # week_sales_qty=frappe.db.sql("""select sum(qty) from `tabSales Order Item` where item_code=%s and delivery_date between %s and %s""",(row[0],(today()),add_days(today(),5))) # if not len(week_sales_qty): # week_s_qty=0 # else: # week_s_qty=week_sales_qty[0][0] # week_purchase_qty=frappe.db.sql("""select sum(qty) from `tabPurchase Order Item` where item_code=%s and schedule_date between %s and %s""",(row[0],(today()),add_days(today(),5))) # if not len(week_purchase_qty): # week_p_qty=0 # else: # week_p_qty=week_purchase_qty[0][0] # if b_qty==None: # b_qty=0 # if inf_s_qty==None: # inf_s_qty=0 # if inf_p_qty==None: # inf_p_qty=0 # if week_s_qty==None: # week_s_qty=0 # if week_p_qty==None: # week_p_qty=0 # d1 = collections.OrderedDict() # d1['item_code']=row[0] # d1['item_name']=row[1] # d1['balance_qty']=b_qty # d1['infinity_sales_qty']=inf_s_qty # d1['infinity_purchase_qty']=inf_p_qty # d1['week_sales_qty']=week_s_qty # d1['week_purchase_qty']=week_p_qty # object_list.append(d1) item_list1=frappe.db.sql("""select distinct si.item_code,si.item_name from `tabSales Order` so inner join `tabSales Order Item` si on so.name=si.parent where si.qty>0 and so.transaction_date>=%s and so.docstatus=0""",date1) for row in item_list1: balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry` where item_code=%s and is_cancelled='No' order by posting_date desc, posting_time desc, name desc limit 1""", (row[0])) if not len(balance_qty): b_qty=0 else: b_qty=balance_qty[0][0] infinity_sale_qty=frappe.db.sql("""select sum(si.qty) from `tabSales Order` so inner join `tabSales Order Item` si on so.name=si.parent where si.item_code=%s and so.delivery_date>=%s and so.docstatus=0""",(row[0],date1)) if not len(infinity_sale_qty): inf_s_qty=0 else: inf_s_qty=infinity_sale_qty[0][0] infinity_purchase_qty=frappe.db.sql("""select sum(qty) from `tabPurchase Order Item` where item_code=%s and schedule_date>=%s and docstatus=0""",(row[0],date1)) if not len(infinity_purchase_qty): inf_p_qty=0 else: inf_p_qty=infinity_purchase_qty[0][0] week_sales_qty=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.docstatus=0 and so.delivery_date between %s and %s group by si.item_code""",(row[0],date1,add_days(date1,4))) #return week_sales_qty if not len(week_sales_qty): week_s_qty=0 else: week_s_qty=week_sales_qty[0][0] week_purchase_qty=frappe.db.sql("""select sum(qty) from `tabPurchase Order Item` where item_code=%s and schedule_date between %s and %s and docstatus=0""",(row[0],(date1),add_days(date1,5))) if not len(week_purchase_qty): week_p_qty=0 else: week_p_qty=week_purchase_qty[0][0] if b_qty==None: b_qty=0 if inf_s_qty==None: inf_s_qty=0 if inf_p_qty==None: inf_p_qty=0 if week_s_qty==None: week_s_qty=0 if week_p_qty==None: week_p_qty=0 dayname=getdate(date1).strftime("%A") first1=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.delivery_date=%s and so.docstatus=0""",(row[0],date1)) second1=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.delivery_date=%s and so.docstatus=0""",(row[0],add_days(date1,1))) third1=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.delivery_date=%s and so.docstatus=0""",(row[0],add_days(date1,2))) four1=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.delivery_date=%s and so.docstatus=0""",(row[0],add_days(date1,3))) five1=frappe.db.sql("""select sum(si.qty) from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.delivery_date=%s and so.docstatus=0""",(row[0],add_days(date1,4))) if not first1[0][0]==None: first=first1[0][0] else: first=0 if not second1[0][0]==None: second=second1[0][0] else: second=0 if not third1[0][0]==None: third=third1[0][0] else: third=0 if not four1[0][0]==None: four=four1[0][0] else: four=0 if not five1[0][0]==None: five=five1[0][0] else: five=0 d1 = collections.OrderedDict() d1['item_code']=row[0] d1['item_name']=row[1] d1['balance_qty']=b_qty d1['infinity_sales_qty']=inf_s_qty d1['infinity_purchase_qty']=inf_p_qty d1['week_sales_qty']=week_s_qty d1['week_purchase_qty']=week_p_qty d1['dayname']=dayname d1['first_date']=date1 d1['second_date']=add_days(date1,1) d1['third_date']=add_days(date1,2) d1['four_date']=add_days(date1,3) d1['five_date']=add_days(date1,4) d1['first']=first d1['second']=second d1['third']=third d1['four']=four d1['five']=five object_list.append(d1) return object_list
def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=None): if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 if not transaction_date: transaction_date = nowdate() currency_settings = frappe.get_doc("Accounts Settings").as_dict() allow_stale_rates = currency_settings.get("allow_stale") filters = [["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency]] if args == "for_buying": filters.append(["for_buying", "=", "1"]) elif args == "for_selling": filters.append(["for_selling", "=", "1"]) if not allow_stale_rates: stale_days = currency_settings.get("stale_days") checkpoint_date = add_days(transaction_date, -stale_days) filters.append(["date", ">", get_datetime_str(checkpoint_date)]) # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all("Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests api_url = "https://frankfurter.erpnext.org/{0}".format( transaction_date) response = requests.get(api_url, params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.msgprint( _("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually" ).format(from_currency, to_currency, transaction_date)) return 0.0
def make_material_request(self): '''Create Material Requests grouped by Sales Order and Material Request Type''' material_request_list = [] material_request_map = {} for item in self.mr_items: item_doc = frappe.get_cached_doc('Item', item.item_code) material_request_type = item.material_request_type or item_doc.default_material_request_type # key for Sales Order:Material Request Type:Customer key = '{}:{}:{}'.format(item.sales_order, material_request_type, item_doc.customer or '') schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) if not key in material_request_map: # make a new MR for the combination material_request_map[key] = frappe.new_doc("Material Request") material_request = material_request_map[key] material_request.update({ "transaction_date": nowdate(), "status": "Draft", "company": self.company, "requested_by": frappe.session.user, 'material_request_type': material_request_type, 'customer': item_doc.customer or '' }) material_request_list.append(material_request) else: material_request = material_request_map[key] # add item material_request.append("items", { "item_code": item.item_code, "qty": item.quantity, "schedule_date": schedule_date, "warehouse": item.warehouse, "sales_order": item.sales_order, 'production_plan': self.name, 'material_request_plan_item': item.name, "project": frappe.db.get_value("Sales Order", item.sales_order, "project") \ if item.sales_order else None }) for material_request in material_request_list: # submit material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") if self.get('submit_material_request'): material_request.submit() else: material_request.save() frappe.flags.mute_messages = False if material_request_list: material_request_list = ["""<a href="#Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \ for m in material_request_list] msgprint(_("{0} created").format(comma_and(material_request_list))) else: msgprint(_("No material request created"))
def get_period_list(fiscal_year, periodicity, from_beginning=False): """Get a list of dict {"to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" fy_start_end_date = frappe.db.get_value( "Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) if not fy_start_end_date: frappe.throw(_("Fiscal Year {0} not found.").format(fiscal_year)) start_date = getdate(fy_start_end_date[0]) end_date = getdate(fy_start_end_date[1]) if periodicity == "Yearly": period_list = [ _dict({ "to_date": end_date, "key": fiscal_year, "label": fiscal_year }) ] else: months_to_add = { "Half-yearly": 6, "Quarterly": 3, "Monthly": 1 }[periodicity] period_list = [] # start with first day, so as to avoid year to_dates like 2-April if ever they occur to_date = get_first_day(start_date) for i in xrange(12 / months_to_add): to_date = add_months(to_date, months_to_add) if to_date == get_first_day(to_date): # if to_date is the first day, get the last day of previous month to_date = add_days(to_date, -1) else: # to_date should be the last day of the new to_date's month to_date = get_last_day(to_date) if to_date <= end_date: # the normal case period_list.append(_dict({"to_date": to_date})) # if it ends before a full year if to_date == end_date: break else: # if a fiscal year ends before a 12 month period period_list.append(_dict({"to_date": end_date})) break # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() label = formatdate(opts["to_date"], "MMM YYYY") opts.update({ "key": key.replace(" ", "_").replace("-", "_"), "label": label, "year_start_date": start_date, "year_end_date": end_date }) if from_beginning: # set start date as None for all fiscal periods, used in case of Balance Sheet opts["from_date"] = None else: opts["from_date"] = start_date return period_list
def create_material_request(material_requests): """ Create indent on reaching reorder level """ mr_list = [] exceptions_list = [] def _log_exception(): if frappe.local.message_log: exceptions_list.extend(frappe.local.message_log) frappe.local.message_log = [] else: exceptions_list.append(frappe.get_traceback()) for request_type in material_requests: for company in material_requests[request_type]: try: items = material_requests[request_type][company] if not items: continue mr = frappe.new_doc("Material Request") mr.update({ "company": company, "transaction_date": nowdate(), "material_request_type": request_type }) for d in items: d = frappe._dict(d) item = frappe.get_doc("Item", d.item_code) mr.append( "items", { "doctype": "Material Request Item", "item_code": d.item_code, "schedule_date": add_days(nowdate(), cint(item.lead_time_days)), "uom": item.stock_uom, "warehouse": d.warehouse, "item_name": item.item_name, "description": item.description, "item_group": item.item_group, "qty": d.reorder_qty, "brand": item.brand, }) mr.insert() mr.submit() mr_list.append(mr) except: _log_exception() if mr_list: if getattr(frappe.local, "reorder_email_notify", None) is None: frappe.local.reorder_email_notify = cint( frappe.db.get_value('Stock Settings', None, 'reorder_email_notify')) if (frappe.local.reorder_email_notify): send_email_notification(mr_list) if exceptions_list: notify_errors(exceptions_list) return mr_list
def update_attendance_time(employee, attendance_date, in_time, out_time): twh = '' if attendance_date: attendance_date = out_date = datetime.strptime(attendance_date, '%Y-%m-%d') if in_time and out_time: in_time_f = datetime.strptime(in_time, '%H:%M:%S').time() out_time_f = datetime.strptime(out_time, '%H:%M:%S').time() if out_time_f < in_time_f: out_date = (add_days(attendance_date, 1)).date() in_time = datetime.strptime(in_time, '%H:%M:%S').time() in_time = datetime.combine(attendance_date, in_time) out_time = datetime.strptime(out_time, '%H:%M:%S').time() out_time = datetime.combine(out_date, out_time) twh = out_time - in_time status = 'Absent' if twh > timedelta(hours=4): status = 'Half Day' if twh >= timedelta(hours=8): status = 'Present' if twh: twh_seconds = twh.total_seconds() minutes = twh_seconds // 60 hours = minutes // 60 twh = "%02d hr %02d min" % (hours, minutes % 60) if frappe.db.exists("Attendance", { "employee": employee, "attendance_date": attendance_date }): att = frappe.db.get_value("Attendance", { "employee": employee, "attendance_date": attendance_date }, "name") # frappe.errprint(att) exist_att = frappe.get_doc("Attendance", att) if not exist_att.in_time or not exist_att.out_time: exist_att.update({ "biometric_id": employee, "attendance_date": attendance_date, "status": status, "in_time": in_time, "out_time": out_time, "total_working_hours": twh, "modified_status": "Miss Punch" }) exist_att.save(ignore_permissions=True) frappe.db.commit() else: exist_att = frappe.new_doc("Attendance") exist_att.update({ "employee": employee, "biometric_id": employee, "attendance_date": attendance_date, "in_time": in_time, "status": status, "out_time": out_time, "total_working_hours": twh, "modified_status": "Miss Punch" }) exist_att.save(ignore_permissions=True) exist_att.submit() frappe.db.commit() return "Ok"
def get_order_details_week(item,date1): data=frappe.db.sql("""select so.name,so.customer,si.item_code,si.item_name,si.qty from `tabSales Order` as so inner join `tabSales Order Item` as si on so.name=si.parent where si.item_code=%s and so.docstatus=0 and si.delivery_date between %s and %s""",(item,date1,add_days(date1,4)),as_dict=True) if len(data): return data else: return _(False)
def test_gle_with_cwip_toggling(self): # TEST: purchase an asset with cwip enabled and then disable cwip and try submitting the asset frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1) pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=5000, do_not_submit=True, location="Test Location") pr.set('taxes', [{ 'category': 'Total', 'add_deduct_tax': 'Add', 'charge_type': 'On Net Total', 'account_head': '_Test Account Service Tax - _TC', 'description': '_Test Account Service Tax', 'cost_center': 'Main - _TC', 'rate': 5.0 }, { 'category': 'Valuation and Total', 'add_deduct_tax': 'Add', 'charge_type': 'On Net Total', 'account_head': '_Test Account Shipping Charges - _TC', 'description': '_Test Account Shipping Charges', 'cost_center': 'Main - _TC', 'rate': 5.0 }]) pr.submit() expected_gle = (("Asset Received But Not Billed - _TC", 0.0, 5250.0), ("CWIP Account - _TC", 5250.0, 0.0)) pr_gle = frappe.db.sql( """select account, debit, credit from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no = %s order by account""", pr.name) self.assertEqual(pr_gle, expected_gle) pi = make_invoice(pr.name) pi.submit() expected_gle = ( ("_Test Account Service Tax - _TC", 250.0, 0.0), ("_Test Account Shipping Charges - _TC", 250.0, 0.0), ("Asset Received But Not Billed - _TC", 5250.0, 0.0), ("Creditors - _TC", 0.0, 5500.0), ("Expenses Included In Asset Valuation - _TC", 0.0, 250.0), ) pi_gle = frappe.db.sql( """select account, debit, credit from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no = %s order by account""", pi.name) self.assertEqual(pi_gle, expected_gle) asset = frappe.db.get_value('Asset', { 'purchase_receipt': pr.name, 'docstatus': 0 }, 'name') asset_doc = frappe.get_doc('Asset', asset) month_end_date = get_last_day(nowdate()) asset_doc.available_for_use_date = nowdate( ) if nowdate() != month_end_date else add_days(nowdate(), -15) self.assertEqual(asset_doc.gross_purchase_amount, 5250.0) asset_doc.append( "finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) # disable cwip and try submitting frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 0) asset_doc.submit() # asset should have gl entries even if cwip is disabled expected_gle = (("_Test Fixed Asset - _TC", 5250.0, 0.0), ("CWIP Account - _TC", 0.0, 5250.0)) gle = frappe.db.sql( """select account, debit, credit from `tabGL Entry` where voucher_type='Asset' and voucher_no = %s order by account""", asset_doc.name) self.assertEqual(gle, expected_gle) frappe.db.set_value("Asset Category", "Computers", "enable_cwip_accounting", 1)
def get_item_details(args): """ args = { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "plc_conversion_rate": 1.0, "doctype": "", "name": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "" "set_warehouse": "" } """ args = process_args(args) item = frappe.get_cached_doc("Item", args.item_code) validate_item_details(args, item) out = get_basic_details(args, item) get_party_item_code(args, item, out) set_valuation_rate(out, args) update_party_blanket_order(args, out) get_price_list_rate(args, item, out) if args.customer and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args)) if out.get("warehouse"): out.update(get_bin_details(args.item_code, out.warehouse)) # update args with out, if key or value not exists for key, value in iteritems(out): if args.get(key) is None: args[key] = value out.update(get_pricing_rule_for_item(args)) update_stock(args, out) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days( args.transaction_date, item.lead_time_days) if args.get("is_subcontracted") == "Yes": out.bom = args.get('bom') or get_default_bom(args.item_code) get_gross_profit(out) if args.doctype == 'Material Request': out.rate = args.rate or out.price_list_rate out.amount = flt(args.qty * out.rate) return out
def get_events(start, end, user=None, for_reminder=False, filters=None): if not user: user = frappe.session.user if isinstance(filters, string_types): filters = json.loads(filters) filter_condition = get_filters_cond('Event', filters, []) tables = ["`tabEvent`"] if "`tabEvent Participants`" in filter_condition: tables.append("`tabEvent Participants`") events = frappe.db.sql(""" SELECT `tabEvent`.name, `tabEvent`.subject, `tabEvent`.description, `tabEvent`.color, `tabEvent`.starts_on, `tabEvent`.ends_on, `tabEvent`.owner, `tabEvent`.all_day, `tabEvent`.event_type, `tabEvent`.repeat_this_event, `tabEvent`.repeat_on, `tabEvent`.repeat_till, `tabEvent`.monday, `tabEvent`.tuesday, `tabEvent`.wednesday, `tabEvent`.thursday, `tabEvent`.friday, `tabEvent`.saturday, `tabEvent`.sunday FROM {tables} WHERE ( ( (date(`tabEvent`.starts_on) BETWEEN date(%(start)s) AND date(%(end)s)) OR (date(`tabEvent`.ends_on) BETWEEN date(%(start)s) AND date(%(end)s)) OR ( date(`tabEvent`.starts_on) <= date(%(start)s) AND date(`tabEvent`.ends_on) >= date(%(end)s) ) ) OR ( date(`tabEvent`.starts_on) <= date(%(start)s) AND `tabEvent`.repeat_this_event=1 AND coalesce(`tabEvent`.repeat_till, '3000-01-01') > date(%(start)s) ) ) {reminder_condition} {filter_condition} AND ( `tabEvent`.event_type='Public' OR `tabEvent`.owner=%(user)s OR EXISTS( SELECT `tabDocShare`.name FROM `tabDocShare` WHERE `tabDocShare`.share_doctype='Event' AND `tabDocShare`.share_name=`tabEvent`.name AND `tabDocShare`.user=%(user)s ) ) AND `tabEvent`.status='Open' ORDER BY `tabEvent`.starts_on""".format( tables=", ".join(tables), filter_condition=filter_condition, reminder_condition="AND coalesce(`tabEvent`.send_reminder, 0)=1" if for_reminder else ""), { "start": start, "end": end, "user": user, }, as_dict=1) # process recurring events start = start.split(" ")[0] end = end.split(" ")[0] add_events = [] remove_events = [] def add_event(e, date): new_event = e.copy() enddate = add_days(date,int(date_diff(e.ends_on.split(" ")[0], e.starts_on.split(" ")[0]))) \ if (e.starts_on and e.ends_on) else date new_event.starts_on = date + " " + e.starts_on.split(" ")[1] new_event.ends_on = new_event.ends_on = enddate + " " + e.ends_on.split( " ")[1] if e.ends_on else None add_events.append(new_event) for e in events: if e.repeat_this_event: e.starts_on = get_datetime_str(e.starts_on) e.ends_on = get_datetime_str(e.ends_on) if e.ends_on else None event_start, time_str = get_datetime_str(e.starts_on).split(" ") repeat = "3000-01-01" if cstr( e.repeat_till) == "" else e.repeat_till if e.repeat_on == "Yearly": start_year = cint(start.split("-")[0]) end_year = cint(end.split("-")[0]) # creates a string with date (27) and month (07) eg: 07-27 event_start = "-".join(event_start.split("-")[1:]) # repeat for all years in period for year in range(start_year, end_year + 1): date = str(year) + "-" + event_start if getdate(date) >= getdate(start) and getdate( date) <= getdate(end) and getdate(date) <= getdate( repeat): add_event(e, date) remove_events.append(e) if e.repeat_on == "Monthly": # creates a string with date (27) and month (07) and year (2019) eg: 2019-07-27 date = start.split("-")[0] + "-" + start.split( "-")[1] + "-" + event_start.split("-")[2] # last day of month issue, start from prev month! try: getdate(date) except ValueError: date = date.split("-") date = date[0] + "-" + str(cint(date[1]) - 1) + "-" + date[2] start_from = date for i in range(int(date_diff(end, start) / 30) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_months(start_from, i + 1) remove_events.append(e) if e.repeat_on == "Weekly": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start) \ and e[weekdays[getdate(date).weekday()]]: add_event(e, date) remove_events.append(e) if e.repeat_on == "Daily": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(event_start) and getdate( date) <= getdate(end) and getdate(date) <= getdate( repeat): add_event(e, date) remove_events.append(e) for e in remove_events: events.remove(e) events = events + add_events for e in events: # remove weekday properties (to reduce message size) for w in weekdays: del e[w] return events
def validate_fields(self): if self.export_or_import == 'Export': if self.reference_doctype != 'Sales Invoice': frappe.throw('Only Sales Invoice is Allowed for Exports') #Allow only Sales Invoices with Sales Taxes marked as export and shipping country outside India. ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) stct_doc = frappe.get_doc("Sales Taxes and Charges Template", ref_doc.taxes_and_charges) ship_add_doc = frappe.get_doc("Address", ref_doc.shipping_address_name) bill_add_doc = frappe.get_doc("Address", ref_doc.customer_address) if ref_doc.docstatus != 1: frappe.throw("Only Submitted Documents are Allowed") if self.reference_doctype == 'Sales Invoice': ship_country = frappe.db.get_value( "Address", ref_doc.shipping_address_name, "country") if stct_doc.is_export != 1: frappe.throw( "Only Sales Invoices Marked as Exports are Allowed") if ship_country == "India": frappe.throw("Only Invoices shipped outside India allowed") self.reference_date = ref_doc.posting_date self.reference_currency = ref_doc.currency self.customer_or_supplier = 'Customer' self.customer_or_supplier_name = ref_doc.customer self.iec_number = stct_doc.iec_code self.bill_to_country = bill_add_doc.country self.ship_to_country = ship_add_doc.country self.grand_total = ref_doc.grand_total self.grand_total_inr = ref_doc.base_grand_total if self.pan_number: validate_pan(self.pan_number) if self.shipping_bill_number: if self.fob_value == 0: frappe.throw(("Enter FOB Value in {0}").format( self.reference_currency)) else: if self.fob_value > self.grand_total: frappe.throw( ("FOB Value has to be less than {0}").format( self.grand_total)) if len(str(self.shipping_bill_number)) != 7: frappe.throw("Shipping Bill Number is Exactly 7 Digits") p = re.compile("[0-9]{7}") if not p.match(str(self.shipping_bill_number)): frappe.throw("Invalid Shipping Bill Number") if not self.shipping_bill_date: frappe.throw( 'Shipping Bill Date is Mandatory for Shipping Bill') if self.shipping_bill_date: self.submission_date_deadline = add_days( self.shipping_bill_date, 21) diff = getdate(self.shipping_bill_date) - getdate( self.reference_date) if diff.days > 20 or diff.days < -20: frappe.throw( 'Out of Range Difference, Contact [email protected]') if self.bank_ifsc_code: validate_ifsc_code(self.bank_ifsc_code) else: self.submission_date_deadline = add_days( self.reference_date, 21) if self.brc_number: if not self.brc_date: frappe.throw("BRC Date is Mandatory for BRC Number") else: if self.brc_date < add_days(self.shipping_bill_date, 15): frappe.throw("BRC Date is NOT VALID") if not self.bank_ifsc_code: frappe.throw("Bank IFSC is Mandatory for BRC Number") if not self.brc_bill_id: frappe.throw( "BRC Bill ID is mandatory and is different from BRC Number \ goto DGFT site and enter only IEC Code for Bill ID") else: if self.brc_bill_id == self.brc_number: frappe.throw( "BRC Number and Bill ID should be different") validate_brc_no(self.brc_number, self.bank_ifsc_code) self.brc_status = 'BRC Issued' else: self.brc_status = 'BRC Pending' else: frappe.throw("Import Related Tracking Is Not Implemented Yet.") if self.reference_doctype != 'Purchase Invoice': frappe.throw('Only Purchase Invoice is Allowed for Imports') #If IMPORT RELATED TRACKING isimport = frappe.db.get_value( "Purchase Taxes and Charges Template", ref_doc.taxes_and_charges, "is_import") if isimport != 1: frappe.throw( "Only Purchase Invoices Marked as Import are allowed here") self.customer_or_supplier = 'Supplier' self.customer_or_supplier_name = ref_doc.supplier ship_country = frappe.db.get_value("Address", )
def test_make_time_log(self): from erpnext.projects.doctype.time_log.test_time_log import make_time_log_test_record prod_order = make_prod_order_test_record(item="_Test FG Item 2", planned_start_date=now(), qty=1, do_not_save=True) prod_order.set_production_order_operations() prod_order.insert() prod_order.submit() d = prod_order.operations[0] d.completed_qty = flt(d.completed_qty) time_log = make_time_log_test_record(hours=1, production_order=prod_order.name, operation=d.operation, completed_qty=prod_order.qty - d.completed_qty, operation_id=d.name, for_manufacturing=1, simulate=True) self.assertEqual(prod_order.name, time_log.production_order) self.assertEqual((prod_order.qty - d.completed_qty), time_log.completed_qty) self.assertEqual( time_diff_in_hours(d.planned_end_time, d.planned_start_time), time_log.hours) manufacturing_settings = frappe.get_doc({ "doctype": "Manufacturing Settings", "allow_production_on_holidays": 0 }) manufacturing_settings.save() prod_order.load_from_db() self.assertEqual(prod_order.operations[0].status, "Completed") self.assertEqual(prod_order.operations[0].completed_qty, prod_order.qty) self.assertEqual(prod_order.operations[0].actual_operation_time, 60) self.assertEqual(prod_order.operations[0].actual_operating_cost, 100) time_log.cancel() prod_order.load_from_db() self.assertEqual(prod_order.operations[0].status, "Pending") self.assertEqual(flt(prod_order.operations[0].completed_qty), 0) self.assertEqual(flt(prod_order.operations[0].actual_operation_time), 0) self.assertEqual(flt(prod_order.operations[0].actual_operating_cost), 0) time_log2 = make_time_log_test_record(from_time=add_days( time_log.to_time, 1), production_order=prod_order.name, operation=d.operation, completed_qty=5, operation_id=d.name, for_manufacturing=1, do_not_save=True) self.assertRaises(OverProductionLoggedError, time_log2.save)
def execute(filters=None): filters.day_before_from_date = add_days(filters.from_date, -1) columns, data = get_columns(filters), get_data(filters) return columns, data
def test_validate_start_date_before_end_date(self): self.contract_doc.start_date = nowdate() self.contract_doc.end_date = add_days(nowdate(), -1) self.assertRaises(frappe.ValidationError, self.contract_doc.insert)
def set_end_date(self): if self.loan_start_date and self.loan_period: self.loan_end_date = add_days(self.loan_start_date, self.loan_period)
def test_payment_days_based_on_leave_application(self): no_of_days = self.get_no_of_days() # Payroll based on attendance frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") emp_id = make_employee( "*****@*****.**") frappe.db.set_value("Employee", emp_id, { "relieving_date": None, "status": "Active" }) frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0) month_start_date = get_first_day(nowdate()) month_end_date = get_last_day(nowdate()) first_sunday = frappe.db.sql( """ select holiday_date from `tabHoliday` where parent = 'Salary Slip Test Holiday List' and holiday_date between %s and %s order by holiday_date """, (month_start_date, month_end_date))[0][0] make_leave_application(emp_id, first_sunday, add_days(first_sunday, 3), "Leave Without Pay") leave_type_ppl = create_leave_type( leave_type_name="Test Partially Paid Leave", is_ppl=1) leave_type_ppl.save() alloc = create_leave_allocation(employee=emp_id, from_date=add_days(first_sunday, 4), to_date=add_days(first_sunday, 10), new_leaves_allocated=3, leave_type="Test Partially Paid Leave") alloc.save() alloc.submit() #two day leave ppl with fraction_of_daily_salary_per_leave = 0.5 equivalent to single day lwp make_leave_application(emp_id, add_days(first_sunday, 4), add_days(first_sunday, 5), "Test Partially Paid Leave") ss = make_employee_salary_slip( "*****@*****.**", "Monthly", "Test Payment Based On Leave Application") self.assertEqual(ss.leave_without_pay, 4) days_in_month = no_of_days[0] no_of_holidays = no_of_days[1] self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 4) frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
def update_transactions(transactions, after_date, bank_account): trans_ids = frappe.get_all( "Bank Transaction", filters=[ ["creation", ">", add_days(after_date, -1)], ["bank_account", "=", bank_account], ], fields="transaction_id", ) existing_transactions = [ item["transaction_id"] for item in trans_ids ] count = 0 for transaction in transactions: for key in ("Withdrawal", "Deposit", "Closing Balance"): if transaction.get(key): transaction[key] = flt(transaction[key]) transaction["Cheque/Ref. No."] = str( transaction["Cheque/Ref. No."]).replace('.0', '') transaction_id = hashlib.sha224( str(transaction).encode()).hexdigest() if transaction_id in existing_transactions: continue bank_transaction = frappe.get_doc( {"doctype": "Bank Transaction"}) bank_transaction.update({ "transaction_id": transaction_id, "date": getdate(transaction["Date"]), "description": transaction["Narration"], "debit": flt(transaction["Withdrawal"]), "credit": flt(transaction["Deposit"]), "reference_number": transaction["Cheque/Ref. No."], "closing_balance": flt(transaction["Closing Balance"]), "bank_account": bank_account, "unallocated_amount": abs( flt(transaction["Deposit"]) - flt(transaction["Withdrawal"])), }) bank_transaction.submit() count += 1 frappe.publish_realtime( "sync_transactions", { "uid": self.uid, "count": count, "after_date": add_days(after_date, -1), }, user=frappe.session.user, )