def setup_complete(args): """Calls hooks for `setup_wizard_complete`, sets home page as `desktop` and clears cache. If wizard breaks, calls `setup_wizard_exception` hook""" # Setup complete: do not throw an exception, let the user continue to desk if cint(frappe.db.get_single_value('System Settings', 'setup_complete')): return args = parse_args(args) stages = get_setup_stages(args) try: current_task = None for idx, stage in enumerate(stages): frappe.publish_realtime('setup_task', {"progress": [idx, len(stages)], "stage_status": stage.get('status')}, user=frappe.session.user) for task in stage.get('tasks'): current_task = task task.get('fn')(task.get('args')) except Exception: handle_setup_exception(args) return {'status': 'fail', 'fail': current_task.get('fail_msg')} else: run_setup_success(args) return {'status': 'ok'}
def set_delivery_status(self, commit=False): """Look into the status of Bulk Email linked to this Communication and set the Delivery Status of this Communication""" delivery_status = None status_counts = Counter( frappe.db.sql_list("""select status from `tabBulk Email` where communication=%s""", self.name) ) if status_counts.get("Not Sent") or status_counts.get("Sending"): delivery_status = "Sending" elif status_counts.get("Error"): delivery_status = "Error" elif status_counts.get("Expired"): delivery_status = "Expired" elif status_counts.get("Sent"): delivery_status = "Sent" if delivery_status: self.db_set("delivery_status", delivery_status) frappe.publish_realtime( "update_communication", self.as_dict(), doctype=self.reference_doctype, docname=self.reference_name, after_commit=True, ) # for list views and forms self.notify_update() if commit: frappe.db.commit()
def bulk_clone(name): source_plant = frappe.get_doc("Plant", name) if source_plant.qty > 1: warehouse = frappe.get_doc("Warehouse", source_plant.get("warehouse")) location = frappe.get_value("BioTrack Settings", None, "location") remaining_qty = source_plant.qty - 1 result = biotrackthc_call("plant_new", { "room": warehouse.external_id, "quantity": remaining_qty, "strain": source_plant.strain, "source": source_plant.item_code, "mother": cint(source_plant.get("is_mother")), "location": location }) for barcode in result.get("barcode_id"): plant = frappe.new_doc("Plant") plant.update({ "barcode": barcode, "item_group": source_plant.item_group, "source": source_plant.item_code, "strain": source_plant.strain, "warehouse": source_plant.warehouse, "state": source_plant.state, "birthdate": now(), }) plant.save() # save directly with sql to avoid mistimestamp check frappe.db.set_value("Plant", source_plant.name, "qty", 1, update_modified=False) frappe.publish_realtime("list_update", {"doctype": "Plant"})
def migrate(verbose=True, rebuild_website=False): '''Migrate all apps to the latest version, will: - run patches - sync doctypes (schema) - sync fixtures - sync desktop icons - sync web pages (from /www)''' clear_global_cache() # run patches frappe.modules.patch_handler.run_all() # sync frappe.model.sync.sync_all(verbose=verbose) frappe.translate.clear_cache() sync_fixtures() sync_desktop_icons() # syncs statics render.clear_cache() if rebuild_website: statics.sync(verbose=verbose).start(True) else: statics.sync_statics() frappe.db.commit() clear_notifications() frappe.publish_realtime("version-update")
def migrate(context, rebuild_website=False): "Run patches, sync schema and rebuild files/translations" import frappe.modules.patch_handler import frappe.model.sync from frappe.utils.fixtures import sync_fixtures import frappe.translate from frappe.desk.notifications import clear_notifications for site in context.sites: print 'Migrating', site frappe.init(site=site) frappe.connect() try: prepare_for_update() # run patches frappe.modules.patch_handler.run_all() # sync frappe.model.sync.sync_all(verbose=context.verbose) frappe.translate.clear_cache() sync_fixtures() clear_notifications() finally: frappe.publish_realtime("version-update") frappe.destroy() if rebuild_website: call_command(build_website, context) else: call_command(sync_www, context)
def run_background(prepared_report): instance = frappe.get_doc("Prepared Report", prepared_report) report = frappe.get_doc("Report", instance.ref_report_doctype) try: report.custom_columns = [] if report.report_type == 'Custom Report': custom_report_doc = report reference_report = custom_report_doc.reference_report report = frappe.get_doc("Report", reference_report) report.custom_columns = custom_report_doc.json result = generate_report_result(report, filters=instance.filters, user=instance.owner) create_json_gz_file(result['result'], 'Prepared Report', instance.name) instance.status = "Completed" instance.columns = json.dumps(result["columns"]) instance.report_end_time = frappe.utils.now() instance.save() except Exception: frappe.log_error(frappe.get_traceback()) instance = frappe.get_doc("Prepared Report", prepared_report) instance.status = "Error" instance.error_message = frappe.get_traceback() instance.save() frappe.publish_realtime( 'report_generated', {"report_name": instance.report_name, "name": instance.name}, user=frappe.session.user )
def set_delivery_status(self, commit=False): '''Look into the status of Bulk Email linked to this Communication and set the Delivery Status of this Communication''' delivery_status = None status_counts = Counter(frappe.db.sql_list('''select status from `tabBulk Email` where communication=%s''', self.name)) if status_counts.get('Not Sent') or status_counts.get('Sending'): delivery_status = 'Sending' elif status_counts.get('Error'): delivery_status = 'Error' elif status_counts.get('Expired'): delivery_status = 'Expired' elif status_counts.get('Sent'): delivery_status = 'Sent' if delivery_status: self.db_set('delivery_status', delivery_status) frappe.publish_realtime('update_communication', self.as_dict(), doctype=self.reference_doctype, docname=self.reference_name, after_commit=True) # for list views and forms self.notify_update() if commit: frappe.db.commit()
def install_app(name): """Install app, if app is not installed in local environment, install it via git url in `frappe/data/app_listing/`""" frappe.only_for("System Manager") if name not in frappe.get_all_apps(True): if not frappe.conf.disallow_app_listing: get_app(name) frappe.cache().delete_value(["app_hooks"]) # reload sys.path import site reload(site) else: # will only come via direct API frappe.throw("Listing app not allowed") app_hooks = frappe.get_hooks(app_name=name) if app_hooks.get('hide_in_installer'): frappe.throw(_("You cannot install this app")) frappe.publish_realtime("install_app_progress", {"status": _("Installing App {0}").format(name)}, user=frappe.session.user, now=True) frappe.installer.install_app(name) frappe.publish_realtime("install_app_progress", {"status": _("{0} Installed").format(name)}, user=frappe.session.user, now=True)
def verifica_check_in(): # loop no Doc a procura de quartos com limite da DATA de ENTRADA. for d in frappe.db.sql("""SELECT codigo,numero_quarto,check_in,check_out,reservation_status, pay_advance FROM `tabRESERVAS` WHERE reservation_status = "Nova" and check_in <=%s """, frappe.utils.now(), as_dict=True): print "RESERVAS +++++++++++++++++++++++++++++++" if (frappe.utils.data.time_diff_in_hours(frappe.utils.now(),d.check_in) >2): reser = frappe.get_doc("RESERVAS",d.codigo) dd= datetime.datetime.fromtimestamp(frappe.utils.data.time_diff_in_hours(frappe.utils.now(),d.check_in)).strftime('%H:%M:%S') # str(frappe.utils.data.time_diff_in_hours(frappe.utils.now(),d.check_in)) ddd = make_autoname('CANCEL/' + '.#####') print " Numer " + ddd frappe.db.sql("INSERT into tabCommunication (name,docstatus,seen,unread_notification_sent,subject,reference_name,reference_doctype,sent_or_received,content,communication_type,creation,modified) values (%s,0,0,0,'RESERVA Cancelada ',%s,'RESERVAS','Sent','RESERVA Cancelada <!-- markdown -->','Comment',%s,%s) ",(ddd,d.codigo,frappe.utils.now(),frappe.utils.now())) # reser._comments =[{"comment": "Reserva " + d.codigo + " " + str(d.check_in) + " Cancelada por mais de " + datetime.datetime.fromtimestamp(dd).strftime('%H:%M:%S') + " horas; by name: " + ddd}] reser._comments = "Reserva " + str(d.codigo) + " " + str(d.check_in) + " Cancelada por mais de " + dd + " horas" print " AGORA " + frappe.utils.now() print " CHECK IN " + str(d.check_in) print "Reserva " + d.codigo + " " + str(d.check_in) + " Cancelada por mais de " + dd + " horas" reser.reservation_status="Cancelada" reser.save() #frappe.redirect_to_message(_('INFORMACAO RESERVAS'),"<div>RESERVA " + d.codigo + " FOI CANCELADA </div>") frappe.publish_realtime(event='msgprint', message='RESERVA ' + d.codigo + ' ' + str(d.check_in) + ' Cancelada por mais de ' + dd + ' horas', user=frappe.session.user,doctype='RESERVAS')
def create_student_groups(self): if not self.courses: frappe.throw(_("""No Student Groups created.""")) l = len(self.courses) for d in self.courses: if not d.student_group_name: frappe.throw(_("""Student Group Name is mandatory in row {0}""".format(d.idx))) if d.group_based_on == "Course" and not d.course: frappe.throw(_("""Course is mandatory in row {0}""".format(d.idx))) if d.group_based_on == "Batch" and not d.batch: frappe.throw(_("""Batch is mandatory in row {0}""".format(d.idx))) frappe.publish_realtime('student_group_creation_progress', {"progress": [d.idx, l]}, user=frappe.session.user) student_group = frappe.new_doc("Student Group") student_group.student_group_name = d.student_group_name student_group.group_based_on = d.group_based_on student_group.program = self.program student_group.course = d.course student_group.batch = d.batch student_group.max_strength = d.max_strength student_group.academic_term = self.academic_term student_group.academic_year = self.academic_year student_list = get_students(self.academic_year, d.group_based_on, self.academic_term, self.program, d.batch, d.course) for student in student_list: student_group.append('students', student) student_group.save() frappe.msgprint(_("{0} Student Groups created.".format(l)))
def migrate(verbose=True, rebuild_website=False): '''Migrate all apps to the latest version, will: - run before migrate hooks - run patches - sync doctypes (schema) - sync fixtures - sync desktop icons - sync web pages (from /www) - sync web pages (from /www) - run after migrate hooks ''' touched_tables_file = frappe.get_site_path('touched_tables.json') if os.path.exists(touched_tables_file): os.remove(touched_tables_file) try: frappe.flags.touched_tables = set() frappe.flags.in_migrate = True clear_global_cache() #run before_migrate hooks for app in frappe.get_installed_apps(): for fn in frappe.get_hooks('before_migrate', app_name=app): frappe.get_attr(fn)() # run patches frappe.modules.patch_handler.run_all() # sync frappe.model.sync.sync_all(verbose=verbose) frappe.translate.clear_cache() sync_fixtures() sync_customizations() sync_desktop_icons() sync_languages() frappe.get_doc('Portal Settings', 'Portal Settings').sync_menu() # syncs statics render.clear_cache() # add static pages to global search router.sync_global_search() #run after_migrate hooks for app in frappe.get_installed_apps(): for fn in frappe.get_hooks('after_migrate', app_name=app): frappe.get_attr(fn)() frappe.db.commit() clear_notifications() frappe.publish_realtime("version-update") frappe.flags.in_migrate = False finally: with open(touched_tables_file, 'w') as f: json.dump(list(frappe.flags.touched_tables), f, sort_keys=True, indent=4) frappe.flags.touched_tables.clear()
def notify_update(self): """Publish realtime that the current document is modified""" frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name}, doctype=self.doctype, docname=self.name, after_commit=True) if not self.meta.get("read_only") and not self.meta.get("issingle") and \ not self.meta.get("istable"): frappe.publish_realtime("list_update", {"doctype": self.doctype}, after_commit=True)
def start_install(name): frappe.publish_realtime("install_app_progress", {"status": _("Installing App {0}").format(name)}, user=frappe.session.user) frappe.installer.install_app(name) frappe.publish_realtime("install_app_progress", {"status": _("{0} Installed").format(name)}, user=frappe.session.user)
def after_insert(self): # send new comment to listening clients comment = self.as_dict() comment["comment"] = comment["content"] comment["comment_by"] = comment["sender"] comment["comment_type"] = comment["communication_medium"] frappe.publish_realtime("new_comment", comment, doctype=self.reference_doctype, docname=self.reference_name)
def import_data(data_import): frappe.db.set_value("Data Import", data_import, "import_status", "In Progress", update_modified=False) frappe.publish_realtime("data_import_progress", {"progress": "0", "data_import": data_import, "reload": True}, user=frappe.session.user) from frappe.core.page.background_jobs.background_jobs import get_info enqueued_jobs = [d.get("job_name") for d in get_info()] if data_import not in enqueued_jobs: enqueue(upload, queue='default', timeout=6000, event='data_import', job_name=data_import, data_import_doc=data_import, from_data_import="Yes", user=frappe.session.user)
def receive(self, test_mails=None): """Called by scheduler to receive emails from this EMail account using POP3/IMAP.""" if self.enable_incoming: exceptions = [] if frappe.local.flags.in_test: incoming_mails = test_mails else: email_server = self.get_server(in_receive=True) if not email_server: return try: incoming_mails = email_server.get_messages() except Exception as e: frappe.db.sql("update `tabEmail Account` set no_remaining = NULL where name = %s",(self.name), auto_commit=1) incoming_mails = [] for msg in incoming_mails: try: communication = self.insert_communication(msg) #self.notify_update() except SentEmailInInbox as e: frappe.db.rollback() if self.use_imap: self.handle_bad_emails(email_server, msg[1], msg[0], "sent email in inbox") except Exception as e: frappe.db.rollback() log('email_account.receive') if self.use_imap: self.handle_bad_emails(email_server, msg[1], msg[0], frappe.get_traceback()) exceptions.append(frappe.get_traceback()) else: frappe.db.commit() attachments = [d.file_name for d in communication._attachments] if communication.message_id and not communication.timeline_hide: first = frappe.db.get_value("Communication", {"message_id": communication.message_id},["name"],order_by="creation",as_dict=1) if first: if first.name != communication.name: frappe.db.sql("""update tabCommunication set timeline_hide =%s where name = %s""",(first.name,communication.name),auto_commit=1) if self.no_remaining == '0' and not frappe.local.flags.in_test: if communication.reference_doctype : if not communication.timeline_hide and not communication.unread_notification_sent: communication.notify(attachments=attachments, fetched_from_email_account=True) #notify if user is linked to account if len(incoming_mails)>0 and not frappe.local.flags.in_test: frappe.publish_realtime('new_email', {"account":self.email_account_name, "account_name": self.name, "number":len(incoming_mails)}) if exceptions: raise Exception, frappe.as_json(exceptions)
def create(kind, owner, users = None, name = None): authenticate(owner) users = safe_json_loads(users) create = True if kind == 'Visitor': room = squashify(frappe.db.sql(""" SELECT name FROM `tabChat Room` WHERE owner = "{owner}" """.format(owner = owner), as_dict = True)) if room: room = frappe.get_doc('Chat Room', room.name) create = False if create: room = frappe.new_doc('Chat Room') room.type = kind room.owner = owner room.room_name = name dusers = [ ] if kind != 'Visitor': if users: users = listify(users) for user in users: duser = frappe.new_doc('Chat Room User') duser.user = user dusers.append(duser) room.users = dusers else: dsettings = frappe.get_single('Website Settings') room.room_name = dsettings.chat_room_name users = [user for user in room.users] if hasattr(room, 'users') else [ ] for user in dsettings.chat_operators: if user.user not in users: # appending user to room.users will remove the user from chat_operators # this is undesirable, create a new Chat Room User instead chat_room_user = {"doctype": "Chat Room User", "user": user.user} room.append('users', chat_room_user) room.save(ignore_permissions = True) room = get(owner, rooms = room.name) users = [room.owner] + [u for u in room.users] for u in users: frappe.publish_realtime('frappe.chat.room:create', room, user = u, after_commit = True) return room
def generate_csrf_token(): frappe.local.session.data.csrf_token = frappe.generate_hash() frappe.local.session_obj.update(force=True) # send sid and csrf token to the user # handles the case when a user logs in again from another tab # and it leads to invalid request in the current tab frappe.publish_realtime(event="csrf_generated", message={"sid": frappe.local.session.sid, "csrf_token": frappe.local.session.data.csrf_token}, user=frappe.session.user)
def seen(message, user = None): authenticate(user) mess = frappe.get_doc('Chat Message', message) mess.add_seen(user) room = mess.room resp = dict(message = message, data = dict(seen = json.loads(mess._seen))) frappe.publish_realtime('frappe.chat.message:update', resp, room = room, after_commit = True)
def reload_linked_analysis(self): linked_doctypes = ['Soil Texture', 'Soil Analysis', 'Plant Analysis'] required_fields = ['location', 'name', 'collection_datetime'] output = {} for doctype in linked_doctypes: output[doctype] = frappe.get_all(doctype, fields=required_fields) output['Land Unit'] = [] for land in self.linked_land_unit: output['Land Unit'].append(frappe.get_doc('Land Unit', land.land_unit)) frappe.publish_realtime("List of Linked Docs", output, user=frappe.session.user)
def after_insert(self): if not (self and self.name): return # Obtains the conversation linked to this Livechat Message conversation = frappe.get_doc('Chat Conversation', self.parent) # Sends new comment to listening clients so they get a realtime update frappe.publish_realtime('new_message', self.as_dict(), doctype= 'Chat Conversation', docname = conversation.name, after_commit=True) frappe.publish_realtime(event='livechat_update', message='''{u'doctype': u'Livechat Message'}''')
def publish_realtime(context, event, message, room, user, doctype, docname, after_commit): "Publish realtime event from bench" from frappe import publish_realtime for site in context.sites: try: frappe.init(site=site) frappe.connect() publish_realtime(event, message=message, room=room, user=user, doctype=doctype, docname=docname, after_commit=after_commit) frappe.db.commit() finally: frappe.destroy()
def on_trash(self): if (not self.flags.ignore_permissions and self.communication_type=="Comment" and self.comment_type != "Comment"): # prevent deletion of auto-created comments if not ignore_permissions frappe.throw(_("Sorry! You cannot delete auto-generated comments")) if self.communication_type in ("Communication", "Comment"): # send delete comment to listening clients frappe.publish_realtime('delete_communication', self.as_dict(), doctype= self.reference_doctype, docname = self.reference_name, after_commit=True)
def create_fees(self): self.db_set("fee_creation_status", "In Process") frappe.publish_realtime("fee_schedule_progress", {"progress": "0", "reload": 1}, user=frappe.session.user) total_records = sum([int(d.total_students) for d in self.student_groups]) if total_records > 10: frappe.msgprint(_('''Fee records will be created in the background. In case of any error the error message will be updated in the Schedule.''')) enqueue(generate_fee, queue='default', timeout=6000, event='generate_fee', fee_schedule=self.name) else: generate_fee(self.name)
def make_invoices(self): names = [] mandatory_error_msg = _("Row {0}: {1} is required to create the Opening {2} Invoices") if not self.company: frappe.throw(_("Please select the Company")) for row in self.invoices: if not row.qty: row.qty = 1.0 # always mandatory fields for the invoices if not row.temporary_opening_account: row.temporary_opening_account = get_temporary_opening_account(self.company) row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier" # Allow to create invoice even if no party present in customer or supplier. if not frappe.db.exists(row.party_type, row.party): if self.create_missing_party: self.add_party(row.party_type, row.party) else: frappe.throw(_("{0} {1} does not exist.").format(frappe.bold(row.party_type), frappe.bold(row.party))) if not row.item_name: row.item_name = _("Opening Invoice Item") if not row.posting_date: row.posting_date = nowdate() if not row.due_date: row.due_date = nowdate() for d in ("Party", "Outstanding Amount", "Temporary Opening Account"): if not row.get(scrub(d)): frappe.throw(mandatory_error_msg.format(row.idx, _(d), self.invoice_type)) args = self.get_invoice_dict(row=row) if not args: continue doc = frappe.get_doc(args).insert() doc.submit() names.append(doc.name) if len(self.invoices) > 5: frappe.publish_realtime( "progress", dict( progress=[row.idx, len(self.invoices)], title=_('Creating {0}').format(doc.doctype) ), user=frappe.session.user ) return names
def generate_fee(fee_schedule): doc = frappe.get_doc("Fee Schedule", fee_schedule) error = False total_records = sum([int(d.total_students) for d in doc.student_groups]) created_records = 0 if not total_records: frappe.throw(_("Please setup Students under Student Groups")) for d in doc.student_groups: students = frappe.db.sql(""" select sg.program, sg.batch, sgs.student, sgs.student_name from `tabStudent Group` sg, `tabStudent Group Student` sgs where sg.name=%s and sg.name=sgs.parent and sgs.active=1""", d.student_group, as_dict=1) for student in students: try: fees_doc = get_mapped_doc("Fee Schedule", fee_schedule, { "Fee Schedule": { "doctype": "Fees", "field_map": { "name": "Fee Schedule" } } }) fees_doc.student = student.student fees_doc.student_name = student.student_name fees_doc.program = student.program fees_doc.student_batch = student.batch fees_doc.send_payment_request = doc.send_email fees_doc.save() fees_doc.submit() created_records += 1 frappe.publish_realtime("fee_schedule_progress", {"progress": str(int(created_records * 100/total_records))}, user=frappe.session.user) except Exception as e: error = True err_msg = frappe.local.message_log and "\n\n".join(frappe.local.message_log) or cstr(e) if error: frappe.db.rollback() frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Failed") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", err_msg) else: frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Successful") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", None) frappe.publish_realtime("fee_schedule_progress", {"progress": "100", "reload": 1}, user=frappe.session.user)
def realtime_eval(rte_id, tag, event, msg): """ Use publish_realtime to run javascript code using custom event handler. rte_id: persistent id for the current form tag: communications tag specific to one series of communications event: name of custom event to trigger on client. msg: JSON serializable object (e.g. dict) to push to client. """ rte_msg = json.dumps(msg) js = "erpnext_ebay_realtime_event('{}', '{}', '{}', '{}');" js = js.format(rte_id, tag, event, rte_msg) frappe.publish_realtime(event='eval_js', message=js, user=frappe.session.user)
def run_background(instance): report = frappe.get_doc("Report", instance.ref_report_doctype) result = generate_report_result(report, filters=instance.filters, user=instance.owner) create_json_gz_file(result['result'], 'Prepared Report', instance.name) instance.status = "Completed" instance.columns = json.dumps(result["columns"]) instance.report_end_time = frappe.utils.now() instance.save() frappe.publish_realtime( 'report_generated', {"report_name": instance.report_name, "name": instance.name}, user=frappe.session.user )
def migrate(verbose=True, rebuild_website=False): '''Migrate all apps to the latest version, will: - run before migrate hooks - run patches - sync doctypes (schema) - sync fixtures - sync desktop icons - sync web pages (from /www) - sync web pages (from /www) - run after migrate hooks ''' frappe.flags.in_migrate = True clear_global_cache() #run before_migrate hooks for app in frappe.get_installed_apps(): for fn in frappe.get_hooks('before_migrate', app_name=app): frappe.get_attr(fn)() # run patches frappe.modules.patch_handler.run_all() # sync frappe.model.sync.sync_all(verbose=verbose) frappe.translate.clear_cache() sync_fixtures() sync_customizations() sync_desktop_icons() sync_languages() frappe.get_doc('Portal Settings', 'Portal Settings').sync_menu() # syncs statics render.clear_cache() # add static pages to global search router.sync_global_search() #run after_migrate hooks for app in frappe.get_installed_apps(): for fn in frappe.get_hooks('after_migrate', app_name=app): frappe.get_attr(fn)() frappe.db.commit() clear_notifications() frappe.publish_realtime("version-update") frappe.flags.in_migrate = False
def delete_items(): """delete selected items""" import json il = json.loads(frappe.form_dict.get('items')) doctype = frappe.form_dict.get('doctype') for i, d in enumerate(il): try: frappe.delete_doc(doctype, d) if len(il) >= 5: frappe.publish_realtime("progress", dict(progress=[i+1, len(il)], title=_('Deleting {0}').format(doctype)), user=frappe.session.user) except Exception: pass
def long_job(arg1, arg2): frappe.publish_realtime('msgprint', 'Starting long job...') doc = frappe.get_doc('OpenRouteService') client = ors.Client(key=doc.api_openrouteservice) home_address = doc.address_line1 + ", " + doc.pincode + " " + doc.city home_address_location = client.pelias_search(text=home_address) home_address_coordinates = home_address_location["features"][0][ "geometry"]["coordinates"] # get list of all adresses all_adresses = frappe.db.get_list("Address", fields=['name'], as_list=True) for i in all_adresses: # strip it from address_id = i[0] print(address_id) address_line1 = frappe.db.get_value("Address", address_id, "address_line1") pincode = frappe.db.get_value("Address", address_id, "pincode") city = frappe.db.get_value("Address", address_id, "city") destination_address = str(address_line1) + ", " + str( pincode) + " " + str(city) print(destination_address) destination_address_location = client.pelias_search( text=destination_address) destination_address_coordinates = destination_address_location[ "features"][0]["geometry"]["coordinates"] print(destination_address_coordinates) coordinates = [ home_address_coordinates, destination_address_coordinates ] route = client.directions(coordinates=coordinates, profile='driving-car', geometry_simplify=True, instructions=False, geometry=False) distance_and_duration = route.get("routes")[0].get("summary") print(distance_and_duration) try: distance = distance_and_duration["distance"] distance = distance / 1000 except: distance = 0 try: duration = distance_and_duration["duration"] duration = duration / 60 except: duration = 0 frappe.db.set_value("Address", address_id, "distance", distance) frappe.db.set_value("Address", address_id, "duration_from_home_address_in_minutes", duration) time.sleep(1.6) frappe.publish_realtime('msgprint', 'Ending long job...') return distance, duration
def run_command(commands, doctype, key, cwd='..', docname=' ', after_command=None): verify_whitelisted_call() start_time = frappe.utils.time.time() console_dump = '' logged_command = ' && '.join(commands) logged_command += ' ' #to make sure passwords at the end of the commands are also hidden sensitive_data = [ "--mariadb-root-password", "--admin-password", "--root-password" ] for password in sensitive_data: logged_command = re.sub("{password} .*? ".format(password=password), '', logged_command, flags=re.DOTALL) doc = frappe.get_doc({ 'doctype': 'Bench Manager Command', 'key': key, 'source': doctype + ': ' + docname, 'command': logged_command, 'console': console_dump, 'status': 'Ongoing' }) doc.insert() frappe.db.commit() frappe.publish_realtime(key, "Executing Command:\n{logged_command}\n\n".format( logged_command=logged_command), user=frappe.session.user) try: for command in commands: terminal = Popen(shlex.split(command), stdin=PIPE, stdout=PIPE, stderr=STDOUT, cwd=cwd) for c in iter(lambda: terminal.stdout.read(1), ''): frappe.publish_realtime(key, c, user=frappe.session.user) console_dump += c if terminal.wait(): _close_the_doc(start_time, key, console_dump, status='Failed', user=frappe.session.user) else: _close_the_doc(start_time, key, console_dump, status='Success', user=frappe.session.user) except: _close_the_doc(start_time, key, console_dump, status='Failed', user=frappe.session.user) finally: frappe.db.commit() # hack: frappe.db.commit() to make sure the log created is robust, # and the _refresh throws an error if the doc is deleted frappe.enqueue('bench_manager.bench_manager.utils._refresh', doctype=doctype, docname=docname, commands=commands)
def import_data(self): # set user lang for translations frappe.cache().hdel("lang", frappe.session.user) frappe.set_user_lang(frappe.session.user) if not self.console: self.data_import.db_set("template_warnings", "") # set flags frappe.flags.in_import = True frappe.flags.mute_emails = self.data_import.mute_emails # prepare a map for missing link field values self.prepare_missing_link_field_values() # parse docs from rows payloads = self.get_payloads_for_import() # dont import if there are non-ignorable warnings warnings = [w for w in self.warnings if w.get("type") != "info"] if warnings: if self.console: self.print_grouped_warnings(warnings) else: self.data_import.db_set("template_warnings", json.dumps(warnings)) frappe.publish_realtime("data_import_refresh", {"data_import": self.data_import.name}) return # setup import log if self.data_import.import_log: import_log = frappe.parse_json(self.data_import.import_log) else: import_log = [] # remove previous failures from import log import_log = [l for l in import_log if l.get("success") == True] # get successfully imported rows imported_rows = [] for log in import_log: log = frappe._dict(log) if log.success: imported_rows += log.row_indexes # start import total_payload_count = len(payloads) batch_size = frappe.conf.data_import_batch_size or 1000 for batch_index, batched_payloads in enumerate( frappe.utils.create_batch(payloads, batch_size)): for i, payload in enumerate(batched_payloads): doc = payload.doc row_indexes = [row[0] for row in payload.rows] current_index = (i + 1) + (batch_index * batch_size) if set(row_indexes).intersection(set(imported_rows)): print("Skipping imported rows", row_indexes) if total_payload_count > 5: frappe.publish_realtime( "data_import_progress", { "current": current_index, "total": total_payload_count, "skipping": True, "data_import": self.data_import.name, }, ) continue try: start = timeit.default_timer() doc = self.process_doc(doc) processing_time = timeit.default_timer() - start eta = self.get_eta(current_index, total_payload_count, processing_time) if total_payload_count > 5: frappe.publish_realtime( "data_import_progress", { "current": current_index, "total": total_payload_count, "docname": doc.name, "data_import": self.data_import.name, "success": True, "row_indexes": row_indexes, "eta": eta, }, ) if self.console: update_progress_bar( "Importing {0} records".format( total_payload_count), current_index, total_payload_count, ) import_log.append( frappe._dict(success=True, docname=doc.name, row_indexes=row_indexes)) # commit after every successful import frappe.db.commit() except Exception: import_log.append( frappe._dict( success=False, exception=frappe.get_traceback(), messages=frappe.local.message_log, row_indexes=row_indexes, )) frappe.clear_messages() # rollback if exception frappe.db.rollback() # set status failures = [l for l in import_log if l.get("success") == False] if len(failures) == total_payload_count: status = "Pending" elif len(failures) > 0: status = "Partial Success" else: status = "Success" if self.console: self.print_import_log(import_log) else: self.data_import.db_set("status", status) self.data_import.db_set("import_log", json.dumps(import_log)) frappe.flags.in_import = False frappe.flags.mute_emails = False frappe.publish_realtime("data_import_refresh", {"data_import": self.data_import.name}) return import_log
def set_pos_profile(doc, method=None): frappe.publish_realtime("pos_profile_update", pos_profile_data())
def debug_data(data): frappe.publish_realtime("debug_data", data)
def sync_events_from_google_calendar(g_calendar, method=None): """ Syncs Events from Google Calendar in Framework Calendar. Google Calendar returns nextSyncToken when all the events in Google Calendar are fetched. nextSyncToken is returned at the very last page https://developers.google.com/calendar/v3/sync """ google_calendar, account = get_google_calendar_object(g_calendar) if not account.pull_from_google_calendar: return sync_token = account.get_password(fieldname="next_sync_token", raise_exception=False) or None events = frappe._dict() results = [] while True: try: # API Response listed at EOF events = google_calendar.events().list( calendarId=account.google_calendar_id, maxResults=2000, pageToken=events.get("nextPageToken"), singleEvents=False, showDeleted=True, syncToken=sync_token).execute() except HttpError as err: msg = _( "Google Calendar - Could not fetch event from Google Calendar, error code {0}." ).format(err.resp.status) if err.resp.status == 410: set_encrypted_password("Google Calendar", account.name, "", "next_sync_token") frappe.db.commit() msg += ' ' + _( 'Sync token was invalid and has been resetted, Retry syncing.' ) frappe.msgprint(msg, title='Invalid Sync Token', indicator='blue') else: frappe.throw(msg) for event in events.get("items", []): results.append(event) if not events.get("nextPageToken"): if events.get("nextSyncToken"): account.next_sync_token = events.get("nextSyncToken") account.save() break for idx, event in enumerate(results): frappe.publish_realtime("import_google_calendar", dict(progress=idx + 1, total=len(results)), user=frappe.session.user) # If Google Calendar Event if confirmed, then create an Event if event.get("status") == "confirmed": recurrence = None if event.get("recurrence"): try: recurrence = event.get("recurrence")[0] except IndexError: pass if not frappe.db.exists( "Event", {"google_calendar_event_id": event.get("id")}): insert_event_to_calendar(account, event, recurrence) else: update_event_in_calendar(account, event, recurrence) elif event.get("status") == "cancelled": # If any synced Google Calendar Event is cancelled, then close the Event frappe.db.set_value( "Event", { "google_calendar_id": account.google_calendar_id, "google_calendar_event_id": event.get("id") }, "status", "Closed") frappe.get_doc({ "doctype": "Comment", "comment_type": "Info", "reference_doctype": "Event", "reference_name": frappe.db.get_value( "Event", { "google_calendar_id": account.google_calendar_id, "google_calendar_event_id": event.get("id") }, "name"), "content": " - Event deleted from Google Calendar.", }).insert(ignore_permissions=True) else: pass if not results: return _("No Google Calendar Event to sync.") elif len(results) == 1: return _("1 Google Calendar Event synced.") else: return _("{0} Google Calendar Events synced.").format(len(results))
def estudante_enroll(source_name): """Creates a Student Record and returns a Program Enrollment. :param source_name: Student Applicant. """ frappe.publish_realtime('enroll_student_progress', {"progress": [1, 4]}, user=frappe.session.user) student = get_mapped_doc("Student Applicant", source_name, { "Student Applicant": { "doctype": "Student", "field_map": { "name": "student_applicant" } } }, ignore_permissions=True) student.save() frappe.db.set_value('Student', student.name, '_user_tags', student.title[0]) frappe.db.commit() #Cria Customer cliente = get_mapped_doc("Student Applicant", source_name, { "Student Applicant": { "doctype": "Customer", "field_map": { "name": "student_applicant" } } }, ignore_permissions=True) cliente.customer_name = student.title cliente.customer_group = 'Individual' cliente.territory = 'Angola' cliente.language = 'pt' print "ALUNO GENDER" print _(student.gender) cliente.save() frappe.db.set_value('Customer', cliente.name, '_user_tags', student.title[0]) frappe.db.commit() contacto = frappe.new_doc("Contact") contacto.name = student.title contacto.first_name = student.first_name contacto.middle_name = student.middle_name contacto.last_name = student.last_name contacto.gender = student.gender contacto.email_id = student.student_email_id contacto.mobile_no = student.student_mobile_number #contacto.parent contacto.status = 'Passive' contacto.save() contacto_link = frappe.new_doc('Dynamic Link') contacto_link.parent = contacto.name contacto_link.parentfield = 'links' contacto_link.parenttype = 'Contact' contacto_link.link_title = student.title contacto_link.link_doctype = 'Customer' contacto_link.link_name = student.title contacto_link.save() program_enrollment = frappe.new_doc("Program Enrollment") program_enrollment.student = student.name program_enrollment.student_name = student.title program_enrollment.program = frappe.db.get_value("Student Applicant", source_name, "program") frappe.publish_realtime('enroll_student_progress', {"progress": [4, 4]}, user=frappe.session.user) return program_enrollment
def emit_js(js, user=False, **kwargs): from frappe. async import publish_realtime if user == False: user = session.user publish_realtime('eval_js', js, user=user, **kwargs)
def publish_realtime(*args, **kwargs): """Publish real-time updates :param event: Event name, like `task_progress` etc. :param message: JSON message object. For async must contain `task_id` :param room: Room in which to publish update (default entire site) :param user: Transmit to user :param doctype: Transmit to doctype, docname :param docname: Transmit to doctype, docname :param after_commit: (default False) will emit after current transaction is committed """ import frappe. async return frappe. async .publish_realtime(*args, **kwargs) def local_cache(namespace, key, generator, regenerate_if_none=False): """A key value store for caching within a request :param namespace: frappe.local.cache[namespace] :param key: frappe.local.cache[namespace][key] used to retrieve value :param generator: method to generate a value if not found in store """ if namespace not in local.cache: local.cache[namespace] = {} if key not in local.cache[namespace]: local.cache[namespace][key] = generator()
def generate_fee(fee_schedule): doc = frappe.get_doc("Fee Schedule", fee_schedule) error = False total_records = sum([int(d.total_students) for d in doc.student_groups]) created_records = 0 if not total_records: frappe.throw(_("Please setup Students under Student Groups")) for d in doc.student_groups: students = frappe.db.sql( """ select sg.program, sg.batch, sgs.student, sgs.student_name from `tabStudent Group` sg, `tabStudent Group Student` sgs where sg.name=%s and sg.name=sgs.parent and sgs.active=1""", d.student_group, as_dict=1) for student in students: try: fees_doc = get_mapped_doc( "Fee Schedule", fee_schedule, { "Fee Schedule": { "doctype": "Fees", "field_map": { "name": "Fee Schedule" } } }) fees_doc.student = student.student fees_doc.student_name = student.student_name fees_doc.program = student.program fees_doc.student_batch = student.batch fees_doc.send_payment_request = doc.send_email fees_doc.save() fees_doc.submit() created_records += 1 frappe.publish_realtime("fee_schedule_progress", { "progress": str(int(created_records * 100 / total_records)) }, user=frappe.session.user) except Exception as e: error = True err_msg = frappe.local.message_log and "\n\n".join( frappe.local.message_log) or cstr(e) if error: frappe.db.rollback() frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Failed") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", err_msg) else: frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Successful") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", None) frappe.publish_realtime("fee_schedule_progress", { "progress": "100", "reload": 1 }, user=frappe.session.user)
def trigger_indicator_hide(): frappe.publish_realtime("indicator_hide", user=frappe.session.user)
def console(*data): frappe.publish_realtime('out_to_console', data, user=frappe.session.user)
def delete_post(post_name): post = frappe.get_doc('Post', post_name) post.delete() frappe.publish_realtime('delete_post' + post_name, after_commit=True)
def publish(message): frappe.publish_realtime("msgprint", message=str(message), user="******")
return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name) error = False total = len(data) for i, row in enumerate(data): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None # publish task_update frappe.publish_realtime("data_import_progress", {"progress": [i, total]}, user=frappe.session.user) try: doc = get_doc(row_idx) if pre_process: pre_process(doc) if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() log('Inserted row for %s at #%s' % (as_link(parenttype, doc.parent),text_type(doc.idx))) else: if overwrite and doc["name"] and frappe.db.exists(doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"])
def on_update(self): frappe.cache().delete_value('user_permissions') frappe.publish_realtime('update_user_permissions')
def publish_realtime(self, current, total): frappe.publish_realtime("real_progress", { "progress": flt(current) / flt(total) * 100, }, user=frappe.session.user)
def on_trash(self): # pylint: disable=no-self-use frappe.cache().delete_value('user_permissions') frappe.publish_realtime('update_user_permissions')
def send(user, room, content): mess = get_new_chat_message(user, room, content) frappe.publish_realtime('frappe.chat.message:create', mess, room = room, after_commit = True)
def after_insert(self): frappe.publish_realtime('new_post', self.owner, after_commit=True)
def notify_to_check_command(command_foods): frappe.publish_realtime("notify_to_check_order_data", dict(commands_foods=command_foods))
def receive(self, test_mails=None): """Called by scheduler to receive emails from this EMail account using POP3/IMAP.""" def get_seen(status): if not status: return None seen = 1 if status == "SEEN" else 0 return seen if self.enable_incoming: uid_list = [] exceptions = [] seen_status = [] uid_reindexed = False if frappe.local.flags.in_test: incoming_mails = test_mails else: email_sync_rule = self.build_email_sync_rule() email_server = None try: email_server = self.get_incoming_server(in_receive=True, email_sync_rule=email_sync_rule) except Exception: frappe.log_error(title=_("Error while connecting to email account {0}").format(self.name)) if not email_server: return emails = email_server.get_messages() if not emails: return incoming_mails = emails.get("latest_messages", []) uid_list = emails.get("uid_list", []) seen_status = emails.get("seen_status", []) uid_reindexed = emails.get("uid_reindexed", False) for idx, msg in enumerate(incoming_mails): uid = None if not uid_list else uid_list[idx] try: args = { "uid": uid, "seen": None if not seen_status else get_seen(seen_status.get(uid, None)), "uid_reindexed": uid_reindexed } communication = self.insert_communication(msg, args=args) except SentEmailInInbox: frappe.db.rollback() except Exception: frappe.db.rollback() log('email_account.receive') if self.use_imap: self.handle_bad_emails(email_server, uid, msg, frappe.get_traceback()) exceptions.append(frappe.get_traceback()) else: frappe.db.commit() if communication: attachments = [d.file_name for d in communication._attachments] communication.notify(attachments=attachments, fetched_from_email_account=True) #notify if user is linked to account if len(incoming_mails)>0 and not frappe.local.flags.in_test: frappe.publish_realtime('new_email', {"account":self.email_account_name, "number":len(incoming_mails)}) if exceptions: raise Exception(frappe.as_json(exceptions))
def set_progress(progress, message): frappe.publish_realtime("upload_to_google_drive", dict(progress=progress, total=3, message=message), user=frappe.session.user)
def boski_command_manager(key, commands, site_name, password, email): log_commands = " && ".join(commands) frappe.publish_realtime( key, "Sit Tight With US and Feel the GRYNN Magic...!!!\n\n\n", user=frappe.session.user) frappe.publish_realtime(key, "Getting Ready:\n\n", user=frappe.session.user) try: for command in commands: terminal = Popen(shlex.split(command), stdin=PIPE, stdout=PIPE, stderr=STDOUT, cwd="..") for c in iter(lambda: safe_decode(terminal.stdout.read(1)), ''): print(c) frappe.publish_realtime(key, c, user=frappe.session.user) if terminal.wait(): frappe.msgprint(_("Process Failed.")) else: frappe.msgprint(_("Process Successful.")) frappe.publish_realtime( key, "\n\nYour Site is Ready. Thanks For Choosing GRYNN...!!!", user=frappe.session.user) try: msg = """<div> Hey, <br><br> Thanks for choosing GRYNN. <br><br> {site_name} is now ready. <br><br> Login id: Administrator. <br><br> Password: {password} . <br><br> Cheers, <br><br> GRYNN Team </div> """.format(site_name=site_name, password=password) email_args = { "recipients": [email], "subject": "Your Domain is Ready", "message": msg } enqueue(method=frappe.sendmail, queue='short', timeout=300, async=True, **email_args) except Exception as e: frappe.throw(_("{0}").format(e)) except Exception as e: frappe.throw( _("Kindly contact to admin with the error screen shot. {0}"). format(e))
def popup_notification(): get_notification = frappe.db.sql( """select name, customer, delivery_time, popup_reminder, notify_before, re_notify, last_note_time, notified, re_notify_every from `tabTrip Order` where delivery_time is not null and order_status != 'Assigned And Notified' and popup_reminder = 1 and month(delivery_time) = month(now()) and year(delivery_time) = year(now()) and docstatus = 0 and (notified = 'No' or (notified = 'Yes' and re_notify = 1)) """, as_dict=True) for d in get_notification: if d['notified'] == 'No': cur_time = datetime.datetime.now() if int(d['delivery_time'].day) == cur_time.day: time_diff = ((d['delivery_time'].hour - cur_time.hour) * 60 + (d['delivery_time'].minute - cur_time.minute)) if time_diff < int(d['notify_before']) and time_diff > -60: msg_var = "Please follow up Trip Order # {0} as its delivery time is: {1} for customer: {2} and the time difference is {3} and notify before is {4}".format( d['name'], d['delivery_time'], d['customer'], time_diff, d['notify_before']) # test_msg = "The popup reminder case is {0}".format(d['popup_reminder']) frappe.publish_realtime(event='msgprint', message=msg_var, user=frappe.session.user) elif int(d['delivery_time'].day) == (cur_time.day - 1): # if (int(d['delivery_time'].hour) - cur_time.hour) == 23: if (int(d['delivery_time'].hour) - 0) == 23: time_diff = (d['delivery_time'].minute - cur_time.minute) if time_diff <= 59 and time_diff >= 0: msg_var = "Please follow up Trip Order # {0} as its delivery time is: {1} for customer: {2} and the time difference is {3} and notify before is {4}".format( d['name'], d['delivery_time'], d['customer'], time_diff, d['notify_before']) frappe.publish_realtime(event='msgprint', message=msg_var, user=frappe.session.user) else: cur_time = datetime.datetime.now() if int(d['last_note_time'].day) == cur_time.day: time_diff = (cur_time.hour - d['last_note_time'].hour) * 60 + ( cur_time.minute - d['last_note_time'].minute) if time_diff > int(d['re_notify_every']): msg_var = "Please follow up Trip Order # {0} as its delivery time is: {1} for customer: {2} and the time difference is {3} and notify before is {4}".format( d['name'], d['delivery_time'], d['customer'], time_diff, d['notify_before']) frappe.publish_realtime(event='msgprint', message=msg_var, user=frappe.session.user) elif int(d['last_note_time'].day) == (cur_time.day - 1): time_diff = (cur_time.hour + 24 - d['last_note_time'].hour) * 60 + ( cur_time.minute - d['last_note_time'].minute) if time_diff > int(d['re_notify_every']): msg_var = "Please follow up Trip Order # {0} as its delivery time is: {1} for customer: {2} and the time difference is {3} and notify before is {4}".format( d['name'], d['delivery_time'], d['customer'], time_diff, d['notify_before']) frappe.publish_realtime(event='msgprint', message=msg_var, user=frappe.session.user) # if d.notified == "Yes": # if d.re_notify == 1: # cur_time = datetime.datetime.now() # cur_time.hour - d.last_note_time.hour # d.last_note_time # test_msg = "This is delivery time: {0} and the hour is {1}".format(d['delivery_time'], d['delivery_time'].hour) # test_msg = "This is delivery time" # frappe.publish_realtime(event='msgprint', message=test_msg, user=frappe.session.user) cur_time = datetime.datetime.now() msg_var = "The returned values are {0}, {1}, {2}, {3} and current time is {4} and current hour is {5} and current minute is {6}".format( get_notification[0]['name'], get_notification[0]['customer'], get_notification[0]['delivery_time'], get_notification[0]['popup_reminder'], cur_time, cur_time.hour, cur_time.minute) # frappe.publish_realtime(event='eval_js', message='show_alert("Show Alert: {0}")'.format(msg_var), user=frappe.session.user) frappe.publish_realtime( event='eval_js', message='show_alert("Show Alert for 30 sec {0}", 30)'.format(msg_var), user=frappe.session.user) return
def on_update(self): if (self.is_globally_pinned): frappe.publish_realtime('global_pin', after_commit=True)
def show_progress(i, l): if l > 2: frappe.publish_realtime("progress", dict(progress=[i, l], title=_('Updating...')), user=frappe.session.user)
def upload(rows=None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, ignore_links=False, pre_process=None, via_console=False): """upload data""" frappe.flags.in_import = True # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') if params.get("submit_after_import"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True if not params.get("no_email"): no_email = False frappe.flags.mute_emails = no_email from frappe.utils.csvutils import read_csv_content_from_uploaded_file def get_data_keys_definition(): return get_data_keys() def bad_template(): frappe.throw( _("Please do not change the rows above {0}").format( get_data_keys_definition().data_separator)) def check_data_length(): max_rows = 5000 if not data: frappe.throw(_("No data found")) elif not via_console and len(data) > max_rows: frappe.throw( _("Only allowed {0} rows in one import").format(max_rows)) def get_start_row(): for i, row in enumerate(rows): if row and row[0] == get_data_keys_definition().data_separator: return i + 1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0] == key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = filter(lambda x: x in ("", None), columns) if empty_cols: if columns[-1 * len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1 * len(empty_cols)] else: frappe.msgprint(_( "Please make sure that there are no empty columns in the file." ), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx( get_data_keys_definition().doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d and doctype_row[i] in (None, '', '~', '-', 'DocType:'): dt, parentfield = d, doctype_row[i + 2] or None doctypes.append((dt, parentfield)) column_idx_to_fieldname[(dt, parentfield)] = {} column_idx_to_fieldtype[(dt, parentfield)] = {} if dt: column_idx_to_fieldname[(dt, parentfield)][i + 1] = rows[row_idx + 2][i + 1] column_idx_to_fieldtype[(dt, parentfield)][i + 1] = rows[row_idx + 4][i + 1] def get_doc(start_idx): if doctypes: doc = {} for idx in xrange(start_idx, len(rows)): if (not doc) or main_doc_empty(rows[idx]): for dt, parentfield in doctypes: d = {} for column_idx in column_idx_to_fieldname[( dt, parentfield)]: try: fieldname = column_idx_to_fieldname[( dt, parentfield)][column_idx] fieldtype = column_idx_to_fieldtype[( dt, parentfield)][column_idx] d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": d[fieldname] = getdate( parse_date(d[fieldname]) ) if d[fieldname] else None elif fieldtype == "Datetime": if d[fieldname]: if " " in d[fieldname]: _date, _time = d[fieldname].split() else: _date, _time = d[ fieldname], '00:00:00' _date = parse_date(d[fieldname]) d[fieldname] = get_datetime(_date + " " + _time) else: d[fieldname] = None except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d['doctype'] = dt if dt == doctype: doc.update(d) else: if not overwrite: d['parent'] = doc["name"] d['parenttype'] = doctype d['parentfield'] = parentfield doc.setdefault(d['parentfield'], []).append(d) else: break return doc else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc['doctype'] = doctype return doc def main_doc_empty(row): return not (row and ((len(row) > 1 and row[1]) or (len(row) > 2 and row[2]))) users = frappe.db.sql_list("select name from tabUser") def prepare_for_insert(doc): # don't block data import if user is not set # migrating from another system if not doc.owner in users: doc.owner = frappe.session.user if not doc.modified_by in users: doc.modified_by = frappe.session.user # header if not rows: rows = read_csv_content_from_uploaded_file(ignore_encoding_errors) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] doctype = get_header_row(get_data_keys_definition().main_table)[1] columns = filter_empty_columns( get_header_row(get_data_keys_definition().columns)[1:]) doctypes = [] column_idx_to_fieldname = {} column_idx_to_fieldtype = {} if submit_after_import and not cint( frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(get_data_keys_definition().parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return { "messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True } # allow limit rows to be uploaded check_data_length() make_column_map() if overwrite == None: overwrite = params.get('overwrite') # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) ret = [] def log(msg): if via_console: print msg.encode('utf-8') else: ret.append(msg) def as_link(doctype, name): if via_console: return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name) error = False total = len(data) for i, row in enumerate(data): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None # publish task_update frappe.publish_realtime("data_import_progress", {"progress": [i, total]}, user=frappe.session.user) try: doc = get_doc(row_idx) if pre_process: pre_process(doc) if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() log('Inserted row for %s at #%s' % (as_link(parenttype, doc.parent), unicode(doc.idx))) else: if overwrite and doc["name"] and frappe.db.exists( doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original_name = original.name original.update(doc) # preserve original name for case sensitivity original.name = original_name original.flags.ignore_links = ignore_links original.save() log('Updated row (#%d) %s' % (row_idx + 1, as_link(original.doctype, original.name))) doc = original else: doc = frappe.get_doc(doc) prepare_for_insert(doc) doc.flags.ignore_links = ignore_links doc.insert() log('Inserted row (#%d) %s' % (row_idx + 1, as_link(doc.doctype, doc.name))) if submit_after_import: doc.submit() log('Submitted row (#%d) %s' % (row_idx + 1, as_link(doc.doctype, doc.name))) except Exception, e: error = True if doc: frappe.errprint( doc if isinstance(doc, dict) else doc.as_dict()) err_msg = frappe.local.message_log and "\n\n".join( frappe.local.message_log) or cstr(e) log('Error for row (#%d) %s : %s' % (row_idx + 1, len(row) > 1 and row[1] or "", err_msg)) frappe.errprint(frappe.get_traceback()) finally:
def upload(rows=None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, update_only=None, ignore_links=False, pre_process=None, via_console=False, from_data_import="No"): """upload data""" frappe.flags.in_import = True # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') if params.get("submit_after_import"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True if not params.get("no_email"): no_email = False if params.get('update_only'): update_only = True if params.get('from_data_import'): from_data_import = params.get('from_data_import') frappe.flags.mute_emails = no_email def get_data_keys_definition(): return get_data_keys() def bad_template(): frappe.throw( _("Please do not change the rows above {0}").format( get_data_keys_definition().data_separator)) def check_data_length(): max_rows = 5000 if not data: frappe.throw(_("No data found")) elif not via_console and len(data) > max_rows: frappe.throw( _("Only allowed {0} rows in one import").format(max_rows)) def get_start_row(): for i, row in enumerate(rows): if row and row[0] == get_data_keys_definition().data_separator: return i + 1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0] == key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = list(filter(lambda x: x in ("", None), columns)) if empty_cols: if columns[-1 * len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1 * len(empty_cols)] else: frappe.msgprint(_( "Please make sure that there are no empty columns in the file." ), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx( get_data_keys_definition().doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d and doctype_row[i] in (None, '', '~', '-', 'DocType:'): dt, parentfield = d, None # xls format truncates the row, so it may not have more columns if len(doctype_row) > i + 2: parentfield = doctype_row[i + 2] doctypes.append((dt, parentfield)) column_idx_to_fieldname[(dt, parentfield)] = {} column_idx_to_fieldtype[(dt, parentfield)] = {} if dt: column_idx_to_fieldname[(dt, parentfield)][i + 1] = rows[row_idx + 2][i + 1] column_idx_to_fieldtype[(dt, parentfield)][i + 1] = rows[row_idx + 4][i + 1] def get_doc(start_idx): if doctypes: doc = {} for idx in range(start_idx, len(rows)): if (not doc) or main_doc_empty(rows[idx]): for dt, parentfield in doctypes: d = {} for column_idx in column_idx_to_fieldname[( dt, parentfield)]: try: fieldname = column_idx_to_fieldname[( dt, parentfield)][column_idx] fieldtype = column_idx_to_fieldtype[( dt, parentfield)][column_idx] d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": if d[fieldname] and isinstance( d[fieldname], string_types): d[fieldname] = getdate( parse_date(d[fieldname])) elif fieldtype == "Datetime": if d[fieldname]: if " " in d[fieldname]: _date, _time = d[fieldname].split() else: _date, _time = d[ fieldname], '00:00:00' _date = parse_date(d[fieldname]) d[fieldname] = get_datetime(_date + " " + _time) else: d[fieldname] = None elif fieldtype in ("Image", "Attach Image", "Attach"): # added file to attachments list attachments.append(d[fieldname]) elif fieldtype in ("Link", "Dynamic Link" ) and d[fieldname]: # as fields can be saved in the number format(long type) in data import template d[fieldname] = cstr(d[fieldname]) except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d['doctype'] = dt if dt == doctype: doc.update(d) else: if not overwrite: d['parent'] = doc["name"] d['parenttype'] = doctype d['parentfield'] = parentfield doc.setdefault(d['parentfield'], []).append(d) else: break return doc else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc['doctype'] = doctype return doc def main_doc_empty(row): return not (row and ((len(row) > 1 and row[1]) or (len(row) > 2 and row[2]))) users = frappe.db.sql_list("select name from tabUser") def prepare_for_insert(doc): # don't block data import if user is not set # migrating from another system if not doc.owner in users: doc.owner = frappe.session.user if not doc.modified_by in users: doc.modified_by = frappe.session.user def is_valid_url(url): is_valid = False if url.startswith("/files") or url.startswith("/private/files"): url = get_url(url) try: r = requests.get(url) is_valid = True if r.status_code == 200 else False except Exception: pass return is_valid def attach_file_to_doc(doctype, docname, file_url): # check if attachment is already available # check if the attachement link is relative or not if not file_url: return if not is_valid_url(file_url): return files = frappe.db.sql( """Select name from `tabFile` where attached_to_doctype='{doctype}' and attached_to_name='{docname}' and (file_url='{file_url}' or thumbnail_url='{file_url}')""" .format(doctype=doctype, docname=docname, file_url=file_url)) if files: # file is already attached return save_url(file_url, None, doctype, docname, "Home/Attachments", 0) # header if not rows: from frappe.utils.file_manager import get_file_doc file_doc = get_file_doc(dt='', dn="Data Import", folder='Home', is_private=1) filename, file_extension = os.path.splitext(file_doc.file_name) if file_extension == '.xlsx' and from_data_import == 'Yes': from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file rows = read_xlsx_file_from_attached_file(file_id=file_doc.name) elif file_extension == '.csv': from frappe.utils.file_manager import get_file from frappe.utils.csvutils import read_csv_content fname, fcontent = get_file(file_doc.name) rows = read_csv_content(fcontent, ignore_encoding_errors) else: frappe.throw(_("Unsupported File Format")) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] doctype = get_header_row(get_data_keys_definition().main_table)[1] columns = filter_empty_columns( get_header_row(get_data_keys_definition().columns)[1:]) doctypes = [] column_idx_to_fieldname = {} column_idx_to_fieldtype = {} attachments = [] if submit_after_import and not cint( frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(get_data_keys_definition().parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return { "messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True } # allow limit rows to be uploaded check_data_length() make_column_map() if overwrite == None: overwrite = params.get('overwrite') # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) ret = [] def log(msg): if via_console: print(msg.encode('utf-8')) else: ret.append(msg) def as_link(doctype, name): if via_console: return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name) error = False total = len(data) for i, row in enumerate(data): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None # publish task_update frappe.publish_realtime("data_import_progress", {"progress": [i, total]}, user=frappe.session.user) try: doc = get_doc(row_idx) if pre_process: pre_process(doc) if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() log('Inserted row for %s at #%s' % (as_link(parenttype, doc.parent), text_type(doc.idx))) else: if overwrite and doc["name"] and frappe.db.exists( doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original_name = original.name original.update(doc) # preserve original name for case sensitivity original.name = original_name original.flags.ignore_links = ignore_links original.save() log('Updated row (#%d) %s' % (row_idx + 1, as_link(original.doctype, original.name))) doc = original else: if not update_only: doc = frappe.get_doc(doc) prepare_for_insert(doc) doc.flags.ignore_links = ignore_links doc.insert() log('Inserted row (#%d) %s' % (row_idx + 1, as_link(doc.doctype, doc.name))) else: log('Ignored row (#%d) %s' % (row_idx + 1, row[1])) if attachments: # check file url and create a File document for file_url in attachments: attach_file_to_doc(doc.doctype, doc.name, file_url) if submit_after_import: doc.submit() log('Submitted row (#%d) %s' % (row_idx + 1, as_link(doc.doctype, doc.name))) except Exception as e: error = True if doc: frappe.errprint( doc if isinstance(doc, dict) else doc.as_dict()) err_msg = frappe.local.message_log and "\n\n".join( frappe.local.message_log) or cstr(e) log('Error for row (#%d) %s : %s' % (row_idx + 1, len(row) > 1 and row[1] or "", err_msg)) frappe.errprint(frappe.get_traceback()) finally: frappe.local.message_log = [] if error: frappe.db.rollback() else: frappe.db.commit() frappe.flags.mute_emails = False frappe.flags.in_import = False return {"messages": ret, "error": error}
def create(kind, token, users=None, name=None): authenticate(token) users = safe_json_loads(users) create = True if kind == 'Visitor': room = squashify( frappe.db.sql(""" SELECT name FROM `tabChat Room` WHERE owner=%s """, (frappe.session.user), as_dict=True)) if room: room = frappe.get_doc('Chat Room', room.name) create = False if create: room = frappe.new_doc('Chat Room') room.type = kind room.owner = frappe.session.user room.room_name = name dusers = [] if kind != 'Visitor': if users: users = listify(users) for user in users: duser = frappe.new_doc('Chat Room User') duser.user = user dusers.append(duser) room.users = dusers else: dsettings = frappe.get_single('Website Settings') room.room_name = dsettings.chat_room_name users = [user for user in room.users] if hasattr(room, 'users') else [] for user in dsettings.chat_operators: if user.user not in users: # appending user to room.users will remove the user from chat_operators # this is undesirable, create a new Chat Room User instead chat_room_user = { "doctype": "Chat Room User", "user": user.user } room.append('users', chat_room_user) room.save(ignore_permissions=True) room = get(token=token, rooms=room.name) if room: users = [room.owner] + [u for u in room.users] for user in users: frappe.publish_realtime('frappe.chat.room:create', room, user=user, after_commit=True) return room