def get_item_list(self): il = [] for d in self.get("items"): if d.qty is None: frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx)) if self.has_product_bundle(d.item_code): for p in self.get("packed_items"): if p.parent_detail_docname == d.name and p.parent_item == d.item_code: # the packing details table's qty is already multiplied with parent's qty il.append(frappe._dict({ 'warehouse': p.warehouse or d.warehouse, 'item_code': p.item_code, 'qty': flt(p.qty), 'uom': p.uom, 'batch_no': cstr(p.batch_no).strip(), 'serial_no': cstr(p.serial_no).strip(), 'name': d.name, 'target_warehouse': p.target_warehouse })) else: il.append(frappe._dict({ 'warehouse': d.warehouse, 'item_code': d.item_code, 'qty': d.stock_qty, 'uom': d.uom, 'stock_uom': d.stock_uom, 'conversion_factor': d.conversion_factor, 'batch_no': cstr(d.get("batch_no")).strip(), 'serial_no': cstr(d.get("serial_no")).strip(), 'name': d.name, 'target_warehouse': d.target_warehouse })) return il
def _set_limits(context, site, limits): import datetime if not limits: return if not site: site = get_site(context) with frappe.init_site(site): frappe.connect() new_limits = {} for limit, value in limits: if limit not in ('daily_emails', 'emails', 'space', 'users', 'email_group', 'expiry', 'support_email', 'support_chat', 'upgrade_url'): frappe.throw(_('Invalid limit {0}').format(limit)) if limit=='expiry' and value: try: datetime.datetime.strptime(value, '%Y-%m-%d') except ValueError: raise ValueError("Incorrect data format, should be YYYY-MM-DD") elif limit=='space': value = float(value) elif limit in ('users', 'emails', 'email_group', 'daily_emails'): value = int(value) new_limits[limit] = value update_limits(new_limits)
def declare_order_lost(self, arg): if not self.has_sales_order(): frappe.db.set(self, 'status', 'Lost') frappe.db.set(self, 'order_lost_reason', arg) self.update_opportunity() else: frappe.throw(_("Cannot set as Lost as Sales Order is made."))
def get_gl_dict(self, args, account_currency=None): """this method populates the common properties of a gl entry record""" fiscal_years = get_fiscal_years(self.posting_date, company=self.company) if len(fiscal_years) > 1: frappe.throw(_("Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year").format(formatdate(self.posting_date))) else: fiscal_year = fiscal_years[0][0] gl_dict = frappe._dict({ 'company': self.company, 'posting_date': self.posting_date, 'fiscal_year': fiscal_year, 'voucher_type': self.doctype, 'voucher_no': self.name, 'remarks': self.get("remarks"), 'debit': 0, 'credit': 0, 'debit_in_account_currency': 0, 'credit_in_account_currency': 0, 'is_opening': self.get("is_opening") or "No", 'party_type': None, 'party': None, 'project': self.get("project") }) gl_dict.update(args) if not account_currency: account_currency = get_account_currency(gl_dict.account) if self.doctype not in ["Journal Entry", "Period Closing Voucher", "Payment Entry"]: self.validate_account_currency(gl_dict.account, account_currency) set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"), self.company_currency) return gl_dict
def validate_duplicate_warehouse(obj): warehouse_list = [] if obj.get('locations'): data = [ data.location for data in obj.get('locations')] for warehouse in data: if data.count(warehouse) > 1: frappe.throw(_('You have enter location {0} more than once').format(warehouse))
def get_item_details(self, args=None): item = frappe.db.sql("""select stock_uom, description, image, item_name, expense_account, buying_cost_center, item_group from `tabItem` where name = %s and (ifnull(end_of_life,'0000-00-00')='0000-00-00' or end_of_life > now())""", (args.get('item_code')), as_dict = 1) if not item: frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code"))) item = item[0] ret = { 'uom' : item.stock_uom, 'stock_uom' : item.stock_uom, 'description' : item.description, 'image' : item.image, 'item_name' : item.item_name, 'expense_account' : args.get("expense_account") \ or frappe.db.get_value("Company", args.get("company"), "stock_adjustment_account"), 'cost_center' : get_default_cost_center(args, item), 'qty' : 0, 'transfer_qty' : 0, 'conversion_factor' : 1, 'batch_no' : '', 'actual_qty' : 0, 'incoming_rate' : 0 } stock_and_rate = args.get('warehouse') and self.get_warehouse_details(args) or {} ret.update(stock_and_rate) return ret
def _make_customer(source_name, ignore_permissions=False): quotation = frappe.db.get_value("Quotation", source_name, ["lead", "order_type", "customer"]) if quotation and quotation[0] and not quotation[2]: lead_name = quotation[0] customer_name = frappe.db.get_value("Customer", {"lead_name": lead_name}, ["name", "customer_name"], as_dict=True) if not customer_name: from erpnext.crm.doctype.lead.lead import _make_customer customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions) customer = frappe.get_doc(customer_doclist) customer.flags.ignore_permissions = ignore_permissions if quotation[1] == "Shopping Cart": customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None, "default_customer_group") try: customer.insert() return customer except frappe.NameError: if frappe.defaults.get_global_default('cust_master_name') == "Customer Name": customer.run_method("autoname") customer.name += "-" + lead_name customer.insert() return customer else: raise except frappe.MandatoryError: frappe.throw(_("Please create Customer from Lead {0}").format(lead_name)) else: return customer_name
def set_against_expense_account(self): auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) if auto_accounting_for_stock: stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") against_accounts = [] stock_items = self.get_stock_items() for item in self.get("items"): if auto_accounting_for_stock and item.item_code in stock_items \ and self.is_opening == 'No': # in case of auto inventory accounting, against expense account is always # Stock Received But Not Billed for a stock item item.expense_account = stock_not_billed_account item.cost_center = None if stock_not_billed_account not in against_accounts: against_accounts.append(stock_not_billed_account) elif not item.expense_account: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) elif item.expense_account not in against_accounts: # if no auto_accounting_for_stock or not a stock item against_accounts.append(item.expense_account) self.against_expense_account = ",".join(against_accounts)
def validate_item(self): stock_items = self.get_stock_items() serialized_items = self.get_serialized_items() for item in self.get("items"): if item.item_code not in stock_items: frappe.throw(_("{0} is not a stock Item").format(item.item_code)) item_details = self.get_item_details(frappe._dict({"item_code": item.item_code, "company": self.company, "project_name": self.project_name})) for f in ("uom", "stock_uom", "description", "item_name", "expense_account", "cost_center", "conversion_factor"): if f not in ["expense_account", "cost_center"] or not item.get(f): item.set(f, item_details.get(f)) if self.difference_account: item.expense_account = self.difference_account if not item.transfer_qty: item.transfer_qty = item.qty * item.conversion_factor if (self.purpose in ("Material Transfer", "Sales Return", "Purchase Return", "Material Transfer for Manufacture") and not item.serial_no and item.item_code in serialized_items): frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code), frappe.MandatoryError)
def get_company_default(company, fieldname): value = frappe.db.get_value("Company", company, fieldname) if not value: throw(_("Please set default value {0} in Company {1}").format(frappe.get_meta("Company").get_label(fieldname), company)) return value
def validate_fiscal_year(date, fiscal_year, label=_("Date"), doc=None): years = [f[0] for f in get_fiscal_years(date, label=label)] if fiscal_year not in years: if doc: doc.fiscal_year = years[0] else: throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
def bulk_rename(doctype, rows=None, via_console = False): """Bulk rename documents :param doctype: DocType to be renamed :param rows: list of documents as `((oldname, newname), ..)`""" if not rows: frappe.throw(_("Please select a valid csv file with data")) if not via_console: max_rows = 500 if len(rows) > max_rows: frappe.throw(_("Maximum {0} rows allowed").format(max_rows)) rename_log = [] for row in rows: # if row has some content if len(row) > 1 and row[0] and row[1]: try: if rename_doc(doctype, row[0], row[1]): msg = _("Successful: {0} to {1}").format(row[0], row[1]) frappe.db.commit() else: msg = _("Ignored: {0} to {1}").format(row[0], row[1]) except Exception, e: msg = _("** Failed: {0} to {1}: {2}").format(row[0], row[1], repr(e)) frappe.db.rollback() if via_console: print msg else: rename_log.append(msg)
def validate_attendance(self): attendance = frappe.db.sql("""select name from `tabAttendance` where employee = %s and (attendance_date between %s and %s) and status = "Present" and docstatus = 1""", (self.employee, self.from_date, self.to_date)) if attendance: frappe.throw(_("Attendance for employee {0} is already marked for this day").format(self.employee), AttendanceAlreadyMarkedError)
def get_default_bom(item_code=None): if item_code: bom = frappe.db.get_value("BOM", {"docstatus": 1, "is_default": 1, "is_active": 1, "item": item_code}) if bom: return bom else: frappe.throw(_("No default BOM exists for Item {0}").format(item_code))
def on_cancel(self): if self.has_drop_ship_item(): self.update_status_updater() pc_obj = frappe.get_doc('Purchase Common') self.check_for_stopped_or_closed_status(pc_obj) # Check if Purchase Receipt has been submitted against current Purchase Order pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.name, detail_doctype = 'Purchase Receipt Item') # Check if Purchase Invoice has been submitted against current Purchase Order submitted = frappe.db.sql_list("""select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = %s and t1.docstatus = 1""", self.name) if submitted: throw(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted))) frappe.db.set(self,'status','Cancelled') self.update_prevdoc_status() # Must be called after updating ordered qty in Material Request self.update_requested_qty() self.update_ordered_qty() pc_obj.update_last_purchase_rate(self, is_submit = 0)
def validate_fieldtype_change(self, df, old_value, new_value): for allowed_changes in self.allowed_fieldtype_change: if ((old_value in allowed_changes and new_value in allowed_changes) or (old_value not in allowed_changes and new_value not in allowed_changes)): continue else: frappe.throw(_("Fieldtype must be one of {0} in row {1}").format(", ".join([_(fieldtype) for fieldtype in allowed_changes]), df.idx))
def validate_price_list(args): if args.get("price_list"): if not frappe.db.get_value("Price List", {"name": args.price_list, args.transaction_type: 1, "enabled": 1}): throw(_("Price List {0} is disabled").format(args.price_list)) else: throw(_("Price List not selected"))
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None): if not self.fiscal_year: self.fiscal_year = frappe.db.get_default("fiscal_year") if not self.month: self.month = "%02d" % getdate(nowdate()).month if not joining_date: joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) m = get_month_details(self.fiscal_year, self.month) holidays = self.get_holidays_for_employee(m['month_start_date'], m['month_end_date']) working_days = m["month_days"] if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")): working_days -= len(holidays) if working_days < 0: frappe.throw(_("There are more holidays than working days this month.")) if not lwp: lwp = self.calculate_lwp(holidays, m) self.total_days_in_month = working_days self.leave_without_pay = lwp payment_days = flt(self.get_payment_days(m, joining_date, relieving_date)) - flt(lwp) self.payment_days = payment_days > 0 and payment_days or 0
def get_conditions(filters): conditions = "" if not filters.get("from_date"): frappe.throw(_("'From Date' is required")) if filters.get("to_date"): conditions += " and sle.posting_date <= '%s'" % frappe.db.escape(filters.get("to_date")) else: frappe.throw(_("'To Date' is required")) if filters.get("item_group"): ig_details = frappe.db.get_value("Item Group", filters.get("item_group"), ["lft", "rgt"], as_dict=1) if ig_details: conditions += """ and exists (select name from `tabItem Group` ig where ig.lft >= %s and ig.rgt <= %s and item.item_group = ig.name) """ % (ig_details.lft, ig_details.rgt) if filters.get("item_code"): conditions += " and sle.item_code = '%s'" % frappe.db.escape(filters.get("item_code"), percent=False) if filters.get("warehouse"): warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1) if warehouse_details: conditions += " and exists (select name from `tabWarehouse` wh \ where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(warehouse_details.lft, warehouse_details.rgt) return conditions
def prepare_to_notify(self, print_html=None, print_format=None, attachments=None): """Prepare to make multipart MIME Email :param print_html: Send given value as HTML attachment. :param print_format: Attach print format of parent document.""" if print_format: self.content += self.get_attach_link(print_format) self.set_incoming_outgoing_accounts() if not self.sender or cint(self.outgoing_email_account.always_use_account_email_id_as_sender): self.sender = formataddr([frappe.session.data.full_name or "Notification", self.outgoing_email_account.email_id]) self.attachments = [] if print_html or print_format: self.attachments.append(frappe.attach_print(self.reference_doctype, self.reference_name, print_format=print_format, html=print_html)) if attachments: if isinstance(attachments, basestring): attachments = json.loads(attachments) for a in attachments: if isinstance(a, basestring): # is it a filename? try: file = get_file(a) self.attachments.append({"fname": file[0], "fcontent": file[1]}) except IOError: frappe.throw(_("Unable to find attachment {0}").format(a)) else: self.attachments.append(a)
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None): if not self.fiscal_year: # if default fiscal year is not set, get from nowdate self.fiscal_year = get_fiscal_year(nowdate())[0] if not self.month: self.month = "%02d" % getdate(nowdate()).month self.set_month_dates() if not joining_date: joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) holidays = self.get_holidays_for_employee(self.start_date, self.end_date) working_days = date_diff(self.end_date, self.start_date) + 1 if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")): working_days -= len(holidays) if working_days < 0: frappe.throw(_("There are more holidays than working days this month.")) if not lwp: lwp = self.calculate_lwp(holidays, working_days) self.total_days_in_month = working_days self.leave_without_pay = lwp payment_days = flt(self.get_payment_days(joining_date, relieving_date)) - flt(lwp) self.payment_days = payment_days > 0 and payment_days or 0
def get_exchange_rate(account, account_currency=None, company=None, reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None): from erpnext.setup.utils import get_exchange_rate account_details = frappe.db.get_value("Account", account, ["account_type", "root_type", "account_currency", "company"], as_dict=1) if not account_details: frappe.throw(_("Please select correct account")) if not company: company = account_details.company if not account_currency: account_currency = account_details.account_currency company_currency = get_company_currency(company) if account_currency != company_currency: if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name: exchange_rate = frappe.db.get_value(reference_type, reference_name, "conversion_rate") elif account_details and account_details.account_type == "Bank" and \ ((account_details.root_type == "Asset" and flt(credit) > 0) or (account_details.root_type == "Liability" and debit)): exchange_rate = get_average_exchange_rate(account) if not exchange_rate and account_currency: exchange_rate = get_exchange_rate(account_currency, company_currency) else: exchange_rate = 1 # don't return None or 0 as it is multipled with a value and that value could be lost return exchange_rate or 1
def validate_against_jv(self): for d in self.get('accounts'): if d.reference_type=="Journal Entry": account_root_type = frappe.db.get_value("Account", d.account, "root_type") if account_root_type == "Asset" and flt(d.debit) > 0: frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry") .format(d.account)) elif account_root_type == "Liability" and flt(d.credit) > 0: frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry") .format(d.account)) if d.reference_name == self.name: frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column")) against_entries = frappe.db.sql("""select * from `tabJournal Entry Account` where account = %s and docstatus = 1 and parent = %s and (reference_type is null or reference_type in ("", "Sales Order", "Purchase Order")) """, (d.account, d.reference_name), as_dict=True) if not against_entries: frappe.throw(_("Journal Entry {0} does not have account {1} or already matched against other voucher") .format(d.reference_name, d.account)) else: dr_or_cr = "debit" if d.credit > 0 else "credit" valid = False for jvd in against_entries: if flt(jvd[dr_or_cr]) > 0: valid = True if not valid: frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry") .format(d.reference_name, dr_or_cr))
def validate_column_name(n): n = n.replace(' ','_').strip().lower() special_characters = re.findall("[\W]", n, re.UNICODE) if special_characters: special_characters = ", ".join('"{0}"'.format(c) for c in special_characters) frappe.throw(_("Fieldname {0} cannot have special characters like {1}").format(cstr(n), special_characters), InvalidColumnName) return n
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False): out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype)) party = out[party_type.lower()] if not ignore_permissions and not frappe.has_permission(party_type, "read", party): frappe.throw(_("Not permitted"), frappe.PermissionError) party = frappe.get_doc(party_type, party) set_address_details(out, party, party_type) set_contact_details(out, party, party_type) set_other_values(out, party, party_type) set_price_list(out, party, party_type, price_list) out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type) if not out.get("currency"): out["currency"] = currency # sales team if party_type=="Customer": out["sales_team"] = [{ "sales_person": d.sales_person, "allocated_percentage": d.allocated_percentage or None } for d in party.get("sales_team")] return out
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 set_total_advance_paid(self): if self.doctype == "Sales Order": dr_or_cr = "credit" against_field = "against_sales_order" else: dr_or_cr = "debit" against_field = "against_purchase_order" advance_paid = frappe.db.sql(""" select sum(ifnull({dr_or_cr}, 0)) from `tabJournal Entry Account` where {against_field} = %s and docstatus = 1 and is_advance = "Yes" """.format(dr_or_cr=dr_or_cr, \ against_field=against_field), self.name) if advance_paid: advance_paid = flt(advance_paid[0][0], self.precision("advance_paid")) if flt(self.base_grand_total) >= advance_paid: frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid) else: frappe.throw(_("Total advance ({0}) against Order {1} cannot be greater \ than the Grand Total ({2})") .format(advance_paid, self.name, self.base_grand_total))
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 validate_overlap_for(self, fieldname, args, value): if not value: return existing = self.get_overlap_for(fieldname, args, value) if existing: frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}") .format(args.idx, self.name, existing.name), OverlapError)
def validate_item_attribute_value(attributes_list, attribute, attribute_value, item): allow_rename_attribute_value = frappe.db.get_single_value('Item Variant Settings', 'allow_rename_attribute_value') if allow_rename_attribute_value: pass elif attribute_value not in attributes_list: frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values for Item {2}").format( attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Invalid Attribute'))
def validate_has_variants(self): if not self.has_variants and frappe.db.get_value( "Item", self.name, "has_variants"): if frappe.db.exists("Item", {"variant_of": self.name}): frappe.throw(_("Item has variants."))
def validate_warehouse_company(warehouse, company): warehouse_company = frappe.db.get_value("Warehouse", warehouse, "company") if warehouse_company and warehouse_company != company: frappe.throw( _("Warehouse {0} does not belong to company {1}").format( warehouse, company), InvalidWarehouseCompany)
def validate_operation_id(self): if (self.get("operation_id") and self.get("operation_row_number") and self.operation and self.work_order and frappe.get_cached_value("Work Order Operation", self.operation_row_number, "name") != self.operation_id): work_order = frappe.bold(get_link_to_form("Work Order", self.work_order)) frappe.throw(_("Operation {0} does not belong to the work order {1}") .format(frappe.bold(self.operation), work_order), OperationMismatchError)
def get_incoming_server(self, in_receive=False, email_sync_rule="UNSEEN"): """Returns logged in POP3/IMAP connection object.""" if frappe.cache().get_value("workers:no-internet") == True: return None args = frappe._dict({ "email_account": self.name, "host": self.email_server, "use_ssl": self.use_ssl, "username": getattr(self, "login_id", None) or self.email_id, "use_imap": self.use_imap, "email_sync_rule": email_sync_rule, "uid_validity": self.uidvalidity, "initial_sync_count": self.initial_sync_count or 100 }) if self.password: args.password = self.get_password() if not args.get("host"): frappe.throw(_("{0} is required").format("Email Server")) email_server = EmailServer(frappe._dict(args)) try: email_server.connect() except (error_proto, imaplib.IMAP4.error) as e: message = e.message.lower().replace(" ", "") if in_receive and any( map( lambda t: t in message, [ 'authenticationfail', 'loginviayourwebbrowser', #abbreviated to work with both failure and failed 'loginfailed', 'err[auth]', 'errtemporaryerror' ])): #temporary error to deal with godaddy # if called via self.receive and it leads to authentication error, disable incoming # and send email to system manager self.handle_incoming_connect_error(description=_( 'Authentication failed while receiving emails from Email Account {0}. Message from server: {1}' .format(self.name, e.message))) return None else: frappe.throw(e.message) except socket.error: if in_receive: # timeout while connecting, see receive.py connect method description = frappe.message_log.pop( ) if frappe.message_log else "Socket Error" if test_internet(): self.db_set("no_failed", self.no_failed + 1) if self.no_failed > 2: self.handle_incoming_connect_error( description=description) else: frappe.cache().set_value("workers:no-internet", True) return None else: raise if not in_receive: if self.use_imap: email_server.imap.logout() # reset failed attempts count self.set_failed_attempts_count(0) return email_server
def generate_fee(fee_schedule): doc = frappe.get_doc("Fee Schedule", fee_schedule) error = False total_records = sum([int(d.total_students) for d in doc.student_groups]) created_records = 0 if not total_records: frappe.throw(_("Please setup Students under Student Groups")) for d in doc.student_groups: students = frappe.db.sql( """ select sg.program, sg.batch, sgs.student, sgs.student_name from `tabStudent Group` sg, `tabStudent Group Student` sgs where sg.name=%s and sg.name=sgs.parent and sgs.active=1""", d.student_group, as_dict=1) for student in students: try: fees_doc = get_mapped_doc( "Fee Schedule", fee_schedule, { "Fee Schedule": { "doctype": "Fees", "field_map": { "name": "Fee Schedule" } } }) fees_doc.student = student.student fees_doc.student_name = student.student_name fees_doc.program = student.program fees_doc.student_batch = student.batch fees_doc.send_payment_request = doc.send_email fees_doc.save() fees_doc.submit() created_records += 1 frappe.publish_realtime("fee_schedule_progress", { "progress": str(int(created_records * 100 / total_records)) }, user=frappe.session.user) except Exception as e: error = True err_msg = frappe.local.message_log and "\n\n".join( frappe.local.message_log) or cstr(e) if error: frappe.db.rollback() frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Failed") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", err_msg) else: frappe.db.set_value("Fee Schedule", fee_schedule, "fee_creation_status", "Successful") frappe.db.set_value("Fee Schedule", fee_schedule, "error_log", None) frappe.publish_realtime("fee_schedule_progress", { "progress": "100", "reload": 1 }, user=frappe.session.user)
def validate_table_has_rows(self, parentfield, raise_exception=None): """Raise exception if Table field is empty.""" if not (isinstance(self.get(parentfield), list) and len(self.get(parentfield)) > 0): label = self.meta.get_label(parentfield) frappe.throw(_("Table {0} cannot be empty").format(label), raise_exception or frappe.EmptyTableError)
def on_cancel(self): frappe.throw("Dokumen tidak dapat di batalkan")
def validate_dates(self): if date_diff(self.end_date, self.start_date) < 0: frappe.throw(_("To date cannot be before From date"))
def validate_attendance_date(self): attendance_date = self.attendance_date date = frappe.utils.nowdate() if attendance_date < date: frappe.throw("Attendance Date Can Not Less Than To Todays Date")
def validate_name_with_item_group(self): # causes problem with tree build if frappe.db.exists("Item Group", self.name): frappe.throw( _("An Item Group exists with same name, please change the item name or rename the item group" ))
def setup_account(args=None): try: if frappe.db.sql("select name from tabCompany"): frappe.throw(_("Setup Already Complete!!")) if not args: args = frappe.local.form_dict if isinstance(args, basestring): args = json.loads(args) args = frappe._dict(args) if args.language != "english": set_default_language(args.language) install_fixtures.install(args.get("country")) update_user_name(args) frappe.local.message_log = [] create_fiscal_year_and_company(args) frappe.local.message_log = [] set_defaults(args) frappe.local.message_log = [] create_territories() frappe.local.message_log = [] create_price_lists(args) frappe.local.message_log = [] create_feed_and_todo() frappe.local.message_log = [] create_email_digest() frappe.local.message_log = [] create_letter_head(args) frappe.local.message_log = [] create_taxes(args) frappe.local.message_log = [] create_items(args) frappe.local.message_log = [] create_customers(args) frappe.local.message_log = [] create_suppliers(args) frappe.local.message_log = [] frappe.db.set_default('desktop:home_page', 'desktop') website_maker(args.company_name.strip(), args.company_tagline, args.name) create_logo(args) login_as_first_user(args) frappe.clear_cache() frappe.db.commit() except: if args: traceback = frappe.get_traceback() for hook in frappe.get_hooks("setup_wizard_exception"): frappe.get_attr(hook)(traceback, args) raise else: for hook in frappe.get_hooks("setup_wizard_success"): frappe.get_attr(hook)(args)
def get_healthcare_services_to_invoice(patient): patient = frappe.get_doc("Patient", patient) if patient: if patient.customer: item_to_invoice = [] patient_appointments = frappe.get_list("Patient Appointment", { 'patient': patient.name, 'invoiced': False }, order_by="appointment_date") if patient_appointments: fee_validity_details = [] valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") for patient_appointment in patient_appointments: patient_appointment_obj = frappe.get_doc( "Patient Appointment", patient_appointment['name']) if patient_appointment_obj.procedure_template: if frappe.db.get_value( "Clinical Procedure Template", patient_appointment_obj.procedure_template, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': patient_appointment_obj.procedure_template }) else: practitioner_exist_in_list = False skip_invoice = False if fee_validity_details: for validity in fee_validity_details: if validity[ 'practitioner'] == patient_appointment_obj.practitioner: practitioner_exist_in_list = True if validity[ 'valid_till'] >= patient_appointment_obj.appointment_date: validity[ 'visits'] = validity['visits'] + 1 if int(max_visit) > validity['visits']: skip_invoice = True if not skip_invoice: validity['visits'] = 1 validity[ 'valid_till'] = patient_appointment_obj.appointment_date + datetime.timedelta( days=int(valid_days)) if not practitioner_exist_in_list: valid_till = patient_appointment_obj.appointment_date + datetime.timedelta( days=int(valid_days)) visits = 0 validity_exist = validity_exists( patient_appointment_obj.practitioner, patient_appointment_obj.patient) if validity_exist: fee_validity = frappe.get_doc( "Fee Validity", validity_exist[0][0]) valid_till = fee_validity.valid_till visits = fee_validity.visited fee_validity_details.append({ 'practitioner': patient_appointment_obj.practitioner, 'valid_till': valid_till, 'visits': visits }) if not skip_invoice: practitioner_charge = 0 income_account = None service_item = None if patient_appointment_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge( patient_appointment_obj) income_account = get_income_account( patient_appointment_obj.practitioner, patient_appointment_obj.company) item_to_invoice.append({ 'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account }) encounters = frappe.get_list("Patient Encounter", { 'patient': patient.name, 'invoiced': False, 'docstatus': 1 }) if encounters: for encounter in encounters: encounter_obj = frappe.get_doc("Patient Encounter", encounter['name']) if not encounter_obj.appointment: practitioner_charge = 0 income_account = None service_item = None if encounter_obj.practitioner: service_item, practitioner_charge = service_item_and_practitioner_charge( encounter_obj) income_account = get_income_account( encounter_obj.practitioner, encounter_obj.company) item_to_invoice.append({ 'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name, 'service': service_item, 'rate': practitioner_charge, 'income_account': income_account }) lab_tests = frappe.get_list("Lab Test", { 'patient': patient.name, 'invoiced': False, 'docstatus': 1 }) if lab_tests: for lab_test in lab_tests: lab_test_obj = frappe.get_doc("Lab Test", lab_test['name']) if frappe.db.get_value("Lab Test Template", lab_test_obj.template, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Lab Test', 'reference_name': lab_test_obj.name, 'service': frappe.db.get_value("Lab Test Template", lab_test_obj.template, "item") }) lab_rxs = frappe.db.sql( """select lp.name from `tabPatient Encounter` et, `tabLab Prescription` lp where et.patient=%s and lp.parent=et.name and lp.lab_test_created=0 and lp.invoiced=0""", (patient.name)) if lab_rxs: for lab_rx in lab_rxs: rx_obj = frappe.get_doc("Lab Prescription", lab_rx[0]) if rx_obj.lab_test_code and (frappe.db.get_value( "Lab Test Template", rx_obj.lab_test_code, "is_billable") == 1): item_to_invoice.append({ 'reference_type': 'Lab Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "item") }) procedures = frappe.get_list("Clinical Procedure", { 'patient': patient.name, 'invoiced': False }) if procedures: for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) if not procedure_obj.appointment: if procedure_obj.procedure_template and ( frappe.db.get_value( "Clinical Procedure Template", procedure_obj.procedure_template, "is_billable") == 1): item_to_invoice.append({ 'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': frappe.db.get_value( "Clinical Procedure Template", procedure_obj.procedure_template, "item") }) procedure_rxs = frappe.db.sql( """select pp.name from `tabPatient Encounter` et, `tabProcedure Prescription` pp where et.patient=%s and pp.parent=et.name and pp.procedure_created=0 and pp.invoiced=0 and pp.appointment_booked=0""", (patient.name)) if procedure_rxs: for procedure_rx in procedure_rxs: rx_obj = frappe.get_doc("Procedure Prescription", procedure_rx[0]) if frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "is_billable") == 1: item_to_invoice.append({ 'reference_type': 'Procedure Prescription', 'reference_name': rx_obj.name, 'service': frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "item") }) procedures = frappe.get_list( "Clinical Procedure", { 'patient': patient.name, 'invoice_separately_as_consumables': True, 'consumption_invoiced': False, 'consume_stock': True, 'status': 'Completed' }) if procedures: service_item = get_healthcare_service_item( 'clinical_procedure_consumable_item') if not service_item: msg = _(("Please Configure {0} in ").format("Clinical Procedure Consumable Item") \ + """<b><a href="#Form/Healthcare Settings">Healthcare Settings</a></b>""") frappe.throw(msg) for procedure in procedures: procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) item_to_invoice.append({ 'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': service_item, 'rate': procedure_obj.consumable_total_amount, 'description': procedure_obj.consumption_details }) inpatient_services = frappe.db.sql( """select io.name, io.parent from `tabInpatient Record` ip, `tabInpatient Occupancy` io where ip.patient=%s and io.parent=ip.name and io.left=1 and io.invoiced=0""", (patient.name)) if inpatient_services: for inpatient_service in inpatient_services: inpatient_occupancy = frappe.get_doc( "Inpatient Occupancy", inpatient_service[0]) service_unit_type = frappe.get_doc( "Healthcare Service Unit Type", frappe.db.get_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "service_unit_type")) if service_unit_type and service_unit_type.is_billable == 1: hours_occupied = time_diff_in_hours( inpatient_occupancy.check_out, inpatient_occupancy.check_in) qty = 0.5 if hours_occupied > 0: actual_qty = hours_occupied / service_unit_type.no_of_hours floor = math.floor(actual_qty) decimal_part = actual_qty - floor if decimal_part > 0.5: qty = rounded(floor + 1, 1) elif decimal_part < 0.5 and decimal_part > 0: qty = rounded(floor + 0.5, 1) if qty <= 0: qty = 0.5 item_to_invoice.append({ 'reference_type': 'Inpatient Occupancy', 'reference_name': inpatient_occupancy.name, 'service': service_unit_type.item, 'qty': qty }) return item_to_invoice else: frappe.throw( _("The Patient {0} do not have customer refrence to invoice"). format(patient.name))
def validate_dates(self): if self.fecha_inicial and self.fecha_final: if self.fecha_inicial > self.fecha_final: frappe.throw("La fecha inicial debe ser menor a la fecha final del contrato")
def validate_shift_type(self): shift_type = frappe.db.get_value("Employee", self.employee, "shift_type") if shift_type != "Rotational": frappe.throw("Shift Type for Employee {0} should be Rotational".format(self.employee))
def validate_tax_declaration(declarations): subcategories = [] for d in declarations: if d.exemption_sub_category in subcategories: frappe.throw(_("More than one selection for {0} not allowed").format(d.exemption_sub_category)) subcategories.append(d.exemption_sub_category)
def get_invalid_links(self, is_submittable=False): """Returns list of invalid links and also updates fetch values if not set""" def get_msg(df, docname): if self.parentfield: return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname) else: return "{}: {}".format(_(df.label), docname) invalid_links = [] cancelled_links = [] for df in ( self.meta.get_link_fields() + self.meta.get("fields", {"fieldtype": ('=', "Dynamic Link")})): docname = self.get(df.fieldname) if docname: if df.fieldtype == "Link": doctype = df.options if not doctype: frappe.throw( _("Options not set for link field {0}").format( df.fieldname)) else: doctype = self.get(df.options) if not doctype: frappe.throw( _("{0} must be set first").format( self.meta.get_label(df.options))) # MySQL is case insensitive. Preserve case of the original docname in the Link Field. # get a map of values ot fetch along with this link query # that are mapped as link_fieldname.source_fieldname in Options of # Readonly or Data or Text type fields fields_to_fetch = [ _df for _df in self.meta.get_fields_to_fetch(df.fieldname) if not _df.get('fetch_if_empty') or (_df.get('fetch_if_empty') and not self.get(_df.fieldname)) ] if not fields_to_fetch: # cache a single value type values = frappe._dict(name=frappe.db.get_value( doctype, docname, 'name', cache=True)) else: values_to_fetch = ['name'] + [ _df.fetch_from.split('.')[-1] for _df in fields_to_fetch ] # don't cache if fetching other values too values = frappe.db.get_value(doctype, docname, values_to_fetch, as_dict=True) if frappe.get_meta(doctype).issingle: values.name = doctype if values: setattr(self, df.fieldname, values.name) for _df in fields_to_fetch: if self.is_new( ) or self.docstatus != 1 or _df.allow_on_submit: self.set_fetch_from_value(doctype, _df, values) notify_link_count(doctype, docname) if not values.name: invalid_links.append( (df.fieldname, docname, get_msg(df, docname))) elif (df.fieldname != "amended_from" and (is_submittable or self.meta.is_submittable) and frappe.get_meta(doctype).is_submittable and cint( frappe.db.get_value(doctype, docname, "docstatus")) == 2): cancelled_links.append( (df.fieldname, docname, get_msg(df, docname))) return invalid_links, cancelled_links
def validate_reference_document(self): if not self.reference_doctype or not self.reference_name: frappe.throw( _("To create a Payment Request reference document is required") )
def is_group_warehouse(warehouse): if frappe.db.get_value("Warehouse", warehouse, "is_group"): frappe.throw(_("Group node warehouse is not allowed to select for transactions"))
def validate_schedule_date(self): for d in self.get('items'): if d.schedule_date and getdate(d.schedule_date) < getdate(self.transaction_date): frappe.throw(_("Expected Date cannot be before Material Request Date"))
def throw_overlap_error(doc, exists_for, overlap_doc, from_date, to_date): msg = _("A {0} exists between {1} and {2} (").format(doc.doctype, formatdate(from_date), formatdate(to_date)) \ + """ <b><a href="#Form/{0}/{1}">{1}</a></b>""".format(doc.doctype, overlap_doc) \ + _(") for {0}").format(exists_for) frappe.throw(msg)
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)
if current and current[0][0]==count: frappe.db.sql("update tabSeries set current=current-1 where name=%s", prefix) def get_default_naming_series(doctype): """get default value for `naming_series` property""" naming_series = frappe.get_meta(doctype).get_field("naming_series").options or "" if naming_series: naming_series = naming_series.split("\n") return naming_series[0] or naming_series[1] else: return None def validate_name(doctype, name, case=None, merge=False): if not name: return 'No Name Specified for %s' % doctype if name.startswith('New '+doctype): frappe.throw(_('There were some errors setting the name, please contact the administrator'), frappe.NameError) if case=='Title Case': name = name.title() if case=='UPPER CASE': name = name.upper() name = name.strip() if not frappe.get_meta(doctype).get("issingle") and (doctype == name) and (name!="DocType"): frappe.throw(_("Name of {0} cannot be {1}").format(doctype, name), frappe.NameError) special_characters = "<>" if re.findall("[{0}]+".format(special_characters), name): message = ", ".join("'{0}'".format(c) for c in special_characters) frappe.throw(_("Name cannot contain special characters like {0}").format(message), frappe.NameError) return name def _set_amended_name(doc):
def _validate_gift_card_expiry(posting_date, giftcard): if giftcard.expiry_date and getdate(giftcard.expiry_date) < getdate(posting_date): frappe.throw(_("Gift Card {} has expired.".format(giftcard.gift_card_no)))
def _raise_exception(): frappe.throw(_('Use of sub-query or function is restricted'), frappe.DataError)
def _validate_loyalty_card_no(customer, loyalty_card_no): if loyalty_card_no != frappe.db.get_value("Customer", customer, "os_loyalty_card_no"): frappe.throw( _("Loyalty Card No: {} does not belong to this Customer".format( loyalty_card_no)))
def _validate_gift_card_balance(payments, gift_cards): get_gift_card_balances = compose(sum, partial(map, lambda x: x.balance)) if _get_gift_card_amounts(payments) > get_gift_card_balances(gift_cards): frappe.throw(_("Gift Card(s) has insufficient balance."))
def check_mandatory(self): for fieldname in ['company', 'start_date', 'end_date']: if not self.get(fieldname): frappe.throw(_("Please set {0}").format(self.meta.get_label(fieldname)))
def validate_query(self, q): """Throw exception for dangerous queries: `ALTER`, `DROP`, `TRUNCATE` if not `Administrator`.""" cmd = q.strip().lower().split()[0] if cmd in ['alter', 'drop', 'truncate'] and frappe.session.user != 'Administrator': frappe.throw(_("Not permitted"), frappe.PermissionError)
def make_accrual_jv_entry(self): self.check_permission('write') earnings = self.get_salary_component_total(component_type = "earnings") or {} deductions = self.get_salary_component_total(component_type = "deductions") or {} default_payroll_payable_account = self.get_default_payroll_payable_account() loan_details = self.get_loan_details() jv_name = "" precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency") if earnings or deductions: journal_entry = frappe.new_doc('Journal Entry') journal_entry.voucher_type = 'Journal Entry' journal_entry.user_remark = _('Accrual Journal Entry for salaries from {0} to {1}')\ .format(self.start_date, self.end_date) journal_entry.company = self.company journal_entry.posting_date = self.posting_date accounts = [] payable_amount = 0 # Earnings for acc, amount in earnings.items(): payable_amount += flt(amount, precision) accounts.append({ "account": acc, "debit_in_account_currency": flt(amount, precision), "cost_center": self.cost_center, "project": self.project }) # Deductions for acc, amount in deductions.items(): payable_amount -= flt(amount, precision) accounts.append({ "account": acc, "credit_in_account_currency": flt(amount, precision), "cost_center": self.cost_center, "project": self.project }) # Loan for data in loan_details: accounts.append({ "account": data.loan_account, "credit_in_account_currency": data.principal_amount, "reference_type": "Loan", "reference_name": data.loan }) if data.interest_amount and not data.interest_income_account: frappe.throw(_("Select interest income account in loan {0}").format(data.loan)) if data.interest_income_account and data.interest_amount: accounts.append({ "account": data.interest_income_account, "credit_in_account_currency": data.interest_amount, "cost_center": self.cost_center, "project": self.project }) payable_amount -= flt(data.total_payment, precision) # Payable amount accounts.append({ "account": default_payroll_payable_account, "credit_in_account_currency": flt(payable_amount, precision) }) journal_entry.set("accounts", accounts) journal_entry.title = default_payroll_payable_account journal_entry.save() try: journal_entry.submit() jv_name = journal_entry.name self.update_salary_slip_status(jv_name = jv_name) except Exception as e: frappe.msgprint(e) return jv_name
def validate_folder(self): if not self.is_home_folder and not self.folder and \ not self.flags.ignore_folder_validate: frappe.throw(_("Folder is mandatory"))