def check_before_exe_time_pos_invoices(last_execution_time=None): time = get_time(str(last_execution_time)) date = get_date_str(str(last_execution_time)) data = frappe.db.sql(""" select * from `tabPOS Invoice` where docstatus = 1 and posting_date >= %s and posting_time >= %s and ifnull(consolidated_invoice,'') = '' order by pos_profile,posting_date,posting_time """, (date, time), as_dict=1) pos_dict = {} for res in data: key = (res.pos_profile, res.posting_date) pos_dict.setdefault(key, []) pos_dict[key].append(res) for res in pos_dict.keys(): start_date = pos_dict[res][0]['posting_date'] start_time = pos_dict[res][0]['posting_time'] start_datetime = str(start_date)+" "+str(start_time) start_datetime = get_datetime_str(start_datetime) start_datetime = add_to_date(start_datetime, minutes=-1) # pos opening start date end_date = pos_dict[res][0]['posting_date'] end_time = pos_dict[res][0]['posting_time'] end_datetime = str(end_date)+" "+str(end_time) end_datetime = get_datetime_str(end_datetime) end_datetime = add_to_date(end_datetime, minutes=1) # pos closing end date pos_o_entry = make_opening_entry(res[0], date_time=start_datetime, execute_previous_entry=True) create_close_entry(pos_o_entry,end_datetime,end_date)
def validate(self): #Check if entry with same academic_year and the term_name already exists validate_duplication(self) self.title = self.academic_year + " ({})".format( self.term_name) if self.term_name else "" #Check that start of academic year is earlier than end of academic year if self.term_start_date and self.term_end_date and self.term_start_date > self.term_end_date: frappe.throw( _("The Term End Date cannot be earlier than the Term Start Date. Please correct the dates and try again." )) """Check that the start of the term is not before the start of the academic year and end of term is not after the end of the academic year""" year = frappe.get_doc("Academic Year", self.academic_year) if self.term_start_date and get_datetime_str( year.year_start_date ) and (self.term_start_date < get_datetime_str(year.year_start_date)): frappe.throw( _("The Term Start Date cannot be earlier than the Year Start Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again." ).format(self.academic_year)) if self.term_end_date and get_datetime_str(year.year_end_date) and ( self.term_end_date > get_datetime_str(year.year_end_date)): frappe.throw( _("The Term End Date cannot be later than the Year End Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again." ).format(self.academic_year))
def get_exchange_rate(from_currency, to_currency, transaction_date=None): if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 if not transaction_date: transaction_date = nowdate() currency_settings = frappe.get_doc("Accounts Settings").as_dict() allow_stale_rates = currency_settings.get("allow_stale") filters = [["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency]] if not allow_stale_rates: stale_days = currency_settings.get("stale_days") checkpoint_date = add_days(transaction_date, -stale_days) filters.append(["date", ">", get_datetime_str(checkpoint_date)]) # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all("Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests api_url = "https://exchangeratesapi.io/api/{0}".format( transaction_date) response = requests.get(api_url, params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.msgprint( _("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually" ).format(from_currency, to_currency, transaction_date)) return 0.0
def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=None): if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 if not transaction_date: transaction_date = nowdate() currency_settings = frappe.get_doc("Accounts Settings").as_dict() allow_stale_rates = currency_settings.get("allow_stale") filters = [ ["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency] ] if args == "for_buying": filters.append(["for_buying", "=", "1"]) elif args == "for_selling": filters.append(["for_selling", "=", "1"]) if not allow_stale_rates: stale_days = currency_settings.get("stale_days") checkpoint_date = add_days(transaction_date, -stale_days) filters.append(["date", ">", get_datetime_str(checkpoint_date)]) # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all( "Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests api_url = "https://frankfurter.app/{0}".format(transaction_date) response = requests.get(api_url, params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.log_error(title="Get Exchange Rate") frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date)) return 0.0
def import_file_by_path(path, force=False): frappe.flags.in_import = True docs = read_doc_from_file(path) if docs: if not isinstance(docs, list): docs = [docs] for doc in docs: if not force: # check if timestamps match db_modified = frappe.db.get_value(doc["doctype"], doc["name"], "modified") if db_modified and doc.get("modified") == get_datetime_str(db_modified): return False original_modified = doc.get("modified") import_doc(doc) if original_modified: # since there is a new timestamp on the file, update timestamp in if doc["doctype"] == doc["name"]: frappe.db.sql( """update tabSingles set value=%s where field="modified" and doctype=%s""", (original_modified, doc["name"]), ) else: frappe.db.sql( "update `tab%s` set modified=%s where name=%s" % (doc["doctype"], "%s", "%s"), (original_modified, doc["name"]), ) frappe.flags.in_import = False return True
def get_currency(filters): """ Returns a dictionary containing currency information. The keys of the dict are - company: The company for which we are fetching currency information. if no company is specified, it will fallback to the default company. - company currency: The functional currency of the said company. - presentation currency: The presentation currency to use. Only currencies that have been used for transactions will be allowed. - report date: The report date. :param filters: Report filters :type filters: dict :return: str - Currency """ company = get_appropriate_company(filters) company_currency = get_company_currency(company) presentation_currency = filters['presentation_currency'] if filters.get( 'presentation_currency') else company_currency report_date = filters.get('to_date') if not report_date: fiscal_year_to_date = get_from_and_to_date( filters.get('to_fiscal_year'))["to_date"] report_date = formatdate(get_datetime_str(fiscal_year_to_date), "dd-MM-yyyy") currency_map = dict(company=company, company_currency=company_currency, presentation_currency=presentation_currency, report_date=report_date) return currency_map
def get_payouts(shopify_settings: "ShopifySettings", start_date: str = str()): """ Request Shopify API for the latest payouts Args: shopify_settings (ShopifySettings): The Shopify configuration for the store. start_date (str, optional): The date to start pulling payouts from. Returns: list of shopify.Payout: The list of Shopify payouts, if any. """ kwargs = {} if start_date: kwargs['date_min'] = start_date elif shopify_settings.last_sync_datetime: kwargs['date_min'] = shopify_settings.last_sync_datetime else: # default to first day of current month for first sync kwargs['date_min'] = get_datetime_str(get_first_day(today())) try: payouts = shopify_settings.get_payouts(**kwargs) except Exception as e: make_shopify_log(status="Payout Error", exception=e, rollback=True) return [] else: return payouts
def get_currency(filters): """ Returns a dictionary containing currency information. The keys of the dict are - company: The company for which we are fetching currency information. if no company is specified, it will fallback to the default company. - company currency: The functional currency of the said company. - presentation currency: The presentation currency to use. Only currencies that have been used for transactions will be allowed. - report date: The report date. :param filters: Report filters :type filters: dict :return: str - Currency """ company = get_appropriate_company(filters) company_currency = get_company_currency(company) presentation_currency = filters['presentation_currency'] if filters.get('presentation_currency') else company_currency report_date = filters.get('to_date') if not report_date: fiscal_year_to_date = get_from_and_to_date(filters.get('to_fiscal_year'))["to_date"] report_date = formatdate(get_datetime_str(fiscal_year_to_date), "dd-MM-yyyy") currency_map = dict(company=company, company_currency=company_currency, presentation_currency=presentation_currency, report_date=report_date) return currency_map
def create_reply_from_customer(erpnext_support_user, subject, description, raised_by, recipients, bench_site, frappe_issue_id, attachments=None): authenticate_erpnext_support_user(erpnext_support_user) comm = frappe.get_doc({ "doctype": "Communication", "subject": subject, "content": description, "sent_or_received": "Received", "reference_doctype": "Issue", "communication_medium": "Email", "sender": raised_by, "recipients": recipients, "reference_name": frappe_issue_id, "has_attachment": 1 if attachments else 0 }).insert(ignore_permissions=True) if attachments: attachments = json.loads(attachments) for d in attachments: save_file(d.get("filename"), base64.b64decode(d.get("content")), "Communication", comm.name) frappe.db.set_value("Issue", frappe_issue_id, "status", "Open") return json.dumps({"last_sync_on": get_datetime_str(now_datetime())})
def prepare_data_for_import(self, file_content, file_name, encoded_content): for line in file_content.find_all("DatiGeneraliDocumento"): invoices_args = { "company": self.company, "naming_series": self.invoice_series, "document_type": line.TipoDocumento.text, "bill_date": get_datetime_str(line.Data.text), "bill_no": line.Numero.text, "total_discount": 0, "items": [], "buying_price_list": self.default_buying_price_list } if not invoices_args.get("bill_no", ''): frappe.throw(_("Numero has not set in the XML file")) supp_dict = get_supplier_details(file_content) invoices_args["destination_code"] = get_destination_code_from_file(file_content) self.prepare_items_for_invoice(file_content, invoices_args) invoices_args["taxes"] = get_taxes_from_file(file_content, self.tax_account) invoices_args["terms"] = get_payment_terms_from_file(file_content) supplier_name = create_supplier(self.supplier_group, supp_dict) address = create_address(supplier_name, supp_dict) pi_name = create_purchase_invoice(supplier_name, file_name, invoices_args, self.name) self.file_count += 1 if pi_name: self.purchase_invoices_count += 1 file_save = save_file(file_name, encoded_content, "Purchase Invoice", pi_name, folder=None, decode=False, is_private=0, df=None)
def import_file_by_path(path, force=False, data_import=False, pre_process=None): frappe.flags.in_import = True try: docs = read_doc_from_file(path) except IOError: print path + " missing" return if docs: if not isinstance(docs, list): docs = [docs] for doc in docs: if not force: # check if timestamps match db_modified = frappe.db.get_value(doc['doctype'], doc['name'], 'modified') if db_modified and doc.get('modified')==get_datetime_str(db_modified): return False original_modified = doc.get("modified") import_doc(doc, force=force, data_import=data_import, pre_process=pre_process) if original_modified: # since there is a new timestamp on the file, update timestamp in if doc["doctype"] == doc["name"] and doc["name"]!="DocType": frappe.db.sql("""update tabSingles set value=%s where field="modified" and doctype=%s""", (original_modified, doc["name"])) else: frappe.db.sql("update `tab%s` set modified=%s where name=%s" % \ (doc['doctype'], '%s', '%s'), (original_modified, doc['name'])) frappe.flags.in_import = False return True
def get_billing_date(current_date, billing_day=1): '''Return the next billing date from current_date''' date_obj = getdate(current_date) billing_date = date_obj.replace(day=billing_day) if billing_date <= date_obj: billing_date = add_months(billing_date, 1) return get_datetime_str(billing_date).split(' ')[0]
def create_vars_from_doc(doc: Document, key=None) -> list: """ Utility function to prepare the template vars from a doc :param doc: The document as a dictionary :param key: Optionally specify the key name. If not specified, the scrub name of the doctype will be used For instance, Sales Order will be called sales_order :return: """ if not doc: return [] doc = doc.as_dict(convert_dates_to_str=True, no_nulls=True) if len(doc) == 0: return [] doctype = doc.get("doctype").lower() template_vars = [] to_del = [] for k, v in doc.items(): # Remove iterables from the variables if isinstance(v, (list, tuple, dict)): to_del.append(k) continue # Convert date object to string if isinstance(v, datetime.date): doc[k] = get_datetime_str(v) for k in to_del: del doc[k] template_vars.append({"name": key if key is not None else frappe.scrub(doctype), "content": doc}) return template_vars
def validate(self): #Check if entry with same academic_year and the term_name already exists validate_duplication(self) self.title = self.academic_year + " ({})".format(self.term_name) if self.term_name else "" #Check that start of academic year is earlier than end of academic year if self.term_start_date and self.term_end_date and self.term_start_date > self.term_end_date: frappe.throw(_("The Term End Date cannot be earlier than the Term Start Date. Please correct the dates and try again.")) """Check that the start of the term is not before the start of the academic year and end of term is not after the end of the academic year""" year = frappe.get_doc("Academic Year",self.academic_year) if self.term_start_date and get_datetime_str(year.year_start_date) and (self.term_start_date < get_datetime_str(year.year_start_date)): frappe.throw(_("The Term Start Date cannot be earlier than the Year Start Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year)) if self.term_end_date and get_datetime_str(year.year_end_date) and (self.term_end_date > get_datetime_str(year.year_end_date)): frappe.throw(_("The Term End Date cannot be later than the Year End Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
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_post_list_html(group, view, limit_start=0, limit_length=20): from frappe.website.doctype.website_group.website_group import get_views # verify permission for paging if frappe.local.form_dict.cmd == "get_post_list_html": doc = frappe.get_doc("Website Group", group) access = get_access(doc, doc.get_route()) 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) 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 sync_payouts(self, start_date: str = str()): "Pull and sync payouts from Shopify Payments transactions" from shopify_integration.payouts import create_shopify_payouts if not start_date: start_date = get_datetime_str(get_first_day(today())) frappe.enqueue(method=create_shopify_payouts, queue='long', is_async=True, **{ "shop_name": self.name, "start_date": start_date })
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 get_exchange_rate(from_currency, to_currency, transaction_date=None, args=None): if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 if not transaction_date: transaction_date = nowdate() currency_settings = frappe.get_doc("Accounts Settings").as_dict() allow_stale_rates = currency_settings.get("allow_stale") filters = [["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency]] if args == "for_buying": filters.append(["for_buying", "=", "1"]) elif args == "for_selling": filters.append(["for_selling", "=", "1"]) if not allow_stale_rates: stale_days = currency_settings.get("stale_days") checkpoint_date = add_days(transaction_date, -stale_days) filters.append(["date", ">", get_datetime_str(checkpoint_date)]) # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all("Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) return 0.0 '''try:
def add_age_to_filter(filters, doctype, field, date): from frappe.utils import now_datetime, add_days, add_months, add_years, get_datetime_str if date == "All Time": return filters today = now_datetime() selected_dates = { 'Last 7 Days': [add_days(today,-6)], 'Last 30 Days': [add_days(today,-29)], 'This Month': [add_days(today, -today.day)], 'Last Month': [add_months(add_days(today, -today.day),-1), add_days(today, -today.day-1)], 'Last 3 Months': [add_months(add_days(today, -today.day),-3)], 'This Financial Year': [frappe.db.get_default("year_start_date"),frappe.db.get_default("year_end_date")], 'Last Financial Year': [add_years(frappe.db.get_default("year_start_date"), -1), add_years(frappe.db.get_default("year_end_date"), -1)] }[date] if len(selected_dates)==2: return filters + [[ doctype, field,">", get_datetime_str(selected_dates[0]) ], [ doctype, field, "<", get_datetime_str(selected_dates[1]) ]] else: return filters + [[ doctype, field, ">", get_datetime_str(selected_dates[0]) ]]
def autoname(self): if not self.date: self.date = nowdate() # If both selling and buying enabled purpose = "Selling-Buying" if cint(self.for_buying) == 0 and cint(self.for_selling) == 1: purpose = "Selling" if cint(self.for_buying) == 1 and cint(self.for_selling) == 0: purpose = "Buying" self.name = '{0}-{1}-{2}{3}'.format( formatdate(get_datetime_str(self.date), "yyyy-MM-dd"), self.from_currency, self.to_currency, ("-" + _(purpose)) if purpose else "")
def get_exchange_rate(from_currency, to_currency, transaction_date=None): if not transaction_date: transaction_date = nowdate() if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all( "Currency Exchange", fields=["exchange_rate"], filters=[["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency]], order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests response = requests.get("http://api.fixer.io/latest", params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.msgprint( _("Unable to find exchange rate for {0} to {1} for key date {2}"). format(from_currency, to_currency, transaction_date)) return 0.0
def deploy_package(): package, doc = export_package() file_name = "Package-" + get_datetime_str(get_datetime()) length = len(doc.instances) for idx, instance in enumerate(doc.instances): frappe.publish_realtime("package", { "progress": idx, "total": length, "message": instance.instance_url, "prefix": _("Deploying") }, user=frappe.session.user) install_package_to_remote(package, instance) frappe.db.set_value("Package Publish Tool", "Package Publish Tool", "last_deployed_on", frappe.utils.now_datetime())
def get_exchange_rate(from_currency, to_currency, transaction_date=None): if not transaction_date: transaction_date = nowdate() if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all("Currency Exchange", fields = ["exchange_rate"], filters=[ ["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency] ], order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests response = requests.get("http://api.fixer.io/latest", params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}").format(from_currency, to_currency, transaction_date)) return 0.0
def send_reminder(self): patient_first_name = frappe.db.get_value("Patient Record", self.patient_record, "patient_first_name") patient_email = self.email appointment_date = formatdate(get_datetime_str(self.start_dt), "dd/MM/yyyy") sending_date = get_datetime(self.date) + relativedelta(days=-1) start_time = get_datetime(self.start_dt).strftime("%H:%M") subject = _( """N'oubliez pas votre rendez-vous avec {0}, prévu le {1} à {2}""". format(self.practitioner, appointment_date, start_time)) content = _( """Bonjour {0}, <br><br>Votre rendez-vous est toujours prévu le {1}, à {2}. <br><br>Si vous avez un empêchement, veuillez me l'indiquer au plus vite par retour de mail.<br><br>Merci beaucoup.<br><br>{3}""" .format(patient_first_name, appointment_date, start_time, self.practitioner)) frappe.sendmail(patient_email, subject=subject, content=content, send_after=sending_date)
def sync(erpnext_support_issue=None): """ Syncs Support Issue with Server. """ fields = ["name", "frappe_issue_id", "status", "last_sync_on"] filters = [["status", "=", "Open"], ["frappe_issue_id", "!=", ""], ["last_sync_on", "!=", ""]] if erpnext_support_issue: filters.append(["name", "=", erpnext_support_issue]) support_issues = frappe.get_all("ERPNext Support Issue", filters=filters, fields=fields) if not support_issues: return erpnext_support_issues = [] # Batch issue sync requests to 10 per call for idx, issue in enumerate(support_issues): issue.last_sync_on = get_datetime_str(issue.last_sync_on) erpnext_support_issues.append(issue) if erpnext_support_issues and ( (idx and idx % 10 == 0) or idx == len(erpnext_support_issues) - 1): params = { "erpnext_support_issues": json.dumps(erpnext_support_issues) } response = call_remote_method("serve_communications_and_statuses", params) if not response: continue update_erpnext_support_issue_status_and_communications( erpnext_support_issues, json.loads(response)) erpnext_support_issues = []
def autoname(self): self.name = "OUT-" + self.type + '-' + re.sub( '[^A-Za-z0-9]+', '-', get_datetime_str(datetime.now())[2:])
def get_signature(self): """Returns signature (hash) for private URL.""" return hashlib.sha224(get_datetime_str(self.creation)).hexdigest()
def get_events(start, end, user=None, for_reminder=False, filters=None): if isinstance(filters, string_types): filters = json.loads(filters) events = frappe.db.sql("""select name, subject, description, color, starts_on, ends_on, owner, all_day, event_type, repeat_this_event, repeat_on,repeat_till, monday, tuesday, wednesday, thursday, friday, saturday, sunday, employee_emails from `tabvBooking Event` where (( (date(starts_on) between date(%(start)s) and date(%(end)s)) or (date(ends_on) between date(%(start)s) and date(%(end)s)) or (date(starts_on) <= date(%(start)s) and date(ends_on) >= date(%(end)s)) ) or ( date(starts_on) <= date(%(start)s) and repeat_this_event=1 and ifnull(repeat_till, %(max_repeat_till)s) > date(%(start)s) )) {reminder_condition} {filter_condition} order by starts_on""".format( filter_condition=get_filters_cond('Event', filters, []), reminder_condition="and ifnull(send_reminder,0)=1" if for_reminder else ""), { "max_repeat_till": max_repeat_till, "start": start, "end": end, }, as_dict=1) # process recurring events start = start.split(" ")[0] end = end.split(" ")[0] add_events = [] remove_events = [] def add_event(e, date): new_event = e.copy() enddate = add_days(date,int(date_diff(e.ends_on.split(" ")[0], e.starts_on.split(" ")[0]))) \ if (e.starts_on and e.ends_on) else date new_event.starts_on = date + " " + e.starts_on.split(" ")[1] if e.ends_on: new_event.ends_on = enddate + " " + e.ends_on.split(" ")[1] add_events.append(new_event) for e in events: if e.repeat_this_event: e.starts_on = get_datetime_str(e.starts_on) if e.ends_on: e.ends_on = get_datetime_str(e.ends_on) event_start, time_str = get_datetime_str(e.starts_on).split(" ") if cstr(e.repeat_till) == "": repeat = max_repeat_till else: repeat = e.repeat_till if e.repeat_on == "Every Year": start_year = cint(start.split("-")[0]) end_year = cint(end.split("-")[0]) event_start = "-".join(event_start.split("-")[1:]) # repeat for all years in period for year in range(start_year, end_year + 1): date = str(year) + "-" + event_start if getdate(date) >= getdate(start) and getdate( date) <= getdate(end) and getdate(date) <= getdate( repeat): add_event(e, date) remove_events.append(e) if e.repeat_on == "Every Month": date = start.split("-")[0] + "-" + start.split( "-")[1] + "-" + event_start.split("-")[2] # last day of month issue, start from prev month! try: getdate(date) except ValueError: date = date.split("-") date = date[0] + "-" + str(cint(date[1]) - 1) + "-" + date[2] start_from = date for i in range(int(date_diff(end, start) / 30) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_months(start_from, i + 1) remove_events.append(e) if e.repeat_on == "Every Week": weekday = getdate(event_start).weekday() # monday is 0 start_weekday = getdate(start).weekday() # start from nearest weeday after last monday date = add_days(start, weekday - start_weekday) for cnt in range(int(date_diff(end, start) / 7) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_days(date, 7) remove_events.append(e) if e.repeat_on == "Every Day": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(event_start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and e[weekdays[getdate(date).weekday()]]: add_event(e, date) remove_events.append(e) for e in remove_events: events.remove(e) events = events + add_events for e in events: # remove weekday properties (to reduce message size) for w in weekdays: del e[w] return events
def autoname(self): if not self.date: self.date = nowdate() self.name = '{0}-{1}-{2}'.format( formatdate(get_datetime_str(self.date), "yyyy-MM-dd"), self.from_currency, self.to_currency)
def autoname(self): if not self.date: self.date = nowdate() self.name = "{0}-{1}-{2}".format( formatdate(get_datetime_str(self.date), "yyyy-MM-dd"), self.from_currency, self.to_currency )
def get_events(start, end, user=None, for_reminder=False, filters=None): if not user: user = frappe.session.user if isinstance(filters, string_types): filters = json.loads(filters) filter_condition = get_filters_cond('Event', filters, []) tables = ["`tabEvent`"] if "`tabEvent Participants`" in filter_condition: tables.append("`tabEvent Participants`") events = frappe.db.sql(""" SELECT `tabEvent`.name, `tabEvent`.subject, `tabEvent`.description, `tabEvent`.color, `tabEvent`.starts_on, `tabEvent`.ends_on, `tabEvent`.owner, `tabEvent`.all_day, `tabEvent`.event_type, `tabEvent`.repeat_this_event, `tabEvent`.repeat_on, `tabEvent`.repeat_till, `tabEvent`.monday, `tabEvent`.tuesday, `tabEvent`.wednesday, `tabEvent`.thursday, `tabEvent`.friday, `tabEvent`.saturday, `tabEvent`.sunday FROM {tables} WHERE ( ( (date(`tabEvent`.starts_on) BETWEEN date(%(start)s) AND date(%(end)s)) OR (date(`tabEvent`.ends_on) BETWEEN date(%(start)s) AND date(%(end)s)) OR ( date(`tabEvent`.starts_on) <= date(%(start)s) AND date(`tabEvent`.ends_on) >= date(%(end)s) ) ) OR ( date(`tabEvent`.starts_on) <= date(%(start)s) AND `tabEvent`.repeat_this_event=1 AND coalesce(`tabEvent`.repeat_till, '3000-01-01') > date(%(start)s) ) ) {reminder_condition} {filter_condition} AND ( `tabEvent`.event_type='Public' OR `tabEvent`.owner=%(user)s OR EXISTS( SELECT `tabDocShare`.name FROM `tabDocShare` WHERE `tabDocShare`.share_doctype='Event' AND `tabDocShare`.share_name=`tabEvent`.name AND `tabDocShare`.user=%(user)s ) ) AND `tabEvent`.status='Open' ORDER BY `tabEvent`.starts_on""".format( tables=", ".join(tables), filter_condition=filter_condition, reminder_condition="AND coalesce(`tabEvent`.send_reminder, 0)=1" if for_reminder else "" ), { "start": start, "end": end, "user": user, }, as_dict=1) # process recurring events start = start.split(" ")[0] end = end.split(" ")[0] add_events = [] remove_events = [] def add_event(e, date): new_event = e.copy() enddate = add_days(date,int(date_diff(e.ends_on.split(" ")[0], e.starts_on.split(" ")[0]))) \ if (e.starts_on and e.ends_on) else date new_event.starts_on = date + " " + e.starts_on.split(" ")[1] new_event.ends_on = new_event.ends_on = enddate + " " + e.ends_on.split(" ")[1] if e.ends_on else None add_events.append(new_event) for e in events: if e.repeat_this_event: e.starts_on = get_datetime_str(e.starts_on) e.ends_on = get_datetime_str(e.ends_on) if e.ends_on else None event_start, time_str = get_datetime_str(e.starts_on).split(" ") repeat = "3000-01-01" if cstr(e.repeat_till) == "" else e.repeat_till if e.repeat_on == "Yearly": start_year = cint(start.split("-")[0]) end_year = cint(end.split("-")[0]) # creates a string with date (27) and month (07) eg: 07-27 event_start = "-".join(event_start.split("-")[1:]) # repeat for all years in period for year in range(start_year, end_year+1): date = str(year) + "-" + event_start if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) and getdate(date) <= getdate(repeat): add_event(e, date) remove_events.append(e) if e.repeat_on == "Monthly": # creates a string with date (27) and month (07) and year (2019) eg: 2019-07-27 date = start.split("-")[0] + "-" + start.split("-")[1] + "-" + event_start.split("-")[2] # last day of month issue, start from prev month! try: getdate(date) except ValueError: date = date.split("-") date = date[0] + "-" + str(cint(date[1]) - 1) + "-" + date[2] start_from = date for i in range(int(date_diff(end, start) / 30) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_months(start_from, i+1) remove_events.append(e) if e.repeat_on == "Weekly": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start) \ and e[weekdays[getdate(date).weekday()]]: add_event(e, date) remove_events.append(e) if e.repeat_on == "Daily": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(event_start) and getdate(date) <= getdate(end) and getdate(date) <= getdate(repeat): add_event(e, date) remove_events.append(e) for e in remove_events: events.remove(e) events = events + add_events for e in events: # remove weekday properties (to reduce message size) for w in weekdays: del e[w] return events
def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=None): if not (from_currency and to_currency): # manqala 19/09/2016: Should this be an empty return or should it throw and exception? return if from_currency == to_currency: return 1 if not transaction_date: transaction_date = nowdate() currency_settings = frappe.get_doc("Accounts Settings").as_dict() allow_stale_rates = currency_settings.get("allow_stale") filters = [ ["date", "<=", get_datetime_str(transaction_date)], ["from_currency", "=", from_currency], ["to_currency", "=", to_currency], ] if args == "for_buying": filters.append(["for_buying", "=", "1"]) elif args == "for_selling": filters.append(["for_selling", "=", "1"]) if not allow_stale_rates: stale_days = currency_settings.get("stale_days") checkpoint_date = add_days(transaction_date, -stale_days) filters.append(["date", ">", get_datetime_str(checkpoint_date)]) # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency. entries = frappe.get_all("Currency Exchange", fields=["exchange_rate"], filters=filters, order_by="date desc", limit=1) if entries: return flt(entries[0].exchange_rate) try: cache = frappe.cache() key = "currency_exchange_rate_{0}:{1}:{2}".format( transaction_date, from_currency, to_currency) value = cache.get(key) if not value: import requests settings = frappe.get_cached_doc("Currency Exchange Settings") req_params = { "transaction_date": transaction_date, "from_currency": from_currency, "to_currency": to_currency, } params = {} for row in settings.req_params: params[row.key] = format_ces_api(row.value, req_params) response = requests.get(format_ces_api(settings.api_endpoint, req_params), params=params) # expire in 6 hours response.raise_for_status() value = response.json() for res_key in settings.result_key: value = value[format_ces_api(str(res_key.key), req_params)] cache.setex(name=key, time=21600, value=flt(value)) return flt(value) except Exception: frappe.log_error("Unable to fetch exchange rate") frappe.msgprint( _("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually" ).format(from_currency, to_currency, transaction_date)) return 0.0
print("venda") bfa_i += 1 print("DONE =============") #Geral cambios_ = frappe.db.sql( """ select name,from_currency,to_currency,max(date),exchange_rate from `tabCurrency Exchange` where to_currency='kz' and from_currency=%s ;""", (moeda), as_dict=True) print "moeda ", moeda print cambios_[0]['max(date)'] print formatdate(get_datetime_str(frappe.utils.nowdate()), "YYY-MM-dd") print formatdate(cambios_[0]['max(date)'], "YYYY-MM-dd") == formatdate( get_datetime_str(frappe.utils.nowdate()), "YYY-MM-dd") if type(moedavenda) == str: #BFA uses , instead of . moedavenda = moedavenda.replace(",", ".") moedavenda = float(moedavenda) elif moedacompra == 0 and moedavenda == 0: #BIC or others with , print moedacompraUSD print moedavendaUSD moedavenda = moedavendaUSD
def get_events(start, end, user=None, for_reminder=False): if not user: user = frappe.session.user roles = frappe.get_roles(user) events = frappe.db.sql("""select name, subject, description, starts_on, ends_on, owner, all_day, event_type, repeat_this_event, repeat_on,repeat_till, monday, tuesday, wednesday, thursday, friday, saturday, sunday from tabEvent where (( (date(starts_on) between date(%(start)s) and date(%(end)s)) or (date(ends_on) between date(%(start)s) and date(%(end)s)) or (date(starts_on) <= date(%(start)s) and date(ends_on) >= date(%(end)s)) ) or ( date(starts_on) <= date(%(start)s) and repeat_this_event=1 and ifnull(repeat_till, "3000-01-01") > date(%(start)s) )) {reminder_condition} and (event_type='Public' or owner=%(user)s or exists(select name from `tabDocShare` where tabDocShare.share_doctype="Event" and `tabDocShare`.share_name=tabEvent.name and tabDocShare.user=%(user)s) or exists(select * from `tabEvent Role` where `tabEvent Role`.parent=tabEvent.name and `tabEvent Role`.role in ({roles}))) order by starts_on""".format( reminder_condition="and ifnull(send_reminder,0)=1" if for_reminder else "", roles=", ".join('"{}"'.format(frappe.db.escape(r)) for r in roles) ), { "start": start, "end": end, "user": user, }, as_dict=1) # process recurring events start = start.split(" ")[0] end = end.split(" ")[0] add_events = [] remove_events = [] def add_event(e, date): new_event = e.copy() enddate = add_days(date,int(date_diff(e.ends_on.split(" ")[0], e.starts_on.split(" ")[0]))) \ if (e.starts_on and e.ends_on) else date new_event.starts_on = date + " " + e.starts_on.split(" ")[1] if e.ends_on: new_event.ends_on = enddate + " " + e.ends_on.split(" ")[1] add_events.append(new_event) for e in events: if e.repeat_this_event: e.starts_on = get_datetime_str(e.starts_on) if e.ends_on: e.ends_on = get_datetime_str(e.ends_on) event_start, time_str = get_datetime_str(e.starts_on).split(" ") if cstr(e.repeat_till) == "": repeat = "3000-01-01" else: repeat = e.repeat_till if e.repeat_on=="Every Year": start_year = cint(start.split("-")[0]) end_year = cint(end.split("-")[0]) event_start = "-".join(event_start.split("-")[1:]) # repeat for all years in period for year in range(start_year, end_year+1): date = str(year) + "-" + event_start if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) and getdate(date) <= getdate(repeat): add_event(e, date) remove_events.append(e) if e.repeat_on=="Every Month": date = start.split("-")[0] + "-" + start.split("-")[1] + "-" + event_start.split("-")[2] # last day of month issue, start from prev month! try: getdate(date) except ValueError: date = date.split("-") date = date[0] + "-" + str(cint(date[1]) - 1) + "-" + date[2] start_from = date for i in xrange(int(date_diff(end, start) / 30) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_months(start_from, i+1) remove_events.append(e) if e.repeat_on=="Every Week": weekday = getdate(event_start).weekday() # monday is 0 start_weekday = getdate(start).weekday() # start from nearest weeday after last monday date = add_days(start, weekday - start_weekday) for cnt in xrange(int(date_diff(end, start) / 7) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_days(date, 7) remove_events.append(e) if e.repeat_on=="Every Day": for cnt in xrange(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(event_start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and e[weekdays[getdate(date).weekday()]]: add_event(e, date) remove_events.append(e) for e in remove_events: events.remove(e) events = events + add_events for e in events: # remove weekday properties (to reduce message size) for w in weekdays: del e[w] return events
def serve_communications_and_statuses(erpnext_support_user, erpnext_support_issues, bench_site): """ returns a dict of support issue communications and statuses response = { "issue_name_1": { "communications": [], "status": "status", "last_sync_on": "last_sync_on" }, "issue_name_2": { "communications": [], "status": "status", "last_sync_on": "last_sync_on" } } """ authenticate_erpnext_support_user(erpnext_support_user) sync_time = get_datetime_str(now_datetime()) res = {} for erpnext_support_issue in json.loads(erpnext_support_issues): if not erpnext_support_issue.get("frappe_issue_id"): continue # Sync Communications for Issue fields = ["name", "subject", "content", "recipients", "has_attachment"] filters = [["reference_doctype", "=", "Issue"], [ "reference_name", "=", erpnext_support_issue.get("frappe_issue_id") ], ["communication_medium", "=", "Email"], [ "creation", ">", get_datetime(erpnext_support_issue.get("last_sync_on")) ]] communications = frappe.get_all("Communication", filters=filters, fields=fields, order_by="creation ASC") # Sync Attachments for Communications communications = get_attachments(communications) # Sync Status for Issue frappe_issue = frappe.get_doc( "Issue", erpnext_support_issue.get("frappe_issue_id")) res[erpnext_support_issue.get("name")] = { "communications": communications, "status": "Open" if frappe_issue.get("status") not in ["Open", "Closed"] else frappe_issue.get("status"), "priority": frappe_issue.get("priority"), "resolution_by": get_datetime_str(frappe_issue.resolution_by) if frappe_issue.resolution_by else None, "last_sync_on": sync_time, "release": frappe_issue.get("release") } return json.dumps(res)
def serve_split_issues(erpnext_support_user, bench_site): """ returns a dict of support issue communications and statuses of split issues response = { "issue_name_1": "{ "issue": [], "communications": [], "last_sync_on": "last_sync_on" }", "issue_name_2": "{ "issue": [], "communications": [], "last_sync_on": "last_sync_on" }" } """ authenticate_erpnext_support_user(erpnext_support_user) res = {} sync_time = get_datetime_str(now_datetime()) fields = [ "name", "subject", "raised_by", "module", "issue_type", "owner", "status", "priority", "resolution_by" ] filters = [["bench_site", "=", bench_site], ["issue_split_from", "!=", ""], ["client_issue_id", "=", ""], ["split_issue_sync", "=", 0]] for split_issue in frappe.get_all("Issue", filters=filters, fields=fields): frappe.db.set_value("Issue", split_issue.name, "split_issue_sync", 1) fields = [ "name", "subject", "content", "recipients", "sent_or_received", "has_attachment" ] filters = [["reference_doctype", "=", "Issue"], ["reference_name", "=", split_issue.name], ["communication_medium", "=", "Email"]] # Sync Communications for Issue communications = frappe.get_all("Communication", filters=filters, fields=fields, order_by="creation ASC") # Sync Attachments for Communications communications = get_attachments(communications) res[split_issue.name] = { "frappe_issue_id": split_issue.get("name"), "subject": split_issue.get("subject"), "communications": communications, "last_sync_on": sync_time, "status": split_issue.get("status"), "priority": split_issue.get("priority"), "resolution_by": get_datetime_str(split_issue.resolution_by) if split_issue.resolution_by else None, "release": split_issue.get("release"), "raised_by": split_issue.get("raised_by"), "issue_type": split_issue.get("issue_type") } return json.dumps(res)
def get_repeat_events(e): if e.repeat_this_event: e.starts_on = get_datetime_str(e.starts_on) if e.ends_on: e.ends_on = get_datetime_str(e.ends_on) event_start, time_str = get_datetime_str( e.starts_on).split(" ") if cstr(e.repeat_till) == "": repeat = max_repeat_till else: repeat = e.repeat_till if e.repeat_on == "Every Year": start_year = cint(start.split("-")[0]) end_year = cint(end.split("-")[0]) event_start = "-".join(event_start.split("-")[1:]) # repeat for all years in period for year in range(start_year, end_year + 1): date = str(year) + "-" + event_start if getdate(date) >= getdate(start) and getdate( date) <= getdate(end) and getdate( date) <= getdate(repeat): add_event(e, date) remove_events.append(e) if e.repeat_on == "Every Month": date = start.split("-")[0] + "-" + start.split( "-")[1] + "-" + event_start.split("-")[2] # last day of month issue, start from prev month! try: getdate(date) except ValueError: date = date.split("-") date = date[0] + "-" + str(cint(date[1]) - 1) + "-" + date[2] start_from = date for i in range(int(date_diff(end, start) / 30) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_months(start_from, i + 1) remove_events.append(e) if e.repeat_on == "Every Week": weekday = getdate(event_start).weekday() # monday is 0 start_weekday = getdate(start).weekday() # start from nearest weeday after last monday date = add_days(start, weekday - start_weekday) for cnt in range(int(date_diff(end, start) / 7) + 3): if getdate(date) >= getdate(start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and getdate(date) >= getdate(event_start): add_event(e, date) date = add_days(date, 7) remove_events.append(e) if e.repeat_on == "Every Day": for cnt in range(date_diff(end, start) + 1): date = add_days(start, cnt) if getdate(date) >= getdate(event_start) and getdate(date) <= getdate(end) \ and getdate(date) <= getdate(repeat) and e[weekdays[getdate(date).weekday()]]: add_event(e, date) remove_events.append(e)