def validate_expense_against_budget(args): args = frappe._dict(args) if frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"}): budget = frappe.db.sql(""" select bd.budget_allocated, cc.distribution_id from `tabCost Center` cc, `tabBudget Detail` bd where cc.name=bd.parent and cc.name=%s and account=%s and bd.fiscal_year=%s """, (args.cost_center, args.account, args.fiscal_year), as_dict=True) if budget and budget[0].budget_allocated: yearly_action, monthly_action = frappe.db.get_value("Company", args.company, ["yearly_bgt_flag", "monthly_bgt_flag"]) action_for = action = "" if monthly_action in ["Stop", "Warn"]: budget_amount = get_allocated_budget(budget[0].distribution_id, args.posting_date, args.fiscal_year, budget[0].budget_allocated) args["month_end_date"] = frappe.db.sql("select LAST_DAY(%s)", args.posting_date)[0][0] action_for, action = _("Monthly"), monthly_action elif yearly_action in ["Stop", "Warn"]: budget_amount = budget[0].budget_allocated action_for, action = _("Annual"), yearly_action if action_for: actual_expense = get_actual_expense(args) if actual_expense > budget_amount: frappe.msgprint(_("{0} budget for Account {1} against Cost Center {2} will exceed by {3}").format( _(action_for), args.account, args.cost_center, cstr(actual_expense - budget_amount))) if action=="Stop": raise BudgetError
def validate_for_items(self, obj): items = [] for d in obj.get("items"): if not d.qty: if obj.doctype == "Purchase Receipt" and d.rejected_qty: continue frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code)) # udpate with latest quantities bin = frappe.db.sql("""select projected_qty from `tabBin` where item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1) f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0} if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'): f_lst.pop('received_qty') for x in f_lst : if d.meta.get_field(x): d.set(x, f_lst[x]) item = frappe.db.sql("""select is_stock_item, is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""", d.item_code, as_dict=1)[0] from erpnext.stock.doctype.item.item import validate_end_of_life validate_end_of_life(d.item_code, item.end_of_life, item.disabled) # validate stock item if item.is_stock_item==1 and d.qty and not d.warehouse: frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx)) items.append(cstr(d.item_code)) if items and len(items) != len(set(items)) and \ not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0): frappe.msgprint(_("Warning: Same item has been entered multiple times."), alert=True)
def connect(self): """Connect to **Email Account**.""" try: if cint(self.settings.use_ssl): self.pop = Timed_POP3_SSL(self.settings.host, timeout=frappe.conf.get("pop_timeout")) else: self.pop = Timed_POP3(self.settings.host, timeout=frappe.conf.get("pop_timeout")) self.pop.user(self.settings.username) self.pop.pass_(self.settings.password) # connection established! return True except _socket.error: # Invalid mail server -- due to refusing connection frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.')) raise except poplib.error_proto, e: if self.is_temporary_system_problem(e): return False else: frappe.msgprint(_('Invalid User Name or Support Password. Please rectify and try again.')) raise
def get_pending_raw_materials(self): """ issue (item quantity) that is pending to issue or desire to transfer, whichever is less """ item_dict = self.get_bom_raw_materials(1) issued_item_qty = self.get_issued_qty() max_qty = flt(self.pro_doc.qty) for item in item_dict: pending_to_issue = (max_qty * item_dict[item]["qty"]) - issued_item_qty.get(item, 0) desire_to_transfer = flt(self.fg_completed_qty) * item_dict[item]["qty"] if desire_to_transfer <= pending_to_issue: item_dict[item]["qty"] = desire_to_transfer elif pending_to_issue > 0: item_dict[item]["qty"] = pending_to_issue else: item_dict[item]["qty"] = 0 # delete items with 0 qty for item in item_dict.keys(): if not item_dict[item]["qty"]: del item_dict[item] # show some message if not len(item_dict): frappe.msgprint(_("""All items have already been transferred for this Production Order.""")) return item_dict
def get_shipping_rates(delivery_note, add_shipping_overhead=False): """get packages Information from delivery note, create the xml request to fetch the ups rates""" try: # dn = frappe.get_doc("Delivery Note",delivery_note) if isinstance(delivery_note, DeliveryNote): dn = delivery_note else: dn = frappe.get_doc(json.loads(delivery_note)) if dn.dn_status in ["Draft", "Partialy Packed"]: frappe.throw("First create the packing slips") params = Helper.get_ups_api_params() rating_api = get_rating_service(params) request = get_ups_rating_request(dn, params) response = rating_api.request(request) shipping_rates = parse_xml_response_to_json(response) dn.ups_rates = json.dumps(shipping_rates) dn.dn_status = "UPS Rates Fetched" dn.save(ignore_permissions= True) if shipping_rates.get("03"): if add_shipping_overhead: add_shipping_charges(dn_name=dn.name, service_code="03") # return True return shipping_rates else: frappe.msgprint("UPS Ground rates are not available. Please select other services") return shipping_rates # return shipping_rates except PyUPSException, e: """ e is PyUPSException obj returns tuple as structured (message, request, response)""" frappe.throw(e[0])
def validate_filters(filters): if not filters.fiscal_year: frappe.throw(_("Fiscal Year {0} is required").format(filters.fiscal_year)) fiscal_year = frappe.db.get_value("Fiscal Year", filters.fiscal_year, ["year_start_date", "year_end_date"], as_dict=True) if not fiscal_year: frappe.throw(_("Fiscal Year {0} does not exist").format(filters.fiscal_year)) else: filters.year_start_date = getdate(fiscal_year.year_start_date) filters.year_end_date = getdate(fiscal_year.year_end_date) if not filters.from_date: filters.from_date = filters.year_start_date if not filters.to_date: filters.to_date = filters.year_end_date filters.from_date = getdate(filters.from_date) filters.to_date = getdate(filters.to_date) if filters.from_date > filters.to_date: frappe.throw(_("From Date cannot be greater than To Date")) if (filters.from_date < filters.year_start_date) or (filters.from_date > filters.year_end_date): frappe.msgprint(_("From Date should be within the Fiscal Year. Assuming From Date = {0}")\ .format(formatdate(filters.year_start_date))) filters.from_date = filters.year_start_date if (filters.to_date < filters.year_start_date) or (filters.to_date > filters.year_end_date): frappe.msgprint(_("To Date should be within the Fiscal Year. Assuming To Date = {0}")\ .format(formatdate(filters.year_end_date))) filters.to_date = filters.year_end_date
def get_data(filters): conditions, filters = get_conditions(filters) data = frappe.db.sql(""" select t1.employee, t3.employee_name, t1.designation, t3.passport_number, sum(case when t2.salary_component = 'Basic Pay' then ifnull(t2.amount,0) else 0 end) as basicpay, t3.nppf_number, sum(case when t2.salary_component = 'PF' then ifnull(t2.amount,0) else 0 end) as employeepf, sum(case when t2.salary_component = 'PF' then ifnull(t2.amount,0) else 0 end) as employerpf, sum(case when t2.salary_component = 'PF' then ifnull(t2.amount,0)*2 else 0 end) as total, t1.company, t1.branch, t1.department, t1.division, t1.section, t1.fiscal_year, t1.month from `tabSalary Slip` t1, `tabSalary Detail` t2, `tabEmployee` t3 where t1.docstatus = 1 %s and t3.employee = t1.employee and t2.parent = t1.name and t2.salary_component in ('Basic Pay','PF') group by t1.employee, t3.employee_name, t1.designation, t3.passport_number, t3.nppf_number, t1.company, t1.branch, t1.department, t1.division, t1.section, t1.fiscal_year, t1.month """ % conditions, filters) if not data: msgprint(_("No Data Found for month: ") + cstr(filters.get("month")) + _(" and year: ") + cstr(filters.get("fiscal_year")), raise_exception=1) return data
def create_remarks(self): r = [] if self.cheque_no: if self.cheque_date: r.append(_('Reference #{0} dated {1}').format(self.cheque_no, formatdate(self.cheque_date))) else: msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError) for d in self.get('accounts'): if d.reference_type=="Sales Invoice" and d.credit: r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \ d.reference_name)) if d.reference_type=="Sales Order" and d.credit: r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \ d.reference_name)) if d.reference_type == "Purchase Invoice" and d.debit: bill_no = frappe.db.sql("""select bill_no, bill_date from `tabPurchase Invoice` where name=%s""", d.reference_name) if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \ not in ['na', 'not applicable', 'none']: r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=self.company_currency), bill_no[0][0], bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d')))) if d.reference_type == "Purchase Order" and d.debit: r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = self.company_currency), \ d.reference_name)) if self.user_remark: r.append(_("Note: {0}").format(self.user_remark)) if r: self.remark = ("\n").join(r) #User Remarks is not mandatory
def validate_credit_debit_note(self): if self.stock_entry: if frappe.db.get_value("Stock Entry", self.stock_entry, "docstatus") != 1: frappe.throw(_("Stock Entry {0} is not submitted").format(self.stock_entry)) if frappe.db.exists({"doctype": "Journal Entry", "stock_entry": self.stock_entry, "docstatus":1}): frappe.msgprint(_("Warning: Another {0} # {1} exists against stock entry {2}".format(self.voucher_type, self.name, self.stock_entry)))
def get_balance(self): if not self.get('accounts'): msgprint(_("'Entries' cannot be empty"), raise_exception=True) else: flag, self.total_debit, self.total_credit = 0, 0, 0 diff = flt(self.difference, self.precision("difference")) # If any row without amount, set the diff on that row if diff: blank_row = None for d in self.get('accounts'): if not d.credit_in_account_currency and not d.debit_in_account_currency and diff != 0: blank_row = d if not blank_row: blank_row = self.append('accounts', {}) blank_row.exchange_rate = 1 if diff>0: blank_row.credit_in_account_currency = diff blank_row.credit = diff elif diff<0: blank_row.debit_in_account_currency = abs(diff) blank_row.debit = abs(diff) self.validate_total_debit_and_credit()
def validate_advance_jv(self, advance_table_fieldname, against_order_field): order_list = list(set([d.get(against_order_field) for d in self.get("items") if d.get(against_order_field)])) if order_list: account = self.get("debit_to" if self.doctype=="Sales Invoice" else "credit_to") jv_against_order = frappe.db.sql("""select parent, %s as against_order from `tabJournal Entry Account` where docstatus=1 and account=%s and ifnull(is_advance, 'No') = 'Yes' and ifnull(against_sales_order, '') in (%s) group by parent, against_sales_order""" % ("against_" + against_order_field, '%s', ', '.join(['%s']*len(order_list))), tuple([account] + order_list), as_dict=1) if jv_against_order: order_jv_map = {} for d in jv_against_order: order_jv_map.setdefault(d.against_order, []).append(d.parent) advance_jv_against_si = [d.journal_entry for d in self.get(advance_table_fieldname)] for order, jv_list in order_jv_map.items(): for jv in jv_list: if not advance_jv_against_si or jv not in advance_jv_against_si: frappe.msgprint(_("Journal Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.") .format(jv, order))
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield): from erpnext.controllers.status_updater import get_tolerance_for item_tolerance = {} global_tolerance = None for item in self.get("items"): if item.get(item_ref_dn): ref_amt = flt(frappe.db.get_value(ref_dt + " Item", item.get(item_ref_dn), based_on), self.precision(based_on, item)) if not ref_amt: frappe.msgprint(_("Warning: System will not check overbilling since amount for Item {0} in {1} is zero").format(item.item_code, ref_dt)) else: already_billed = frappe.db.sql("""select sum(%s) from `tab%s` where %s=%s and docstatus=1 and parent != %s""" % (based_on, self.doctype + " Item", item_ref_dn, '%s', '%s'), (item.get(item_ref_dn), self.name))[0][0] total_billed_amt = flt(flt(already_billed) + flt(item.get(based_on)), self.precision(based_on, item)) tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code, item_tolerance, global_tolerance) max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100) if total_billed_amt - max_allowed_amt > 0.01: frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt))
def validate_inspection(self): for d in self.get('purchase_receipt_details'): #Enter inspection date for all items that require inspection ins_reqd = frappe.db.sql("select inspection_required from `tabItem` where name = %s", (d.item_code,), as_dict = 1) ins_reqd = ins_reqd and ins_reqd[0]['inspection_required'] or 'No' if ins_reqd == 'Yes' and not d.qa_no: frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
def validate_value(self, fieldname, condition, val2, doc=None, raise_exception=None): """Check that value of fieldname should be 'condition' val2 else throw Exception.""" error_condition_map = { "in": _("one of"), "not in": _("none of"), "^": _("beginning with"), } if not doc: doc = self val1 = doc.get_value(fieldname) df = doc.meta.get_field(fieldname) val2 = doc.cast(val2, df) if not frappe.compare(val1, condition, val2): label = doc.meta.get_label(fieldname) condition_str = error_condition_map.get(condition, condition) if doc.parentfield: msg = _("Incorrect value in row {0}: {1} must be {2} {3}".format(doc.idx, label, condition_str, val2)) else: msg = _("Incorrect value: {0} must be {1} {2}".format(label, condition_str, val2)) # raise passed exception or True msgprint(msg, raise_exception=raise_exception or True)
def reconcile(self, args): self.get_invoice_entries() self.validate_invoice() dr_or_cr = "credit" if self.party_type == "Customer" else "debit" lst = [] for e in self.get('payments'): if e.invoice_type and e.invoice_number and e.allocated_amount: lst.append({ 'voucher_no' : e.journal_entry, 'voucher_detail_no' : e.voucher_detail_number, 'against_voucher_type' : e.invoice_type, 'against_voucher' : e.invoice_number, 'account' : self.receivable_payable_account, 'party_type': self.party_type, 'party': self.party, 'is_advance' : e.is_advance, 'dr_or_cr' : dr_or_cr, 'unadjusted_amt' : flt(e.amount), 'allocated_amt' : flt(e.allocated_amount) }) if lst: from erpnext.accounts.utils import reconcile_against_document reconcile_against_document(lst) msgprint(_("Successfully Reconciled")) self.get_unreconciled_entries()
def get_items(self): so_list = filter(None, [d.sales_order for d in self.get('sales_orders')]) if not so_list: msgprint(_("Please enter sales order in the above table")) return [] item_condition = "" if self.fg_item: item_condition = ' and so_item.item_code = "' + self.fg_item + '"' items = frappe.db.sql("""select distinct parent, item_code, warehouse, (qty - ifnull(delivered_qty, 0)) as pending_qty from `tabSales Order Item` so_item where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0) and exists (select * from `tabItem` item where item.name=so_item.item_code and (item.is_pro_applicable = 1 or item.is_sub_contracted_item = 1)) %s""" % \ (", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1) if self.fg_item: item_condition = ' and pi.item_code = "' + self.fg_item + '"' packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse, (((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty) as pending_qty from `tabSales Order Item` so_item, `tabPacked Item` pi where so_item.parent = pi.parent and so_item.docstatus = 1 and pi.parent_item = so_item.item_code and so_item.parent in (%s) and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0) and exists (select * from `tabItem` item where item.name=pi.item_code and (item.is_pro_applicable = 1 or item.is_sub_contracted_item = 1)) %s""" % \ (", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1) return items + packed_items
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 get_exchange_rate(from_currency, to_currency): exchange = "%s-%s" % (from_currency, to_currency) value = flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate")) if not value: try: cache = frappe.cache() key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency) value = cache.get(key) if not value: import requests response = requests.get("http://api.fixer.io/latest", params={ "base": from_currency, "symbols": to_currency }) # expire in 6 hours response.raise_for_status() value = response.json()["rates"][to_currency] cache.setex(key, value, 6 * 60 * 60) return flt(value) except: frappe.msgprint(_("Unable to find exchange rate for {0} to {1}").format(from_currency, to_currency)) return 0.0 else: return value
def stop_sales_order(self): self.check_modified_date() frappe.db.set(self, 'status', 'Stopped') self.update_reserved_qty() frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name)) self.notify_modified() clear_doctype_notifications(self)
def upload(): # get record details dt = frappe.form_dict.doctype dn = frappe.form_dict.docname folder = frappe.form_dict.folder file_url = frappe.form_dict.file_url filename = frappe.form_dict.filename if not filename and not file_url: frappe.msgprint(_("Please select a file or url"), raise_exception=True) # save if filename: filedata = save_uploaded(dt, dn, folder) elif file_url: filedata = save_url(file_url, dt, dn, folder) comment = {} if dt and dn: comment = frappe.get_doc(dt, dn).add_comment("Attachment", _("Added {0}").format("<a href='{file_url}' target='_blank'>{file_name}</a>".format(**filedata.as_dict()))) return { "name": filedata.name, "file_name": filedata.file_name, "file_url": filedata.file_url, "comment": comment.as_dict() if comment else {} }
def update(doctype, field, value, condition='', limit=500): if not limit or cint(limit) > 500: limit = 500 if condition: condition = ' where ' + condition if ';' in condition: frappe.throw(_('; not allowed in condition')) items = frappe.db.sql_list('''select name from `tab{0}`{1} limit 0, {2}'''.format(doctype, condition, limit), debug=1) n = len(items) for i, d in enumerate(items): doc = frappe.get_doc(doctype, d) doc.set(field, value) try: doc.save() except Exception as e: frappe.msgprint(_("Validation failed for {0}").format(frappe.bold(doc.name))) raise e frappe.publish_progress(float(i)*100/n, title = _('Updating Records'), doctype='Bulk Update', docname='Bulk Update') # clear messages frappe.local.message_log = [] frappe.msgprint(_('{0} records updated').format(n), title=_('Success'), indicator='green')
def get_conditions(filters): conditions = "" party_accounts = [] if filters.get("account"): party_accounts = [filters["account"]] else: cond = filters.get("company") and (" and company = '%s'" % filters["company"].replace("'", "\'")) or "" if filters.get("payment_type") == "Incoming": cond += " and master_type = 'Customer'" else: cond += " and master_type = 'Supplier'" party_accounts = frappe.db.sql_list("""select name from `tabAccount` where ifnull(master_name, '')!='' and docstatus < 2 %s""" % cond) if party_accounts: conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(party_accounts))) else: msgprint(_("No Customer or Supplier Accounts found"), raise_exception=1) if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"] if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"] return conditions, party_accounts
def scrap_asset(asset_name): asset = frappe.get_doc("Asset", asset_name) if asset.docstatus != 1: frappe.throw(_("Asset {0} must be submitted").format(asset.name)) elif asset.status in ("Cancelled", "Sold", "Scrapped"): frappe.throw(_("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status)) depreciation_series = frappe.db.get_value("Company", asset.company, "series_for_depreciation_entry") je = frappe.new_doc("Journal Entry") je.voucher_type = "Journal Entry" je.naming_series = depreciation_series je.posting_date = today() je.company = asset.company je.remark = "Scrap Entry for asset {0}".format(asset_name) for entry in get_gl_entries_on_asset_disposal(asset): entry.update({ "reference_type": "Asset", "reference_name": asset_name }) je.append("accounts", entry) je.flags.ignore_permissions = True je.submit() frappe.db.set_value("Asset", asset_name, "disposal_date", today()) frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") frappe.msgprint(_("Asset scrapped via Journal Entry {0}").format(je.name))
def remove_sal_slip(self): cond = '' for f in ['company', 'branch', 'department', 'division', 'designation', 'employee']: if self.get(f): cond += " and t1." + f + " = '" + self.get(f).replace("'", "\'") + "'" ss_list = frappe.db.sql_list(""" select t1.name from `tabSalary Slip` as t1 where t1.fiscal_year = '%s' and t1.month = '%s' and t1.docstatus = 0 %s """ % (self.fiscal_year, self.month, cond)) if ss_list: frappe.delete_doc("Salary Slip", frappe.db.sql_list(""" select t1.name from `tabSalary Slip` as t1 where t1.fiscal_year = '%s' and t1.month = '%s' and t1.docstatus = 0 %s """ % (self.fiscal_year, self.month, cond)), for_reload=True) frappe.msgprint(_("Un-submitted Salary Slip(s) for the Month:{0} and Year:{1} removed successfully.")\ .format(self.month, self.fiscal_year)) else: frappe.msgprint(_("No Un-submitted Salary Slip(s) Found."))
def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None): """Returns dict of account balance and party type to be set in Journal Entry on selection of account.""" if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) company_currency = get_company_currency(company) account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1) if account_details.account_type == "Receivable": party_type = "Customer" elif account_details.account_type == "Payable": party_type = "Supplier" else: party_type = "" grid_values = { "balance": get_balance_on(account, date), "party_type": party_type, "account_type": account_details.account_type, "account_currency": account_details.account_currency or company_currency, "exchange_rate": get_exchange_rate(account, account_details.account_currency, company, debit=debit, credit=credit, exchange_rate=exchange_rate) } # un-set party if not party type if not party_type: grid_values["party"] = "" return grid_values
def make_thumbnail(self): if self.file_url: if self.file_url.startswith("/files"): try: image, filename, extn = get_local_image(self.file_url) except IOError: return else: try: image, filename, extn = get_web_image(self.file_url) except (requests.exceptions.HTTPError, requests.exceptions.SSLError, IOError): return thumbnail = ImageOps.fit( image, (300, 300), Image.ANTIALIAS ) thumbnail_url = filename + "_small." + extn path = os.path.abspath(frappe.get_site_path("public", thumbnail_url.lstrip("/"))) try: thumbnail.save(path) self.db_set("thumbnail_url", thumbnail_url) except IOError: frappe.msgprint("Unable to write file format for {0}".format(path)) return return thumbnail_url
def validate_fixed_asset_account(self): """Validate Fixed Asset and whether Income Account Entered Exists""" for d in self.get('items'): is_asset_item = frappe.db.get_value("Item", d.item_code, "is_asset_item") account_type = frappe.db.get_value("Account", d.income_account, "account_type") if is_asset_item == 1 and account_type != 'Fixed Asset': msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(d.income_account, d.item_code), raise_exception=True)
def update_rfq_supplier_status(self, include_me): rfq_list = set([]) for item in self.items: if item.request_for_quotation: rfq_list.add(item.request_for_quotation) for rfq in rfq_list: doc = frappe.get_doc('Request for Quotation', rfq) doc_sup = frappe.get_all('Request for Quotation Supplier', filters= {'parent': doc.name, 'supplier': self.supplier}, fields=['name', 'quote_status'])[0] quote_status = _('Received') for item in doc.items: sqi_count = frappe.db.sql(""" SELECT COUNT(sqi.name) as count FROM `tabSupplier Quotation Item` as sqi, `tabSupplier Quotation` as sq WHERE sq.supplier = %(supplier)s AND sqi.docstatus = 1 AND sq.name != %(me)s AND sqi.request_for_quotation_item = %(rqi)s AND sqi.parent = sq.name""", {"supplier": self.supplier, "rqi": item.name, 'me': self.name}, as_dict=1)[0] self_count = sum(my_item.request_for_quotation_item == item.name for my_item in self.items) if include_me else 0 if (sqi_count.count + self_count) == 0: quote_status = _('Pending') if quote_status == _('Received') and doc_sup.quote_status == _('No Quote'): frappe.msgprint(_("{0} indicates that {1} will not provide a quotation, but all items \ have been quoted. Updating the RFQ quote status.").format(doc.name, self.supplier)) frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'quote_status', quote_status) frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'no_quote', 0) elif doc_sup.quote_status != _('No Quote'): frappe.db.set_value('Request for Quotation Supplier', doc_sup.name, 'quote_status', quote_status)
def export_customizations(module, doctype, sync_on_migrate=0, with_permissions=0): """Export Custom Field and Property Setter for the current document to the app folder. This will be synced with bench migrate""" if not frappe.get_conf().developer_mode: raise Exception('Not developer mode') custom = {'custom_fields': [], 'property_setters': [], 'custom_perms': [], 'doctype': doctype, 'sync_on_migrate': 1} def add(_doctype): custom['custom_fields'] += frappe.get_all('Custom Field', fields='*', filters={'dt': _doctype}) custom['property_setters'] += frappe.get_all('Property Setter', fields='*', filters={'doc_type': _doctype}) add(doctype) if with_permissions: custom['custom_perms'] = frappe.get_all('Custom DocPerm', fields='*', filters={'parent': doctype}) # also update the custom fields and property setters for all child tables for d in frappe.get_meta(doctype).get_table_fields(): export_customizations(module, d.options, sync_on_migrate, with_permissions) if custom["custom_fields"] or custom["property_setters"] or custom["custom_perms"]: folder_path = os.path.join(get_module_path(module), 'custom') if not os.path.exists(folder_path): os.makedirs(folder_path) path = os.path.join(folder_path, scrub(doctype)+ '.json') with open(path, 'w') as f: f.write(frappe.as_json(custom)) frappe.msgprint(_('Customizations for <b>{0}</b> exported to:<br>{1}').format(doctype,path))
def get_conditions(filters): if not (filters.get("month") and filters.get("fiscal_year")): msgprint(_("Please select month and year"), raise_exception=1) filters["month"] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].index( filters["month"] ) + 1 from frappe.model.document import Document fiscal_years = frappe.get_doc("Fiscal Year", filters["fiscal_year"]) import datetime year_start = fiscal_years.year_start_date.strftime("%Y") year_end = fiscal_years.year_end_date.strftime("%Y") dt_test = datetime.datetime.strptime(year_end + "-" + str(100 + int(filters["month"]))[2:3] + "-01", "%Y-%m-%d") date_test = datetime.date(dt_test.year, dt_test.month, dt_test.day) if date_test > fiscal_years.year_end_date: year_target = year_start else: year_target = year_end from calendar import monthrange filters["total_days_in_month"] = monthrange(cint(year_target), filters["month"])[1] conditions = " and month(att_date) = %(month)s and fiscal_year = %(fiscal_year)s" # if filters.get("company"): conditions += " and company = %(company)s" if filters.get("employee"): conditions += " and employee = %(employee)s" return conditions, filters
def get_gl_entries(self, warehouse_account=None): from erpnext.accounts.general_ledger import process_gl_map stock_rbnb = self.get_company_default("stock_received_but_not_billed") expenses_included_in_valuation = self.get_company_default( "expenses_included_in_valuation") gl_entries = [] warehouse_with_no_account = [] negative_expense_to_be_booked = 0.0 stock_items = self.get_stock_items() for d in self.get("items"): if d.item_code in stock_items and flt(d.valuation_rate) and flt( d.qty): if warehouse_account.get(d.warehouse): stock_value_diff = frappe.db.get_value( "Stock Ledger Entry", { "voucher_type": "Purchase Receipt", "voucher_no": self.name, "voucher_detail_no": d.name }, "stock_value_difference") if not stock_value_diff: continue gl_entries.append( self.get_gl_dict( { "account": warehouse_account[d.warehouse]["name"], "against": stock_rbnb, "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": stock_value_diff }, warehouse_account[d.warehouse] ["account_currency"])) # stock received but not billed stock_rbnb_currency = get_account_currency(stock_rbnb) gl_entries.append(self.get_gl_dict({ "account": stock_rbnb, "against": warehouse_account[d.warehouse]["name"], "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(d.base_net_amount, d.precision("base_net_amount")), "credit_in_account_currency": flt(d.base_net_amount, d.precision("base_net_amount")) \ if stock_rbnb_currency==self.company_currency else flt(d.net_amount, d.precision("net_amount")) }, stock_rbnb_currency)) negative_expense_to_be_booked += flt(d.item_tax_amount) # Amount added through landed-cost-voucher if flt(d.landed_cost_voucher_amount): gl_entries.append( self.get_gl_dict({ "account": expenses_included_in_valuation, "against": warehouse_account[d.warehouse]["name"], "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(d.landed_cost_voucher_amount), "project": d.project })) # sub-contracting warehouse if flt(d.rm_supp_cost) and warehouse_account.get( self.supplier_warehouse): gl_entries.append( self.get_gl_dict( { "account": warehouse_account[ self.supplier_warehouse]["name"], "against": warehouse_account[d.warehouse]["name"], "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(d.rm_supp_cost) }, warehouse_account[self.supplier_warehouse] ["account_currency"])) # divisional loss adjustment valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \ flt(d.landed_cost_voucher_amount) + flt(d.rm_supp_cost) + flt(d.item_tax_amount) divisional_loss = flt( valuation_amount_as_per_doc - stock_value_diff, d.precision("base_net_amount")) if divisional_loss: if self.is_return or flt(d.item_tax_amount): loss_account = expenses_included_in_valuation else: loss_account = stock_rbnb gl_entries.append( self.get_gl_dict( { "account": loss_account, "against": warehouse_account[d.warehouse]["name"], "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": divisional_loss, "project": d.project }, stock_rbnb_currency)) elif d.warehouse not in warehouse_with_no_account or \ d.rejected_warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(d.warehouse) # Cost center-wise amount breakup for other charges included for valuation valuation_tax = {} for tax in self.get("taxes"): if tax.category in ("Valuation", "Valuation and Total") and flt( tax.base_tax_amount_after_discount_amount): if not tax.cost_center: frappe.throw( _("Cost Center is required in row {0} in Taxes table for type {1}" ).format(tax.idx, _(tax.category))) valuation_tax.setdefault(tax.cost_center, 0) valuation_tax[tax.cost_center] += \ (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount) if negative_expense_to_be_booked and valuation_tax: # Backward compatibility: # If expenses_included_in_valuation account has been credited in against PI # and charges added via Landed Cost Voucher, # post valuation related charges on "Stock Received But Not Billed" negative_expense_booked_in_pi = frappe.db.sql( """select name from `tabPurchase Invoice Item` pi where docstatus = 1 and purchase_receipt=%s and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=pi.parent and account=%s)""", (self.name, expenses_included_in_valuation)) if negative_expense_booked_in_pi: expenses_included_in_valuation = stock_rbnb against_account = ", ".join( [d.account for d in gl_entries if flt(d.debit) > 0]) total_valuation_amount = sum(valuation_tax.values()) amount_including_divisional_loss = negative_expense_to_be_booked i = 1 for cost_center, amount in valuation_tax.items(): if i == len(valuation_tax): applicable_amount = amount_including_divisional_loss else: applicable_amount = negative_expense_to_be_booked * ( amount / total_valuation_amount) amount_including_divisional_loss -= applicable_amount gl_entries.append( self.get_gl_dict({ "account": expenses_included_in_valuation, "cost_center": cost_center, "credit": applicable_amount, "remarks": self.remarks or _("Accounting Entry for Stock"), "against": against_account })) i += 1 if warehouse_with_no_account: frappe.msgprint( _("No accounting entries for the following warehouses") + ": \n" + "\n".join(warehouse_with_no_account)) return process_gl_map(gl_entries)
def validate_delivery_note(self): for d in self.get("items"): if d.delivery_note: msgprint(_("Stock cannot be updated against Delivery Note {0}" ).format(d.delivery_note), raise_exception=1)
def save_data_to_Excel(month, company, year): filename = "PAYE.xlsm" Month = datetime.date(1900, int(month), 1).strftime('%B') Abbr = frappe.db.get_value("Company", company, "abbr") tin = frappe.db.get_value("Company", company, "tax_id") new_filename = Abbr + "-PAYE-" + Month + "-" + year + ".xlsm" save_path = 'fwcedu.org/private/files/' file_name = os.path.join(save_path, filename) new_file_name = os.path.join(save_path, new_filename) ferp = frappe.new_doc("File") ferp.file_name = new_filename ferp.folder = "Home/PAYE_TAX" ferp.is_private = 0 ferp.file_url = "/private/files/PAYE_TAX/" + new_filename # ferp.folder = "Home" # ferp.is_private = 1 # ferp.file_url = "/private/files/Form_7/"+new_filename paye_data = [] paye_data = get_paye_data(month, year, company) df = pd.DataFrame(paye_data) df = df.drop('emp_id', axis=1) # frappe.msgprint(_("Data {0}").format(df)) workbook1 = openpyxl.load_workbook(file_name, read_only=False, keep_vba=True) workbook1.template = True sheetname = workbook1.get_sheet_by_name('PAYE') sheetname['C5'] = str(tin) sheetname['C7'] = str(Month) sheetname['E7'] = str(year) sheetname['C9'] = str(company) writer = pd.ExcelWriter(new_file_name, engine='openpyxl') writer.book = workbook1 writer.sheets = dict((ws.title, ws) for ws in workbook1.worksheets) df.to_excel(writer, sheet_name='PAYE', index=False, header=False, startrow=12, startcol=2) # with pd.ExcelWriter(file_name) as writer: # writer.book = openpyxl.load_workbook(file_name, read_only=False, keep_vba= True) # df.to_excel(writer, sheet_name=sheetname, index=False, header=False, startrow=13, startcol=1) writer.save() ferp.save() frappe.db.sql( '''UPDATE `tabFile` SET file_url = %s WHERE file_name = %s''', ("/files/" + new_filename, new_filename), as_dict=True) frappe.msgprint(_("File created - {0}").format(new_filename))
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): if not filters: filters = {} invoice_list = get_invoices(filters, additional_query_columns) columns, expense_accounts, tax_accounts = get_columns( invoice_list, additional_table_columns) if not invoice_list: msgprint(_("No record found")) return columns, invoice_list invoice_expense_map = get_invoice_expense_map(invoice_list) invoice_expense_map, invoice_tax_map = get_invoice_tax_map( invoice_list, invoice_expense_map, expense_accounts) invoice_po_pr_map = get_invoice_po_pr_map(invoice_list) suppliers = list(set([d.supplier for d in invoice_list])) supplier_details = get_supplier_details(suppliers) company_currency = frappe.get_cached_value('Company', filters.company, "default_currency") data = [] for inv in invoice_list: # invoice details purchase_order = list( set(invoice_po_pr_map.get(inv.name, {}).get("purchase_order", []))) purchase_receipt = list( set( invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", []))) project = list( set(invoice_po_pr_map.get(inv.name, {}).get("project", []))) row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name] if additional_query_columns: for col in additional_query_columns: row.append(inv.get(col)) row += [ supplier_details.get(inv.supplier), # supplier_group inv.tax_id, inv.credit_to, inv.mode_of_payment, ", ".join(project), inv.bill_no, inv.bill_date, inv.remarks, ", ".join(purchase_order), ", ".join(purchase_receipt), company_currency ] # map expense values base_net_total = 0 for expense_acc in expense_accounts: expense_amount = flt( invoice_expense_map.get(inv.name, {}).get(expense_acc)) base_net_total += expense_amount row.append(expense_amount) # net total row.append(base_net_total or inv.base_net_total) # tax account total_tax = 0 for tax_acc in tax_accounts: if tax_acc not in expense_accounts: tax_amount = flt( invoice_tax_map.get(inv.name, {}).get(tax_acc)) total_tax += tax_amount row.append(tax_amount) # total tax, grand total, outstanding amount & rounded total row += [ total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount ] data.append(row) return columns, data
def get_orders(): """Returns a list of recent orders from the eBay TradingAPI. This list is NOT filtered by a siteid as the API call does not filter by siteid. """ num_days = frappe.db.get_value('eBay Manager Settings', filters=None, fieldname='ebay_sync_days') try: if num_days < 1: frappe.msgprint('Invalid number of days: ' + str(num_days)) except TypeError: raise ValueError('Invalid type in ebay_sync_days') orders = [] page = 1 try: # Initialize TradingAPI; default timeout is 20. # Always use the US site for GetOrders as it returns fields we need # (which the UK site, for example, doesn't) and it doesn't filter by # siteID anyway api = Trading(config_file=PATH_TO_YAML, siteid=0, warnings=True, timeout=20) while True: # TradingAPI results are paginated, so loop until # all pages have been obtained api.execute( 'GetOrders', { 'NumberOfDays': num_days, 'Pagination': { 'EntriesPerPage': 50, 'PageNumber': page } }) orders_api = api.response.dict() test_for_message(orders_api) n_orders = int(orders_api['ReturnedOrderCountActual']) if n_orders > 0: if not isinstance(orders_api['OrderArray']['Order'], list): raise AssertionError('Invalid type in get_orders!') orders.extend(orders_api['OrderArray']['Order']) if orders_api['HasMoreOrders'] == 'false': break page += 1 except ConnectionError as e: handle_ebay_error(e) if six.PY2: # Convert all strings to unicode orders = convert_to_unicode(orders) return orders, num_days
def execute(filters=None): if not filters: filters = {} invoice_list = get_invoices(filters) columns, income_accounts, tax_accounts = get_columns(invoice_list) if not invoice_list: msgprint(_("No record found")) return columns, invoice_list invoice_income_map = get_invoice_income_map(invoice_list) invoice_income_map, invoice_tax_map = get_invoice_tax_map( invoice_list, invoice_income_map, income_accounts) invoice_so_dn_map = get_invoice_so_dn_map(invoice_list) customer_map = get_customer_details(invoice_list) company_currency = frappe.db.get_value("Company", filters.company, "default_currency") mode_of_payments = get_mode_of_payments([inv.name for inv in invoice_list]) data = [] for inv in invoice_list: # invoice details sales_order = list( set(invoice_so_dn_map.get(inv.name, {}).get("sales_order", []))) delivery_note = list( set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", []))) row = [ inv.name, inv.posting_date, inv.customer, inv.customer_name, customer_map.get(inv.customer, {}).get("customer_group"), customer_map.get(inv.customer, {}).get("territory"), inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])), inv.project, inv.remarks, ", ".join(sales_order), ", ".join(delivery_note), company_currency ] # map income values base_net_total = 0 for income_acc in income_accounts: income_amount = flt( invoice_income_map.get(inv.name, {}).get(income_acc)) base_net_total += income_amount row.append(income_amount) # net total row.append(base_net_total or inv.base_net_total) # tax account total_tax = 0 for tax_acc in tax_accounts: if tax_acc not in income_accounts: tax_amount = flt( invoice_tax_map.get(inv.name, {}).get(tax_acc)) total_tax += tax_amount row.append(tax_amount) # total tax, grand total, outstanding amount & rounded total row += [ total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount ] data.append(row) return columns, data
def check_warrant_number(self): if not self.custom_warrant: frappe.msgprint(_("Custom Warrant Number is Required"), raise_exception=True)
def validate_write_off_account(self): if flt(self.write_off_amount) and not self.write_off_account: msgprint(_("Please enter Write Off Account"), raise_exception=1)
def makeBackOrder(so,method): frappe.msgprint("Test") for row in so.items: if row.projected_qty<0: available=row.qty else: available=row.qty-row.projected_qty if row.projected_qty<row.qty: data=frappe.get_doc({ "docstatus": 0, "doctype": "Back Order", "name": "New Back Order 1", "__islocal": 1, "__unsaved": 1, "naming_series": "SO-", "transaction_date": so.transaction_date, "items": [{ "docstatus": 0, "doctype": "Back Order Item", "name": "New Back Order Item 1", "__islocal": 1, "__unsaved": 1, "owner":str(frappe.session.user), "parent": "New Back Order 1", "parentfield": "items", "parenttype": "Back Order", "customer": so.customer, "item_code": row.item_code, "order_qty": row.qty, "available_qty": row.projected_qty, "back_qty": available, "sales_order_number":so.name }] }) doc=data.insert() so=frappe.get_doc("Sales Order",str(so.name)) # si = make_sales_invoice(so.name) # for item in so.items: # if not item.projected_qty<0: # if item.qty>item.projected_qty: # item.qty=item.projected_qty # else: # item.qty=item.qty # else: # frappe.delete_doc("Sales Invoice Item",item.name) # si.save() dt = getdate(add_days(today(),1)) po_date=str(dt.month)+"-"+str(dt.day)+"-"+str(dt.year) data=frappe.get_doc({ "docstatus": 0, "doctype": "Sales Invoice", "name": "New Sales Invoice 1", "__islocal": 1, "__unsaved": 1, "owner": str(frappe.session.user), "naming_series": "SINV-", "posting_date":str(po_date), "items": [], "customer_name": so.customer_name, "customer": so.customer, "address_display": so.address_display, "due_date": add_days(today(),1), "taxes_and_charges": so.taxes_and_charges, "customer_address": so.customer_address, }) sinv_doc=data.insert() # if sinv_doc: for item in so.items: if not item.projected_qty<0: if item.qty>item.projected_qty: save_invoice_item(item.item_code,sinv_doc.name,item.projected_qty,item.conversion_factor,item.rate,item.price_list_rate,item.uom,item.base_price_list_rate,so.name) else: save_invoice_item(item.item_code,sinv_doc.name,item.qty,item.conversion_factor,item.rate,item.price_list_rate,item.uom,item.base_price_list_rate,so.name) sales_invoice_data=frappe.get_doc("Sales Invoice",sinv_doc.name) final=sales_invoice_data.save() d1=frappe.get_doc("Sales Invoice",final.name) arr_len=len(final.items) if arr_len==0: frappe.delete_doc("Sales Invoice",final.name) else: sales_invoice_data.docstatus=1 sales_invoice_data.update_stock=1 sales_invoice_data.taxes_and_charges=so.taxes_and_charges final1=sales_invoice_data.save()
def validate_item_code(self): for d in self.get('items'): if not d.item_code: msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
def allow_property_change(self, prop, meta_df, df): if prop == "fieldtype": self.validate_fieldtype_change(df, meta_df[0].get(prop), df.get(prop)) elif prop == "length": old_value_length = cint(meta_df[0].get(prop)) new_value_length = cint(df.get(prop)) if new_value_length and (old_value_length > new_value_length): self.check_length_for_fieldtypes.append({ 'df': df, 'old_value': meta_df[0].get(prop) }) self.validate_fieldtype_length() else: self.flags.update_db = True elif prop == "allow_on_submit" and df.get(prop): if not frappe.db.get_value("DocField", { "parent": self.doc_type, "fieldname": df.fieldname }, "allow_on_submit"): frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\ .format(df.idx)) return False elif prop == "reqd" and \ ((frappe.db.get_value("DocField", {"parent":self.doc_type,"fieldname":df.fieldname}, "reqd") == 1) \ and (df.get(prop) == 0)): frappe.msgprint(_("Row {0}: Not allowed to disable Mandatory for standard fields")\ .format(df.idx)) return False elif prop == "in_list_view" and df.get(prop) \ and df.fieldtype!="Attach Image" and df.fieldtype in no_value_fields: frappe.msgprint( _("'In List View' not allowed for type {0} in row {1}").format( df.fieldtype, df.idx)) return False elif prop == "precision" and cint(df.get("precision")) > 6 \ and cint(df.get("precision")) > cint(meta_df[0].get("precision")): self.flags.update_db = True elif prop == "unique": self.flags.update_db = True elif (prop == "read_only" and cint(df.get("read_only")) == 0 and frappe.db.get_value("DocField", { "parent": self.doc_type, "fieldname": df.fieldname }, "read_only") == 1): # if docfield has read_only checked and user is trying to make it editable, don't allow it frappe.msgprint( _("You cannot unset 'Read Only' for field {0}").format( df.label)) return False elif prop == "options" and df.get( "fieldtype") not in ALLOWED_OPTIONS_CHANGE: frappe.msgprint( _("You can't set 'Options' for field {0}").format(df.label)) return False elif prop == 'translatable' and not supports_translation( df.get('fieldtype')): frappe.msgprint( _("You can't set 'Translatable' for field {0}").format( df.label)) return False elif (prop == 'in_global_search' and df.in_global_search != meta_df[0].get("in_global_search")): self.flags.rebuild_doctype_for_global_search = True return True
def package_buy(doc, method): customer = doc.customer tday = today() flag = False # frappe.errprint(package) pacakage_list = frappe.db.sql("select package_name from tabMembership", as_list=1) pl = [x[0] for x in pacakage_list] frappe.errprint([pacakage_list, pl]) for p in doc.get("items"): frappe.errprint([p.item_code, pl]) if p.item_code in pl: frappe.errprint("successfull match") mem = frappe.get_doc("Membership", p.item_code) if mem.is_enabled: flag = True for it in mem.get("services"): frappe.errprint("iteration in progress") cp = frappe.new_doc("Customer wise package") cp.customer = customer cp.package = p.item_code cp.services = it.services cp.quantity_issued = it.number_of_services cp.valid_from = datetime.strptime(tday, "%Y-%m-%d") cp.valid_to = cp.valid_from + timedelta(days=it.validity) cp.used_qty = 0 cp.insert(ignore_permissions=True) cp.submit() frappe.errprint("successfull submission ") else: frappe.errprint("not enabled") frappe.msgprint("Package inactive") cwp = frappe.db.sql("select * from `tabCustomer wise package", as_list=1) check = [x[0] for x in cwp] frappe.errprint(check) for c in check: cp = frappe.get_doc("Customer wise package", c) # frappe.errprint(cp) # frappe.errprint(cp.customer) # frappe.errprint(p.item_code) # frappe.errprint(customer) # frappe.errprint(cp.services) aaj = date.today().strftime('%Y-%m-%d') end_date = date.strftime(cp.valid_to, '%Y-%m-%d') if aaj < end_date: frappe.errprint(cp.valid_to) if customer == cp.customer and p.item_code == cp.services and cp.quantity_issued != cp.used_qty and aaj < end_date: # frappe.errprint(p.amount) frappe.errprint(doc.outstanding_amount) frappe.errprint("in package with " + cp.services + "for " + cp.package) p.rate = 0 p.amount = 0 #calculate_taxes_and_totals.calculate_totals() #calculate_net_total() doc.package_name = cp.package cp.used_qty = cp.used_qty + 1 cp.save flag = True break if not flag: frappe.msgprint("no package available")
def get_columns(filters, tempColoumn): columns = [] # tempColoumn = [] frappe.msgprint(len(tempColoumn)) if filters.get("presentation_currency"): currency = filters["presentation_currency"] else: if filters.get("company"): currency = get_company_currency(filters["company"]) else: company = get_default_company() currency = get_company_currency(company) columns = [ { "label": _("Jv Ref"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 180 }, { "label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 90 }, { "label": _("Particulars"), "fieldname": "particulars", "width": 120 }, { "label": _("Party Name"), "fieldname": "party_name", "width": 100 }, { "label": _("Party"), "fieldname": "party_type", "width": 100 }, { "label": _("Company"), "fieldname": "company", "width": 180 }, { "label": _("Voucher Type"), "fieldname": "voucher_type", "width": 120 }, { "label": _("Bill No"), "fieldname": "bill_no", "width": 100 }, { "label": _("Bill Date"), "fieldname": "bill_date", "fieldtype": "Date", "width": 90 }, { "label": _("Remarks"), "fieldname": "remark", "width": 400 }, { "label": _("Ref No."), "fieldname": "bill_no", "width": 100 }, { "label": _("Ref Date"), "fieldname": "bill_date", "fieldtype": "Date", "width": 90 }, { "label": _("Is Advance"), "fieldname": "is_advance", "width": 90 }, { "label": _("Is Opening"), "fieldname": "is_opening", "width": 90 }, { "label": _("Created by whom"), "fieldname": "created_by_whom", "width": 90 }, { "label": _("Modified by whom"), "fieldname": "modified_by_whom", "width": 90 }, { "label": _("Gross ({0})".format(currency)), "fieldname": "gross", "fieldtype": "Float", "width": 100 } ] if tempColoumn: for i in tempColoumn: columns.append(i) return columns
def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False): fiscal_years = frappe.cache().hget("fiscal_years", company) or [] if not fiscal_years: # if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate) cond = "" if fiscal_year: cond += " and fy.name = {0}".format(frappe.db.escape(fiscal_year)) if company: cond += """ and (not exists (select name from `tabFiscal Year Company` fyc where fyc.parent = fy.name) or exists(select company from `tabFiscal Year Company` fyc where fyc.parent = fy.name and fyc.company=%(company)s) ) """ fiscal_years = frappe.db.sql(""" select fy.name, fy.year_start_date, fy.year_end_date from `tabFiscal Year` fy where disabled = 0 {0} order by fy.year_start_date desc""".format(cond), {"company": company}, as_dict=True) frappe.cache().hset("fiscal_years", company, fiscal_years) if transaction_date: transaction_date = getdate(transaction_date) for fy in fiscal_years: matched = False if fiscal_year and fy.name == fiscal_year: matched = True if (transaction_date and getdate(fy.year_start_date) <= transaction_date and getdate(fy.year_end_date) >= transaction_date): matched = True if matched: if as_dict: return (fy, ) else: return ((fy.name, fy.year_start_date, fy.year_end_date), ) error_msg = _("""{0} {1} not in any active Fiscal Year.""").format( label, formatdate(transaction_date)) if verbose == 1: frappe.msgprint(error_msg) raise FiscalYearError(error_msg)
def get_gl_entries(self): gl_entry = [] if self.is_return: gl_entry.append( self.get_gl_dict( { "posting_date": self.posting_date, "account": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "account_currency": self.currency, "credit": self.base_amount, "credit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.from_account, "party_type": '' if self.type != 'Employee' else 'Employee Account', "party": '' if self.type != 'Employee' else frappe.db.get_value( "Employee Account", { "employee": self.employee, "currency": self.currency }, "name"), "against_voucher_type": self.doctype, "against_voucher": self.name, "remarks": self.user_remark, "cost_center": self.cost_center }, item=self)) gl_entry.append( self.get_gl_dict( { "posting_date": self.posting_date, "account": self.from_account, "account_currency": self.currency, "debit": self.base_amount, "debit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "remarks": self.user_remark, "cost_center": self.cost_center }, item=self)) else: party_type = '' party = '' if self.type == 'Employee': party_type == 'Employee Account' party = frappe.db.get_value("Employee Account", { "employee": self.employee, "currency": self.currency }, "name") elif self.type == 'Supplier': frappe.msgprint("test") party_type == self.type ##frappe.msgprint("{0}".format(self.type)) ##frappe.msgprint("party_type={0}".format(party_type)) party = self.supplier ##frappe.msgprint("{0}-{1}".format(party_type,party)) ##frappe.msgprint("{0}-{1}".format(self.type,self.supplier)) ##frappe.msgprint("{0}".format(self)) gl_entry.append( self.get_gl_dict( { "posting_date": self.posting_date, "account": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "account_currency": self.currency, "debit": self.base_amount, "debit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.from_account, "party_type": 'Supplier' if self.type == 'Supplier' else ('Employee Account' if self.type == 'Employee' else ''), "party": party, "remarks": self.user_remark, "cost_center": self.cost_center }, item=self)) gl_entry.append( self.get_gl_dict( { "posting_date": self.posting_date, "account": self.from_account, "account_currency": self.currency, "credit": self.base_amount, "credit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "remarks": self.user_remark, "cost_center": self.cost_center }, item=self)) return gl_entry
def validate_items_mandatory(self): rows = [d.item_code for d in self.get("items")] if not rows: frappe.msgprint(_("No Items to pack"), raise_exception=1)
def get_items_for_material_requests(doc, warehouses=None): if isinstance(doc, string_types): doc = frappe._dict(json.loads(doc)) warehouse_list = [] if warehouses: if isinstance(warehouses, string_types): warehouses = json.loads(warehouses) for row in warehouses: child_warehouses = frappe.db.get_descendants( 'Warehouse', row.get("warehouse")) if child_warehouses: warehouse_list.extend(child_warehouses) else: warehouse_list.append(row.get("warehouse")) if warehouse_list: warehouses = list(set(warehouse_list)) if doc.get("for_warehouse") and doc.get("for_warehouse") in warehouses: warehouses.remove(doc.get("for_warehouse")) warehouse_list = None doc['mr_items'] = [] po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items') # Check for empty table or empty rows if not po_items or not [ row.get('item_code') for row in po_items if row.get('item_code') ]: frappe.throw(_( "Items to Manufacture are required to pull the Raw Materials associated with it." ), title=_("Items Required")) company = doc.get('company') ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty') include_safety_stock = doc.get('include_safety_stock') 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 warehouse = doc.get('for_warehouse') 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: # fetch exploded items from BOM item_details = get_exploded_items(item_details, company, bom_no, include_non_stock_items, planned_qty=planned_qty) else: item_details = get_subitems(doc, data, item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1, planned_qty=planned_qty) 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, 'safety_stock': item_master.safety_stock }) 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.qty > 0: items = get_material_request_items( details, sales_order, company, ignore_existing_ordered_qty, include_safety_stock, warehouse, bin_dict) if items: mr_items.append(items) if not ignore_existing_ordered_qty and warehouses: new_mr_items = [] for item in mr_items: get_materials_from_other_locations(item, warehouses, new_mr_items, company) mr_items = new_mr_items if not mr_items: to_enable = frappe.bold(_("Ignore Existing Projected Quantity")) warehouse = frappe.bold(doc.get('for_warehouse')) message = _( "As there are sufficient raw materials, Material Request is not required for Warehouse {0}." ).format(warehouse) + "<br><br>" message += _("If you still want to proceed, please enable {0}." ).format(to_enable) frappe.msgprint(message, title=_("Note")) return mr_items
def make_accrual_jv_entry(self): journal_entry = frappe.new_doc('Journal Entry') journal_entry.voucher_type = 'Journal Entry' journal_entry.user_remark = self.user_remark journal_entry.cheque_date = self.posting_date journal_entry.cheque_no = self.name journal_entry.company = self.company journal_entry.posting_date = nowdate() journal_entry.multi_currency = 1 accounts = [] ## if self.is_return: accounts.append({ "account": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "account_currency": self.currency, "credit": self.base_amount, "credit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.from_account, "party_type": '' if self.type != 'Employee' else 'Employee Account', "party": '' if self.type != 'Employee' else frappe.db.get_value( "Employee Account", { "employee": self.employee, "currency": self.currency }, "name"), "against_voucher_type": self.doctype, "against_voucher": self.name, "remarks": self.user_remark, "cost_center": self.cost_center, "reference_type": self.doctype, "reference_name": self.name }) accounts.append({ "account": self.from_account, "account_currency": self.currency, "debit": self.base_amount, "debit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "remarks": self.user_remark, "cost_center": self.cost_center, "reference_type": self.doctype, "reference_name": self.name }) else: party_type = '' party = '' if self.type == 'Employee': party_type == 'Employee Account' party = frappe.db.get_value("Employee Account", { "employee": self.employee, "currency": self.currency }, "name") elif self.type == 'Supplier': frappe.msgprint("test") party_type == self.type party = self.supplier accounts.append({ "account": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "account_currency": self.currency, "debit": self.base_amount, "debit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.from_account, "party_type": 'Supplier' if self.type == 'Supplier' else ('Employee Account' if self.type == 'Employee' else ''), "party": party, "remarks": self.user_remark, "cost_center": self.cost_center, "reference_type": self.doctype, "reference_name": self.name }) accounts.append({ "account": self.from_account, "account_currency": self.currency, "credit": self.base_amount, "credit_in_account_currency": self.amount, "conversion_rate": self.conversion_rate, "against": self.payment_account if self.type != 'Employee' else frappe.db.get_value( "Account", { "parent_account": self.payment_account, "account_currency": self.currency }, "name"), "remarks": self.user_remark, "cost_center": self.cost_center, "reference_type": self.doctype, "reference_name": self.name }) ## journal_entry.set("accounts", accounts) journal_entry.title = self.purpose try: journal_entry.save() except Exception as e: frappe.msgprint(e) self.jv_created = 1 self.save() frappe.msgprint( _("Journal Entry Created for Currenct Document {0} ").format( journal_entry.name)) self.reload() return journal_entry
def validate(self): """Check if change in varchar length isn't truncating the columns""" if self.is_new(): return self.setup_table_columns() columns = [ frappe._dict({ "fieldname": f, "fieldtype": "Data" }) for f in frappe.db.STANDARD_VARCHAR_COLUMNS ] columns += self.columns.values() for col in columns: if len(col.fieldname) >= 64: frappe.throw( _("Fieldname is limited to 64 characters ({0})").format( frappe.bold(col.fieldname))) if 'varchar' in frappe.db.type_map.get(col.fieldtype, ()): # validate length range new_length = cint(col.length) or cint(frappe.db.VARCHAR_LEN) if not (1 <= new_length <= 1000): frappe.throw( _("Length of {0} should be between 1 and 1000").format( col.fieldname)) current_col = self.current_columns.get(col.fieldname, {}) if not current_col: continue current_type = self.current_columns[col.fieldname]["type"] current_length = re.findall(r'varchar\(([\d]+)\)', current_type) if not current_length: # case when the field is no longer a varchar continue current_length = current_length[0] if cint(current_length) != cint(new_length): try: # check for truncation max_length = frappe.db.sql( """SELECT MAX(CHAR_LENGTH(`{fieldname}`)) FROM `tab{doctype}`""" .format(fieldname=col.fieldname, doctype=self.doctype)) except frappe.db.InternalError as e: if frappe.db.is_missing_column(e): # Unknown column 'column_name' in 'field list' continue raise if max_length and max_length[0][ 0] and max_length[0][0] > new_length: if col.fieldname in self.columns: self.columns[col.fieldname].length = current_length info_message = _("Reverting length to {0} for '{1}' in '{2}'. Setting the length as {3} will cause truncation of data.") \ .format(current_length, col.fieldname, self.doctype, new_length) frappe.msgprint(info_message)
def make_material_request(self): '''Create Material Requests grouped by Sales Order and Material Request Type''' material_request_list = [] material_request_map = {} for item in self.mr_items: item_doc = frappe.get_cached_doc('Item', item.item_code) material_request_type = item.material_request_type or item_doc.default_material_request_type # key for Sales Order:Material Request Type:Customer key = '{}:{}:{}'.format(item.sales_order, material_request_type, item_doc.customer or '') schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days)) if not key in material_request_map: # make a new MR for the combination material_request_map[key] = frappe.new_doc("Material Request") material_request = material_request_map[key] material_request.update({ "transaction_date": nowdate(), "status": "Draft", "company": self.company, 'material_request_type': material_request_type, 'customer': item_doc.customer or '' }) material_request_list.append(material_request) else: material_request = material_request_map[key] # add item material_request.append("items", { "item_code": item.item_code, "from_warehouse": item.from_warehouse, "qty": item.quantity, "schedule_date": schedule_date, "warehouse": item.warehouse, "sales_order": item.sales_order, 'production_plan': self.name, 'material_request_plan_item': item.name, "project": frappe.db.get_value("Sales Order", item.sales_order, "project") \ if item.sales_order else None }) for material_request in material_request_list: # submit material_request.flags.ignore_permissions = 1 material_request.run_method("set_missing_values") if self.get('submit_material_request'): material_request.submit() else: material_request.save() frappe.flags.mute_messages = False if material_request_list: material_request_list = ["""<a href="/app/Form/Material Request/{0}">{1}</a>""".format(m.name, m.name) \ for m in material_request_list] msgprint(_("{0} created").format(comma_and(material_request_list))) else: msgprint(_("No material request created"))
def send_one(email, smtpserver=None, auto_commit=True, now=False, from_test=False): '''Send Email Queue with given smtpserver''' email = frappe.db.sql('''select name, status, communication, message, sender, reference_doctype, reference_name, unsubscribe_param, unsubscribe_method, expose_recipients, show_as_cc, add_unsubscribe_link, attachments, retry from `tabEmail Queue` where name=%s for update''', email, as_dict=True)[0] recipients_list = frappe.db.sql('''select name, recipient, status from `tabEmail Queue Recipient` where parent=%s''',email.name,as_dict=1) if frappe.are_emails_muted(): frappe.msgprint(_("Emails are muted")) return if cint(frappe.defaults.get_defaults().get("hold_queue"))==1 : return if email.status not in ('Not Sent','Partially Sent') : # rollback to release lock and return frappe.db.rollback() return frappe.db.sql("""update `tabEmail Queue` set status='Sending', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) try: if not frappe.flags.in_test: if not smtpserver: smtpserver = SMTPServer() smtpserver.setup_email_account(email.reference_doctype, sender=email.sender) for recipient in recipients_list: if recipient.status != "Not Sent": continue message = prepare_message(email, recipient.recipient, recipients_list) if not frappe.flags.in_test: smtpserver.sess.sendmail(email.sender, recipient.recipient, encode(message)) recipient.status = "Sent" frappe.db.sql("""update `tabEmail Queue Recipient` set status='Sent', modified=%s where name=%s""", (now_datetime(), recipient.name), auto_commit=auto_commit) #if all are sent set status if any("Sent" == s.status for s in recipients_list): frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: frappe.db.sql("""update `tabEmail Queue` set status='Error', error=%s where name=%s""", ("No recipients to send to", email.name), auto_commit=auto_commit) if frappe.flags.in_test: frappe.flags.sent_mail = message return if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError, smtplib.SMTPHeloError, smtplib.SMTPAuthenticationError, JobTimeoutException): # bad connection/timeout, retry later if any("Sent" == s.status for s in recipients_list): frappe.db.sql("""update `tabEmail Queue` set status='Partially Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) # no need to attempt further return except Exception as e: frappe.db.rollback() if email.retry < 3: frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s, retry=retry+1 where name=%s""", (now_datetime(), email.name), auto_commit=auto_commit) else: if any("Sent" == s.status for s in recipients_list): frappe.db.sql("""update `tabEmail Queue` set status='Partially Errored', error=%s where name=%s""", (text_type(e), email.name), auto_commit=auto_commit) else: frappe.db.sql("""update `tabEmail Queue` set status='Error', error=%s where name=%s""", (text_type(e), email.name), auto_commit=auto_commit) if email.communication: frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) if now: print(frappe.get_traceback()) raise e else: # log to Error Log log('frappe.email.queue.flush', text_type(e))
def run_cron_create_xml(): """ # NOTE Should run sync ebay_ids before running anything else so database is up to date If is_auction then specify a startingBid which switches on auction mode """ frappe.msgprint("Exporting all listings in QC Passed status") #Before doing anything sync the ebay_id to Erpnext update_ebay_data(multiple_error_sites=['UK']) design = "Pro: Classic" layout = "thumb gallery" #decline = 0.9 #accept = 0.1 duration = 10 # GTC = 1000 handling_time = 1 root = ET.Element("items") records = get_item_records_by_item_status() for r in records: item_code = r.name post_code = "NP4 0HZ" if is_scotland(item_code): post_code = "DG1 3PH" is_auction = False quantity = r.actual_qty + r.unsubmitted_prec_qty - get_draft_sales( item_code) # Don't run if quantity not matching stock locations qty # Items only come through if ebay_id is Null or blank - no need to exclude e.g Awaiting # Garagesale (see sql query) #if quantity > 0.0 and quantity == r.sum_sl: FUDGE THIS FOR THE MOMENT if quantity > 0.0 and r.sum_sl > 0.0: if r.sum_sl < quantity: quantity = r.sum_sl title = "" title += r.item_name category = lookup_category(r.item_group, r.item_group_ebay) # if an item_price use that otherwise try item.standard_rate (either case ifnull=0) if r.item_price == 0.0: ebay_price = r.price * ugssettings.VAT else: ebay_price = r.item_price * ugssettings.VAT #resize_images(item_code) #image = r.image ws_image = r.website_image ss_images_list = get_slideshow_records(r.slideshow) pounds, ounces = kg_to_imperial(r.net_weight) version = 0 body = "<![CDATA[<br></br>" body += jtemplate(version, r.description, r.function_grade, r.grade_details, r.condition, r.tech_details, r.delivery_type, r.accessories_extras, r.power_cable_included, r.power_supply_included, r.remote_control_included, r.case_included, r.warranty_period) body += footer body += """<br><br>sku: {}""".format(item_code) #body += """<br>approx (unit) weight: {}""".format(r.weight_per_unit) #body += """<br>approx l x w x h: {} x {} x {}""".format(r.length, r.width, r.height) body += "]]" doc = ET.SubElement(root, "item") ET.SubElement(doc, "bestOffer").text = "true" #ET.SubElement(doc, "bestOfferAutoAcceptPrice").text = str(price - (price * accept)) #ET.SubElement(doc, "bestOfferAutoDeclinePrice").text = str(price - (price * decline)) ET.SubElement(doc, "buyItNowPrice").text = str(ebay_price) ET.SubElement(doc, "category").text = category #ET.SubElement(doc, "category2").text = condition_desc, condition_id = lookup_condition( r.condition, r.function_grade) ET.SubElement(doc, "condition").text = str(condition_desc) ET.SubElement(doc, "conditionDescription").text = r.grade_details ET.SubElement(doc, "convertDescriptionToHTML").text = "false" ET.SubElement(doc, "convertMarkdownToHTML").text = "false" ET.SubElement(doc, "description").text = body ET.SubElement(doc, "design").text = design # Ensure that blank brands are set as unbranded if r.brand == '': brand = 'Unbranded' else: brand = frappe.db.escape(r.brand) try: st = """<customSpecific> <specificName>Brand</specificName> <specificValue>{}</specificValue></customSpecific>""".format( brand) brand_xml = ET.fromstring(st) doc.append(brand_xml) except Exception: print('Problem with this brand: ', brand) if r.delivery_type == 'Pallet': ET.SubElement(doc, "shippingProfile").text = 'B. Pallet Shipping' if r.delivery_type == 'Standard Parcel': pounds, ounces = kg_to_imperial(29) ET.SubElement(doc, "shippingProfile").text = 'A. Standard Parcel' if r.delivery_type == 'Collection Only': ET.SubElement(doc, "shippingProfile").text = 'Collection in person.' ET.SubElement(doc, "duration").text = str(duration) ET.SubElement(doc, "handlingTime").text = str(handling_time) if USE_SERVER_IMAGES: for ssi in ss_images_list: print(ssi) if ssi.image: # and exists(images_url + ssi.image): ET.SubElement(doc, "imageURL").text = images_url + ssi.image ''''' # IF there is no slideshow then try the ws_image if not ssi: if r.website_image != 'NULL': ET.SubElement(doc, "imageURL").text = images_url + ws_image ''' ET.SubElement(doc, "layout").text = layout #ET.SubElement(doc, "lotSize").text = "1" if r.height: ET.SubElement(doc, "packageDepth").text = str(r.height) if r.length: ET.SubElement(doc, "packageLength").text = str(r.length) ET.SubElement(doc, "packageOunces").text = str(ounces) ET.SubElement(doc, "packagePounds").text = str(pounds) if r.width: ET.SubElement(doc, "packageWidth").text = str(r.width) #ET.SubElement(doc, "paymentInstructions").text = "" ET.SubElement(doc, "privateAuction").text = "false" ET.SubElement(doc, "quantity").text = str(quantity) if r.warranty_period == "45" or r.warranty_period == "None": ET.SubElement( doc, "returnPolicyDescription" ).text = "Buy with confidence. If you wish to return the item, for whatever reason, you may do so within 45 days." else: ET.SubElement(doc, "returnPolicyDescription").text = "".join([ """Buy with confidence. If you wish to return the item, """, """for whatever reason, you may do so within 45 days. """, """This item also includes our Limited Warranty """, """(please see our terms and conditions for details).""" ]) # TODO This item also includes our " + r.warranty_period + " Day Limited Warranty # (please see our terms and conditions for details)." ET.SubElement(doc, "returnsAccepted").text = "true" ET.SubElement(doc, "returnsWithinDays").text = "45" #ET.SubElement(doc, "reservePrice").text = "" #ET.SubElement(doc, "siteName").text = "" ET.SubElement(doc, "SKU").text = item_code if is_auction: ET.SubElement(doc, "startingBid").text = str(ebay_price) #ET.SubElement(doc, ****storCategory).text = "" #ET.SubElement(doc, "subTitle").text = sub_title ET.SubElement(doc, "title").text = title #ET.SubElement(doc, "variation").text = "" ET.SubElement(doc, "zipCode").text = post_code tree = ET.ElementTree(root) file_name = (os.path.join( os.sep, garage_xml_path, str(date.today()) + "_garageimportfile.xml")) # must create xml directory for this to work tree.write(file_name) # Update ebay_id to 'Awaiting Garagesale' marker frappe.db.set_value('Item', item_code, 'ebay_id', ugssettings.AWAITING_GARAGESALE_STATUS) # Xml file created now download it (does not work properly) #download_xml(site_url + '/files/xml/' + str(date.today()) + "_garageimportfile.xml", # str(date.today()) + "_garageimportfile.xml") frappe.msgprint("Export completed.")
def guardar_factura_electronica(datos_recibidos, serie_fact, tiempo_envio): '''Guarda los datos recibidos de infile en la tabla Envios Facturas Electronicas de la base de datos ERPNext''' try: # es-GT: documento: con la libreria xmltodict, se convierte de XML a Diccionario, para acceder a los datos atraves de sus llaves. # es-GT: Se asigna a la variable 'documento' # en-US: documento: with the xmltodict library, it is converted from XML to Dictionary, to access the data through the dictionary keys # en-US: All this is assigned to the 'document' variable. respuestaINFILE = xmltodict.parse(datos_recibidos) # es-GT: Crea un nuevo record de Envios Facturas Electronica en la base de datos. # en-US: Creates a new Electronic Invoice Sent record in the database tabFacturaElectronica = frappe.new_doc("Envios Facturas Electronicas") # es-GT: Obtiene y Guarda la serie de factura. # en-US: Obtains and Saves the invoice series. tabFacturaElectronica.serie_factura_original = serie_fact # es-GT: Obtiene y Guarda el CAE (Codigo de Autorización Electronico) # en-US: Obtains and Saves the CAE or literally translated: "Code of Electronic Authorization" tabFacturaElectronica.cae = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['cae']) cae_dato = str(respuestaINFILE['S:Envelope']['S:Body'] ['ns2:registrarDteResponse']['return']['cae']) # es-GT: Obtiene y Guarda el Numero de Documento que quedo registrada ante el Generador de Factura Electronica y la SAT # en-US: Obtains and Saves the Document Number that was registered with the Electronic Invoice Generator and SAT tabFacturaElectronica.numero_documento = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['numeroDocumento']) # es-GT: Obtiene y Guarda el Estado según GFACE (GFACE = Generador de Factura Electronica) # en-US: Obtains and Saves the current State of the document as per GFACE (Electronic Invoice Generator) tabFacturaElectronica.estado = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['estado']) # es-GT: Obtiene y Guarda las Anotaciones segun GFACE # en-US: Obtains and Saves the Annotations as per GFACE tabFacturaElectronica.anotaciones = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['anotaciones']) # es-GT: Obtiene y Guarda la Descripcion: En este campo estan todas las descripciones de errores y mensaje de generacion correcta # en-US: Obtains and Saves the Description: This field contains all the descriptions of errors and correct generation messages tabFacturaElectronica.descripcion = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['descripcion']) # es-GT: Obtiene y Guarda la Validez del documento # en-US: Obtains and Saves the Validity state of the document tabFacturaElectronica.valido = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['valido']) # es-GT: Obtiene y Guarda el Numero DTE # en-US: Obtains and Saves the DTE Number tabFacturaElectronica.numero_dte = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['numeroDte']) # numeroDTEINFILE: Guarda el numero DTE, sera utilizado para renombrar la serie original de la factura que lo origino numeroDTEINFILE = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['numeroDte']) # es-GT: Obtiene y Guarda el Rango Final Autorizado # en-US: Obtains and Saves the Authorized Final Range tabFacturaElectronica.rango_final_autorizado = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['rangoFinalAutorizado']) # es-GT: Obtiene y Guarda el Rango Inicial Autorizado # en-US: Obtains and Saves the Initial Authorized Range tabFacturaElectronica.rango_inicial_autorizado = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['rangoInicialAutorizado']) # es-GT: Obtiene y Guarda el Regimen de impuestos # en-US: Obtains and Saves the Legal Tax Structure, aka 'Regimen' tabFacturaElectronica.regimen = str( respuestaINFILE['S:Envelope']['S:Body']['ns2:registrarDteResponse'] ['return']['regimen']) # es-GT: Obtiene y Guarda el tiempo en que se recibieron los datos de INFILE # en-US: Obtains and Saves the timestamp of data reception from INFILE tabFacturaElectronica.recibido = datetime.now() # es-GT: Obtiene y Guarda el tiempo en que se enviaron los datos a INFILE # es-GT: Estos datos de tiempo se obtienen para poder monitorear el tiempo de transacción # en-US: Obtains and Saves the timestamp the data was sent to INFILE # en-US: These timestamps are obtained to keep track of transaction time tabFacturaElectronica.enviado = tiempo_envio # es-GT: Guarda todos los datos en la tabla llamada 'FACTURAS ELECTRONICAS' de la base de datos de ERPNext # en-US: Saves all the data in the table called 'ELECTRONIC INVOICES' of the ERPNext database tabFacturaElectronica.save() # es-GT: Al terminar de guardar el registro en la base de datos, retorna el CAE # en-US: When done saving the records to the database, it returns de CAE # return cae_dato # frappe.msgprint(_("Factura Electronica Generada!")) except: # es-GT: Si algo falla, muestra el error en el navegador. # es-GT: Este mensaje solo indica que no se guardo la confirmacion de la factura electronica. # en-US: If something fails, the exception shows this message in the browser # en-US: This message simply states that the Electronic Invoice Confirmation was not saved. frappe.msgprint( _("""Error: No se guardo correctamente la Factura Electronica. Por favor vuelva a presionar el boton de Factura Electronica""")) else: # Si los datos se Guardan correctamente, se retornara el cae generado, que sera capturado por api.py # Puede utlizar para futuros cambios en el codigo return cae_dato
def get_gl_entries(self, warehouse_account=None, default_expense_account=None, default_cost_center=None): if not warehouse_account: warehouse_account = get_warehouse_account() sle_map = self.get_stock_ledger_details() voucher_details = self.get_voucher_details(default_expense_account, default_cost_center, sle_map) gl_list = [] warehouse_with_no_account = [] for detail in voucher_details: sle_list = sle_map.get(detail.name) if sle_list: for sle in sle_list: if warehouse_account.get(sle.warehouse): # from warehouse account self.check_expense_account(detail) gl_list.append( self.get_gl_dict({ "account": warehouse_account[sle.warehouse], "against": detail.expense_account, "cost_center": detail.cost_center, "remarks": self.get("remarks") or "Accounting Entry for Stock", "debit": flt(sle.stock_value_difference, 2) })) # to target warehouse / expense account gl_list.append( self.get_gl_dict({ "account": detail.expense_account, "against": warehouse_account[sle.warehouse], "cost_center": detail.cost_center, "remarks": self.get("remarks") or "Accounting Entry for Stock", "credit": flt(sle.stock_value_difference, 2) })) elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) if warehouse_with_no_account: msgprint( _("No accounting entries for the following warehouses") + ": \n" + "\n".join(warehouse_with_no_account)) return process_gl_map(gl_list)
def validate_employee_role(doc, method): # called via User hook if "Employee" in [d.role for d in doc.get("roles")]: if not frappe.db.get_value("Employee", {"user_id": doc.name}): frappe.msgprint(_("Please set User ID field in an Employee record to set Employee Role")) doc.get("roles").remove(doc.get("roles", {"role": "Employee"})[0])
def add_bank_accounts(response, bank, company): try: response = json.loads(response) except TypeError: pass bank = json.loads(bank) result = [] default_gl_account = get_default_bank_cash_account(company, "Bank") if not default_gl_account: frappe.throw( _("Please setup a default bank account for company {0}").format( company)) for account in response["accounts"]: acc_type = frappe.db.get_value("Bank Account Type", account["type"]) if not acc_type: add_account_type(account["type"]) acc_subtype = frappe.db.get_value("Bank Account Subtype", account["subtype"]) if not acc_subtype: add_account_subtype(account["subtype"]) if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])): try: new_account = frappe.get_doc({ "doctype": "Bank Account", "bank": bank["bank_name"], "account": default_gl_account.account, "account_name": account["name"], "account_type": account["type"] or "", "account_subtype": account["subtype"] or "", "mask": account["mask"] or "", "integration_id": account["id"], "is_company_account": 1, "company": company }) new_account.insert() result.append(new_account.name) except frappe.UniqueValidationError: frappe.msgprint( _("Bank account {0} already exists and could not be created again" ).format(account["name"])) except Exception: frappe.throw(frappe.get_traceback()) else: result.append( frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name")) return result
def actualizarTablas(serieOriginalFac): """Funcion permite actualizar tablas en la base de datos, despues de haber generado la factura electronica""" # Verifica que exista un documento en la tabla Envios Facturas Electronicas con el nombre de la serie original if frappe.db.exists('Envios Facturas Electronicas', {'serie_factura_original': serieOriginalFac}): factura_guardada = frappe.db.get_values( 'Envios Facturas Electronicas', filters={'serie_factura_original': serieOriginalFac}, fieldname=['numero_dte', 'cae', 'serie_factura_original'], as_dict=1) # Esta seccion se encarga de actualizar la serie, con una nueva que es el numero de DTE # buscara en las tablas donde exista una coincidencia actualizando con la nueva serie try: # serieDte: guarda el numero DTE retornado por INFILE, se utilizara para reemplazar el nombre de la serie de la # factura que lo generó. serieDte = str(factura_guardada[0]['numero_dte']) # serie_fac_original: Guarda la serie original de la factura. serie_fac_original = serieOriginalFac # Actualizacion de tablas que son modificadas directamente. # 01 - tabSales Invoice frappe.db.sql( '''UPDATE `tabSales Invoice` SET name=%(name)s, cae_factura_electronica=%(cae_correcto)s, serie_original_del_documento=%(serie_orig_correcta)s WHERE name=%(serieFa)s ''', { 'name': serieDte, 'cae_correcto': factura_guardada[0]['cae'], 'serie_orig_correcta': serie_fac_original, 'serieFa': serie_fac_original }) # 02 - tabSales Invoice Item frappe.db.sql( '''UPDATE `tabSales Invoice Item` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # 03 - tabGL Entry frappe.db.sql( '''UPDATE `tabGL Entry` SET voucher_no=%(name)s, against_voucher=%(name)s WHERE voucher_no=%(serieFa)s AND against_voucher=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) frappe.db.sql( '''UPDATE `tabGL Entry` SET voucher_no=%(name)s, docstatus=1 WHERE voucher_no=%(serieFa)s AND against_voucher IS NULL''', { 'name': serieDte, 'serieFa': serie_fac_original }) # Actualizacion de tablas que pueden ser modificadas desde Sales Invoice # Verificara tabla por tabla en busca de un valor existe, en caso sea verdadero actualizara, # en caso no encuentre nada no hara nada # 04 - tabSales Taxes and Charges if frappe.db.exists('Sales Taxes and Charges', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Taxes and Charges` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) if frappe.db.exists('Otros Impuestos Factura Electronica', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabOtros Impuestos Factura Electronica` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Sales Taxes and Charges')) # Pago programado # 05 - tabPayment Schedule if frappe.db.exists('Payment Schedule', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabPayment Schedule` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Payment Schedule')) # subscripcion # 06 - tabSubscription if frappe.db.exists('Subscription', {'reference_document': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSubscription` SET reference_document=%(name)s WHERE reference_document=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Subscription')) # Entrada del libro mayor de inventarios # 07 - tabStock Ledger Entry if frappe.db.exists('Stock Ledger Entry', {'voucher_no': serie_fac_original}): frappe.db.sql( '''UPDATE `tabStock Ledger Entry` SET voucher_no=%(name)s WHERE voucher_no=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Stock Ledger Entry')) # Hoja de tiempo de factura de ventas # 08 - tabSales Invoice Timesheet if frappe.db.exists('Sales Invoice Timesheet', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Invoice Timesheet` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Sales Invoice Timesheet')) # Equipo Ventas # 09 - tabSales Team if frappe.db.exists('Sales Team', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Team` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en Sales Team')) # Packed Item # 10 - tabPacked Item if frappe.db.exists('Packed Item', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabPacked Item` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabPackedItem)) # Sales Invoice Advance - Anticipos a facturas # 11 - tabSales Invoice Advance if frappe.db.exists('Sales Invoice Advance', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Invoice Advance` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabSales Invoice Advance)) # Sales Invoice Payment - Pagos sobre a facturas # 12 - tabSales Invoice Payment if frappe.db.exists('Sales Invoice Payment', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Invoice Payment` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabSales Invoice Payment)) # Payment Entry Reference - # 13 - tabPayment Entry Reference if frappe.db.exists('Payment Entry Reference', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Invoice Payment` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabPayment Entry Reference)) # Sales Order # 15 - tabSales Order if frappe.db.exists('Sales Order', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabSales Order` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabSales Order)) # Parece que este no enlaza directamente con sales invoice es el sales invoice que enlaza con este. # Delivery Note # 16 - tabDelivery Note if frappe.db.exists('Delivery Note', {'parent': serie_fac_original}): frappe.db.sql( '''UPDATE `tabDelivery Note` SET parent=%(name)s WHERE parent=%(serieFa)s''', { 'name': serieDte, 'serieFa': serie_fac_original }) # else: # frappe.msgprint(_('No hay registro en tabSales Order)) frappe.db.commit() # Posible modifacadas # # Artículo empaquetado # if frappe.db.exists('Packed Item', {'': }): # ? # # Avance de Factura de Ventas # if frappe.db.exists('Sales Invoice Advance', {'': }): # ? # # Pago de factura de ventas # if frappe.db.exists('Sales Invoice Payment', {'': }): # ? # # Entrada de Diario # if frappe.db.exists('Journal Entry', {'': }): # ? # # hoja de tiempo # if frappe.db.exists('Timesheet', {'': }): # No hay registro except: # En caso exista un error al renombrar la factura retornara el mensaje con el error frappe.msgprint( _('Error al renombrar Factura. Por favor intente de nuevo presionando el boton Factura Electronica' )) else: # Si los datos se Guardan correctamente, se retornara el Numero Dte generado, que sera capturado por api.py # para luego ser capturado por javascript, se utilizara para recargar la url con los cambios correctos return str(factura_guardada[0]['numero_dte'])
def rename_doc( doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False, show_alert=True, rebuild_search=True ): """Rename a doc(dt, old) to doc(dt, new) and update all linked fields of type "Link".""" if not frappe.db.exists(doctype, old): return if ignore_if_exists and frappe.db.exists(doctype, new): return if old==new: frappe.msgprint(_('Please select a new name to rename')) return force = cint(force) merge = cint(merge) meta = frappe.get_meta(doctype) # call before_rename old_doc = frappe.get_doc(doctype, old) out = old_doc.run_method("before_rename", old, new, merge) or {} new = (out.get("new") or new) if isinstance(out, dict) else (out or new) if doctype != "DocType": new = validate_rename(doctype, new, meta, merge, force, ignore_permissions) if not merge: rename_parent_and_child(doctype, old, new, meta) # update link fields' values link_fields = get_link_fields(doctype) update_link_field_values(link_fields, old, new, doctype) rename_dynamic_links(doctype, old, new) # save the user settings in the db update_user_settings(old, new, link_fields) if doctype=='DocType': rename_doctype(doctype, old, new, force) update_customizations(old, new) update_attachments(doctype, old, new) rename_versions(doctype, old, new) # call after_rename new_doc = frappe.get_doc(doctype, new) # copy any flags if required new_doc._local = getattr(old_doc, "_local", None) new_doc.run_method("after_rename", old, new, merge) if not merge: rename_password(doctype, old, new) # update user_permissions frappe.db.sql("""UPDATE `tabDefaultValue` SET `defvalue`=%s WHERE `parenttype`='User Permission' AND `defkey`=%s AND `defvalue`=%s""", (new, doctype, old)) if merge: new_doc.add_comment('Edit', _("merged {0} into {1}").format(frappe.bold(old), frappe.bold(new))) else: new_doc.add_comment('Edit', _("renamed from {0} to {1}").format(frappe.bold(old), frappe.bold(new))) if merge: frappe.delete_doc(doctype, old) frappe.clear_cache() if rebuild_search: frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype', doctype=doctype) if show_alert: frappe.msgprint(_('Document renamed from {0} to {1}').format(bold(old), bold(new)), alert=True, indicator='green') return new
def validate_inspection(self): for d in self.get('items'): #Enter inspection date for all items that require inspection if frappe.db.get_value("Item", d.item_code, "inspection_required") and not d.qa_no: frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code)) if self.docstatus==1: raise frappe.ValidationError
def validate_prefered_email(self): if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)): frappe.msgprint(_("Please enter " + self.prefered_contact_email))