def log_sync_status( entity_type, count_response={}, entities_to_sync=0, pages_to_sync=0, entities_received=0, synced_entities={}, start=None, end=None, is_resync=False, max_date=None, urls=[], response=[]): """ log Magento >> ERPNext entity sync status """ log = frappe.new_doc("Sync Log") log.max_updated_at = max_date log.date = start or now_datetime() log.sync_end = end or now_datetime() log.sync_time = end - start log.entity_type = entity_type log.total_count = entities_to_sync log.received = entities_received log.pagewise_count = pages_to_sync - 1 if pages_to_sync else 0 log.synced_failed = len([entity_id for entity_id, status in synced_entities.iteritems() if status.get("operation") == None]) log.synced_count = len([entity_id for entity_id, status in synced_entities.iteritems() if status.get("operation") != None]) log.count_api_response = json.dumps(count_response) log.synced_entities = json.dumps(synced_entities) log.sync_stat = "" log.is_resync = 1 if is_resync else 0 log.url = "<pre><code>%s</code></pre>"%(json.dumps(urls or [], indent=2)) log.magento_response = "<pre><code>%s</code></pre>"%(json.dumps(response or {}, indent=2)) log.save(ignore_permissions=True)
def send_one(email, smtpserver=None, auto_commit=True, now=False): '''Send Email Queue with given smtpserver''' email = frappe.db.sql('''select name, status, communication, message, sender, recipient, reference_doctype from `tabEmail Queue` where name=%s for update''', email, as_dict=True)[0] if email.status != 'Not Sent': # rollback to release lock and return frappe.db.rollback() return frappe.db.sql("""update `tabEmail Queue` set status='Sending', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) try: if auto_commit: if not smtpserver: smtpserver = SMTPServer() smtpserver.setup_email_account(email.reference_doctype) smtpserver.sess.sendmail(email.sender, email.recipient, encode(email.message)) frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError, smtplib.SMTPHeloError, smtplib.SMTPAuthenticationError, JobTimeoutException): # bad connection/timeout, retry later frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) # no need to attempt further return except Exception, e: frappe.db.rollback() frappe.db.sql("""update `tabEmail Queue` set status='Error', error=%s where name=%s""", (unicode(e), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) if now: raise e else: # log to scheduler log log('frappe.email.queue.flush', unicode(e))
def test_enabled_events_day_change(self): val = json.dumps(["daily", "daily_long", "weekly", "weekly_long", "monthly", "monthly_long"]) frappe.db.set_global('enabled_scheduler_events', val) last = now_datetime() - relativedelta(days=2) enqueue_applicable_events(frappe.local.site, now_datetime(), last) self.assertTrue("all" in frappe.flags.ran_schedulers) self.assertTrue("hourly" in frappe.flags.ran_schedulers)
def get_post_list_html(group, view, limit_start=0, limit_length=20): from frappe.templates.generators.website_group import get_views # verify permission for paging if frappe.local.form_dict.cmd == "get_post_list_html": pathname = frappe.db.get_value("Website Route", {"ref_doctype": "Website Group", "docname": group}) access = get_access(pathname) if not access.get("read"): return frappe.PermissionError conditions = "" values = [group] group_type = frappe.db.get_value("Website Group", group, "group_type") if group_type == "Events": # should show based on time upto precision of hour # because the current hour should also be in upcoming values.append(now_datetime().replace(minute=0, second=0, microsecond=0)) if view in ("feed", "closed"): order_by = "p.creation desc" if view == "closed": conditions += " and p.is_task=1 and p.status='Closed'" elif view in ("popular", "open"): now = get_datetime_str(now_datetime()) order_by = """(p.upvotes + post_reply_count - (timestampdiff(hour, p.creation, \"{}\") / 2)) desc, p.creation desc""".format(now) if view == "open": conditions += " and p.is_task=1 and p.status='Open'" elif view == "upcoming": conditions += " and p.is_event=1 and p.event_datetime >= %s" order_by = "p.event_datetime asc" elif view == "past": conditions += " and p.is_event=1 and p.event_datetime < %s" order_by = "p.event_datetime desc" values += [int(limit_start), int(limit_length)] posts = frappe.db.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name, (select count(pc.name) from `tabPost` pc where pc.parent_post=p.name) as post_reply_count from `tabPost` p, `tabUser` pr where p.website_group = %s and pr.name = p.owner and ifnull(p.parent_post, '')='' {conditions} order by {order_by} limit %s, %s""".format(conditions=conditions, order_by=order_by), tuple(values), as_dict=True, debug=True) context = { "posts": posts, "limit_start": limit_start, "view": get_views(group_type)[view] } return frappe.get_template("templates/includes/post_list.html").render(context)
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 set_dates(self): today = now_datetime().date() # decide from date based on email digest frequency if self.frequency == "Daily": # from date, to_date is today self.future_from_date = self.future_to_date = today self.past_from_date = self.past_to_date = today - relativedelta(days = 1) elif self.frequency == "Weekly": # from date is the current week's monday self.future_from_date = today - relativedelta(days=today.weekday()) # to date is the current week's sunday self.future_to_date = self.future_from_date + relativedelta(days=6) self.past_from_date = self.future_from_date - relativedelta(days=7) self.past_to_date = self.future_to_date - relativedelta(days=7) else: # from date is the 1st day of the current month self.future_from_date = today - relativedelta(days=today.day-1) # to date is the last day of the current month self.future_to_date = self.future_from_date + relativedelta(days=-1, months=1) self.past_from_date = self.future_from_date - relativedelta(month=1) self.past_to_date = self.future_to_date - relativedelta(month=1)
def get_report_content(self): '''Returns file in for the report in given format''' report = frappe.get_doc('Report', self.report) if self.report_type=='Report Builder' and self.data_modified_till: self.filters = json.loads(self.filters) if self.filters else {} self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till)) columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user, filters = self.filters, as_dict=True) # add serial numbers columns.insert(0, frappe._dict(fieldname='idx', label='', width='30px')) for i in range(len(data)): data[i]['idx'] = i+1 if len(data)==0 and self.send_if_data: return None if self.format == 'HTML': return self.get_html_table(columns, data) elif self.format == 'XLSX': spreadsheet_data = self.get_spreadsheet_data(columns, data) xlsx_file = make_xlsx(spreadsheet_data, "Auto Email Report") return xlsx_file.getvalue() elif self.format == 'CSV': spreadsheet_data = self.get_spreadsheet_data(columns, data) return to_csv(spreadsheet_data) else: frappe.throw(_('Invalid Output Format'))
def flush(from_test=False): """flush email queue, every time: called from scheduler""" smtpserver = SMTPServer() auto_commit = not from_test if frappe.flags.mute_emails or frappe.conf.get("mute_emails") or False: msgprint(_("Emails are muted")) from_test = True for i in xrange(500): email = frappe.db.sql("""select * from `tabBulk Email` where status='Not Sent' and ifnull(send_after, "2000-01-01 00:00:00") < %s order by creation asc limit 1 for update""", now_datetime(), as_dict=1) if email: email = email[0] else: break frappe.db.sql("""update `tabBulk Email` set status='Sending' where name=%s""", (email["name"],), auto_commit=auto_commit) try: if not from_test: smtpserver.setup_email_account(email.reference_doctype) smtpserver.sess.sendmail(email["sender"], email["recipient"], encode(email["message"])) frappe.db.sql("""update `tabBulk Email` set status='Sent' where name=%s""", (email["name"],), auto_commit=auto_commit) except Exception, e: frappe.db.sql("""update `tabBulk Email` set status='Error', error=%s where name=%s""", (unicode(e), email["name"]), auto_commit=auto_commit)
def create_production_plan(**args): args = frappe._dict(args) pln = frappe.get_doc({ 'doctype': 'Production Plan', 'company': args.company or '_Test Company', 'posting_date': nowdate(), 'include_non_stock_items': args.include_non_stock_items or 1, 'include_subcontracted_items': args.include_subcontracted_items or 1, 'ignore_existing_ordered_qty': args.ignore_existing_ordered_qty or 1, 'po_items': [{ 'use_multi_level_bom': args.use_multi_level_bom or 1, 'item_code': args.item_code, 'bom_no': frappe.db.get_value('Item', args.item_code, 'default_bom'), 'planned_qty': args.planned_qty or 1, 'planned_start_date': args.planned_start_date or now_datetime() }] }) mr_items = get_items_for_material_requests(pln.as_dict()) for d in mr_items: pln.append('mr_items', d) if not args.do_not_save: pln.insert() if not args.do_not_submit: pln.submit() return pln
def flush(from_test=False): """flush email queue, every time: called from scheduler""" # additional check check_email_limit([]) auto_commit = not from_test if frappe.are_emails_muted(): msgprint(_("Emails are muted")) from_test = True frappe.db.sql("""update `tabEmail Queue` set status='Expired' where datediff(curdate(), creation) > 7 and status='Not Sent'""", auto_commit=auto_commit) smtpserver = SMTPServer() for i in xrange(500): # don't use for update here, as it leads deadlocks email = frappe.db.sql('''select * from `tabEmail Queue` where status='Not Sent' and (send_after is null or send_after < %(now)s) order by priority desc, creation asc limit 1''', { 'now': now_datetime() }, as_dict=True) if email: email = email[0] else: break send_one(email, smtpserver, auto_commit)
def test_admit_and_discharge(self): frappe.db.sql("""delete from `tabInpatient Record`""") patient = get_patient() # Schedule Admission ip_record = create_inpatient(patient) ip_record.save(ignore_permissions = True) self.assertEqual(ip_record.name, frappe.db.get_value("Patient", patient, "inpatient_record")) self.assertEqual(ip_record.status, frappe.db.get_value("Patient", patient, "inpatient_status")) # Admit service_unit = get_healthcare_service_unit() admit_patient(ip_record, service_unit, now_datetime()) self.assertEqual("Admitted", frappe.db.get_value("Patient", patient, "inpatient_status")) self.assertEqual("Occupied", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) # Discharge schedule_discharge(patient=patient) self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name) # Validate Pending Invoices self.assertRaises(frappe.ValidationError, ip_record.discharge) mark_invoiced_inpatient_occupancy(ip_record1) discharge_patient(ip_record1) self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_record")) self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_status"))
def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None): update_activity_type(activity_type) timesheet = frappe.new_doc("Timesheet") timesheet.employee = employee timesheet_detail = timesheet.append('time_logs', {}) timesheet_detail.billable = billable timesheet_detail.activity_type = activity_type timesheet_detail.from_time = now_datetime() timesheet_detail.hours = 2 timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta(hours= timesheet_detail.hours) timesheet_detail.project = project timesheet_detail.task = task timesheet_detail.company = company or '_Test Company' for data in timesheet.get('time_logs'): if simulate: while True: try: timesheet.save(ignore_permissions=True) break except OverlapError: data.from_time = data.from_time + datetime.timedelta(minutes=10) data.to_time = data.from_time + datetime.timedelta(hours= data.hours) else: timesheet.save(ignore_permissions=True) timesheet.submit() return timesheet
def validate(self): if session['user'] != 'Guest' and not self.customer: frappe.throw(_("Customer is required")) if self.status=="Closed" and not self.resolution_date and \ frappe.db.get_value("Warranty Claim", self.name, "status")!="Closed": self.resolution_date = now_datetime()
def validate_end_of_life(item_code, end_of_life=None, verbose=1): if not end_of_life: end_of_life = frappe.db.get_value("Item", item_code, "end_of_life") if end_of_life and end_of_life!="0000-00-00" and getdate(end_of_life) <= now_datetime().date(): msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life)) _msgprint(msg, verbose)
def check_out_inpatient(inpatient_record): if inpatient_record.inpatient_occupancies: for inpatient_occupancy in inpatient_record.inpatient_occupancies: if inpatient_occupancy.left != 1: inpatient_occupancy.left = True inpatient_occupancy.check_out = now_datetime() frappe.db.set_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "occupancy_status", "Vacant")
def parse_naming_series(parts, doctype= '', doc = ''): n = '' if isinstance(parts, string_types): parts = parts.split('.') series_set = False today = now_datetime() for e in parts: part = '' if e.startswith('#'): if not series_set: digits = len(e) part = getseries(n, digits, doctype) series_set = True elif e=='YY': part = today.strftime('%y') elif e=='MM': part = today.strftime('%m') elif e=='DD': part = today.strftime("%d") elif e=='YYYY': part = today.strftime('%Y') elif doc and doc.get(e): part = doc.get(e) else: part = e if isinstance(part, string_types): n+=part return n
def create_delivery_trip(contact=None): if not contact: contact = get_contact_and_address("_Test Customer") delivery_trip = frappe.new_doc("Delivery Trip") delivery_trip.update({ "doctype": "Delivery Trip", "company": erpnext.get_default_company(), "departure_time": add_days(now_datetime(), 5), "driver": frappe.db.get_value('Driver', {"full_name": "Newton Scmander"}), "vehicle": "JB 007", "delivery_stops": [{ "customer": "_Test Customer", "address": contact.shipping_address.parent, "contact": contact.contact_person.parent }, { "customer": "_Test Customer", "address": contact.shipping_address.parent, "contact": contact.contact_person.parent }] }) delivery_trip.insert() return delivery_trip
def get_expiry_message(): if "System Manager" not in frappe.get_roles(): return "" limits = get_limits() if not limits.expiry: return "" expires_on = getdate(get_limits().get("expiry")) today = now_datetime().date() message = "" if today > expires_on: message = _("Your subscription has expired.") else: days_to_expiry = (expires_on - today).days if days_to_expiry == 0: message = _("Your subscription will expire today.") elif days_to_expiry == 1: message = _("Your subscription will expire tomorrow.") elif days_to_expiry <= EXPIRY_WARNING_DAYS: message = _("Your subscription will expire on {0}.").format(formatdate(expires_on)) if message and limits.upgrade_url: upgrade_link = get_upgrade_link(limits.upgrade_url) message += " " + _("To renew, {0}.").format(upgrade_link) return message
def test_format_autoname(self): ''' Test if braced params are replaced in format autoname ''' doctype = 'ToDo' todo_doctype = frappe.get_doc('DocType', doctype) todo_doctype.autoname = 'format:TODO-{MM}-{status}-{##}' todo_doctype.save() description = 'Format' todo = frappe.new_doc(doctype) todo.description = description todo.insert() series = getseries('', 2, doctype) series = str(int(series)-1) if len(series) < 2: series = '0' + series self.assertEqual(todo.name, 'TODO-{month}-{status}-{series}'.format( month=now_datetime().strftime('%m'), status=todo.status, series=series))
def get_leave_period(): leave_period_name = frappe.db.exists({ "doctype": "Leave Period", "company": "_Test Company" }) if leave_period_name: return frappe.get_doc("Leave Period", leave_period_name[0][0]) else: return frappe.get_doc(dict( name = 'Test Leave Period', doctype = 'Leave Period', from_date = "{0}-12-01".format(now_datetime().year - 1), to_date = "{0}-12-31".format(now_datetime().year), company = "_Test Company", is_active = 1 )).insert()
def get_creation_count(self, doctype, minutes): """Get count of records created in the last x minutes""" from frappe.utils import now_datetime from dateutil.relativedelta import relativedelta return frappe.db.sql("""select count(name) from `tab{doctype}` where creation >= %s""".format(doctype=doctype), now_datetime() - relativedelta(minutes=minutes))[0][0]
def send(): now_date = now_datetime().date() for ed in frappe.db.sql("""select name from `tabEmail Digest` where enabled=1 and docstatus<2""", as_list=1): ed_obj = frappe.get_doc('Email Digest', ed[0]) if (now_date == ed_obj.get_next_sending()): ed_obj.send()
def validate_posting_time(self): # set Edit Posting Date and Time to 1 while data import if frappe.flags.in_import and self.posting_date: self.set_posting_time = 1 if not getattr(self, 'set_posting_time', None): now = now_datetime() self.posting_date = now.strftime('%Y-%m-%d') self.posting_time = now.strftime('%H:%M:%S')
def test_timesheet_std_working_hours(self): company = frappe.get_doc('Company', "_Test Company") company.standard_working_hours = 8 company.save() timesheet = frappe.new_doc("Timesheet") timesheet.employee = "_T-Employee-00001" timesheet.company = '_Test Company' timesheet.append( 'time_logs', { "activity_type": "_Test Activity Type", "from_time": now_datetime(), "to_time": now_datetime() + datetime.timedelta(days= 4) } ) timesheet.save() ts = frappe.get_doc('Timesheet', timesheet.name) self.assertEqual(ts.total_hours, 32) ts.submit() ts.cancel() company = frappe.get_doc('Company', "_Test Company") company.standard_working_hours = 0 company.save() timesheet = frappe.new_doc("Timesheet") timesheet.employee = "_T-Employee-00001" timesheet.company = '_Test Company' timesheet.append( 'time_logs', { "activity_type": "_Test Activity Type", "from_time": now_datetime(), "to_time": now_datetime() + datetime.timedelta(days= 4) } ) timesheet.save() ts = frappe.get_doc('Timesheet', timesheet.name) self.assertEqual(ts.total_hours, 96) ts.submit() ts.cancel()
def test_enabled_events(self): frappe.flags.enabled_events = ["hourly", "hourly_long", "daily", "daily_long", "weekly", "weekly_long", "monthly", "monthly_long"] # maintain last_event and next_event on the same day last_event = now_datetime().replace(hour=0, minute=0, second=0, microsecond=0) next_event = last_event + relativedelta(minutes=30) enqueue_applicable_events(frappe.local.site, next_event, last_event) self.assertFalse("all" in frappe.flags.ran_schedulers) # maintain last_event and next_event on the same day last_event = now_datetime().replace(hour=0, minute=0, second=0, microsecond=0) next_event = last_event + relativedelta(hours=2) enqueue_applicable_events(frappe.local.site, next_event, last_event) self.assertTrue("all" in frappe.flags.ran_schedulers) self.assertTrue("hourly" in frappe.flags.ran_schedulers) del frappe.flags['enabled_events']
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1): if (not end_of_life) or (disabled is None): end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"]) if end_of_life and end_of_life!="0000-00-00" and getdate(end_of_life) <= now_datetime().date(): msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life)) _msgprint(msg, verbose) if disabled: _msgprint(_("Item {0} is disabled").format(item_code), verbose)
def test_enabled_events_day_change(self): val = json.dumps(["daily", "daily_long", "weekly", "weekly_long", "monthly", "monthly_long"]) frappe.db.set_global('enabled_scheduler_events', val) # maintain last_event and next_event on different days next_event = now_datetime().replace(hour=0, minute=0, second=0, microsecond=0) last_event = next_event - relativedelta(hours=2) enqueue_applicable_events(frappe.local.site, next_event, last_event) self.assertTrue("all" in frappe.flags.ran_schedulers) self.assertTrue("hourly" in frappe.flags.ran_schedulers)
def get_queue(): return frappe.db.sql('''select name, sender from `tabEmail Queue` where (status='Not Sent' or status='Partially Sent') and (send_after is null or send_after < %(now)s) order by priority desc, creation asc limit 500''', { 'now': now_datetime() }, as_dict=True)
def has_expired(): if frappe.session.user == "Administrator": return False expires_on = get_limits().expiry if not expires_on: return False if now_datetime().date() <= getdate(expires_on): return False return True
def make_autoname(key='', doctype='', doc=''): """ Creates an autoname from the given key: **Autoname rules:** * The key is separated by '.' * '####' represents a series. The string before this part becomes the prefix: Example: ABC.#### creates a series ABC0001, ABC0002 etc * 'MM' represents the current month * 'YY' and 'YYYY' represent the current year *Example:* * DE/./.YY./.MM./.##### will create a series like DE/09/01/0001 where 09 is the year, 01 is the month and 0001 is the series """ if key=="hash": return frappe.generate_hash(doctype, 10) if not "#" in key: key = key + ".#####" elif not "." in key: frappe.throw(_("Invalid naming series (. missing)") + (_(" for {0}").format(doctype) if doctype else "")) n = '' l = key.split('.') series_set = False today = now_datetime() for e in l: part = '' if e.startswith('#'): if not series_set: digits = len(e) part = getseries(n, digits, doctype) series_set = True elif e=='YY': part = today.strftime('%y') elif e=='MM': part = today.strftime('%m') elif e=='DD': part = today.strftime("%d") elif e=='YYYY': part = today.strftime('%Y') elif doc and doc.get(e): part = doc.get(e) else: part = e if isinstance(part, basestring): n+=part return n
def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date): if not from_date: from_date = get_from_date_from_timespan(to_date, timespan) from_date = get_period_beginning(from_date, timegrain) if not to_date: to_date = now_datetime() doctype = chart.document_type datefield = chart.based_on aggregate_function = get_aggregate_function(chart.chart_type) value_field = chart.value_based_on or '1' from_date = from_date.strftime('%Y-%m-%d') to_date = to_date filters.append([doctype, datefield, '>=', from_date, False]) filters.append([doctype, datefield, '<=', to_date, False]) data = frappe.db.get_list(doctype, fields=[ '{} as _unit'.format(datefield), '{aggregate_function}({value_field})'.format( aggregate_function=aggregate_function, value_field=value_field), ], filters=filters, group_by='_unit', order_by='_unit asc', as_list=True, ignore_ifnull=True) result = get_result(data, timegrain, from_date, to_date) chart_config = { "labels": [get_period(r[0], timegrain) for r in result], "datasets": [{ "name": chart.name, "values": [r[1] for r in result] }] } return chart_config
def test_monthly_attendance_sheet_with_detailed_view(self): now = now_datetime() previous_month = now.month - 1 previous_month_first = now.replace(day=1).replace( month=previous_month).date() company = frappe.db.get_value("Employee", self.employee, "company") # attendance with shift mark_attendance(self.employee, previous_month_first, "Absent", "Day Shift") mark_attendance(self.employee, previous_month_first + relativedelta(days=1), "Present", "Day Shift") # attendance without shift mark_attendance(self.employee, previous_month_first + relativedelta(days=2), "On Leave") mark_attendance(self.employee, previous_month_first + relativedelta(days=3), "Present") filters = frappe._dict({ "month": previous_month, "year": now.year, "company": company, }) report = execute(filters=filters) day_shift_row = report[1][0] row_without_shift = report[1][1] self.assertEqual(day_shift_row["shift"], "Day Shift") self.assertEqual(day_shift_row[1], "A") # absent on the 1st day of the month self.assertEqual(day_shift_row[2], "P") # present on the 2nd day self.assertEqual(row_without_shift["shift"], None) self.assertEqual(row_without_shift[3], "L") # on leave on the 3rd day self.assertEqual(row_without_shift[4], "P") # present on the 4th day
def send_daily(): '''Check reports to be sent daily''' current_day = calendar.day_name[now_datetime().weekday()] enabled_reports = frappe.get_all('Auto Email Report', filters={'enabled': 1, 'frequency': ('in', ('Daily', 'Weekdays', 'Weekly'))}) for report in enabled_reports: auto_email_report = frappe.get_doc('Auto Email Report', report.name) # if not correct weekday, skip if auto_email_report.frequency == "Weekdays": if current_day in ("Saturday", "Sunday"): continue elif auto_email_report.frequency == 'Weekly': if auto_email_report.day_of_week != current_day: continue try: auto_email_report.send() except Exception as e: frappe.log_error(e, _('Failed to send {0} Auto Email Report').format(auto_email_report.name))
def test_to_time(self): emp = make_employee("*****@*****.**") from_time = now_datetime() timesheet = frappe.new_doc("Timesheet") timesheet.employee = emp timesheet.append( "time_logs", { "billable": 1, "activity_type": "_Test Activity Type", "from_time": from_time, "hours": 2, "company": "_Test Company", }, ) timesheet.save() to_time = timesheet.time_logs[0].to_time self.assertEqual(to_time, add_to_date(from_time, hours=2, as_datetime=True))
def reset_service_level_agreement(self, reason, user): if not frappe.db.get_single_value("Support Settings", "allow_resetting_service_level_agreement"): frappe.throw(_("Allow Resetting Service Level Agreement from Support Settings.")) frappe.get_doc( { "doctype": "Comment", "comment_type": "Info", "reference_doctype": self.doctype, "reference_name": self.name, "comment_email": user, "content": " resetted Service Level Agreement - {0}".format(_(reason)), } ).insert(ignore_permissions=True) self.service_level_agreement_creation = now_datetime() self.set_response_and_resolution_time( priority=self.priority, service_level_agreement=self.service_level_agreement ) self.agreement_status = "Ongoing" self.save()
def set_service_level_agreement_variance(issue=None): current_time = frappe.flags.current_time or now_datetime() filters = {"status": "Open", "agreement_status": "Ongoing"} if issue: filters = {"name": issue} for issue in frappe.get_list("Issue", filters=filters): doc = frappe.get_doc("Issue", issue.name) if not doc.first_responded_on: # first_responded_on set when first reply is sent to customer variance = round(time_diff_in_seconds(doc.response_by, current_time), 2) frappe.db.set_value(dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False) if variance < 0: frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False) if not doc.resolution_date: # resolution_date set when issue has been closed variance = round(time_diff_in_seconds(doc.resolution_by, current_time), 2) frappe.db.set_value(dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False) if variance < 0: frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
def set_response_and_resolution_time(self): service_level_agreement = get_active_service_level_agreement_for( self.customer) if service_level_agreement: self.service_level_agreement = service_level_agreement.name self.priority = service_level_agreement.priority if not self.service_level_agreement: return service_level = frappe.get_doc("Service Level", service_level_agreement.service_level) if not self.creation: self.creation = now_datetime() start_date_time = get_datetime(self.creation) self.response_by = get_expected_time_for('response', service_level, start_date_time) self.resolution_by = get_expected_time_for('resolution', service_level, start_date_time)
def set_backup_file_name(self): import random todays_date = now_datetime().strftime('%Y%m%d_%H%M%S') site = frappe.local.site or frappe.generate_hash(length=8) site = site.replace('.', '_') #Generate a random name using today's date and a 8 digit random number for_db = todays_date + "-" + site + "-database.sql" for_public_files = todays_date + "-" + site + "-files.tar" for_private_files = todays_date + "-" + site + "-private-files.tar" backup_path = get_backup_path() if not self.backup_path_db: self.backup_path_db = os.path.join(backup_path, for_db) if not self.backup_path_files: self.backup_path_files = os.path.join(backup_path, for_public_files) if not self.backup_path_private_files: self.backup_path_private_files = os.path.join( backup_path, for_private_files)
def add_pur_invoice(): pur_invoice = frappe.get_doc({ 'doctype': 'Purchase Invoice', 'party': 'test_party_001', 'posting_timestamp': now_datetime(), 'credit_to': 'Creditors', 'assets_account': 'Stock in Hand', 'items': [{ 'item': 'test_item_001', 'item_quantity': 10, 'item_rate': 1000, }], 'total_amount': 10 * 1000 }) pur_invoice.submit()
def test_monthly_budget_on_cancellation2(self): set_total_expense_zero(nowdate(), "project") budget = make_budget(budget_against="Project") month = now_datetime().month if month > 9: month = 9 for i in range(month + 1): jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC", "_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project") self.assertTrue(frappe.db.get_value("GL Entry", {"voucher_type": "Journal Entry", "voucher_no": jv.name})) frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop") self.assertRaises(BudgetError, jv.cancel) budget.load_from_db() budget.cancel()
def setup_leave_allocation(): year = now_datetime().year for employee in frappe.get_all("Employee", fields=["name"]): leave_types = frappe.get_all("Leave Type", fields=["name", "max_continuous_days_allowed"]) for leave_type in leave_types: if not leave_type.max_continuous_days_allowed: leave_type.max_continuous_days_allowed = 10 leave_allocation = frappe.get_doc( { "doctype": "Leave Allocation", "employee": employee.name, "from_date": "{0}-01-01".format(year), "to_date": "{0}-12-31".format(year), "leave_type": leave_type.name, "new_leaves_allocated": random.randint(1, int(leave_type.max_continuous_days_allowed)), } ) leave_allocation.insert() leave_allocation.submit() frappe.db.commit()
def setup_holiday_list(): """Setup Holiday List for the current year""" year = now_datetime().year holiday_list = frappe.get_doc( { "doctype": "Holiday List", "holiday_list_name": str(year), "from_date": "{0}-01-01".format(year), "to_date": "{0}-12-31".format(year), } ) holiday_list.insert() holiday_list.weekly_off = "Saturday" holiday_list.get_weekly_off_dates() holiday_list.weekly_off = "Sunday" holiday_list.get_weekly_off_dates() holiday_list.save() frappe.set_value( "Company", erpnext.get_default_company(), "default_holiday_list", holiday_list.name )
def setup_fiscal_year(): fiscal_year = None year = cstr(now_datetime().year) if not frappe.db.get_value("Fiscal Year", {"year": year}, "name"): try: fiscal_year = frappe.get_doc({ "doctype": "Fiscal Year", "year": year, "year_start_date": "{0}-01-01".format(year), "year_end_date": "{0}-12-31".format(year) }) fiscal_year.insert() except frappe.NameError: pass if fiscal_year: fiscal_year.set_as_default()
def quick_package_creation(customer, packages): '''Method that takes care of validating and creating packages on custom dialog, by passing only guide, customer, type.''' packages = json.loads(packages) # Filter empty or incomplete rows packages = list( filter( lambda x: "guide" in x and "type" in x and x["guide"] != "" and x[ "type"] != "", packages)) if not any(packages): frappe.msgprint(_("No packages values provided, try again")) return # Check if no packages is duplicate. duplicates = frappe.db.get_all( doctype='Package', filters={"guide": ['in'] + [p["guide"] for p in packages]}, fields=["name", "guide"]) if any(duplicates): duplicates = [p.name for p in duplicates] frappe.throw(_("Duplicate packages {0}".format(", ".join(duplicates)))) else: received_date = now_datetime() origin = frappe.db.get_single_value('Package Management Settings', 'default_origin') print("-----my-----", origin) counter = 0 for p in packages: counter += 1 doc = frappe.new_doc('Package') doc.guide = p["guide"] doc.type = p["type"] doc.customer = customer doc.received_date = received_date doc.origin = origin doc.save() frappe.msgprint(_("Created {0} packages".format(counter))) return 1
def make_timesheet( employee, simulate=False, is_billable=0, activity_type="_Test Activity Type", project=None, task=None, company=None, ): update_activity_type(activity_type) timesheet = frappe.new_doc("Timesheet") timesheet.employee = employee timesheet.company = company or "_Test Company" timesheet_detail = timesheet.append("time_logs", {}) timesheet_detail.is_billable = is_billable timesheet_detail.activity_type = activity_type timesheet_detail.from_time = now_datetime() timesheet_detail.hours = 2 timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta( hours=timesheet_detail.hours) timesheet_detail.project = project timesheet_detail.task = task for data in timesheet.get("time_logs"): if simulate: while True: try: timesheet.save(ignore_permissions=True) break except OverlapError: data.from_time = data.from_time + datetime.timedelta( minutes=10) data.to_time = data.from_time + datetime.timedelta( hours=data.hours) else: timesheet.save(ignore_permissions=True) timesheet.submit() return timesheet
def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date): if not from_date: from_date = get_from_date_from_timespan(to_date, timespan) from_date = get_period_beginning(from_date, timegrain) if not to_date: to_date = now_datetime() doctype = chart.document_type datefield = chart.based_on value_field = chart.value_based_on or "1" from_date = from_date.strftime("%Y-%m-%d") to_date = to_date filters.append([doctype, datefield, ">=", from_date, False]) filters.append([doctype, datefield, "<=", to_date, False]) data = frappe.db.get_list( doctype, fields=[ "{} as _unit".format(datefield), "SUM({})".format(value_field), "COUNT(*)" ], filters=filters, group_by="_unit", order_by="_unit asc", as_list=True, ignore_ifnull=True, ) result = get_result(data, timegrain, from_date, to_date, chart.chart_type) chart_config = { "labels": [get_period(r[0], timegrain) for r in result], "datasets": [{ "name": chart.name, "values": [r[1] for r in result] }], } return chart_config
def create_issue_from_customer(client_issue_id, erpnext_support_user, subject, description, issue_found_in, issue_type, raised_by, recipients, bench_site, attachments=None): authenticate_erpnext_support_user(erpnext_support_user) issue = frappe.get_doc({ "doctype": "Issue", "subject": subject, "raised_by": raised_by, "bench_site": bench_site, "client_issue_id": client_issue_id, "module": issue_found_in, "issue_type": issue_type, "owner": raised_by, "raised_via_support_app": 1 }).insert(ignore_permissions=True) create_reply_from_customer(erpnext_support_user=erpnext_support_user, subject=subject, description=description, \ raised_by=raised_by, recipients=recipients, bench_site=bench_site, frappe_issue_id=issue.name, attachments=attachments) return { "name": issue.get("name"), "last_sync_on": get_datetime_str(now_datetime()), "priority": issue.get("priority"), "resolution_by": get_datetime_str(issue.get("resolution_by")) if issue.get("resolution_by") else None, "release": issue.get("release") }
def make_time_log_test_record(**args): args = frappe._dict(args) time_log = frappe.new_doc("Time Log") time_log.from_time = args.from_time or now_datetime() time_log.hours = args.hours or 1 time_log.to_time = args.to_time or time_log.from_time + datetime.timedelta( hours=time_log.hours) time_log.project = args.project time_log.task = args.task time_log.for_manufacturing = args.for_manufacturing time_log.production_order = args.production_order time_log.operation = args.operation time_log.operation_id = args.operation_id time_log.workstation = args.workstation time_log.completed_qty = args.completed_qty time_log.activity_type = args.activity_type or "_Test Activity Type" time_log.billable = args.billable or 1 time_log.employee = args.employee time_log.user = args.user if not args.do_not_save: if args.simulate: while True: try: time_log.save() break except OverlapError: time_log.from_time = time_log.from_time + datetime.timedelta( minutes=10) time_log.to_time = time_log.from_time + datetime.timedelta( hours=time_log.hours) else: time_log.save() if not args.do_not_submit: time_log.submit() return time_log
def get_backup(self, older_than=24, ignore_files=False, force=False): """ Takes a new dump if existing file is old and sends the link to the file as email """ # Check if file exists and is less than a day old # If not Take Dump if not force: ( last_db, last_file, last_private_file, site_config_backup_path, ) = self.get_recent_backup(older_than) else: last_db, last_file, last_private_file, site_config_backup_path = ( False, False, False, False, ) self.todays_date = now_datetime().strftime("%Y%m%d_%H%M%S") if not (self.backup_path_conf and self.backup_path_db and self.backup_path_files and self.backup_path_private_files): self.set_backup_file_name() if not (last_db and last_file and last_private_file and site_config_backup_path): self.take_dump() self.copy_site_config() if not ignore_files: self.backup_files() else: self.backup_path_files = last_file self.backup_path_db = last_db self.backup_path_private_files = last_private_file self.backup_path_conf = site_config_backup_path
def link_loan_security_pledge(self): if self.is_secured_loan and self.loan_application: maximum_loan_value = frappe.db.get_value( "Loan Security Pledge", { "loan_application": self.loan_application, "status": "Requested" }, "sum(maximum_loan_value)", ) if maximum_loan_value: frappe.db.sql( """ UPDATE `tabLoan Security Pledge` SET loan = %s, pledge_time = %s, status = 'Pledged' WHERE status = 'Requested' and loan_application = %s """, (self.name, now_datetime(), self.loan_application), ) self.db_set("maximum_loan_amount", maximum_loan_value)
def parse_naming_series(parts, doctype="", doc=""): n = "" if isinstance(parts, string_types): parts = parts.split(".") series_set = False today = now_datetime() for e in parts: part = "" if e.startswith("#"): if not series_set: digits = len(e) part = getseries(n, digits) series_set = True elif e == "YY": part = today.strftime("%y") elif e == "MM": part = today.strftime("%m") elif e == "DD": part = today.strftime("%d") elif e == "YYYY": part = today.strftime("%Y") elif e == "WW": part = determine_consecutive_week_number(today) elif e == "timestamp": part = str(today) elif e == "FY": part = frappe.defaults.get_user_default("fiscal_year") elif e.startswith("{") and doc: e = e.replace("{", "").replace("}", "") part = doc.get(e) elif doc and doc.get(e): part = doc.get(e) else: part = e if isinstance(part, string_types): n += part return n
def validate_hour(self): """check if user is logging in during restricted hours""" login_before = int( frappe.db.get_value('User', self.user, 'login_before', ignore=True) or 0) login_after = int( frappe.db.get_value('User', self.user, 'login_after', ignore=True) or 0) if not (login_before or login_after): return from frappe.utils import now_datetime current_hour = int(now_datetime().strftime('%H')) if login_before and current_hour > login_before: frappe.throw(_("Login not allowed at this time"), frappe.AuthenticationError) if login_after and current_hour < login_after: frappe.throw(_("Login not allowed at this time"), frappe.AuthenticationError)
def notify_admin_access_to_system_manager(login_manager=None): if ( login_manager and login_manager.user == "Administrator" and frappe.local.conf.notify_admin_access_to_system_manager ): site = '<a href="{0}" target="_blank">{0}</a>'.format(frappe.local.request.host_url) date_and_time = "<b>{0}</b>".format(format_datetime(now_datetime(), format_string="medium")) ip_address = frappe.local.request_ip access_message = _("Administrator accessed {0} on {1} via IP Address {2}.").format( site, date_and_time, ip_address ) frappe.sendmail( recipients=get_system_managers(), subject=_("Administrator Logged In"), template="administrator_logged_in", args={"access_message": access_message}, header=["Access Notification", "orange"], )
def send_naming_series(): today = now_datetime() n = '' naming_series = get_default_naming_series("Planning Master") parts = naming_series.split('.')[:-1] for e in parts: part = '' if e == 'YY': part = today.strftime('%y') elif e == 'MM': part = today.strftime('%m') elif e == 'DD': part = today.strftime("%d") elif e == 'YYYY': part = today.strftime('%Y') elif e == 'FY': part = frappe.defaults.get_user_default("fiscal_year") else: part = e n += part #naming_series = parse_naming_series(naming_series) return n
def validate_hour(self): """check if user is logging in during restricted hours""" login_before = int( frappe.db.get_value( 'Profile', self.user, 'login_before', ignore=True) or 0) login_after = int( frappe.db.get_value( 'Profile', self.user, 'login_after', ignore=True) or 0) if not (login_before or login_after): return from frappe.utils import now_datetime current_hour = int(now_datetime().strftime('%H')) if login_before and current_hour > login_before: frappe.msgprint('Not allowed to login after restricted hour', raise_exception=1) if login_after and current_hour < login_after: frappe.msgprint('Not allowed to login before restricted hour', raise_exception=1)
def check_date_time_diff(date_time, type_of_check, name_of_field, days_diff=0, hours_diff=0): d = get_datetime(date_time) d1 = now_datetime() d0 = add_days(d1.date(), days_diff) if type_of_check == 'date': if d.date() >= d0 and d.date() <= d1.date(): pass else: frappe.throw(("{} Date should be between {} and {}").\ format(name_of_field, str(d0), str(d1.date()))) else: if d.date() < d1.date(): frappe.throw("{} Date cannot be less than Today's Date".format( name_of_field)) if d.date() == d1.date(): if time_diff_in_seconds(d, d1) < (3600 * hours_diff): frappe.throw("{} Time has to be {} hours after the current time".\ format(name_of_field, hours_diff))
def get_report_content(self): '''Returns file in for the report in given format''' report = frappe.get_doc('Report', self.report) self.filters = frappe.parse_json(self.filters) if self.filters else {} if self.report_type=='Report Builder' and self.data_modified_till: self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till)) if self.report_type != 'Report Builder' and self.dynamic_date_filters_set(): self.prepare_dynamic_filters() columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user, filters = self.filters, as_dict=True, ignore_prepared_report=True) # add serial numbers columns.insert(0, frappe._dict(fieldname='idx', label='', width='30px')) for i in range(len(data)): data[i]['idx'] = i+1 if len(data)==0 and self.send_if_data: return None if self.format == 'HTML': columns, data = make_links(columns, data) columns = update_field_types(columns) return self.get_html_table(columns, data) elif self.format == 'XLSX': spreadsheet_data = self.get_spreadsheet_data(columns, data) xlsx_file = make_xlsx(spreadsheet_data, "Auto Email Report") return xlsx_file.getvalue() elif self.format == 'CSV': spreadsheet_data = self.get_spreadsheet_data(columns, data) return to_csv(spreadsheet_data) else: frappe.throw(_('Invalid Output Format'))
def get_new_messages(): last_update = frappe.cache().hget("notifications_last_update", frappe.session.user) now_timestamp = now() frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp) if not last_update: return [] if last_update and time_diff_in_seconds(now_timestamp, last_update) > 1800: # no update for 30 mins, consider only the last 30 mins last_update = (now_datetime() - relativedelta(seconds=1800)).strftime(DATETIME_FORMAT) return frappe.db.sql("""select comment_by_fullname, comment from tabComment where comment_doctype='Message' and comment_docname = %s and ifnull(creation, "2000-01-01") > %s order by creation desc""", (frappe.session.user, last_update), as_dict=1)
def execute(): si_list = frappe.db.sql( """SELECT si.name, si.posting_date, si.transporters, si.lr_no FROM `tabSales Invoice` si, `tabTransporters` tp WHERE si.docstatus = 1 AND tp.name = si.transporters AND tp.track_on_shipway = 1 AND si.posting_date > DATE_SUB(NOW(), INTERVAL 360 day) ORDER BY si.posting_date DESC""", as_dict=1) #create_new_ship_track for si in si_list: si_doc = frappe.get_doc('Sales Invoice', si.name) #print str((si)) if si.posting_date >= getdate(add_days(now_datetime(), -30)): #print(str(si.name) + " " + str(si.transporters) + " " + si.lr_no + " " + str(si.posting_date)) exist_track = check_existing_track(si.name) if exist_track: pass else: create_new_ship_track(si_doc) print("Created New Tracking For SI # " + si_doc.name)