def get_item_group_defaults(item, company): item = frappe.get_cached_doc("Item", item) item_group = frappe.get_cached_doc("Item Group", item.item_group) for d in item_group.item_group_defaults or []: if d.company == company: row = copy.deepcopy(d.as_dict()) row.pop("name") return row return frappe._dict()
def get_pos_profile(company, pos_profile=None, user=None): if pos_profile: return frappe.get_cached_doc('POS Profile', pos_profile) if not user: user = frappe.session['user'] condition = "pfu.user = %(user)s AND pfu.default=1" if user and company: condition = "pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1" pos_profile = frappe.db.sql("""SELECT pf.* FROM `tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu ON pf.name = pfu.parent WHERE {cond} AND pf.disabled = 0 """.format(cond = condition), { 'user': user, 'company': company }, as_dict=1) if not pos_profile and company: pos_profile = frappe.db.sql("""SELECT pf.* FROM `tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu ON pf.name = pfu.parent WHERE pf.company = %(company)s AND pf.disabled = 0 """, { 'company': company }, as_dict=1) return pos_profile and pos_profile[0] or None
def calculate_service_end_date(args, item=None): args = process_args(args) if not item: item = frappe.get_cached_doc("Item", args.item_code) doctype = args.get("parenttype") or args.get("doctype") if doctype == "Sales Invoice": enable_deferred = "enable_deferred_revenue" no_of_months = "no_of_months" account = "deferred_revenue_account" else: enable_deferred = "enable_deferred_expense" no_of_months = "no_of_months_exp" account = "deferred_expense_account" service_start_date = args.service_start_date if args.service_start_date else args.transaction_date service_end_date = add_months(service_start_date, item.get(no_of_months)) deferred_detail = { "service_start_date": service_start_date, "service_end_date": service_end_date } deferred_detail[enable_deferred] = item.get(enable_deferred) deferred_detail[account] = get_default_deferred_account(args, item, fieldname=account) return deferred_detail
def get_item_groups(pos_profile): item_groups = [] pos_profile = frappe.get_cached_doc('POS Profile', pos_profile) if pos_profile.get('item_groups'): # Get items based on the item groups defined in the POS profile for data in pos_profile.get('item_groups'): item_groups.extend(["'%s'" % frappe.db.escape(d.name) for d in get_child_nodes('Item Group', data.item_group)]) return list(set(item_groups))
def get_item_defaults(item_code, company): item = frappe.get_cached_doc('Item', item_code) out = item.as_dict() for d in item.item_defaults: if d.company == company: row = copy.deepcopy(d.as_dict()) row.pop("name") out.update(row) return out
def make_material_request(self): '''Create Material Requests grouped by Sales Order and Material Request Type''' material_request_list = [] material_request_map = {} for item in self.mr_items: item_doc = frappe.get_cached_doc('Item', item.item_code) # key for Sales Order:Material Request Type key = '{}:{}'.format(item.sales_order, item_doc.default_material_request_type) schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) if not key in material_request_map: # make a new MR for the combination material_request_map[key] = frappe.new_doc("Material Request") material_request = material_request_map[key] material_request.update({ "transaction_date": nowdate(), "status": "Draft", "company": self.company, "requested_by": frappe.session.user, 'material_request_type': item_doc.default_material_request_type }) material_request_list.append(material_request) else: material_request = material_request_map[key] # add item material_request.append("items", { "item_code": item.item_code, "qty": item.quantity, "schedule_date": schedule_date, "warehouse": item.warehouse, "sales_order": item.sales_order, 'production_plan': self.name, 'material_request_plan_item': item.name, "project": frappe.db.get_value("Sales Order", item.sales_order, "project") \ if item.sales_order else None }) for material_request in material_request_list: # submit material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") material_request.submit() frappe.flags.mute_messages = False if material_request_list: material_request_list = ["""<a href="#Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \ for m in material_request_list] msgprint(_("{0} created").format(comma_and(material_request_list))) else : msgprint(_("No material request created"))
def link_address(self): """Link address based on owner""" if not self.links and not self.is_your_company_address: contact_name = frappe.db.get_value("Contact", {"email_id": self.owner}) if contact_name: contact = frappe.get_cached_doc('Contact', contact_name) for link in contact.links: self.append('links', dict(link_doctype=link.link_doctype, link_name=link.link_name)) return True return False
def validate_item(self): """ Validate whether serial no is required for this item """ item = frappe.get_cached_doc("Item", self.item_code) if item.has_serial_no!=1: frappe.throw(_("Item {0} is not setup for Serial Nos. Check Item master").format(self.item_code)) self.item_group = item.item_group self.description = item.description self.item_name = item.item_name self.brand = item.brand self.warranty_period = item.warranty_period
def set_item_default(item_code, company, fieldname, value): item = frappe.get_cached_doc('Item', item_code) for d in item.item_defaults: if d.company == company: if not d.get(fieldname): frappe.db.set_value(d.doctype, d.name, fieldname, value) return # no row found, add a new row for the company d = item.append('item_defaults', {fieldname: value, "company": company}) d.db_insert() item.clear_cache()
def fetch_cta(self): if frappe.db.get_single_value("Blog Settings", "show_cta_in_blog", cache=True): blog_settings = frappe.get_cached_doc("Blog Settings") return { "show_cta_in_blog": 1, "title": blog_settings.title, "subtitle": blog_settings.subtitle, "cta_label": blog_settings.cta_label, "cta_url": blog_settings.cta_url, } return {}
def get_tax_template(doctype, txt, searchfield, start, page_len, filters): item_doc = frappe.get_cached_doc('Item', filters.get('item_code')) item_group = filters.get('item_group') taxes = item_doc.taxes or [] while item_group: item_group_doc = frappe.get_cached_doc('Item Group', item_group) taxes += item_group_doc.taxes or [] item_group = item_group_doc.parent_item_group if not taxes: return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """) else: args = { 'item_code': filters.get('item_code'), 'posting_date': filters.get('valid_from'), 'tax_category': filters.get('tax_category') } taxes = _get_item_tax_template(args, taxes, for_validate=True) return [(d, ) for d in set(taxes)]
def get_party_open_orders(party): sales_invoices = [ frappe.get_cached_doc("Sales Invoice", x.get("name")) for x in frappe.db.sql( """ SELECT name FROM `tabSales Invoice` WHERE docstatus = 1 AND outstanding_amount > 0 AND customer = %(customer)s """, values={ "customer": frappe.get_cached_value("Booking Party", party, "customer") }, as_dict=1, ) ] booking_orders = [ frappe.get_cached_doc("Booking Order", name) for name in set([x.gg_booking_order for x in sales_invoices if x]) ] return {"booking_orders": booking_orders, "sales_invoices": sales_invoices}
def get_item_groups(pos_profile): item_groups = [] pos_profile = frappe.get_cached_doc('POS Profile', pos_profile) if pos_profile.get('item_groups'): # Get items based on the item groups defined in the POS profile for data in pos_profile.get('item_groups'): item_groups.extend([ "%s" % frappe.db.escape(d.name) for d in get_child_nodes('Item Group', data.item_group) ]) return list(set(item_groups))
def validate_ip_address(user): """check if IP Address is valid""" user = frappe.get_cached_doc("User", user) ip_list = user.get_restricted_ip_list() if not ip_list: return system_settings = frappe.get_cached_doc("System Settings") # check if bypass restrict ip is enabled for all users bypass_restrict_ip_check = system_settings.bypass_restrict_ip_check_if_2fa_enabled # check if two factor auth is enabled if system_settings.enable_two_factor_auth and not bypass_restrict_ip_check: # check if bypass restrict ip is enabled for login user bypass_restrict_ip_check = user.bypass_restrict_ip_check_if_2fa_enabled for ip in ip_list: if frappe.local.request_ip.startswith(ip) or bypass_restrict_ip_check: return frappe.throw(_("Access not allowed from this IP Address"), frappe.AuthenticationError)
def sync_customer_with_leaflink(customer_name): """ Sync a customer with leaflink by hitting Sync with Customer Button. """ leaflink_settings = frappe.get_cached_doc("LeafLink Settings") header = { leaflink_settings.get("api_key"): leaflink_settings.get("api_value") } #validate if leaflink is enabled if not leaflink_settings.get("enable_leaflink"): frappe.throw("Please enable LeafLink in LeafLink Settings.") #check if customer exists on leaflink try: customers_on_leaflink = requests.get( leaflink_settings.get("customers_url"), headers=header, params={ "name": customer_name }).json() except Exception as e: frappe.throw( _("An Exception: {e} occured while trying to sync customer on LeafLink. Please try again." .format(e))) #create customer record on leaflink if it does not exist if not customers_on_leaflink.get("count"): #create new customer data new_customer = { "name": customer_name, "owner": leaflink_settings.get("leaflink_id") } #post request to create customer in leaflink try: post_response = requests.post( leaflink_settings.get("customers_url"), headers=header, data=new_customer) if post_response.status_code == 201: frappe.msgprint( _("Customer successfully created on LeafLink!")) except Exception as e: frappe.throw( _("An Exception: {e} occured while trying to sync customer on LeafLink. Please try again." .format(e))) else: frappe.msgprint(_("Customer already exists on LeafLink!"))
def check_workstation_time(self, row): workstation_doc = frappe.get_cached_doc("Workstation", self.workstation) if (not workstation_doc.working_hours or cint(frappe.db.get_single_value("Manufacturing Settings", "allow_overtime"))): if get_datetime(row.planned_end_time) < get_datetime(row.planned_start_time): row.planned_end_time = add_to_date(row.planned_start_time, minutes=row.time_in_mins) row.remaining_time_in_mins = 0.0 else: row.remaining_time_in_mins -= time_diff_in_minutes(row.planned_end_time, row.planned_start_time) self.update_time_logs(row) return start_date = getdate(row.planned_start_time) start_time = get_time(row.planned_start_time) new_start_date = workstation_doc.validate_workstation_holiday(start_date) if new_start_date != start_date: row.planned_start_time = datetime.datetime.combine(new_start_date, start_time) start_date = new_start_date total_idx = len(workstation_doc.working_hours) for i, time_slot in enumerate(workstation_doc.working_hours): workstation_start_time = datetime.datetime.combine(start_date, get_time(time_slot.start_time)) workstation_end_time = datetime.datetime.combine(start_date, get_time(time_slot.end_time)) if (get_datetime(row.planned_start_time) >= workstation_start_time and get_datetime(row.planned_start_time) <= workstation_end_time): time_in_mins = time_diff_in_minutes(workstation_end_time, row.planned_start_time) # If remaining time fit in workstation time logs else split hours as per workstation time if time_in_mins > row.remaining_time_in_mins: row.planned_end_time = add_to_date(row.planned_start_time, minutes=row.remaining_time_in_mins) row.remaining_time_in_mins = 0 else: row.planned_end_time = add_to_date(row.planned_start_time, minutes=time_in_mins) row.remaining_time_in_mins -= time_in_mins self.update_time_logs(row) if total_idx != (i+1) and row.remaining_time_in_mins > 0: row.planned_start_time = datetime.datetime.combine(start_date, get_time(workstation_doc.working_hours[i+1].start_time)) if row.remaining_time_in_mins > 0: start_date = add_days(start_date, 1) row.planned_start_time = datetime.datetime.combine(start_date, get_time(workstation_doc.working_hours[0].start_time))
def get_product_list_for_group(product_group=None, start=0, limit=10, search=None): if product_group: item_group = frappe.get_cached_doc('Item Group', product_group) if item_group.is_group: # return child item groups if the type is of "Is Group" return get_child_groups_for_list_in_html(item_group, start, limit, search) child_groups = ", ".join( [frappe.db.escape(i[0]) for i in get_child_groups(product_group)]) # base query query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group, I.description, I.web_long_description as website_description, I.is_stock_item, case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse, I.has_batch_no from `tabItem` I left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse where I.show_in_website = 1 and I.disabled = 0 and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s) and (I.variant_of = '' or I.variant_of is null) and (I.item_group in ({child_groups}) or I.name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups}))) """.format(child_groups=child_groups) # search term condition if search: query += """ and (I.web_long_description like %(search)s or I.item_name like %(search)s or I.name like %(search)s)""" search = "%" + cstr(search) + "%" query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % ( start, limit) data = frappe.db.sql(query, { "product_group": product_group, "search": search, "today": nowdate() }, as_dict=1) data = adjust_qty_for_expired_items(data) if cint(frappe.db.get_single_value("Shopping Cart Settings", "enabled")): for item in data: set_product_info_for_website(item) return data
def make_raw_material_request(items, company, sales_order, project=None): if not frappe.has_permission("Sales Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) if isinstance(items, string_types): items = frappe._dict(json.loads(items)) for item in items.get('items'): item["include_exploded_items"] = items.get('include_exploded_items') item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty') item["include_raw_materials_from_sales_order"] = items.get('include_raw_materials_from_sales_order') items.update({ 'company': company, 'sales_order': sales_order }) raw_materials = get_items_for_material_requests(items) if not raw_materials: frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available.")) return material_request = frappe.new_doc('Material Request') material_request.update(dict( doctype = 'Material Request', transaction_date = nowdate(), company = company, requested_by = frappe.session.user, material_request_type = 'Purchase' )) for item in raw_materials: item_doc = frappe.get_cached_doc('Item', item.get('item_code')) schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) row = material_request.append('items', { 'item_code': item.get('item_code'), 'qty': item.get('quantity'), 'schedule_date': schedule_date, 'warehouse': item.get('warehouse'), 'sales_order': sales_order, 'project': project }) if not (strip_html(item.get("description")) and strip_html(item_doc.description)): row.description = item_doc.item_name or item.get('item_code') material_request.insert() material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") material_request.submit() return material_request
def calc_delivery_charges(doc): if not doc.pos_profile: return old_doc = None calculate_taxes_and_totals = False if not doc.is_new(): old_doc = doc.get_doc_before_save() if not doc.posa_delivery_charges and not old_doc.posa_delivery_charges: return else: if not doc.posa_delivery_charges: return if not doc.posa_delivery_charges: doc.posa_delivery_charges_rate = 0 charges_doc = None if doc.posa_delivery_charges: charges_doc = frappe.get_cached_doc("Delivery Charges", doc.posa_delivery_charges) doc.posa_delivery_charges_rate = charges_doc.default_rate charges_profile = next((i for i in charges_doc.profiles if i.pos_profile == doc.pos_profile), None) if charges_profile: doc.posa_delivery_charges_rate = charges_profile.rate if old_doc and old_doc.posa_delivery_charges: old_charges = next( (i for i in doc.taxes if i.charge_type == "Actual" and i.description == old_doc.posa_delivery_charges), None, ) if old_charges: doc.taxes.remove(old_charges) calculate_taxes_and_totals = True if doc.posa_delivery_charges: doc.append( "taxes", { "charge_type": "Actual", "description": doc.posa_delivery_charges, "tax_amount": doc.posa_delivery_charges_rate, "cost_center": charges_doc.cost_center, "account_head": charges_doc.shipping_account, }, ) calculate_taxes_and_totals = True if calculate_taxes_and_totals: doc.calculate_taxes_and_totals()
def validate_item_tax_template(self): for item in self.doc.get("items"): if item.item_code and item.get("item_tax_template"): item_doc = frappe.get_cached_doc("Item", item.item_code) args = { "net_rate": item.net_rate or item.rate, "tax_category": self.doc.get("tax_category"), "posting_date": self.doc.get("posting_date"), "bill_date": self.doc.get("bill_date"), "transaction_date": self.doc.get("transaction_date"), "company": self.doc.get("company"), } item_group = item_doc.item_group item_group_taxes = [] while item_group: item_group_doc = frappe.get_cached_doc( "Item Group", item_group) item_group_taxes += item_group_doc.taxes or [] item_group = item_group_doc.parent_item_group item_taxes = item_doc.taxes or [] if not item_group_taxes and (not item_taxes): # No validation if no taxes in item or item group continue taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True) if taxes: if item.item_tax_template not in taxes: item.item_tax_template = taxes[0] frappe.msgprint( _("Row {0}: Item Tax template updated as per validity and rate applied" ).format(item.idx, frappe.bold(item.item_code)))
def set_document_detail_in_return_document(doctype): """Map each row of the original document in the return document.""" mapped = [] return_document_map = defaultdict(list) detail_field = "purchase_receipt_item" if doctype == "Purchase Receipt" else "dn_detail" child_doc = frappe.scrub("{0} Item".format(doctype)) frappe.reload_doc("stock", "doctype", child_doc) return_document_map = make_return_document_map(doctype, return_document_map) count = 0 #iterate through original documents and its return documents for docname in return_document_map: doc_items = frappe.get_cached_doc(doctype, docname).get("items") for return_doc in return_document_map[docname]: return_doc_items = frappe.get_cached_doc( doctype, return_doc).get("items") #iterate through return document items and original document items for mapping for return_item in return_doc_items: for doc_item in doc_items: if row_is_mappable(doc_item, return_item, detail_field) and doc_item.get( 'name') not in mapped: map_rows(doc_item, return_item, detail_field, doctype) mapped.append(doc_item.get('name')) break else: continue # commit after every 100 sql updates count += 1 if count % 100 == 0: frappe.db.commit()
def repost_entries(): riv_entries = get_repost_item_valuation_entries() for row in riv_entries: doc = frappe.get_cached_doc('Repost Item Valuation', row.name) repost(doc) riv_entries = get_repost_item_valuation_entries() if riv_entries: return for d in frappe.get_all('Company', filters={'enable_perpetual_inventory': 1}): check_if_stock_and_account_balance_synced(today(), d.name)
def create_regular_web_item(item_code=None, item_args=None, web_args=None): "Create Regular Item and Website Item." item_code = item_code or "Test Mobile Phone" item = make_item(item_code, properties=item_args) if not frappe.db.exists("Website Item", {"item_code": item_code}): web_item = make_website_item(item, save=False) if web_args: web_item.update(web_args) web_item.save() else: web_item = frappe.get_cached_doc("Website Item", {"item_code": item_code}) return web_item
def check_stock_frozen_date(self): stock_settings = frappe.get_cached_doc('Stock Settings') if stock_settings.stock_frozen_upto: if (getdate(self.posting_date) <= getdate(stock_settings.stock_frozen_upto) and stock_settings.stock_auth_role not in frappe.get_roles()): frappe.throw(_("Stock transactions before {0} are frozen") .format(formatdate(stock_settings.stock_frozen_upto)), StockFreezeError) stock_frozen_upto_days = cint(stock_settings.stock_frozen_upto_days) if stock_frozen_upto_days: older_than_x_days_ago = (add_days(getdate(self.posting_date), stock_frozen_upto_days) <= date.today()) if older_than_x_days_ago and stock_settings.stock_auth_role not in frappe.get_roles(): frappe.throw(_("Not allowed to update stock transactions older than {0}").format(stock_frozen_upto_days), StockFreezeError)
def get_context(context): context.body_class = "product-page" settings = frappe.get_cached_doc("E Commerce Settings") context.categories_enabled = settings.enable_field_filters if context.categories_enabled: categories = [row.fieldname for row in settings.filter_fields] context.tabs = get_tabs(categories) if settings.slideshow: context.slideshow = get_slideshow(settings.slideshow) context.no_cache = 1
def get_stages_from_project_type(project_type): if not project_type: frappe.throw(_("Project Type not provided")) doc = frappe.get_cached_doc("Project Type", project_type) stages = [{ "project_timeline": d.project_timeline, "project_stage": d.project_stage } for d in doc.stages] stages = sorted(stages, key=lambda d: (not frappe.get_cached_value( "Project Timeline", d.get('project_timeline'), "single_stage"), d.get('project_timeline'))) return stages
def get_doc_content(content_type): if content_type == "about": about = frappe.get_cached_doc("About Us Settings") return {"content": about.company_introduction} if content_type in ["privacy", "terms"]: settings = frappe.get_single("Ahong eCommerce Settings") if settings.get(content_type): content = frappe.get_cached_value( "Terms and Conditions", settings.get(content_type), "terms" ) return {"content": content} return {"content": None}
def get_item_tax_info(company, tax_category, item_codes): out = {} if isinstance(item_codes, string_types): item_codes = json.loads(item_codes) for item_code in item_codes: if not item_code or item_code in out: continue out[item_code] = {} item = frappe.get_cached_doc("Item", item_code) get_item_tax_template({"tax_category": tax_category}, item, out[item_code]) out[item_code]["item_tax_rate"] = get_item_tax_map(company, out[item_code].get("item_tax_template"), as_json=True) return out
def get_pages_to_extend(self): pages = frappe.get_all("Workspace", filters={ "extends": self.page_name, 'restrict_to_domain': ['in', frappe.get_active_domains()], 'for_user': '', 'module': ['in', self.allowed_modules] }) pages = [frappe.get_cached_doc("Workspace", page['name']) for page in pages] for page in pages: self.extended_links = self.extended_links + page.get_link_groups() self.extended_charts = self.extended_charts + page.charts self.extended_shortcuts = self.extended_shortcuts + page.shortcuts
def set_roles_and_modules_based_on_user_type(self): user_type_doc = frappe.get_cached_doc("User Type", self.user_type) if user_type_doc.role: self.roles = [] # Check whether User has linked with the 'Apply User Permission On' doctype or not if user_linked_with_permission_on_doctype(user_type_doc, self.name): self.append("roles", {"role": user_type_doc.role}) frappe.msgprint( _("Role has been set as per the user type {0}").format(self.user_type), alert=True ) user_type_doc.update_modules_in_user(self)
def get_bin(item_code, warehouse): bin = frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}) if not bin: bin_obj = frappe.get_doc({ "doctype": "Bin", "item_code": item_code, "warehouse": warehouse, }) bin_obj.flags.ignore_permissions = 1 bin_obj.insert() else: bin_obj = frappe.get_cached_doc('Bin', bin) bin_obj.flags.ignore_permissions = True return bin_obj
def poll_and_process_new_messages(): """ Scheduled method that looks for any pending messages to be processed. Currently only 5 messages are picked up for processing to ensure too many messages are not picked up. Messages are sorted by time they were received at, to ensure processing in same order as receipt. However, this order is not guaranteed and handler implementations should not assume this order. :return: None """ logger = get_module_logger() config = frappe.get_cached_doc("Spine Consumer Config", "Spine Consumer Config").as_dict() # Number of messages to pick up on one call. window_size = config.get("msg_window_size") if not window_size: window_size = 5 # messages = frappe.get_all("Message Log", filters={"status": "Pending", "direction": "Received"}, # fields=["*"], order_by="received_at", limit_page_length=window_size) messages = frappe.db.sql(''' SELECT * from `tabMessage Log` where status = 'Pending' and direction = 'Received' order by received_at limit %(window_size)s for update ''', { 'window_size': window_size, }, as_dict=True) if messages: logger.debug("Found {} unprocessed messages".format(len(messages))) updated_msgs = [] for msg in messages: # Update status for all messages picked up for processing. This will ensure that later scheduled tasks will # not pick up same messages. updated_msgs.append(update_message_status(msg, "Processing")) # Commit updates frappe.db.commit() if updated_msgs and len(updated_msgs) > 0: for msg in updated_msgs: process_message_from_spine(msg) else: logger.info("SpineConsumer: No messages found for processing.") else: logger.info("SpineConsumer: No messages found for processing.")
def save_file(self, content=None, decode=False, ignore_existing_file_check=False): file_exists = False self.content = content if decode: if isinstance(content, text_type): self.content = content.encode("utf-8") if b"," in self.content: self.content = self.content.split(b",")[1] self.content = base64.b64decode(self.content) if not self.is_private: self.is_private = 0 self.file_size = self.check_max_file_size() self.content_hash = get_content_hash(self.content) self.content_type = mimetypes.guess_type(self.file_name)[0] duplicate_file = None # check if a file exists with the same content hash and is also in the same folder (public or private) if not ignore_existing_file_check: duplicate_file = frappe.get_value("File", { "content_hash": self.content_hash, "is_private": self.is_private }, ["file_url", "name"], as_dict=True) if duplicate_file: file_doc = frappe.get_cached_doc('File', duplicate_file.name) if file_doc.exists_on_disk(): self.file_url = duplicate_file.file_url file_exists = True if os.path.exists( encode( get_files_path(self.file_name, is_private=self.is_private))): self.file_name = get_file_name(self.file_name, self.content_hash[-6:]) if not file_exists: call_hook_method("before_write_file", file_size=self.file_size) write_file_method = get_hook_method('write_file') if write_file_method: return write_file_method(self) return self.save_file_on_filesystem()
def send_email_to_leads_or_contacts(): email_campaigns = frappe.get_all( "Email Campaign", filters={ "status": ("not in", ["Unsubscribed", "Completed", "Scheduled"]) }) for camp in email_campaigns: email_campaign = frappe.get_doc("Email Campaign", camp.name) campaign = frappe.get_cached_doc("Campaign", email_campaign.campaign_name) for entry in campaign.get("campaign_schedules"): scheduled_date = add_days(email_campaign.get("start_date"), entry.get("send_after_days")) if scheduled_date == getdate(today()): send_mail(entry, email_campaign)
def get_materials_from_supplier(purchase_order, po_details): if isinstance(po_details, str): po_details = json.loads(po_details) doc = frappe.get_cached_doc("Purchase Order", purchase_order) doc.initialized_fields() doc.purchase_orders = [doc.name] doc.get_available_materials() if not doc.available_materials: frappe.throw( _("Materials are already received against the purchase order {0}").format(purchase_order) ) return make_return_stock_entry_for_subcontract(doc.available_materials, doc, po_details)
def link_address(self): """Link address based on owner""" if not self.links and not self.is_your_company_address: contact_name = frappe.db.get_value("Contact", {"email_id": self.owner}) if contact_name: contact = frappe.get_cached_doc('Contact', contact_name) for link in contact.links: self.append( 'links', dict(link_doctype=link.link_doctype, link_name=link.link_name)) return True return False
def send_email_to_leads_or_contacts(): email_campaigns = frappe.get_all( "Email Campaign", filters={ 'status': ('not in', ['Unsubscribed', 'Completed', 'Scheduled']) }) for camp in email_campaigns: email_campaign = frappe.get_doc("Email Campaign", camp.name) campaign = frappe.get_cached_doc("Campaign", email_campaign.campaign_name) for entry in campaign.get("campaign_schedules"): scheduled_date = add_days(email_campaign.get('start_date'), entry.get('send_after_days')) if scheduled_date == getdate(today()): send_mail(entry, email_campaign)
def get_territory_from_address(address): """Tries to match city, state and country of address to existing territory""" if not address: return if isinstance(address, string_types): address = frappe.get_cached_doc("Address", address) territory = None for fieldname in ("city", "state", "country"): if address.get(fieldname): territory = frappe.db.get_value("Territory", address.get(fieldname)) if territory: break return territory
def make_raw_material_request(items, company, sales_order, project=None): if not frappe.has_permission("Sales Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) if isinstance(items, string_types): items = frappe._dict(json.loads(items)) for item in items.get('items'): item["include_exploded_items"] = items.get('include_exploded_items') item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty') item["include_raw_materials_from_sales_order"] = items.get('include_raw_materials_from_sales_order') raw_materials = get_items_for_material_requests(items, sales_order, company) if not raw_materials: frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available.")) return material_request = frappe.new_doc('Material Request') material_request.update(dict( doctype = 'Material Request', transaction_date = nowdate(), company = company, requested_by = frappe.session.user, material_request_type = 'Purchase' )) for item in raw_materials: item_doc = frappe.get_cached_doc('Item', item.get('item_code')) schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) material_request.append('items', { 'item_code': item.get('item_code'), 'qty': item.get('quantity'), 'schedule_date': schedule_date, 'warehouse': item.get('warehouse'), 'sales_order': sales_order, 'project': project }) material_request.insert() material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") material_request.submit() return material_request
def get_product_list_for_group(product_group=None, start=0, limit=10, search=None): if product_group: item_group = frappe.get_cached_doc('Item Group', product_group) if item_group.is_group: # return child item groups if the type is of "Is Group" return get_child_groups_for_list_in_html(item_group, start, limit, search) child_groups = ", ".join(['"' + frappe.db.escape(i[0]) + '"' for i in get_child_groups(product_group)]) # base query query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group, I.description, I.web_long_description as website_description, I.is_stock_item, case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse, I.has_batch_no from `tabItem` I left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse where I.show_in_website = 1 and I.disabled = 0 and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s) and (I.variant_of = '' or I.variant_of is null) and (I.item_group in ({child_groups}) or I.name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups}))) """.format(child_groups=child_groups) # search term condition if search: query += """ and (I.web_long_description like %(search)s or I.item_name like %(search)s or I.name like %(search)s)""" search = "%" + cstr(search) + "%" query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (start, limit) data = frappe.db.sql(query, {"product_group": product_group,"search": search, "today": nowdate()}, as_dict=1) data = adjust_qty_for_expired_items(data) for item in data: set_product_info_for_website(item) return [get_item_for_list_in_html(r) for r in data]
def get_pos_profile(company, pos_profile=None, user=None): if pos_profile: return frappe.get_cached_doc('POS Profile', pos_profile) if not user: user = frappe.session['user'] pos_profile = frappe.db.sql("""SELECT pf.* FROM `tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu ON pf.name = pfu.parent WHERE ( (pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1) OR (pfu.user = %(user)s AND pfu.default=1) OR (ifnull(pfu.user, '') = '' AND pf.company = %(company)s) ) AND pf.disabled = 0 """, { 'user': user, 'company': company }, as_dict=1) return pos_profile and pos_profile[0] or None
def get_item_details(args): """ args = { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "plc_conversion_rate": 1.0, "doctype": "", "name": "", "supplier": None, "transaction_date": None, "conversion_rate": 1.0, "buying_price_list": None, "is_subcontracted": "Yes" / "No", "ignore_pricing_rule": 0/1 "project": "" "set_warehouse": "" } """ args = process_args(args) item = frappe.get_cached_doc("Item", args.item_code) validate_item_details(args, item) out = get_basic_details(args, item) get_party_item_code(args, item, out) set_valuation_rate(out, args) update_party_blanket_order(args, out) get_price_list_rate(args, item, out) if args.customer and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args)) if out.get("warehouse"): out.update(get_bin_details(args.item_code, out.warehouse)) # update args with out, if key or value not exists for key, value in iteritems(out): if args.get(key) is None: args[key] = value out.update(get_pricing_rule_for_item(args)) update_stock(args, out) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days(args.transaction_date, item.lead_time_days) if args.get("is_subcontracted") == "Yes": out.bom = args.get('bom') or get_default_bom(args.item_code) get_gross_profit(out) if args.doctype == 'Material Request': out.rate = args.rate or out.price_list_rate out.amount = flt(args.qty * out.rate) return out