def get_transitions(doc, workflow = None): '''Return list of possible transitions for the given doc''' doc = frappe.get_doc(frappe.parse_json(doc)) if doc.is_new(): return [] frappe.has_permission(doc, 'read', throw=True) roles = frappe.get_roles() if not workflow: workflow = get_workflow(doc.doctype) current_state = doc.get(workflow.workflow_state_field) if not current_state: frappe.throw(_('Workflow State not set'), WorkflowStateError) transitions = [] for transition in workflow.transitions: if transition.state == current_state and transition.allowed in roles: if transition.condition: # if condition, evaluate # access to frappe.db.get_value and frappe.db.get_list success = frappe.safe_eval(transition.condition, dict(frappe = frappe._dict( db = frappe._dict(get_value = frappe.db.get_value, get_list=frappe.db.get_list), session = frappe.session )), dict(doc = doc)) if not success: continue transitions.append(transition.as_dict()) return transitions
def get_item_map(item_code): """Optimization: get only the item doc and re_order_levels table""" condition = "" if item_code: condition = 'and item_code = "{0}"'.format(frappe.db.escape(item_code, percent=False)) items = frappe.db.sql("""select * from `tabItem` item where is_stock_item = 1 and disabled=0 {condition} and (end_of_life > %(today)s or end_of_life is null or end_of_life='0000-00-00') and exists (select name from `tabBin` bin where bin.item_code=item.name)"""\ .format(condition=condition), {"today": today()}, as_dict=True) condition = "" if item_code: condition = 'where parent="{0}"'.format(frappe.db.escape(item_code, percent=False)) reorder_levels = frappe._dict() for ir in frappe.db.sql("""select * from `tabItem Reorder` {condition}""".format(condition=condition), as_dict=1): if ir.parent not in reorder_levels: reorder_levels[ir.parent] = [] reorder_levels[ir.parent].append(ir) item_map = frappe._dict() for item in items: item["reorder_levels"] = reorder_levels.get(item.name) or [] item_map[item.name] = item return item_map
def get_columns_dict(columns): """Returns a dict with column docfield values as dict The keys for the dict are both idx and fieldname, so either index or fieldname can be used to search for a column's docfield properties """ columns_dict = frappe._dict() for idx, col in enumerate(columns): col_dict = frappe._dict() # string if isinstance(col, string_types): col = col.split(":") if len(col) > 1: if "/" in col[1]: col_dict["fieldtype"], col_dict["options"] = col[1].split("/") else: col_dict["fieldtype"] = col[1] col_dict["label"] = col[0] col_dict["fieldname"] = frappe.scrub(col[0]) # dict else: col_dict.update(col) if "fieldname" not in col_dict: col_dict["fieldname"] = frappe.scrub(col_dict["label"]) columns_dict[idx] = col_dict columns_dict[col_dict["fieldname"]] = col_dict return columns_dict
def get_invoice_so_dn_map(invoice_list): si_items = frappe.db.sql( """select parent, sales_order, delivery_note, so_detail from `tabSales Invoice Item` where parent in (%s) and (ifnull(sales_order, '') != '' or ifnull(delivery_note, '') != '')""" % ", ".join(["%s"] * len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1, ) invoice_so_dn_map = {} for d in si_items: if d.sales_order: invoice_so_dn_map.setdefault(d.parent, frappe._dict()).setdefault("sales_order", []).append(d.sales_order) delivery_note_list = None if d.delivery_note: delivery_note_list = [d.delivery_note] elif d.sales_order: delivery_note_list = frappe.db.sql_list( """select distinct parent from `tabDelivery Note Item` where docstatus=1 and so_detail=%s""", d.so_detail, ) if delivery_note_list: invoice_so_dn_map.setdefault(d.parent, frappe._dict()).setdefault("delivery_note", delivery_note_list) return invoice_so_dn_map
def check_for_update(): updates = frappe._dict(major=[], minor=[], patch=[]) apps = get_versions() for app in apps: app_details = check_release_on_github(app) if not app_details: continue github_version, org_name = app_details # Get local instance's current version or the app branch_version = apps[app]['branch_version'].split(' ')[0] if apps[app].get('branch_version', '') else '' instance_version = Version(branch_version or apps[app].get('version')) # Compare and popup update message for update_type in updates: if github_version.__dict__[update_type] > instance_version.__dict__[update_type]: updates[update_type].append(frappe._dict( current_version = str(instance_version), available_version = str(github_version), org_name = org_name, app_name = app, title = apps[app]['title'], )) break if github_version.__dict__[update_type] < instance_version.__dict__[update_type]: break add_message_to_redis(updates)
def update_event(args, field_map): args = frappe._dict(json.loads(args)) field_map = frappe._dict(json.loads(field_map)) w = frappe.get_doc(args.doctype, args.name) w.set(field_map.start, args[field_map.start]) w.set(field_map.end, args.get(field_map.end)) w.save()
def get_default_df(fieldname): if fieldname in default_fields: if fieldname in ("creation", "modified"): return frappe._dict(fieldname=fieldname, fieldtype="Datetime") else: return frappe._dict(fieldname=fieldname, fieldtype="Data")
def get_asset_costs(assets, filters): asset_costs = frappe._dict() for d in assets: asset_costs.setdefault(d.asset_category, frappe._dict({ "cost_as_on_from_date": 0, "cost_of_new_purchase": 0, "cost_of_sold_asset": 0, "cost_of_scrapped_asset": 0 })) costs = asset_costs[d.asset_category] if getdate(d.purchase_date) < getdate(filters.from_date): if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date): costs.cost_as_on_from_date += flt(d.gross_purchase_amount) else: costs.cost_of_new_purchase += flt(d.gross_purchase_amount) if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \ and getdate(d.disposal_date) <= getdate(filters.to_date): if d.status == "Sold": costs.cost_of_sold_asset += flt(d.gross_purchase_amount) elif d.status == "Scrapped": costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount) return asset_costs
def calculate_component_amounts(self): if not getattr(self, '_salary_structure_doc', None): self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure) data = self.get_data_for_eval() for key in ('earnings', 'deductions'): for struct_row in self._salary_structure_doc.get(key): amount = self.eval_condition_and_formula(struct_row, data) if amount and struct_row.statistical_component == 0 and struct_row.variable_based_on_taxable_salary != 1: self.update_component_row(struct_row, amount, key) if key=="earnings" and struct_row.is_flexible_benefit == 1: self.add_employee_flexi_benefits(struct_row) additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date) if additional_components: for additional_component in additional_components: additional_component = frappe._dict(additional_component) amount = additional_component.amount key = "earnings" if additional_component.type == "Deduction": key = "deductions" self.update_component_row(frappe._dict(additional_component.struct_row), amount, key) self.get_last_payroll_period_benefit() # Calculate variable_based_on_taxable_salary after all components updated in salary slip for struct_row in self._salary_structure_doc.get("deductions"): if struct_row.variable_based_on_taxable_salary == 1: tax_row, amount = self.calculate_variable_based_on_taxable_salary(struct_row.salary_component) if tax_row and amount: self.update_component_row(frappe._dict(tax_row), amount, "deductions")
def get_partywise_total(self, party_naming_by, args): party_total = frappe._dict() for d in self.get_voucherwise_data(party_naming_by, args): party_total.setdefault(d.party, frappe._dict({ "invoiced_amt": 0, "paid_amt": 0, "credit_amt": 0, "outstanding_amt": 0, "range1": 0, "range2": 0, "range3": 0, "range4": 0, "sales_person": [] }) ) for k in list(party_total[d.party]): if k not in ["currency", "sales_person"]: party_total[d.party][k] += flt(d.get(k, 0)) party_total[d.party].currency = d.currency if d.sales_person: party_total[d.party].sales_person.append(d.sales_person) return party_total
def get_invoice_po_pr_map(invoice_list): pi_items = frappe.db.sql("""select parent, purchase_order, purchase_receipt, po_detail, project from `tabPurchase Invoice Item` where parent in (%s) and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) invoice_po_pr_map = {} for d in pi_items: if d.purchase_order: invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault( "purchase_order", []).append(d.purchase_order) pr_list = None if d.purchase_receipt: pr_list = [d.purchase_receipt] elif d.po_detail: pr_list = frappe.db.sql_list("""select distinct parent from `tabPurchase Receipt Item` where docstatus=1 and prevdoc_detail_docname=%s""", d.po_detail) if pr_list: invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault("purchase_receipt", pr_list) if d.project: invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault( "project", []).append(d.project) return invoice_po_pr_map
def execute(filters=None): if not filters: filters = {} employee_filters = filters.get("company") and \ [["Employee", "company", "=", filters.get("company")]] or None employees = runreport(doctype="Employee", fields=["name", "employee_name", "department"], filters=employee_filters) if not employees: frappe.throw(_("No employee found!")) leave_types = frappe.db.sql_list("select name from `tabLeave Type`") if filters.get("fiscal_year"): fiscal_years = [filters["fiscal_year"]] else: fiscal_years = frappe.db.sql_list("select name from `tabFiscal Year` order by name desc") allocations = frappe.db.sql("""select employee, fiscal_year, leave_type, total_leaves_allocated from `tabLeave Allocation` where docstatus=1 and employee in (%s)""" % ','.join(['%s']*len(employees)), employees, as_dict=True) applications = frappe.db.sql("""select employee, fiscal_year, leave_type, SUM(total_leave_days) as leaves from `tabLeave Application` where status="Approved" and docstatus = 1 and employee in (%s) group by employee, fiscal_year, leave_type""" % ','.join(['%s']*len(employees)), employees, as_dict=True) columns = [ "Fiscal Year", "Employee:Link/Employee:150", "Employee Name::200", "Department::150" ] for leave_type in leave_types: columns.append(leave_type + " Allocated:Float") columns.append(leave_type + " Taken:Float") columns.append(leave_type + " Balance:Float") data = {} for d in allocations: data.setdefault((d.fiscal_year, d.employee, d.leave_type), frappe._dict()).allocation = d.total_leaves_allocated for d in applications: data.setdefault((d.fiscal_year, d.employee, d.leave_type), frappe._dict()).leaves = d.leaves result = [] for fiscal_year in fiscal_years: for employee in employees: row = [fiscal_year, employee.name, employee.employee_name, employee.department] result.append(row) for leave_type in leave_types: tmp = data.get((fiscal_year, employee.name, leave_type), frappe._dict()) row.append(tmp.allocation or 0) row.append(tmp.leaves or 0) row.append((tmp.allocation or 0) - (tmp.leaves or 0)) return columns, result
def validate_space_limit(file_size): """Stop from writing file if max space limit is reached""" from frappe.utils.file_manager import MaxFileSizeReachedError limits = get_limits() if not limits.space: return # to MB space_limit = flt(limits.space * 1024.0, 2) # in MB usage = frappe._dict(limits.space_usage or {}) if not usage: # first time usage = frappe._dict(update_space_usage()) file_size = file_size / (1024.0 ** 2) if flt(flt(usage.total) + file_size, 2) > space_limit: # Stop from attaching file frappe.throw( _("You have exceeded the max space of {0} for your plan. {1}.").format( "<b>{0}MB</b>".format(cint(space_limit)) if (space_limit < 1024) else "<b>{0}GB</b>".format(limits.space), '<a href="#usage-info">{0}</a>'.format(_("Click here to check your usage or upgrade to a higher plan")), ), MaxFileSizeReachedError, ) # update files size in frappe subscription usage.files_size = flt(usage.files_size) + file_size update_limits({"space_usage": usage})
def get_item_list(self): il = [] for d in self.get("items"): if d.qty is None: frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx)) if self.has_product_bundle(d.item_code): for p in self.get("packed_items"): if p.parent_detail_docname == d.name and p.parent_item == d.item_code: # the packing details table's qty is already multiplied with parent's qty il.append(frappe._dict({ 'warehouse': p.warehouse or d.warehouse, 'item_code': p.item_code, 'qty': flt(p.qty), 'uom': p.uom, 'batch_no': cstr(p.batch_no).strip(), 'serial_no': cstr(p.serial_no).strip(), 'name': d.name, 'target_warehouse': p.target_warehouse })) else: il.append(frappe._dict({ 'warehouse': d.warehouse, 'item_code': d.item_code, 'qty': d.stock_qty, 'uom': d.uom, 'stock_uom': d.stock_uom, 'conversion_factor': d.conversion_factor, 'batch_no': cstr(d.get("batch_no")).strip(), 'serial_no': cstr(d.get("serial_no")).strip(), 'name': d.name, 'target_warehouse': d.target_warehouse })) return il
def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): """returns last purchase details in stock uom""" # get last purchase order item details last_purchase_order = frappe.db.sql("""\ select po.name, po.transaction_date, po.conversion_rate, po_item.conversion_factor, po_item.base_price_list_rate, po_item.discount_percentage, po_item.base_rate from `tabPurchase Order` po, `tabPurchase Order Item` po_item where po.docstatus = 1 and po_item.item_code = %s and po.name != %s and po.name = po_item.parent order by po.transaction_date desc, po.name desc limit 1""", (item_code, cstr(doc_name)), as_dict=1) # get last purchase receipt item details last_purchase_receipt = frappe.db.sql("""\ select pr.name, pr.posting_date, pr.posting_time, pr.conversion_rate, pr_item.conversion_factor, pr_item.base_price_list_rate, pr_item.discount_percentage, pr_item.base_rate from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item where pr.docstatus = 1 and pr_item.item_code = %s and pr.name != %s and pr.name = pr_item.parent order by pr.posting_date desc, pr.posting_time desc, pr.name desc limit 1""", (item_code, cstr(doc_name)), as_dict=1) purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date \ or "1900-01-01") purchase_receipt_date = getdate(last_purchase_receipt and \ last_purchase_receipt[0].posting_date or "1900-01-01") if (purchase_order_date > purchase_receipt_date) or \ (last_purchase_order and not last_purchase_receipt): # use purchase order last_purchase = last_purchase_order[0] purchase_date = purchase_order_date elif (purchase_receipt_date > purchase_order_date) or \ (last_purchase_receipt and not last_purchase_order): # use purchase receipt last_purchase = last_purchase_receipt[0] purchase_date = purchase_receipt_date else: return frappe._dict() conversion_factor = flt(last_purchase.conversion_factor) out = frappe._dict({ "base_price_list_rate": flt(last_purchase.base_price_list_rate) / conversion_factor, "base_rate": flt(last_purchase.base_rate) / conversion_factor, "discount_percentage": flt(last_purchase.discount_percentage), "purchase_date": purchase_date }) conversion_rate = flt(conversion_rate) or 1.0 out.update({ "price_list_rate": out.base_price_list_rate / conversion_rate, "rate": out.base_rate / conversion_rate, "base_rate": out.base_rate }) return out
def validate_conversion_rate(args, meta): from erpnext.controllers.accounts_controller import validate_conversion_rate if (not args.conversion_rate and args.currency==frappe.db.get_value("Company", args.company, "default_currency")): args.conversion_rate = 1.0 # validate currency conversion rate validate_conversion_rate(args.currency, args.conversion_rate, meta.get_label("conversion_rate"), args.company) args.conversion_rate = flt(args.conversion_rate, get_field_precision(meta.get_field("conversion_rate"), frappe._dict({"fields": args}))) # validate price list currency conversion rate if not args.get("price_list_currency"): throw(_("Price List Currency not selected")) else: validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate, meta.get_label("plc_conversion_rate"), args.company) args.plc_conversion_rate = flt(args.plc_conversion_rate, get_field_precision(meta.get_field("plc_conversion_rate"), frappe._dict({"fields": args})))
def get_itemised_tax(taxes, with_tax_account=False): itemised_tax = {} for tax in taxes: if getattr(tax, "category", None) and tax.category=="Valuation": continue item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {} if item_tax_map: for item_code, tax_data in item_tax_map.items(): itemised_tax.setdefault(item_code, frappe._dict()) tax_rate = 0.0 tax_amount = 0.0 if isinstance(tax_data, list): tax_rate = flt(tax_data[0]) tax_amount = flt(tax_data[1]) else: tax_rate = flt(tax_data) itemised_tax[item_code][tax.description] = frappe._dict(dict( tax_rate = tax_rate, tax_amount = tax_amount )) if with_tax_account: itemised_tax[item_code][tax.description].tax_account = tax.account_head return itemised_tax
def build_field_columns(dt): meta = frappe.get_meta(dt) tablecolumns = filter(None, [(meta.get_field(f[0]) or None) for f in frappe.db.sql('desc `tab%s`' % dt)]) tablecolumns.sort(lambda a, b: a.idx - b.idx) if dt==doctype: column_start_end[dt] = frappe._dict({"start": 0}) else: column_start_end[dt] = frappe._dict({"start": len(columns)}) append_field_column(frappe._dict({ "fieldname": "name", "label": "ID", "fieldtype": "Data", "reqd": 1, "idx": 0, "info": _("Leave blank for new records") }), True) for docfield in tablecolumns: append_field_column(docfield, True) # all non mandatory fields for docfield in tablecolumns: append_field_column(docfield, False) # append DocType name tablerow[column_start_end[dt].start + 1] = dt if dt!=doctype: tablerow[column_start_end[dt].start + 2] = doctype_parentfield[dt] column_start_end[dt].end = len(columns) + 1
def get_field_currency(df, doc=None): """get currency based on DocField options and fieldvalue in doc""" currency = None if not df.get("options"): return None if not doc: return None if not getattr(frappe.local, "field_currency", None): frappe.local.field_currency = frappe._dict() if not frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname): if ":" in cstr(df.get("options")): split_opts = df.get("options").split(":") if len(split_opts)==3: currency = frappe.db.get_value(split_opts[0], doc.get(split_opts[1]), split_opts[2]) else: currency = doc.get(df.get("options")) if not currency and doc.parent: currency = frappe.db.get_value(doc.parenttype, doc.parent, df.get("options")) if currency: frappe.local.field_currency.setdefault((doc.doctype, doc.parent or doc.name), frappe._dict())\ .setdefault(df.fieldname, currency) return frappe.local.field_currency.get((doc.doctype, doc.parent or doc.name), {}).get(df.fieldname)
def get_children_data(doctype, meta): """ Get all records from all the child tables of a doctype all_children = { "parent1": { "child_doctype1": [ { "field1": val1, "field2": val2 } ] } } """ all_children = frappe._dict() child_search_fields = frappe._dict() for child in meta.get_table_fields(): child_meta = frappe.get_meta(child.options) search_fields = child_meta.get_global_search_fields() if search_fields: child_search_fields.setdefault(child.options, search_fields) child_fieldnames = get_selected_fields(child_meta, search_fields) child_records = frappe.get_all(child.options, fields=child_fieldnames, filters={ "docstatus": ["!=", 1], "parenttype": doctype }) for record in child_records: all_children.setdefault(record.parent, frappe._dict())\ .setdefault(child.options, []).append(record) return all_children, child_search_fields
def get_list_context(context, doctype): from frappe.modules import load_doctype_module module = load_doctype_module(doctype) if hasattr(module, "get_list_context"): return frappe._dict(module.get_list_context(context) or {}) return frappe._dict()
def get_salesperson_item_month_map(filters): import datetime salesperson_details = get_salesperson_details(filters) tdd = get_target_distribution_details(filters) item_groups = get_item_groups() sales_persons = get_sales_persons() sales_person_achievement_dict = {} for sd in salesperson_details: achieved_details = get_achieved_details(filters, sd.name, sales_persons, sd.item_group, item_groups) for month_id in range(1, 13): month = datetime.date(2013, month_id, 1).strftime('%B') sales_person_achievement_dict.setdefault(sd.name, {}).setdefault(sd.item_group, {})\ .setdefault(month, frappe._dict({ "target": 0.0, "achieved": 0.0 })) sales_target_achieved = sales_person_achievement_dict[sd.name][sd.item_group][month] month_percentage = tdd.get(sd.distribution_id, {}).get(month, 0) \ if sd.distribution_id else 100.0/12 if (filters["target_on"] == "Quantity"): sales_target_achieved.target = flt(sd.target_qty) * month_percentage / 100 else: sales_target_achieved.target = flt(sd.target_amount) * month_percentage / 100 sales_target_achieved.achieved = achieved_details.get(month, frappe._dict())\ .get(filters["target_on"].lower()) return sales_person_achievement_dict
def precision(self, fieldname, parentfield=None): """Returns float precision for a particular field (or get global default). :param fieldname: Fieldname for which precision is required. :param parentfield: If fieldname is in child table.""" from frappe.model.meta import get_field_precision if parentfield and not isinstance(parentfield, basestring): parentfield = parentfield.parentfield cache_key = parentfield or "main" if not hasattr(self, "_precision"): self._precision = frappe._dict() if cache_key not in self._precision: self._precision[cache_key] = frappe._dict() if fieldname not in self._precision[cache_key]: self._precision[cache_key][fieldname] = None doctype = self.meta.get_field(parentfield).options if parentfield else self.doctype df = frappe.get_meta(doctype).get_field(fieldname) if df.fieldtype in ("Currency", "Float", "Percent"): self._precision[cache_key][fieldname] = get_field_precision(df, self) return self._precision[cache_key][fieldname]
def get_itemised_tax_breakup_data(doc): itemised_tax = get_itemised_tax(doc.taxes) itemised_taxable_amount = get_itemised_taxable_amount(doc.items) if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'): return itemised_tax, itemised_taxable_amount item_hsn_map = frappe._dict() for d in doc.items: item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code")) hsn_tax = {} for item, taxes in itemised_tax.items(): hsn_code = item_hsn_map.get(item) hsn_tax.setdefault(hsn_code, frappe._dict()) for tax_account, tax_detail in taxes.items(): hsn_tax[hsn_code].setdefault(tax_account, {"tax_rate": 0, "tax_amount": 0}) hsn_tax[hsn_code][tax_account]["tax_rate"] = tax_detail.get("tax_rate") hsn_tax[hsn_code][tax_account]["tax_amount"] += tax_detail.get("tax_amount") # set taxable amount hsn_taxable_amount = frappe._dict() for item, taxable_amount in itemised_taxable_amount.items(): hsn_code = item_hsn_map.get(item) hsn_taxable_amount.setdefault(hsn_code, 0) hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item) return hsn_tax, hsn_taxable_amount
def get_data(filters, leave_types): user = frappe.session.user allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date) active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department", "user_id"]) data = [] for employee in active_employees: leave_approvers = [l.leave_approver for l in frappe.db.sql("""select leave_approver from `tabEmployee Leave Approver` where parent = %s""", (employee.name),as_dict=True)] if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)): row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: # leaves taken leaves_taken = get_approved_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) # opening balance opening = get_leave_balance_on(employee.name, leave_type, filters.from_date, allocation_records_based_on_from_date.get(employee.name, frappe._dict())) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get(employee.name, frappe._dict())) row += [opening, leaves_taken, closing] data.append(row) return data
def request(context, args=None, path=None): "Run a request as an admin" import frappe.handler import frappe.api for site in context.sites: try: frappe.init(site=site) frappe.connect() if args: if "?" in args: frappe.local.form_dict = frappe._dict([a.split("=") for a in args.split("?")[-1].split("&")]) else: frappe.local.form_dict = frappe._dict() if args.startswith("/api/method"): frappe.local.form_dict.cmd = args.split("?")[0].split("/")[-1] elif path: with open(os.path.join('..', path), 'r') as f: args = json.loads(f.read()) frappe.local.form_dict = frappe._dict(args) frappe.handler.execute_cmd(frappe.form_dict.cmd) print(frappe.response) finally: frappe.destroy()
def get_achieved_details(filters, sales_person, item_groups): start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:] lft, rgt = frappe.get_value("Sales Person", sales_person, ["lft", "rgt"]) item_details = frappe.db.sql(""" select soi.item_code, sum(soi.qty * (st.allocated_percentage/100)) as qty, sum(soi.base_net_amount * (st.allocated_percentage/100)) as amount, st.sales_person, MONTHNAME(so.transaction_date) as month_name from `tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st where soi.parent=so.name and so.docstatus=1 and st.parent=so.name and so.transaction_date>=%s and so.transaction_date<=%s and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name=st.sales_person) group by sales_person, item_code, month_name """, (start_date, end_date, lft, rgt), as_dict=1) item_actual_details = {} for d in item_details: item_group = item_groups[d.item_code] item_actual_details.setdefault(item_group, frappe._dict()).setdefault(d.month_name,\ frappe._dict({ "quantity" : 0, "amount" : 0 })) value_dict = item_actual_details[item_group][d.month_name] value_dict.quantity += flt(d.qty) value_dict.amount += flt(d.amount) return item_actual_details
def get_itemised_tax(taxes): itemised_tax = {} for tax in taxes: if getattr(tax, "category", None) and tax.category=="Valuation": continue tax_amount_precision = tax.precision("tax_amount") tax_rate_precision = tax.precision("rate") item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {} for item_code, tax_data in item_tax_map.items(): itemised_tax.setdefault(item_code, frappe._dict()) if isinstance(tax_data, list): precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision itemised_tax[item_code][tax.description] = frappe._dict(dict( tax_rate=flt(tax_data[0]), tax_amount=flt(tax_data[1]) )) else: itemised_tax[item_code][tax.description] = frappe._dict(dict( tax_rate=flt(tax_data), tax_amount=0.0 )) return itemised_tax
def get_list_context(context, doctype): from frappe.modules import load_doctype_module from frappe.website.doctype.web_form.web_form import get_web_form_list list_context = context or frappe._dict() meta = frappe.get_meta(doctype) if not meta.custom: # custom doctypes don't have modules module = load_doctype_module(doctype) if hasattr(module, "get_list_context"): out = frappe._dict(module.get_list_context(list_context) or {}) if out: list_context = out # get path from '/templates/' folder of the doctype if not list_context.row_template: list_context.row_template = meta.get_row_template() # is web form, show the default web form filters # which is only the owner if frappe.form_dict.web_form_name: list_context.web_form_name = frappe.form_dict.web_form_name if not list_context.get("get_list"): list_context.get_list = get_web_form_list if not frappe.flags.web_form: # update list context from web_form frappe.flags.web_form = frappe.get_doc('Web Form', frappe.form_dict.web_form_name) if frappe.flags.web_form.is_standard: frappe.flags.web_form.update_list_context(list_context) return list_context
def get_default_bank_cash_account(company, account_type=None, mode_of_payment=None, account=None): from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account if mode_of_payment: account = get_bank_cash_account(mode_of_payment, company).get("account") if not account: if account_type=="Bank": account = frappe.db.get_value("Company", company, "default_bank_account") if not account: account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0}) elif account_type=="Cash": account = frappe.db.get_value("Company", company, "default_cash_account") if not account: account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0}) if account: account_details = frappe.db.get_value("Account", account, ["account_currency", "account_type"], as_dict=1) return frappe._dict({ "account": account, "balance": get_balance_on(account), "account_currency": account_details.account_currency, "account_type": account_details.account_type }) else: return frappe._dict()
def get_supplier_parent_child_map(self): self.parent_child_map = frappe._dict( frappe.db.sql( """ select name, supplier_group from `tabSupplier`"""))
def accept(web_form, data, for_payment=False): '''Save the web form''' data = frappe._dict(json.loads(data)) files = [] files_to_delete = [] web_form = frappe.get_doc("Web Form", web_form) if data.doctype != web_form.doc_type: frappe.throw(_("Invalid Request")) elif data.name and not web_form.allow_edit: frappe.throw(_("You are not allowed to update this Web Form Document")) frappe.flags.in_web_form = True if data.name: # update doc = frappe.get_doc(data.doctype, data.name) else: # insert doc = frappe.new_doc(data.doctype) # set values for fieldname, value in iteritems(data): if value and isinstance(value, dict): try: if "__file_attachment" in value: files.append((fieldname, value)) continue if '__no_attachment' in value: files_to_delete.append(doc.get(fieldname)) value = '' except ValueError: pass doc.set(fieldname, str(jinja2.escape(value))) if for_payment: web_form.validate_mandatory(doc) doc.run_method('validate_payment') if doc.name: if has_web_form_permission(doc.doctype, doc.name, "write"): doc.save(ignore_permissions=True) else: # only if permissions are present doc.save() else: # insert if web_form.login_required and frappe.session.user == "Guest": frappe.throw(_("You must login to submit this form")) doc.insert(ignore_permissions=True) # add files if files: for f in files: fieldname, filedata = f # remove earlier attached file (if exists) if doc.get(fieldname): remove_file_by_url(doc.get(fieldname), doc.doctype, doc.name) # save new file filedoc = save_file(filedata["filename"], filedata["dataurl"], doc.doctype, doc.name, decode=True) # update values doc.set(fieldname, filedoc.file_url) doc.save() if files_to_delete: for f in files_to_delete: if f: remove_file_by_url(f, doc.doctype, doc.name) frappe.flags.web_form_doc = doc if for_payment: return web_form.get_payment_gateway_url(doc) else: return doc.name
class WebForm(WebsiteGenerator): website = frappe._dict(no_cache=1) def onload(self): super(WebForm, self).onload() if self.is_standard and not frappe.conf.developer_mode: self.use_meta_fields() def validate(self): super(WebForm, self).validate() if not self.module: self.module = frappe.db.get_value('DocType', self.doc_type, 'module') if (not (frappe.flags.in_install or frappe.flags.in_patch or frappe.flags.in_test or frappe.flags.in_fixtures) and self.is_standard and not frappe.conf.developer_mode): frappe.throw( _("You need to be in developer mode to edit a Standard Web Form" )) if not frappe.flags.in_import: self.validate_fields() if self.accept_payment: self.validate_payment_amount() def validate_fields(self): '''Validate all fields are present''' from frappe.model import no_value_fields missing = [] meta = frappe.get_meta(self.doc_type) for df in self.web_form_fields: if df.fieldname and (df.fieldtype not in no_value_fields and not meta.has_field(df.fieldname)): missing.append(df.fieldname) if missing: frappe.throw( _('Following fields are missing:') + '<br>' + '<br>'.join(missing)) def validate_payment_amount(self): if self.amount_based_on_field and not self.amount_field: frappe.throw(_("Please select a Amount Field.")) elif not self.amount_based_on_field and not self.amount > 0: frappe.throw(_("Amount must be greater than 0.")) def reset_field_parent(self): '''Convert link fields to select with names as options''' for df in self.web_form_fields: df.parent = self.doc_type def use_meta_fields(self): '''Override default properties for standard web forms''' meta = frappe.get_meta(self.doc_type) for df in self.web_form_fields: meta_df = meta.get_field(df.fieldname) if not meta_df: continue for prop in docfield_properties: if df.fieldtype == meta_df.fieldtype and prop not in ( "idx", "reqd", "default", "description", "default", "options", "hidden", "read_only", "label"): df.set(prop, meta_df.get(prop)) # TODO translate options of Select fields like Country # export def on_update(self): """ Writes the .txt for this page and if write_content is checked, it will write out a .html file """ path = export_module_json(self, self.is_standard, self.module) if path: # js if not os.path.exists(path + '.js'): with open(path + '.js', 'w') as f: f.write("""frappe.ready(function() { // bind events here })""") # py if not os.path.exists(path + '.py'): with open(path + '.py', 'w') as f: f.write("""from __future__ import unicode_literals import frappe def get_context(context): # do your magic here pass """) def get_context(self, context): '''Build context to render the `web_form.html` template''' self.set_web_form_module() context._login_required = False if self.login_required and frappe.session.user == "Guest": context._login_required = True doc, delimeter = make_route_string(frappe.form_dict) context.doc = doc context.delimeter = delimeter # check permissions if frappe.session.user == "Guest" and frappe.form_dict.name: frappe.throw( _("You need to be logged in to access this {0}.").format( self.doc_type), frappe.PermissionError) if frappe.form_dict.name and not has_web_form_permission( self.doc_type, frappe.form_dict.name): frappe.throw( _("You don't have the permissions to access this document"), frappe.PermissionError) self.reset_field_parent() if self.is_standard: self.use_meta_fields() if not context._login_required: if self.allow_edit: if self.allow_multiple: if not frappe.form_dict.name and not frappe.form_dict.new: self.build_as_list(context) else: if frappe.session.user != 'Guest' and not frappe.form_dict.name: frappe.form_dict.name = frappe.db.get_value( self.doc_type, {"owner": frappe.session.user}, "name") if not frappe.form_dict.name: # only a single doc allowed and no existing doc, hence new frappe.form_dict.new = 1 # always render new form if login is not required or doesn't allow editing existing ones if not self.login_required or not self.allow_edit: frappe.form_dict.new = 1 self.load_document(context) context.parents = self.get_parents(context) if self.breadcrumbs: context.parents = frappe.safe_eval(self.breadcrumbs, {"_": _}) context.has_header = ((frappe.form_dict.name or frappe.form_dict.new) and (frappe.session.user != "Guest" or not self.login_required)) if context.success_message: context.success_message = frappe.db.escape( context.success_message.replace("\n", "<br>")) self.add_custom_context_and_script(context) if not context.max_attachment_size: context.max_attachment_size = get_max_file_size() / 1024 / 1024 def load_document(self, context): '''Load document `doc` and `layout` properties for template''' if frappe.form_dict.name or frappe.form_dict.new: context.layout = self.get_layout() context.parents = [{"route": self.route, "label": _(self.title)}] if frappe.form_dict.name: context.doc = frappe.get_doc(self.doc_type, frappe.form_dict.name) context.title = context.doc.get(context.doc.meta.get_title_field()) context.doc.add_seen() context.reference_doctype = context.doc.doctype context.reference_name = context.doc.name if self.allow_comments: context.comment_list = get_comment_list( context.doc.doctype, context.doc.name) def build_as_list(self, context): '''Web form is a list, show render as list.html''' from frappe.www.list import get_context as get_list_context # set some flags to make list.py/list.html happy frappe.form_dict.web_form_name = self.name frappe.form_dict.doctype = self.doc_type frappe.flags.web_form = self self.update_params_from_form_dict(context) self.update_list_context(context) get_list_context(context) context.is_list = True def update_params_from_form_dict(self, context): '''Copy params from list view to new view''' context.params_from_form_dict = '' params = {} for key, value in iteritems(frappe.form_dict): if frappe.get_meta(self.doc_type).get_field(key): params[key] = value if params: context.params_from_form_dict = '&' + urlencode(params) def update_list_context(self, context): '''update list context for stanard modules''' if hasattr(self, 'web_form_module') and hasattr( self.web_form_module, 'get_list_context'): self.web_form_module.get_list_context(context) def get_payment_gateway_url(self, doc): if self.accept_payment: controller = get_payment_gateway_controller(self.payment_gateway) title = "Payment for {0} {1}".format(doc.doctype, doc.name) amount = self.amount if self.amount_based_on_field: amount = doc.get(self.amount_field) payment_details = { "amount": amount, "title": title, "description": title, "reference_doctype": doc.doctype, "reference_docname": doc.name, "payer_email": frappe.session.user, "payer_name": frappe.utils.get_fullname(frappe.session.user), "order_id": doc.name, "currency": self.currency, "redirect_to": frappe.utils.get_url(self.route) } # Redirect the user to this url return controller.get_payment_url(**payment_details) def add_custom_context_and_script(self, context): '''Update context from module if standard and append script''' if self.web_form_module: new_context = self.web_form_module.get_context(context) if new_context: context.update(new_context) js_path = os.path.join( os.path.dirname(self.web_form_module.__file__), scrub(self.name) + '.js') if os.path.exists(js_path): context.script = frappe.render_template( open(js_path, 'r').read().decode('utf-8'), context) css_path = os.path.join( os.path.dirname(self.web_form_module.__file__), scrub(self.name) + '.css') if os.path.exists(css_path): context.style = open(css_path, 'r').read() def get_layout(self): layout = [] def add_page(df=None): new_page = {'sections': []} layout.append(new_page) if df and df.fieldtype == 'Page Break': new_page.update(df.as_dict()) return new_page def add_section(df=None): new_section = {'columns': []} layout[-1]['sections'].append(new_section) if df and df.fieldtype == 'Section Break': new_section.update(df.as_dict()) return new_section def add_column(df=None): new_col = [] layout[-1]['sections'][-1]['columns'].append(new_col) return new_col page, section, column = None, None, None for df in self.web_form_fields: # breaks if df.fieldtype == 'Page Break': page = add_page(df) section, column = None, None if df.fieldtype == 'Section Break': section = add_section(df) column = None if df.fieldtype == 'Column Break': column = add_column(df) # input if df.fieldtype not in ('Section Break', 'Column Break', 'Page Break'): if not page: page = add_page() section, column = None, None if not section: section = add_section() column = None if column == None: column = add_column() column.append(df) return layout def get_parents(self, context): parents = None if context.is_list and not context.parents: parents = [{"title": _("My Account"), "name": "me"}] elif context.parents: parents = context.parents return parents def set_web_form_module(self): '''Get custom web form module if exists''' if self.is_standard: self.web_form_module = get_doc_module(self.module, self.doctype, self.name) else: self.web_form_module = None def validate_mandatory(self, doc): '''Validate mandatory web form fields''' missing = [] for f in self.web_form_fields: if f.reqd and doc.get(f.fieldname) in (None, [], ''): missing.append(f) if missing: frappe.throw( _('Mandatory Information missing:') + '<br><br>' + '<br>'.join([ '{0} ({1})'.format(d.label, d.fieldtype) for d in missing ]))
def invoice_paid(): # https://razorpay.com/docs/api/recurring-payments/webhooks/ data = frappe.request.get_data(as_text=True) try: verify_signature(data) except Exception as e: log = frappe.log_error(e, "Webhook Verification Error") return {"status": "Failed", "reason": e} if isinstance(data, six.string_types): data = json.loads(data) data = frappe._dict(data) payment = frappe._dict(data.payload.get("payment", {}).get("entity", {})) if not payment.method == "emandate": return controller = frappe.get_doc("Razorpay Settings") controller.init_client() client = controller.client today = getdate() member = frappe.db.exists("Member", {"customer_id": payment.customer_id}) token_data = client.token.fetch(payment.customer_id, payment.token_id) if not member: max_amount = token_data.get("max_amount") / 100 plan = frappe.db.exists("Membership Type", {"amount": max_amount}) if plan: plan_id = frappe.db.get_value("Membership Type", plan, "razorpay_plan_id") member = create_member(payment.customer_id, plan_id) if member: member = frappe.get_doc("Member", member) membership = frappe.new_doc("Membership") membership.update({ "member": member.name, "membership_status": "New", "membership_type": member.membership_type, "currency": "INR", "paid": 1, "payment_id": payment.id, "from_date": today, "to_date": add_months(today, 1), "amount": frappe.db.get_value("Membership Type", member.membership_type, "amount") }) membership.insert(ignore_permissions=True) # Update membership values member.subscription_activated = 1 member.e_mandate = 1 member.razorpay_token = payment.token_id status = token_data.get("recurring_details").get("status") if status == "confirmed": member.token_status = "Confirmed" if status == "rejected": member.token_status = "Rejected" member.membership_expiry_date = add_months(today, 1) member.save(ignore_permissions=True) settings = frappe.get_doc("Non Profit Settings") if settings.allow_invoicing and settings.automate_membership_invoicing: membership.generate_invoice(with_payment_entry=settings. automate_membership_payment_entries, save=True)
def initialize_gle_map(gl_entries): gle_map = frappe._dict() for gle in gl_entries: gle_map.setdefault(gle.account, _dict(totals=get_totals_dict(), entries=[])) return gle_map
class Tournament(WebsiteGenerator): website = frappe._dict(template="templates/generators/tournament.html") def validate(self): self.route = "tournament/" + self.name
def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None): if isinstance(doc, string_types): doc = frappe._dict(json.loads(doc)) doc['mr_items'] = [] po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items') company = doc.get('company') warehouse = doc.get('for_warehouse') if not ignore_existing_ordered_qty: ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty') so_item_details = frappe._dict() for data in po_items: planned_qty = data.get('required_qty') or data.get('planned_qty') ignore_existing_ordered_qty = data.get( 'ignore_existing_ordered_qty') or ignore_existing_ordered_qty item_details = {} if data.get("bom") or data.get("bom_no"): if data.get('required_qty'): bom_no = data.get('bom') include_non_stock_items = 1 include_subcontracted_items = 1 if data.get( 'include_exploded_items') else 0 else: bom_no = data.get('bom_no') include_subcontracted_items = doc.get( 'include_subcontracted_items') include_non_stock_items = doc.get('include_non_stock_items') if not planned_qty: frappe.throw( _("For row {0}: Enter Planned Qty").format( data.get('idx'))) if bom_no: if data.get('include_exploded_items' ) and include_subcontracted_items and not doc.get( "include_sub_assembly_with_exploded_item"): # fetch exploded items from BOM item_details = get_exploded_items( item_details, company, bom_no, include_non_stock_items, planned_qty=planned_qty, sales_order=data.get("sales_order")) elif data.get('include_exploded_items' ) and include_subcontracted_items and doc.get( "include_sub_assembly_with_exploded_item"): # fetch exploded items with sub assembly item from BOM item_details = get_exploded_items_with_subassembly( item_details, company, bom_no, include_non_stock_items, planned_qty=planned_qty, sales_order=data.get("sales_order")) else: item_details = get_subitems( doc, data, item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1, planned_qty=planned_qty, sales_order=data.get("sales_order")) elif data.get('item_code'): item_master = frappe.get_doc('Item', data['item_code']).as_dict() purchase_uom = item_master.purchase_uom or item_master.stock_uom conversion_factor = 0 for d in item_master.get("uoms"): if d.uom == purchase_uom: conversion_factor = d.conversion_factor item_details[item_master.name] = frappe._dict({ 'item_name': item_master.item_name, 'default_bom': doc.bom, 'purchase_uom': purchase_uom, 'default_warehouse': item_master.default_warehouse, 'min_order_qty': item_master.min_order_qty, 'default_material_request_type': item_master.default_material_request_type, 'qty': planned_qty or 1, 'is_sub_contracted': item_master.is_subcontracted_item, 'item_code': item_master.name, 'description': item_master.description, 'stock_uom': item_master.stock_uom, 'conversion_factor': conversion_factor, 'sales_order': data.get("sales_order") }) sales_order = doc.get("sales_order") for item_code, details in iteritems(item_details): so_item_details.setdefault(sales_order, frappe._dict()) if item_code in so_item_details.get(sales_order, {}): so_item_details[sales_order][item_code][ 'qty'] = so_item_details[sales_order][item_code].get( "qty", 0) + flt(details.qty) else: so_item_details[sales_order][item_code] = details mr_items = [] for sales_order, item_code in iteritems(so_item_details): item_dict = so_item_details[sales_order] for details in item_dict.values(): bin_dict = get_bin_details(details, doc.company, warehouse) bin_dict = bin_dict[0] if bin_dict else {} if details and details.qty > 0: items = get_material_request_items( details, sales_order, company, ignore_existing_ordered_qty, warehouse, bin_dict) if items: mr_items.append(items) if not mr_items: frappe.msgprint( _("""As raw materials projected quantity is more than required quantity, there is no need to create material request. Still if you want to make material request, kindly enable <b>Ignore Existing Projected Quantity</b> checkbox""" )) return mr_items
def get_basic_details(args, item, overwrite_warehouse=True): """ :param args: { "item_code": "", "warehouse": None, "customer": "", "conversion_rate": 1.0, "selling_price_list": None, "price_list_currency": None, "price_list_uom_dependant": 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": "", barcode: "", serial_no: "", currency: "", update_stock: "", price_list: "", company: "", order_type: "", is_pos: "", project: "", qty: "", stock_qty: "", conversion_factor: "" } :param item: `item_code` of Item object :return: frappe._dict """ if not item: item = frappe.get_doc("Item", args.get("item_code")) if item.variant_of: item.update_template_tables() item_defaults = get_item_defaults(item.name, args.company) item_group_defaults = get_item_group_defaults(item.name, args.company) brand_defaults = get_brand_defaults(item.name, args.company) defaults = frappe._dict({ 'item_defaults': item_defaults, 'item_group_defaults': item_group_defaults, 'brand_defaults': brand_defaults }) warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults) if args.get('doctype') == "Material Request" and not args.get( 'material_request_type'): args['material_request_type'] = frappe.db.get_value( 'Material Request', args.get('name'), 'material_request_type', cache=True) expense_account = None if args.get('doctype') == 'Purchase Invoice' and item.is_fixed_asset: from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account expense_account = get_asset_category_account( fieldname="fixed_asset_account", item=args.item_code, company=args.company) #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master if not args.get('uom'): if args.get('doctype') in sales_doctypes: args.uom = item.sales_uom if item.sales_uom else item.stock_uom elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \ (args.get('doctype') == 'Material Request' and args.get('material_request_type') == 'Purchase'): args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom else: args.uom = item.stock_uom out = frappe._dict({ "item_code": item.name, "item_name": item.item_name, "description": cstr(item.description).strip(), "image": cstr(item.image).strip(), "warehouse": warehouse, "income_account": get_default_income_account(args, item_defaults, item_group_defaults, brand_defaults), "expense_account": expense_account or get_default_expense_account( args, item_defaults, item_group_defaults, brand_defaults), "cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults), 'has_serial_no': item.has_serial_no, 'has_batch_no': item.has_batch_no, "batch_no": args.get("batch_no"), "uom": args.uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", "qty": flt(args.qty) or 1.0, "stock_qty": flt(args.qty) or 1.0, "price_list_rate": 0.0, "base_price_list_rate": 0.0, "rate": 0.0, "base_rate": 0.0, "amount": 0.0, "base_amount": 0.0, "net_rate": 0.0, "net_amount": 0.0, "discount_percentage": 0.0, "supplier": get_default_supplier(args, item_defaults, item_group_defaults, brand_defaults), "update_stock": args.get("update_stock") if args.get('doctype') in ['Sales Invoice', 'Purchase Invoice'] else 0, "delivered_by_supplier": item.delivered_by_supplier if args.get("doctype") in ["Sales Order", "Sales Invoice"] else 0, "is_fixed_asset": item.is_fixed_asset, "weight_per_unit": item.weight_per_unit, "weight_uom": item.weight_uom, "last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0, "transaction_date": args.get("transaction_date") }) if item.get("enable_deferred_revenue") or item.get( "enable_deferred_expense"): out.update(calculate_service_end_date(args, item)) # calculate conversion factor if item.stock_uom == args.uom: out.conversion_factor = 1.0 else: out.conversion_factor = args.conversion_factor or \ get_conversion_factor(item.name, args.uom).get("conversion_factor") args.conversion_factor = out.conversion_factor out.stock_qty = out.qty * out.conversion_factor # calculate last purchase rate if args.get('doctype') in purchase_doctypes: from erpnext.buying.doctype.purchase_order.purchase_order import item_last_purchase_rate out.last_purchase_rate = item_last_purchase_rate( args.name, args.conversion_rate, item.name, out.conversion_factor) # if default specified in item is for another company, fetch from company for d in [["Account", "income_account", "default_income_account"], ["Account", "expense_account", "default_expense_account"], ["Cost Center", "cost_center", "cost_center"], ["Warehouse", "warehouse", ""]]: if not out[d[1]]: out[d[1]] = frappe.get_cached_value('Company', args.company, d[2]) if d[2] else None for fieldname in ("item_name", "item_group", "barcodes", "brand", "stock_uom"): out[fieldname] = item.get(fieldname) if args.get("manufacturer"): part_no = get_item_manufacturer_part_no(args.get("item_code"), args.get("manufacturer")) if part_no: out["manufacturer_part_no"] = part_no else: out["manufacturer_part_no"] = None out["manufacturer"] = None else: data = frappe.get_value( "Item", item.name, ["default_item_manufacturer", "default_manufacturer_part_no"], as_dict=1) if data: out.update({ "manufacturer": data.default_item_manufacturer, "manufacturer_part_no": data.default_manufacturer_part_no }) child_doctype = args.doctype + ' Item' meta = frappe.get_meta(child_doctype) if meta.get_field("barcode"): update_barcode_value(out) return out
def run_onload(doc): doc.set("__onload", frappe._dict()) doc.run_method("onload")
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True, party_address=None, company_address=None, shipping_address=None, pos_profile=None): party_details = frappe._dict( set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype)) party = party_details[party_type.lower()] if not ignore_permissions and not frappe.has_permission( party_type, "read", party): frappe.throw( _("Not permitted for {0}").format(party), frappe.PermissionError) party = frappe.get_doc(party_type, party) currency = party.default_currency if party.get( "default_currency") else get_company_currency(company) party_address, shipping_address = set_address_details( party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) set_contact_details(party_details, party, party_type) set_other_values(party_details, party, party_type) set_price_list(party_details, party, party_type, price_list, pos_profile) party_details["tax_category"] = get_address_tax_category( party.get("tax_category"), party_address, shipping_address if party_type != "Supplier" else party_address) if not party_details.get("taxes_and_charges"): party_details["taxes_and_charges"] = set_taxes( party.name, party_type, posting_date, company, customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category, billing_address=party_address, shipping_address=shipping_address) if fetch_payment_terms_template: party_details["payment_terms_template"] = get_pyt_term_template( party.name, party_type, company) if not party_details.get("currency"): party_details["currency"] = currency # sales team if party_type == "Customer": party_details["sales_team"] = [{ "sales_person": d.sales_person, "allocated_percentage": d.allocated_percentage or None } for d in party.get("sales_team")] # supplier tax withholding category if party_type == "Supplier" and party: party_details["supplier_tds"] = frappe.get_value( party_type, party.name, "tax_withholding_category") return party_details
def update_raw_materials_supplied(self, item, raw_material_table): bom_items = self.get_items_from_bom(item.item_code, item.bom) raw_materials_cost = 0 items = list(set([d.item_code for d in bom_items])) item_wh = frappe._dict( frappe.db.sql( """select item_code, default_warehouse from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items)) for bom_item in bom_items: if self.doctype == "Purchase Order": reserve_warehouse = bom_item.source_warehouse or item_wh.get( bom_item.item_code) if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != self.company: reserve_warehouse = None # check if exists exists = 0 for d in self.get(raw_material_table): if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \ and d.reference_name == item.name: rm, exists = d, 1 break if not exists: rm = self.append(raw_material_table, {}) required_qty = flt( flt(bom_item.qty_consumed_per_unit) * flt(item.qty) * flt(item.conversion_factor), rm.precision("required_qty")) rm.reference_name = item.name rm.bom_detail_no = bom_item.name rm.main_item_code = item.item_code rm.rm_item_code = bom_item.item_code rm.stock_uom = bom_item.stock_uom rm.required_qty = required_qty if self.doctype == "Purchase Order" and not rm.reserve_warehouse: rm.reserve_warehouse = reserve_warehouse rm.conversion_factor = item.conversion_factor if self.doctype in ["Purchase Receipt", "Purchase Invoice"]: rm.consumed_qty = required_qty rm.description = bom_item.description if item.batch_no and not rm.batch_no: rm.batch_no = item.batch_no # get raw materials rate if self.doctype == "Purchase Receipt": from erpnext.stock.utils import get_incoming_rate rm.rate = get_incoming_rate({ "item_code": bom_item.item_code, "warehouse": self.supplier_warehouse, "posting_date": self.posting_date, "posting_time": self.posting_time, "qty": -1 * required_qty, "serial_no": rm.serial_no }) if not rm.rate: rm.rate = get_valuation_rate( bom_item.item_code, self.supplier_warehouse, self.doctype, self.name, currency=self.company_currency, company=self.company) else: rm.rate = bom_item.rate rm.amount = required_qty * flt(rm.rate) raw_materials_cost += flt(rm.amount) if self.doctype in ("Purchase Receipt", "Purchase Invoice"): item.rm_supp_cost = raw_materials_cost
def migrate_doctype(self, doctype, filters=None, update=None, verbose=1, exclude=None, preprocess=None): """Migrate records from another doctype""" meta = frappe.get_meta(doctype) tables = {} for df in meta.get_table_fields(): if verbose: print("getting " + df.options) tables[df.fieldname] = self.get_list(df.options, limit_page_length=999999) # get links if verbose: print("getting " + doctype) docs = self.get_list(doctype, limit_page_length=999999, filters=filters) # build - attach children to parents if tables: docs = [frappe._dict(doc) for doc in docs] docs_map = dict((doc.name, doc) for doc in docs) for fieldname in tables: for child in tables[fieldname]: child = frappe._dict(child) if child.parent in docs_map: docs_map[child.parent].setdefault(fieldname, []).append(child) if verbose: print("inserting " + doctype) for doc in docs: if exclude and doc["name"] in exclude: continue if preprocess: preprocess(doc) if not doc.get("owner"): doc["owner"] = "Administrator" if doctype != "User" and not frappe.db.exists( "User", doc.get("owner")): frappe.get_doc({ "doctype": "User", "email": doc.get("owner"), "first_name": doc.get("owner").split("@")[0] }).insert() if update: doc.update(update) doc["doctype"] = doctype new_doc = frappe.get_doc(doc) new_doc.insert() if not meta.istable: if doctype != "Communication": self.migrate_doctype( "Communication", { "reference_doctype": doctype, "reference_name": doc["name"] }, update={"reference_name": new_doc.name}, verbose=0) if doctype != "File": self.migrate_doctype( "File", { "attached_to_doctype": doctype, "attached_to_name": doc["name"] }, update={"attached_to_name": new_doc.name}, verbose=0)
def get_rootwise_opening_balances(filters, report_type): additional_conditions = "" if not filters.show_unclosed_fy_pl_balances: additional_conditions = " and posting_date >= %(year_start_date)s" \ if report_type == "Profit and Loss" else "" if not flt(filters.with_period_closing_entry): additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'" if filters.cost_center: lft, rgt = frappe.db.get_value('Cost Center', filters.cost_center, ['lft', 'rgt']) additional_conditions += """ and cost_center in (select name from `tabCost Center` where lft >= %s and rgt <= %s)""" % (lft, rgt) if filters.finance_book: fb_conditions = " and finance_book = %(finance_book)s" if filters.include_default_book_entries: fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s))" additional_conditions += fb_conditions accounting_dimensions = get_accounting_dimensions() query_filters = { "company": filters.company, "from_date": filters.from_date, "report_type": report_type, "year_start_date": filters.year_start_date, "finance_book": filters.finance_book, "company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book') } if accounting_dimensions: for dimension in accounting_dimensions: additional_conditions += """ and {0} in (%({0})s) """.format( dimension) query_filters.update({dimension: filters.get(dimension)}) gle = frappe.db.sql(""" select account, sum(debit) as opening_debit, sum(credit) as opening_credit from `tabGL Entry` where company=%(company)s {additional_conditions} and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes') and account in (select name from `tabAccount` where report_type=%(report_type)s) group by account""".format(additional_conditions=additional_conditions), query_filters, as_dict=True) opening = frappe._dict() for d in gle: opening.setdefault(d.account, d) return opening
def make_purchase_receipt(**args): if not frappe.db.exists('Location', 'Test Location'): frappe.get_doc({ 'doctype': 'Location', 'location_name': 'Test Location' }).insert() frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) pr = frappe.new_doc("Purchase Receipt") args = frappe._dict(args) pr.posting_date = args.posting_date or today() if args.posting_time: pr.posting_time = args.posting_time if args.posting_date or args.posting_time: pr.set_posting_time = 1 pr.company = args.company or "_Test Company" pr.supplier = args.supplier or "_Test Supplier" pr.is_subcontracted = args.is_subcontracted or "No" pr.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC" pr.currency = args.currency or "INR" pr.is_return = args.is_return pr.return_against = args.return_against qty = args.qty or 5 received_qty = args.received_qty or qty rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty) item_code = args.item or args.item_code or "_Test Item" uom = args.uom or frappe.db.get_value("Item", item_code, "stock_uom") or "_Test UOM" pr.append( "items", { "item_code": item_code, "warehouse": args.warehouse or "_Test Warehouse - _TC", "qty": qty, "received_qty": received_qty, "rejected_qty": rejected_qty, "rejected_warehouse": args.rejected_warehouse or "_Test Rejected Warehouse - _TC" if rejected_qty != 0 else "", "rate": args.rate if args.rate != None else 50, "conversion_factor": args.conversion_factor or 1.0, "serial_no": args.serial_no, "stock_uom": args.stock_uom or "_Test UOM", "uom": uom, "cost_center": args.cost_center or frappe.get_cached_value('Company', pr.company, 'cost_center'), "asset_location": args.location or "Test Location" }) if args.get_multiple_items: pr.items = [] for item in get_items(warehouse=args.warehouse, cost_center=args.cost_center or frappe.get_cached_value( 'Company', pr.company, 'cost_center')): pr.append("items", item) if args.get_taxes_and_charges: for tax in get_taxes(): pr.append("taxes", tax) if not args.do_not_save: pr.insert() if not args.do_not_submit: pr.submit() return pr
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals import frappe from erpnext.setup.page.setup_wizard.test_setup_data import args from erpnext.setup.page.setup_wizard.setup_wizard import setup_account if __name__ == "__main__": frappe.connect() frappe.local.form_dict = frappe._dict(args) setup_account()
def get_outstanding_invoices(party_type, party, account, condition=None): outstanding_invoices = [] precision = frappe.get_precision("Sales Invoice", "outstanding_amount") if party_type in ("Customer", "Student"): dr_or_cr = "debit_in_account_currency - credit_in_account_currency" payment_dr_or_cr = "payment_gl_entry.credit_in_account_currency - payment_gl_entry.debit_in_account_currency" else: dr_or_cr = "credit_in_account_currency - debit_in_account_currency" payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency" invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice' invoice_list = frappe.db.sql(""" select voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, ( select ifnull(sum({payment_dr_or_cr}), 0) from `tabGL Entry` payment_gl_entry where payment_gl_entry.against_voucher_type = invoice_gl_entry.voucher_type and if(invoice_gl_entry.voucher_type='Journal Entry', payment_gl_entry.against_voucher = invoice_gl_entry.voucher_no, payment_gl_entry.against_voucher = invoice_gl_entry.against_voucher) and payment_gl_entry.party_type = invoice_gl_entry.party_type and payment_gl_entry.party = invoice_gl_entry.party and payment_gl_entry.account = invoice_gl_entry.account and {payment_dr_or_cr} > 0 ) as payment_amount from `tabGL Entry` invoice_gl_entry where party_type = %(party_type)s and party = %(party)s and account = %(account)s and {dr_or_cr} > 0 {condition} and ((voucher_type = 'Journal Entry' and (against_voucher = '' or against_voucher is null)) or (voucher_type not in ('Journal Entry', 'Payment Entry'))) group by voucher_type, voucher_no having (invoice_amount - payment_amount) > 0.005 order by posting_date, name""".format(dr_or_cr=dr_or_cr, invoice=invoice, payment_dr_or_cr=payment_dr_or_cr, condition=condition or ""), { "party_type": party_type, "party": party, "account": account, }, as_dict=True) for d in invoice_list: due_date = frappe.db.get_value( d.voucher_type, d.voucher_no, "posting_date" if party_type == "Employee" else "due_date") outstanding_invoices.append( frappe._dict({ 'voucher_no': d.voucher_no, 'voucher_type': d.voucher_type, 'posting_date': d.posting_date, 'invoice_amount': flt(d.invoice_amount), 'payment_amount': flt(d.payment_amount), 'outstanding_amount': flt(d.invoice_amount - d.payment_amount, precision), 'due_date': due_date })) outstanding_invoices = sorted( outstanding_invoices, key=lambda k: k['due_date'] or getdate(nowdate())) return outstanding_invoices
def get_ewb_data(dt, dn): if dt != 'Sales Invoice': frappe.throw( _('e-Way Bill JSON can only be generated from Sales Invoice')) dn = dn.split(',') ewaybills = [] for doc_name in dn: doc = frappe.get_doc(dt, doc_name) validate_sales_invoice(doc) data = frappe._dict({ "transporterId": "", "TotNonAdvolVal": 0, }) data.userGstin = data.fromGstin = doc.company_gstin data.supplyType = 'O' if doc.gst_category in ['Registered Regular', 'SEZ']: data.subSupplyType = 1 elif doc.gst_category in ['Overseas', 'Deemed Export']: data.subSupplyType = 3 else: frappe.throw( _('Unsupported GST Category for e-Way Bill JSON generation')) data.docType = 'INV' data.docDate = frappe.utils.formatdate(doc.posting_date, 'dd/mm/yyyy') company_address = frappe.get_doc('Address', doc.company_address) billing_address = frappe.get_doc('Address', doc.customer_address) shipping_address = frappe.get_doc('Address', doc.shipping_address_name) data = get_address_details(data, doc, company_address, billing_address) data.itemList = [] data.totalValue = doc.total data = get_item_list(data, doc) disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total') data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total data = get_transport_details(data, doc) fields = { "/. -": { 'docNo': doc.name, 'fromTrdName': doc.company, 'toTrdName': doc.customer_name, 'transDocNo': doc.lr_no, }, "@#/,&. -": { 'fromAddr1': company_address.address_line1, 'fromAddr2': company_address.address_line2, 'fromPlace': company_address.city, 'toAddr1': shipping_address.address_line1, 'toAddr2': shipping_address.address_line2, 'toPlace': shipping_address.city, 'transporterName': doc.transporter_name } } for allowed_chars, field_map in fields.items(): for key, value in field_map.items(): if not value: data[key] = '' else: data[key] = re.sub(r'[^\w' + allowed_chars + ']', '', value) ewaybills.append(data) data = {'version': '1.0.1118', 'billLists': ewaybills} return data
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False, company=None, reset_period_on_fy_change=True): """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" fiscal_year = get_fiscal_year_data(from_fiscal_year, to_fiscal_year) validate_fiscal_year(fiscal_year, from_fiscal_year, to_fiscal_year) # start with first day, so as to avoid year to_dates like 2-April if ever they occur] year_start_date = getdate(fiscal_year.year_start_date) year_end_date = getdate(fiscal_year.year_end_date) months_to_add = { "Yearly": 12, "Half-Yearly": 6, "Quarterly": 3, "Monthly": 1 }[periodicity] period_list = [] start_date = year_start_date months = get_months(year_start_date, year_end_date) for i in range(months // months_to_add): period = frappe._dict({"from_date": start_date}) to_date = add_months(start_date, months_to_add) start_date = to_date if to_date == get_first_day(to_date): # if to_date is the first day, get the last day of previous month to_date = add_days(to_date, -1) if to_date <= year_end_date: # the normal case period.to_date = to_date else: # if a fiscal year ends before a 12 month period period.to_date = year_end_date period.to_date_fiscal_year = get_fiscal_year(period.to_date, company=company)[0] period.from_date_fiscal_year_start_date = get_fiscal_year( period.from_date, company=company)[1] period_list.append(period) if period.to_date == year_end_date: break # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() if periodicity == "Monthly" and not accumulated_values: label = formatdate(opts["to_date"], "MMM YYYY") else: if not accumulated_values: label = get_label(periodicity, opts["from_date"], opts["to_date"]) else: if reset_period_on_fy_change: label = get_label(periodicity, opts.from_date_fiscal_year_start_date, opts["to_date"]) else: label = get_label(periodicity, period_list[0].from_date, opts["to_date"]) opts.update({ "key": key.replace(" ", "_").replace("-", "_"), "label": label, "year_start_date": year_start_date, "year_end_date": year_end_date }) return period_list
def get_invoice_summary(items, taxes): summary_data = frappe._dict() for tax in taxes: #Include only VAT charges. if tax.charge_type == "Actual": continue #Charges to appear as items in the e-invoice. if tax.charge_type in ["On Previous Row Total", "On Previous Row Amount"]: reference_row = next((row for row in taxes if row.idx == int(tax.row_id or 0)), None) if reference_row: items.append( frappe._dict( idx=len(items)+1, item_code=reference_row.description, item_name=reference_row.description, description=reference_row.description, rate=reference_row.tax_amount, qty=1.0, amount=reference_row.tax_amount, stock_uom=frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos"), tax_rate=tax.rate, tax_amount=(reference_row.tax_amount * tax.rate) / 100, net_amount=reference_row.tax_amount, taxable_amount=reference_row.tax_amount, item_tax_rate={tax.account_head: tax.rate}, charges=True ) ) #Check item tax rates if tax rate is zero. if tax.rate == 0: for item in items: item_tax_rate = item.item_tax_rate if isinstance(item.item_tax_rate, string_types): item_tax_rate = json.loads(item.item_tax_rate) if item_tax_rate and tax.account_head in item_tax_rate: key = cstr(item_tax_rate[tax.account_head]) if key not in summary_data: summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""}) summary_data[key]["tax_amount"] += item.tax_amount summary_data[key]["taxable_amount"] += item.net_amount if key == "0.0": summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law if summary_data.get("0.0") and tax.charge_type in ["On Previous Row Total", "On Previous Row Amount"]: summary_data[key]["taxable_amount"] = tax.total if summary_data == {}: #Implies that Zero VAT has not been set on any item. summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total, "tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law}) else: item_wise_tax_detail = json.loads(tax.item_wise_tax_detail) for rate_item in [tax_item for tax_item in item_wise_tax_detail.items() if tax_item[1][0] == tax.rate]: key = cstr(tax.rate) if not summary_data.get(key): summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0}) summary_data[key]["tax_amount"] += rate_item[1][1] summary_data[key]["taxable_amount"] += sum([item.net_amount for item in items if item.item_code == rate_item[0]]) for item in items: key = cstr(tax.rate) if item.get("charges"): if not summary_data.get(key): summary_data.setdefault(key, {"taxable_amount": 0.0}) summary_data[key]["taxable_amount"] += item.taxable_amount return summary_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 get_party_and_account_balance(company, date, paid_from=None, paid_to=None, ptype=None, pty=None, cost_center=None): return frappe._dict({ "party_balance": get_balance_on(party_type=ptype, party=pty, cost_center=cost_center), "paid_from_account_balance": get_balance_on(paid_from, date, cost_center=cost_center), "paid_to_account_balance": get_balance_on(paid_to, date=date, cost_center=cost_center) })
def get_incoming_server(self, in_receive=False, email_sync_rule="UNSEEN"): """Returns logged in POP3/IMAP connection object.""" if frappe.cache().get_value("workers:no-internet") == True: return None args = frappe._dict({ "email_account": self.name, "host": self.email_server, "use_ssl": self.use_ssl, "username": getattr(self, "login_id", None) or self.email_id, "use_imap": self.use_imap, "email_sync_rule": email_sync_rule, "uid_validity": self.uidvalidity, "incoming_port": get_port(self), "initial_sync_count": self.initial_sync_count or 100 }) if self.password: args.password = self.get_password() if not args.get("host"): frappe.throw(_("{0} is required").format("Email Server")) email_server = EmailServer(frappe._dict(args)) try: email_server.connect() except (error_proto, imaplib.IMAP4.error) as e: e = cstr(e) message = e.lower().replace(" ", "") if in_receive and any( map( lambda t: t in message, [ 'authenticationfailed', 'loginviayourwebbrowser', #abbreviated to work with both failure and failed 'loginfailed', 'err[auth]', 'errtemporaryerror' ])): #temporary error to deal with godaddy # if called via self.receive and it leads to authentication error, disable incoming # and send email to system manager self.handle_incoming_connect_error(description=_( 'Authentication failed while receiving emails from Email Account {0}. Message from server: {1}' .format(self.name, e))) return None else: frappe.throw(e) except socket.error: if in_receive: # timeout while connecting, see receive.py connect method description = frappe.message_log.pop( ) if frappe.message_log else "Socket Error" if test_internet(): self.db_set("no_failed", self.no_failed + 1) if self.no_failed > 2: self.handle_incoming_connect_error( description=description) else: frappe.cache().set_value("workers:no-internet", True) return None else: raise if not in_receive: if self.use_imap: email_server.imap.logout() # reset failed attempts count self.set_failed_attempts_count(0) return email_server
def generate_otp(medium="sms", medium_id=None, sms_hash=None, purpose="login"): """ Generate and Send an OTP through the medium specified. we generate new pin on each call, ignoring previous pins :param medium: 'email' or 'sms' :param medium_id: The actual email/mobile_no :param sms_hash: The hash that should be appended to OTP SMS :param purpose: Specify an optional purpose (login, pwd_reset) to make a custom context """ if medium not in ("sms", "email"): frappe.throw("medium can only be 'sms' or 'email'") if not medium_id: frappe.throw(f"medium_id is mandatory") user = get_linked_user(id_type=medium, id=medium_id) # generate a pin otp = frappe.safe_decode(str(get_otp())) # saving the hashed pin, not the pin as is hashed_pin = passlibctx.hash(otp) expires_in_sec = (cint( frappe.db.get_value("System Settings", None, "verification_otp_validity")) or 15) * 60 frappe.cache().set_value(get_otp_redis_key(medium, medium_id, purpose), hashed_pin, expires_in_sec=expires_in_sec) status = "success" if medium == "sms": msg = u"Your verification OTP is: " + otp if sms_hash: msg = msg + u". " + sms_hash sms = send_sms([medium_id], msg, success_msg=False) status = "fail" # Since SMS Settings might remove or add '+' character, we will check against the last 5 digits if sms and isinstance( sms, list) and len(sms) == 1 and medium_id[-5:] in sms[0]: status = "success" elif medium == "email": email_otp_template = frappe.db.get_value("System Settings", None, "email_otp_template") if not email_otp_template: frappe.throw("Please set Email OTP Template in System Settings") email_otp_template = frappe.get_doc("Email Template", email_otp_template) render_params = frappe._dict( otp=otp, email=medium_id, user=frappe.get_doc("User", user) if user else frappe._dict()) status = "fail" try: frappe.sendmail( recipients=[medium_id], subject=frappe.render_template(email_otp_template.subject, render_params), message=frappe.render_template(email_otp_template.response, render_params)) status = "success" except frappe.OutgoingEmailError: status = "fail" return frappe._dict({"status": status, medium: medium_id})
class Item(WebsiteGenerator): website = frappe._dict( page_title_field = "item_name", condition_field = "show_in_website", template = "templates/generators/item.html", no_cache = 1 ) def onload(self): super(Item, self).onload() self.set_onload('sle_exists', self.check_if_sle_exists()) if self.is_fixed_asset: asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1) self.set_onload("asset_exists", True if asset else False) def autoname(self): if frappe.db.get_default("item_naming_by")=="Naming Series": if self.variant_of: if not self.item_code: template_item_name = frappe.db.get_value("Item", self.variant_of, "item_name") self.item_code = make_variant_item_code(self.variant_of, template_item_name, self) else: from frappe.model.naming import make_autoname self.item_code = make_autoname(self.naming_series+'.#####') elif not self.item_code: msgprint(_("Item Code is mandatory because Item is not automatically numbered"), raise_exception=1) self.item_code = strip(self.item_code) self.name = self.item_code def before_insert(self): if not self.description: self.description = self.item_name self.publish_in_hub = 1 def after_insert(self): '''set opening stock and item price''' if self.standard_rate: self.add_price() if self.opening_stock: self.set_opening_stock() def validate(self): super(Item, self).validate() if not self.item_name: self.item_name = self.item_code if not self.description: self.description = self.item_name self.validate_uom() self.add_default_uom_in_conversion_factor_table() self.validate_conversion_factor() self.validate_item_type() self.check_for_active_boms() self.fill_customer_code() self.check_item_tax() self.validate_barcode() self.cant_change() self.validate_warehouse_for_reorder() self.update_item_desc() self.synced_with_hub = 0 self.validate_has_variants() self.validate_attributes() self.validate_variant_attributes() self.validate_website_image() self.make_thumbnail() self.validate_fixed_asset() if not self.get("__islocal"): self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") self.old_website_item_groups = frappe.db.sql_list("""select item_group from `tabWebsite Item Group` where parentfield='website_item_groups' and parenttype='Item' and parent=%s""", self.name) def on_update(self): invalidate_cache_for_item(self) self.validate_name_with_item_group() self.update_item_price() self.update_template_item() def add_price(self, price_list=None): '''Add a new price''' if not price_list: price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list') or frappe.db.get_value('Price List', _('Standard Selling'))) if price_list: item_price = frappe.get_doc({ "doctype": "Item Price", "price_list": price_list, "item_code": self.name, "currency": erpnext.get_default_currency(), "price_list_rate": self.standard_rate }) item_price.insert() def set_opening_stock(self): '''set opening stock''' if not self.is_stock_item or self.has_serial_no or self.has_batch_no: return if not self.valuation_rate and self.standard_rate: self.valuation_rate = self.standard_rate if not self.valuation_rate: frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered")) from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry # default warehouse, or Stores default_warehouse = (frappe.db.get_single_value('Stock Settings', 'default_warehouse') or frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})) if default_warehouse: stock_entry = make_stock_entry(item_code=self.name, target=default_warehouse, qty=self.opening_stock, rate=self.valuation_rate) stock_entry.add_comment("Comment", _("Opening Stock")) def make_route(self): if not self.route: return cstr(frappe.db.get_value('Item Group', self.item_group, 'route')) + '/' + self.scrub(self.item_name + '-' + random_string(5)) def get_parents(self, context): item_group, route = frappe.db.get_value('Item Group', self.item_group, ['name', 'route']) context.parents = [{'name': route, 'label': item_group}] def validate_website_image(self): """Validate if the website image is a public file""" auto_set_website_image = False if not self.website_image and self.image: auto_set_website_image = True self.website_image = self.image if not self.website_image: return # find if website image url exists as public file_doc = frappe.get_all("File", filters={ "file_url": self.website_image }, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1) if file_doc: file_doc = file_doc[0] if not file_doc: if not auto_set_website_image: frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found") .format(self.website_image, self.name)) self.website_image = None elif file_doc.is_private: if not auto_set_website_image: frappe.msgprint(_("Website Image should be a public file or website URL")) self.website_image = None def make_thumbnail(self): """Make a thumbnail of `website_image`""" import requests.exceptions if not self.is_new() and self.website_image != frappe.db.get_value(self.doctype, self.name, "website_image"): self.thumbnail = None if self.website_image and not self.thumbnail: file_doc = None try: file_doc = frappe.get_doc("File", { "file_url": self.website_image, "attached_to_doctype": "Item", "attached_to_name": self.name }) except frappe.DoesNotExistError: pass # cleanup frappe.local.message_log.pop() except requests.exceptions.HTTPError: frappe.msgprint(_("Warning: Invalid attachment {0}").format(self.website_image)) self.website_image = None except requests.exceptions.SSLError: frappe.msgprint(_("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image)) self.website_image = None # for CSV import if self.website_image and not file_doc: try: file_doc = frappe.get_doc({ "doctype": "File", "file_url": self.website_image, "attached_to_doctype": "Item", "attached_to_name": self.name }).insert() except IOError: self.website_image = None if file_doc: if not file_doc.thumbnail_url: file_doc.make_thumbnail() self.thumbnail = file_doc.thumbnail_url def validate_fixed_asset(self): if self.is_fixed_asset: if self.is_stock_item: frappe.throw(_("Fixed Asset Item must be a non-stock item.")) if not self.asset_category: frappe.throw(_("Asset Category is mandatory for Fixed Asset item")) def get_context(self, context): context.show_search=True context.search_link = '/product_search' context.parent_groups = get_parent_item_groups(self.item_group) + \ [{"name": self.name}] self.set_variant_context(context) self.set_attribute_context(context) self.set_disabled_attributes(context) context.parents = self.get_parents(context) return context def set_variant_context(self, context): if self.has_variants: context.no_cache = True # load variants # also used in set_attribute_context context.variants = frappe.get_all("Item", filters={"variant_of": self.name, "show_variant_in_website": 1}, order_by="name asc") variant = frappe.form_dict.variant if not variant and context.variants: # the case when the item is opened for the first time from its list variant = context.variants[0] if variant: context.variant = frappe.get_doc("Item", variant) for fieldname in ("website_image", "web_long_description", "description", "website_specifications"): if context.variant.get(fieldname): value = context.variant.get(fieldname) if isinstance(value, list): value = [d.as_dict() for d in value] context[fieldname] = value if self.slideshow: if context.variant and context.variant.slideshow: context.update(get_slideshow(context.variant)) else: context.update(get_slideshow(self)) def set_attribute_context(self, context): if self.has_variants: attribute_values_available = {} context.attribute_values = {} context.selected_attributes = {} # load attributes for v in context.variants: v.attributes = frappe.get_all("Item Variant Attribute", fields=["attribute", "attribute_value"], filters={"parent": v.name}) for attr in v.attributes: values = attribute_values_available.setdefault(attr.attribute, []) if attr.attribute_value not in values: values.append(attr.attribute_value) if v.name==context.variant.name: context.selected_attributes[attr.attribute] = attr.attribute_value # filter attributes, order based on attribute table for attr in self.attributes: values = context.attribute_values.setdefault(attr.attribute, []) if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")): for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt): values.append(val) else: # get list of values defined (for sequence) for attr_value in frappe.db.get_all("Item Attribute Value", fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"): if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []): values.append(attr_value.attribute_value) context.variant_info = json.dumps(context.variants) def set_disabled_attributes(self, context): """Disable selection options of attribute combinations that do not result in a variant""" if not self.attributes or not self.has_variants: return context.disabled_attributes = {} attributes = [attr.attribute for attr in self.attributes] def find_variant(combination): for variant in context.variants: if len(variant.attributes) < len(attributes): continue if "combination" not in variant: ref_combination = [] for attr in variant.attributes: idx = attributes.index(attr.attribute) ref_combination.insert(idx, attr.attribute_value) variant["combination"] = ref_combination if not (set(combination) - set(variant["combination"])): # check if the combination is a subset of a variant combination # eg. [Blue, 0.5] is a possible combination if exists [Blue, Large, 0.5] return True for i, attr in enumerate(self.attributes): if i==0: continue combination_source = [] # loop through previous attributes for prev_attr in self.attributes[:i]: combination_source.append([context.selected_attributes.get(prev_attr.attribute)]) combination_source.append(context.attribute_values[attr.attribute]) for combination in itertools.product(*combination_source): if not find_variant(combination): context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1]) def add_default_uom_in_conversion_factor_table(self): uom_conv_list = [d.uom for d in self.get("uoms")] if self.stock_uom not in uom_conv_list: ch = self.append('uoms', {}) ch.uom = self.stock_uom ch.conversion_factor = 1 to_remove = [] for d in self.get("uoms"): if d.conversion_factor == 1 and d.uom != self.stock_uom: to_remove.append(d) [self.remove(d) for d in to_remove] def update_template_tables(self): template = frappe.get_doc("Item", self.variant_of) # add item taxes from template for d in template.get("taxes"): self.append("taxes", {"tax_type": d.tax_type, "tax_rate": d.tax_rate}) # copy re-order table if empty if not self.get("reorder_levels"): for d in template.get("reorder_levels"): n = {} for k in ("warehouse", "warehouse_reorder_level", "warehouse_reorder_qty", "material_request_type"): n[k] = d.get(k) self.append("reorder_levels", n) def validate_conversion_factor(self): check_list = [] for d in self.get('uoms'): if cstr(d.uom) in check_list: frappe.throw(_("Unit of Measure {0} has been entered more than once in Conversion Factor Table").format(d.uom)) else: check_list.append(cstr(d.uom)) if d.uom and cstr(d.uom) == cstr(self.stock_uom) and flt(d.conversion_factor) != 1: frappe.throw(_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx)) def validate_item_type(self): if self.has_serial_no == 1 and self.is_stock_item == 0: msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1) if self.has_serial_no == 0 and self.serial_no_series: self.serial_no_series = None def check_for_active_boms(self): if self.default_bom: bom_item = frappe.db.get_value("BOM", self.default_bom, "item") if bom_item not in (self.name, self.variant_of): frappe.throw(_("Default BOM ({0}) must be active for this item or its template").format(bom_item)) def fill_customer_code(self): """ Append all the customer codes and insert into "customer_code" field of item table """ cust_code=[] for d in self.get('customer_items'): cust_code.append(d.ref_code) self.customer_code=','.join(cust_code) def check_item_tax(self): """Check whether Tax Rate is not entered twice for same Tax Type""" check_list=[] for d in self.get('taxes'): if d.tax_type: account_type = frappe.db.get_value("Account", d.tax_type, "account_type") if account_type not in ['Tax', 'Chargeable', 'Income Account', 'Expense Account']: frappe.throw(_("Item Tax Row {0} must have account of type Tax or Income or Expense or Chargeable").format(d.idx)) else: if d.tax_type in check_list: frappe.throw(_("{0} entered twice in Item Tax").format(d.tax_type)) else: check_list.append(d.tax_type) def validate_barcode(self): if self.barcode: duplicate = frappe.db.sql("""select name from tabItem where barcode = %s and name != %s""", (self.barcode, self.name)) if duplicate: frappe.throw(_("Barcode {0} already used in Item {1}").format(self.barcode, duplicate[0][0])) def cant_change(self): if not self.get("__islocal"): to_check = ("has_serial_no", "is_stock_item", "valuation_method", "has_batch_no", "is_fixed_asset") vals = frappe.db.get_value("Item", self.name, to_check, as_dict=True) if not vals.get('valuation_method') and self.get('valuation_method'): vals['valuation_method'] = frappe.db.get_single_value("Stock Settings", "valuation_method") or "FIFO" if vals: for key in to_check: if cstr(self.get(key)) != cstr(vals.get(key)): if not self.check_if_linked_document_exists(key): break # no linked document, allowed else: frappe.throw(_("As there are existing transactions against item {0}, you can not change the value of {1}").format(self.name, frappe.bold(self.meta.get_label(key)))) if vals and not self.is_fixed_asset and self.is_fixed_asset != vals.is_fixed_asset: asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1) if asset: frappe.throw(_('"Is Fixed Asset" cannot be unchecked, as Asset record exists against the item')) def check_if_linked_document_exists(self, key): linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "Purchase Receipt Item", "Purchase Invoice Item", "Stock Entry Detail", "Stock Reconciliation Item"] # For "Is Stock Item", following doctypes is important # because reserved_qty, ordered_qty and requested_qty updated from these doctypes if key == "is_stock_item": linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"] for doctype in linked_doctypes: if frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \ frappe.db.get_value("Production Order", filters={"production_item": self.name, "docstatus": 1}): return True for d in self.get("reorder_levels"): if d.warehouse_reorder_level and not d.warehouse_reorder_qty: frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx)) def validate_warehouse_for_reorder(self): warehouse = [] for i in self.get("reorder_levels"): if i.get("warehouse") and i.get("warehouse") not in warehouse: warehouse += [i.get("warehouse")] else: frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}") .format(i.idx, i.warehouse), DuplicateReorderRows) def check_if_sle_exists(self): sle = frappe.db.sql("""select name from `tabStock Ledger Entry` where item_code = %s""", self.name) return sle and 'exists' or 'not exists' def validate_name_with_item_group(self): # causes problem with tree build if frappe.db.exists("Item Group", self.name): frappe.throw(_("An Item Group exists with same name, please change the item name or rename the item group")) def update_item_price(self): frappe.db.sql("""update `tabItem Price` set item_name=%s, item_description=%s, modified=NOW() where item_code=%s""", (self.item_name, self.description, self.name)) def on_trash(self): super(Item, self).on_trash() frappe.db.sql("""delete from tabBin where item_code=%s""", self.item_code) frappe.db.sql("delete from `tabItem Price` where item_code=%s", self.name) for variant_of in frappe.get_all("Item", filters={"variant_of": self.name}): frappe.delete_doc("Item", variant_of.name) def before_rename(self, old_name, new_name, merge=False): if self.item_name==old_name: self.item_name=new_name if merge: # Validate properties before merging if not frappe.db.exists("Item", new_name): frappe.throw(_("Item {0} does not exist").format(new_name)) field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"] new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)] if new_properties != [cstr(self.get(fld)) for fld in field_list]: frappe.throw(_("To merge, following properties must be same for both items") + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list])) def after_rename(self, old_name, new_name, merge): if self.route: invalidate_cache_for_item(self) clear_cache(self.route) frappe.db.set_value("Item", new_name, "item_code", new_name) if merge: self.set_last_purchase_rate(new_name) self.recalculate_bin_qty(new_name) for dt in ("Sales Taxes and Charges", "Purchase Taxes and Charges"): for d in frappe.db.sql("""select name, item_wise_tax_detail from `tab{0}` where ifnull(item_wise_tax_detail, '') != ''""".format(dt), as_dict=1): item_wise_tax_detail = json.loads(d.item_wise_tax_detail) if old_name in item_wise_tax_detail: item_wise_tax_detail[new_name] = item_wise_tax_detail[old_name] item_wise_tax_detail.pop(old_name) frappe.db.set_value(dt, d.name, "item_wise_tax_detail", json.dumps(item_wise_tax_detail), update_modified=False) def set_last_purchase_rate(self, new_name): last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0) frappe.db.set_value("Item", new_name, "last_purchase_rate", last_purchase_rate) def recalculate_bin_qty(self, new_name): from erpnext.stock.stock_balance import repost_stock frappe.db.auto_commit_on_many_writes = 1 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) repost_stock_for_warehouses = frappe.db.sql_list("""select distinct warehouse from tabBin where item_code=%s""", new_name) # Delete all existing bins to avoid duplicate bins for the same item and warehouse frappe.db.sql("delete from `tabBin` where item_code=%s", new_name) for warehouse in repost_stock_for_warehouses: repost_stock(new_name, warehouse) frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) frappe.db.auto_commit_on_many_writes = 0 def copy_specification_from_item_group(self): self.set("website_specifications", []) if self.item_group: for label, desc in frappe.db.get_values("Item Website Specification", {"parent": self.item_group}, ["label", "description"]): row = self.append("website_specifications") row.label = label row.description = desc def update_item_desc(self): if frappe.db.get_value('BOM',self.name, 'description') != self.description: frappe.db.sql("""update `tabBOM` set description = %s where item = %s and docstatus < 2""",(self.description, self.name)) frappe.db.sql("""update `tabBOM Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name)) frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name)) def update_template_item(self): """Set Show in Website for Template Item if True for its Variant""" if self.variant_of and self.show_in_website: self.show_variant_in_website = 1 self.show_in_website = 0 if self.show_variant_in_website: # show template template_item = frappe.get_doc("Item", self.variant_of) if not template_item.show_in_website: template_item.show_in_website = 1 template_item.flags.ignore_permissions = True template_item.save() def validate_has_variants(self): if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"): if frappe.db.exists("Item", {"variant_of": self.name}): frappe.throw(_("Item has variants.")) def validate_uom(self): if not self.get("__islocal"): check_stock_uom_with_bin(self.name, self.stock_uom) if self.has_variants: for d in frappe.db.get_all("Item", filters= {"variant_of": self.name}): check_stock_uom_with_bin(d.name, self.stock_uom) if self.variant_of: template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom") if template_uom != self.stock_uom: frappe.throw(_("Default Unit of Measure for Variant '{0}' must be same as in Template '{1}'") .format(self.stock_uom, template_uom)) def validate_attributes(self): if (self.has_variants or self.variant_of) and self.variant_based_on=='Item Attribute': attributes = [] if not self.attributes: frappe.throw(_("Attribute table is mandatory")) for d in self.attributes: if d.attribute in attributes: frappe.throw(_("Attribute {0} selected multiple times in Attributes Table".format(d.attribute))) else: attributes.append(d.attribute) def validate_variant_attributes(self): if self.variant_of and self.variant_based_on=='Item Attribute': args = {} for d in self.attributes: if not d.attribute_value: frappe.throw(_("Please specify Attribute Value for attribute {0}").format(d.attribute)) args[d.attribute] = d.attribute_value variant = get_variant(self.variant_of, args, self.name) if variant: frappe.throw(_("Item variant {0} exists with same attributes") .format(variant), ItemVariantExistsError) validate_item_variant_attributes(self, args)
def get_bootinfo(): """build and return boot info""" frappe.set_user_lang(frappe.session.user) bootinfo = frappe._dict() hooks = frappe.get_hooks() doclist = [] # user get_user(bootinfo) # system info bootinfo['sysdefaults'] = frappe.defaults.get_defaults() bootinfo['server_date'] = frappe.utils.nowdate() if frappe.session['user'] != 'Guest': bootinfo['user_info'] = get_fullnames() bootinfo['sid'] = frappe.session['sid'] # home page bootinfo.modules = {} for app in frappe.get_installed_apps(): try: bootinfo.modules.update( frappe.get_attr(app + ".config.desktop.get_data")() or {}) except ImportError: pass except AttributeError: pass bootinfo.module_app = frappe.local.module_app bootinfo.hidden_modules = frappe.db.get_global("hidden_modules") bootinfo.doctype_icons = dict( frappe.db.sql("""select name, icon from tabDocType where ifnull(icon,'')!=''""")) bootinfo.single_types = frappe.db.sql_list( """select name from tabDocType where ifnull(issingle,0)=1""") add_home_page(bootinfo, doclist) bootinfo.page_info = get_allowed_pages() load_translations(bootinfo) add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) doclist.extend(get_meta_bundle("Page")) # ipinfo if frappe.session['data'].get('ipinfo'): bootinfo['ipinfo'] = frappe.session['data']['ipinfo'] # add docs bootinfo['docs'] = doclist for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) if bootinfo.lang: bootinfo.lang = unicode(bootinfo.lang) bootinfo['versions'] = {k: v['version'] for k, v in get_versions().items()} bootinfo.error_report_email = frappe.get_hooks("error_report_email") bootinfo.default_background_image = "/assets/frappe/images/ui/into-the-dawn.jpg" bootinfo.calendars = sorted(frappe.get_hooks("calendars")) return bootinfo
def http_response(out): r = frappe._dict(status=out, medium=medium_id) return r
def update_stock_ledger(self): self.update_reserved_qty() sl_entries = [] for d in self.get_item_list(): if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty): return_rate = 0 if cint(self.is_return ) and self.return_against and self.docstatus == 1: return_rate = self.get_incoming_rate_for_sales_return( d.item_code, d.warehouse, self.return_against) # On cancellation or if return entry submission, make stock ledger entry for # target warehouse first, to update serial no values properly if d.warehouse and ( (not cint(self.is_return) and self.docstatus == 1) or (cint(self.is_return) and self.docstatus == 2)): sl_entries.append( self.get_sl_entries( d, { "actual_qty": -1 * flt(d.qty), "incoming_rate": return_rate })) if d.target_warehouse: target_warehouse_sle = self.get_sl_entries( d, { "actual_qty": flt(d.qty), "warehouse": d.target_warehouse }) if self.docstatus == 1: if not cint(self.is_return): args = frappe._dict({ "item_code": d.item_code, "warehouse": d.warehouse, "posting_date": self.posting_date, "posting_time": self.posting_time, "qty": -1 * flt(d.qty), "serial_no": d.serial_no }) target_warehouse_sle.update( {"incoming_rate": get_incoming_rate(args)}) else: target_warehouse_sle.update( {"outgoing_rate": return_rate}) sl_entries.append(target_warehouse_sle) if d.warehouse and ( (not cint(self.is_return) and self.docstatus == 2) or (cint(self.is_return) and self.docstatus == 1)): sl_entries.append( self.get_sl_entries( d, { "actual_qty": -1 * flt(d.qty), "incoming_rate": return_rate })) self.make_sl_entries(sl_entries)
def _get_debit_credit_dict(label): return _dict(account="'{0}'".format(label), debit=0.0, credit=0.0, debit_in_account_currency=0.0, credit_in_account_currency=0.0)
def get_dashboard_info(party_type, party, loyalty_program=None): current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True) doctype = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice" companies = frappe.get_all(doctype, filters={ 'docstatus': 1, party_type.lower(): party }, distinct=1, fields=['company']) company_wise_info = [] company_wise_grand_total = frappe.get_all( doctype, filters={ 'docstatus': 1, party_type.lower(): party, 'posting_date': ('between', [ current_fiscal_year.year_start_date, current_fiscal_year.year_end_date ]) }, group_by="company", fields=[ "company", "sum(grand_total) as grand_total", "sum(base_grand_total) as base_grand_total" ]) loyalty_point_details = [] if party_type == "Customer": loyalty_point_details = frappe._dict( frappe.get_all( "Loyalty Point Entry", filters={ 'customer': party, 'expiry_date': ('>=', getdate()), }, group_by="company", fields=["company", "sum(loyalty_points) as loyalty_points"], as_list=1)) company_wise_billing_this_year = frappe._dict() for d in company_wise_grand_total: company_wise_billing_this_year.setdefault( d.company, { "grand_total": d.grand_total, "base_grand_total": d.base_grand_total }) company_wise_total_unpaid = frappe._dict( frappe.db.sql( """ select company, sum(debit_in_account_currency) - sum(credit_in_account_currency) from `tabGL Entry` where party_type = %s and party=%s group by company""", (party_type, party))) for d in companies: company_default_currency = frappe.db.get_value("Company", d.company, 'default_currency') party_account_currency = get_party_account_currency( party_type, party, d.company) if party_account_currency == company_default_currency: billing_this_year = flt( company_wise_billing_this_year.get(d.company, {}).get("base_grand_total")) else: billing_this_year = flt( company_wise_billing_this_year.get(d.company, {}).get("grand_total")) total_unpaid = flt(company_wise_total_unpaid.get(d.company)) if loyalty_point_details: loyalty_points = loyalty_point_details.get(d.company) info = {} info["billing_this_year"] = flt( billing_this_year) if billing_this_year else 0 info["currency"] = party_account_currency info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0 info["company"] = d.company if party_type == "Customer" and loyalty_point_details: info["loyalty_points"] = loyalty_points if party_type == "Supplier": info["total_unpaid"] = -1 * info["total_unpaid"] company_wise_info.append(info) return company_wise_info
def update_against_document_in_jv(self): """ Links invoice and advance voucher: 1. cancel advance voucher 2. split into multiple rows if partially adjusted, assign against voucher 3. submit advance voucher """ if self.doctype == "Sales Invoice": party_type = "Customer" party = self.customer party_account = self.debit_to dr_or_cr = "credit_in_account_currency" else: party_type = "Supplier" party = self.supplier party_account = self.credit_to dr_or_cr = "debit_in_account_currency" lst = [] for d in self.get('advances'): if flt(d.allocated_amount) > 0: args = frappe._dict({ 'voucher_type': d.reference_type, 'voucher_no': d.reference_name, 'voucher_detail_no': d.reference_row, 'against_voucher_type': self.doctype, 'against_voucher': self.name, 'account': party_account, 'party_type': party_type, 'party': party, 'is_advance': 'Yes', 'dr_or_cr': dr_or_cr, 'unadjusted_amount': flt(d.advance_amount), 'allocated_amount': flt(d.allocated_amount), 'exchange_rate': (self.conversion_rate if self.party_account_currency != self.company_currency else 1), 'grand_total': (self.base_grand_total if self.party_account_currency == self.company_currency else self.grand_total), 'outstanding_amount': self.outstanding_amount }) lst.append(args) if lst: from erpnext.accounts.utils import reconcile_against_document reconcile_against_document(lst)