def get_due_date(posting_date, party_type, party, company=None, bill_date=None): """Get due date from `Payment Terms Template`""" due_date = None if (bill_date or posting_date) and party: due_date = bill_date or posting_date template_name = get_pyt_term_template(party, party_type, company) if template_name: due_date = get_due_date_from_template( template_name, posting_date, bill_date).strftime("%Y-%m-%d") else: if party_type == "Supplier": supplier_group = dataent.get_cached_value( party_type, party, "supplier_group") template_name = dataent.get_cached_value( "Supplier Group", supplier_group, "payment_terms") if template_name: due_date = get_due_date_from_template( template_name, posting_date, bill_date).strftime("%Y-%m-%d") # If due date is calculated from bill_date, check this condition if getdate(due_date) < getdate(posting_date): due_date = posting_date return due_date
def get_pyt_term_template(party_name, party_type, company=None): if party_type not in ("Customer", "Supplier"): return template = None if party_type == 'Customer': customer = dataent.get_cached_value( "Customer", party_name, fieldname=['payment_terms', "customer_group"], as_dict=1) template = customer.payment_terms if not template and customer.customer_group: template = dataent.get_cached_value("Customer Group", customer.customer_group, 'payment_terms') else: supplier = dataent.get_cached_value( "Supplier", party_name, fieldname=['payment_terms', "supplier_group"], as_dict=1) template = supplier.payment_terms if not template and supplier.supplier_group: template = dataent.get_cached_value("Supplier Group", supplier.supplier_group, 'payment_terms') if not template and company: template = dataent.get_cached_value('Company', company, fieldname='payment_terms') return template
def generator(): account_currency, company = dataent.get_cached_value( "Account", account, ["account_currency", "company"]) if not account_currency: account_currency = dataent.get_cached_value( 'Company', company, "default_currency") return account_currency
def notify_assignment(assigned_by, owner, doc_type, doc_name, action='CLOSE', description=None, notify=0): """ Notify assignee that there is a change in assignment """ if not (assigned_by and owner and doc_type and doc_name): return # self assignment / closing - no message if assigned_by == owner: return # Search for email address in description -- i.e. assignee from dataent.utils import get_link_to_form assignment = get_link_to_form(doc_type, doc_name, label="%s: %s" % (doc_type, doc_name)) owner_name = dataent.get_cached_value('User', owner, 'full_name') user_name = dataent.get_cached_value('User', dataent.session.user, 'full_name') if action == 'CLOSE': if owner == dataent.session.get('user'): arg = { 'contact': assigned_by, 'txt': _("The task {0}, that you assigned to {1}, has been closed."). format(assignment, owner_name) } else: arg = { 'contact': assigned_by, 'txt': _("The task {0}, that you assigned to {1}, has been closed by {2}." ).format(assignment, owner_name, user_name) } else: description_html = "<p>{0}</p>".format(description) arg = { 'contact': owner, 'txt': _("A new task, {0}, has been assigned to you by {1}. {2}").format( assignment, user_name, description_html), 'notify': notify } if arg and cint(arg.get("notify")): _notify(arg)
def validate(self): if not self.expense_account: self.expense_account = dataent.get_cached_value( 'Company', self.company, "stock_adjustment_account") if not self.cost_center: self.cost_center = dataent.get_cached_value( 'Company', self.company, "cost_center") self.validate_posting_time() self.remove_items_with_no_change() self.validate_data() self.validate_expense_account() self.set_total_qty_and_amount()
def before_rename(self, old, new, merge=False): # renaming consistency with abbreviation if not dataent.get_cached_value('Company', self.company, 'abbr') in new: new = get_abbreviated_name(new, self.company) return new
def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date): pi = dataent.new_doc("Purchase Invoice") pi.company = company pi.currency = dataent.get_cached_value('Company', company, "default_currency") pi.set_posting_time = 1 pi.posting_date = posting_date pi.append( "items", { "item_code": item_code, "is_fixed_asset": 1, "asset": asset, "expense_account": get_asset_category_account(asset, 'fixed_asset_account'), "qty": 1, "price_list_rate": gross_purchase_amount, "rate": gross_purchase_amount }) pi.set_missing_values() return pi
def make_address(args, customer): if not args.get('address_line1'): return name = args.get('name') if not name: data = get_customers_address(customer) name = data[customer].get('name') if data else None if name: address = dataent.get_doc('Address', name) else: address = dataent.new_doc('Address') address.country = dataent.get_cached_value('Company', args.get('company'), 'country') address.append('links', { 'link_doctype': 'Customer', 'link_name': customer }) address.is_primary_address = 1 address.is_shipping_address = 1 address.update(args) address.flags.ignore_mandatory = True address.save(ignore_permissions=True)
def get_default_deferred_account(args, item, fieldname=None): if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"): return (item.get(fieldname) or args.get(fieldname) or dataent.get_cached_value('Company', args.company, "default_"+fieldname)) else: return None
def get_depreciation_accounts(asset): fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None accounts = dataent.db.get_value("Asset Category Account", filters={'parent': asset.asset_category, 'company_name': asset.company}, fieldname = ['fixed_asset_account', 'accumulated_depreciation_account', 'depreciation_expense_account'], as_dict=1) if accounts: fixed_asset_account = accounts.fixed_asset_account accumulated_depreciation_account = accounts.accumulated_depreciation_account depreciation_expense_account = accounts.depreciation_expense_account if not accumulated_depreciation_account or not depreciation_expense_account: accounts = dataent.get_cached_value('Company', asset.company, ["accumulated_depreciation_account", "depreciation_expense_account"]) if not accumulated_depreciation_account: accumulated_depreciation_account = accounts[0] if not depreciation_expense_account: depreciation_expense_account = accounts[1] if not fixed_asset_account or not accumulated_depreciation_account or not depreciation_expense_account: dataent.throw(_("Please set Depreciation related Accounts in Asset Category {0} or Company {1}") .format(asset.asset_category, asset.company)) return fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
def make_depreciation_entry(self): asset = dataent.get_doc("Asset", self.asset) fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \ get_depreciation_accounts(asset) depreciation_cost_center, depreciation_series = dataent.get_cached_value( 'Company', asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"]) je = dataent.new_doc("Journal Entry") je.voucher_type = "Depreciation Entry" je.naming_series = depreciation_series je.posting_date = self.date je.company = self.company je.remark = "Depreciation Entry against {0} worth {1}".format( self.asset, self.difference_amount) je.append( "accounts", { "account": accumulated_depreciation_account, "credit_in_account_currency": self.difference_amount, "cost_center": depreciation_cost_center or self.cost_center }) je.append( "accounts", { "account": depreciation_expense_account, "debit_in_account_currency": self.difference_amount, "cost_center": depreciation_cost_center or self.cost_center }) je.flags.ignore_permissions = True je.submit() self.db_set("journal_entry", je.name)
def validate_applicable_charges_for_item(self): based_on = self.distribute_charges_based_on.lower() total = sum([flt(d.get(based_on)) for d in self.get("items")]) if not total: dataent.throw( _("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'" ).format(based_on)) total_applicable_charges = sum( [flt(d.applicable_charges) for d in self.get("items")]) precision = get_field_precision(dataent.get_meta( "Landed Cost Item").get_field("applicable_charges"), currency=dataent.get_cached_value( 'Company', self.company, "default_currency")) diff = flt( self.total_taxes_and_charges) - flt(total_applicable_charges) diff = flt(diff, precision) if abs(diff) < (2.0 / (10**precision)): self.items[-1].applicable_charges += diff else: dataent.throw( _("Total Applicable Charges in Purchase Receipt Items table must be same as Total Taxes and Charges" ))
def get_receivable_account(company): receivable_account = get_account(None, "receivable_account", "Healthcare Settings", company) if receivable_account: return receivable_account return dataent.get_cached_value('Company', company, "default_receivable_account")
def get_children(doctype, parent, company, is_root=False): from epaas.accounts.report.financial_statements import sort_accounts parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_') fields = [ 'name as value', 'is_group as expandable' ] filters = [['docstatus', '<', 2]] filters.append(['ifnull(`{0}`,"")'.format(parent_fieldname), '=', '' if is_root else parent]) if is_root: fields += ['root_type', 'report_type', 'account_currency'] if doctype == 'Account' else [] filters.append(['company', '=', company]) else: fields += ['account_currency'] if doctype == 'Account' else [] fields += [parent_fieldname + ' as parent'] acc = dataent.get_list(doctype, fields=fields, filters=filters) if doctype == 'Account': sort_accounts(acc, is_root, key="value") company_currency = dataent.get_cached_value('Company', company, "default_currency") for each in acc: each["company_currency"] = company_currency each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) if each.account_currency != company_currency: each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) return acc
def validate_schedule_date_for_holiday_list(self, schedule_date, sales_person): validated = False employee = dataent.db.get_value("Sales Person", sales_person, "employee") if employee: holiday_list = get_holiday_list_for_employee(employee) else: holiday_list = dataent.get_cached_value('Company', self.company, "default_holiday_list") holidays = dataent.db.sql_list( '''select holiday_date from `tabHoliday` where parent=%s''', holiday_list) if not validated and holidays: # max iterations = len(holidays) for i in range(len(holidays)): if schedule_date in holidays: schedule_date = add_days(schedule_date, -1) else: validated = True break return schedule_date
def get_stock_rbnb_difference(posting_date, company): stock_items = dataent.db.sql_list("""select distinct item_code from `tabStock Ledger Entry` where company=%s""", company) pr_valuation_amount = dataent.db.sql(""" select sum(pr_item.valuation_rate * pr_item.qty * pr_item.conversion_factor) from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr where pr.name = pr_item.parent and pr.docstatus=1 and pr.company=%s and pr.posting_date <= %s and pr_item.item_code in (%s)""" % ('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0] pi_valuation_amount = dataent.db.sql(""" select sum(pi_item.valuation_rate * pi_item.qty * pi_item.conversion_factor) from `tabPurchase Invoice Item` pi_item, `tabPurchase Invoice` pi where pi.name = pi_item.parent and pi.docstatus=1 and pi.company=%s and pi.posting_date <= %s and pi_item.item_code in (%s)""" % ('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0] # Balance should be stock_rbnb = flt(pr_valuation_amount, 2) - flt(pi_valuation_amount, 2) # Balance as per system stock_rbnb_account = "Stock Received But Not Billed - " + dataent.get_cached_value('Company', company, "abbr") sys_bal = get_balance_on(stock_rbnb_account, posting_date, in_account_currency=False) # Amount should be credited return flt(stock_rbnb) + flt(sys_bal)
def get_net_profit(non_gross_income, gross_income, gross_expense, non_gross_expense, period_list, company, currency=None, consolidated=False): profit_loss = { "account_name": "'" + _("Net Profit") + "'", "account": "'" + _("Net Profit") + "'", "warn_if_negative": True, "currency": currency or dataent.get_cached_value('Company', company, "default_currency") } has_value = False for period in period_list: key = period if consolidated else period.key total_income = flt(gross_income[0].get(key, 0)) + flt( non_gross_income[0].get(key, 0)) total_expense = flt(gross_expense[0].get(key, 0)) + flt( non_gross_expense[0].get(key, 0)) profit_loss[key] = flt(total_income) - flt(total_expense) if profit_loss[key]: has_value = True if has_value: return profit_loss
def round_off_debit_credit(gl_map): precision = get_field_precision( dataent.get_meta("GL Entry").get_field("debit"), currency=dataent.get_cached_value('Company', gl_map[0].company, "default_currency")) debit_credit_diff = 0.0 for entry in gl_map: entry.debit = flt(entry.debit, precision) entry.credit = flt(entry.credit, precision) debit_credit_diff += entry.debit - entry.credit debit_credit_diff = flt(debit_credit_diff, precision) if gl_map[0]["voucher_type"] in ("Journal Entry", "Payment Entry"): allowance = 5.0 / (10**precision) else: allowance = .5 if abs(debit_credit_diff) >= allowance: dataent.throw( _("Debit and Credit not equal for {0} #{1}. Difference is {2}."). format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff)) elif abs(debit_credit_diff) >= (1.0 / (10**precision)): make_round_off_gle(gl_map, debit_credit_diff, precision)
def get_last_purchase_rate(self): """get last purchase rates for all items""" conversion_rate = flt(self.get('conversion_rate')) or 1.0 for d in self.get("items"): if d.item_code: last_purchase_details = get_last_purchase_details( d.item_code, self.name) if last_purchase_details: d.base_price_list_rate = ( last_purchase_details['base_price_list_rate'] * (flt(d.conversion_factor) or 1.0)) d.discount_percentage = last_purchase_details[ 'discount_percentage'] d.base_rate = last_purchase_details['base_rate'] * (flt( d.conversion_factor) or 1.0) d.price_list_rate = d.base_price_list_rate / conversion_rate d.rate = d.base_rate / conversion_rate d.last_purchase_rate = d.rate else: item_last_purchase_rate = dataent.get_cached_value( "Item", d.item_code, "last_purchase_rate") if item_last_purchase_rate: d.base_price_list_rate = d.base_rate = d.price_list_rate \ = d.rate = d.last_purchase_rate = item_last_purchase_rate
def validate_party_accounts(doc): companies = [] for account in doc.get("accounts"): if account.company in companies: dataent.throw( _("There can only be 1 Account per Company in {0} {1}").format( doc.doctype, doc.name), DuplicatePartyAccountError) else: companies.append(account.company) party_account_currency = dataent.db.get_value("Account", account.account, "account_currency", cache=True) existing_gle_currency = get_party_gle_currency(doc.doctype, doc.name, account.company) company_default_currency = dataent.get_cached_value( 'Company', dataent.db.get_default("Company"), "default_currency") if existing_gle_currency and party_account_currency != existing_gle_currency: dataent.throw( _("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}." ).format(existing_gle_currency, account.company)) if doc.get("default_currency" ) and party_account_currency and company_default_currency: if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency: dataent.throw( _("Billing currency must be equal to either default company's currency or party account currency" ))
def scrap_asset(asset_name): asset = dataent.get_doc("Asset", asset_name) if asset.docstatus != 1: dataent.throw(_("Asset {0} must be submitted").format(asset.name)) elif asset.status in ("Cancelled", "Sold", "Scrapped"): dataent.throw(_("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status)) depreciation_series = dataent.get_cached_value('Company', asset.company, "series_for_depreciation_entry") je = dataent.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() dataent.db.set_value("Asset", asset_name, "disposal_date", today()) dataent.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name) asset.set_status("Scrapped") dataent.msgprint(_("Asset scrapped via Journal Entry {0}").format(je.name))
def validate_serial_no_based_delivery(self): reserved_items = [] normal_items = [] for item in self.items: if item.ensure_delivery_based_on_produced_serial_no: if item.item_code in normal_items: dataent.throw( _("Cannot ensure delivery by Serial No as \ Item {0} is added with and without Ensure Delivery by \ Serial No.").format(item.item_code)) if item.item_code not in reserved_items: if not dataent.get_cached_value("Item", item.item_code, "has_serial_no"): dataent.throw( _("Item {0} has no Serial No. Only serilialized items \ can have delivery based on Serial No").format(item.item_code)) if not dataent.db.exists("BOM", { "item": item.item_code, "is_active": 1 }): dataent.throw( _("No active BOM found for item {0}. Delivery by \ Serial No cannot be ensured").format(item.item_code)) reserved_items.append(item.item_code) else: normal_items.append(item.item_code) if not item.ensure_delivery_based_on_produced_serial_no and \ item.item_code in reserved_items: dataent.throw( _("Cannot ensure delivery by Serial No as \ Item {0} is added with and without Ensure Delivery by \ Serial No.").format(item.item_code))
def create_purchase_order(**args): po = dataent.new_doc("Purchase Order") args = dataent._dict(args) if args.transaction_date: po.transaction_date = args.transaction_date po.schedule_date = add_days(nowdate(), 1) po.company = args.company or "_Test Company" po.supplier = args.customer or "_Test Supplier" po.is_subcontracted = args.is_subcontracted or "No" po.currency = args.currency or dataent.get_cached_value( 'Company', po.company, "default_currency") po.conversion_factor = args.conversion_factor or 1 po.supplier_warehouse = args.supplier_warehouse or None po.append( "items", { "item_code": args.item or args.item_code or "_Test Item", "warehouse": args.warehouse or "_Test Warehouse - _TC", "qty": args.qty or 10, "rate": args.rate or 500, "schedule_date": add_days(nowdate(), 1), "include_exploded_items": args.get('include_exploded_items', 1) }) if not args.do_not_save: po.insert() if not args.do_not_submit: if po.is_subcontracted == "Yes": supp_items = po.get("supplied_items") for d in supp_items: d.reserve_warehouse = args.warehouse or "_Test Warehouse - _TC" po.submit() return po
def prepare_data(accounts, filters, total_row, parent_children_map, based_on): data = [] company_currency = dataent.get_cached_value('Company', filters.get("company"), "default_currency") for d in accounts: has_value = False row = { "account_name": d.account_name or d.name, "account": d.name, "parent_account": d.parent_account, "indent": d.indent, "fiscal_year": filters.get("fiscal_year"), "currency": company_currency, "based_on": based_on } for key in value_fields: row[key] = flt(d.get(key, 0.0), 3) if abs(row[key]) >= 0.005: # ignore zero values has_value = True row["has_value"] = has_value data.append(row) data.extend([{}, total_row]) return data
def get_parent_account(company, master_type): parent_account = None if "receivables_group" in dataent.db.get_table_columns("Company"): parent_account = dataent.get_cached_value( 'Company', company, "receivables_group" if master_type == "Customer" else "payables_group") if not parent_account: parent_account = dataent.db.get_value( "Account", { "company": company, "account_name": "Accounts Receivable" if master_type == "Customer" else "Accounts Payable" }) if not parent_account: parent_account = dataent.db.sql_list( """select parent_account from tabAccount where company=%s and ifnull(master_type, '')=%s and ifnull(master_name, '')!='' limit 1""", (company, master_type)) parent_account = parent_account[0][0] if parent_account else None return parent_account
def validate_party_frozen_disabled(party_type, party_name): if party_type and party_name: if party_type in ("Customer", "Supplier"): party = dataent.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True) if party.disabled: dataent.throw( _("{0} {1} is disabled").format(party_type, party_name), PartyDisabled) elif party.get("is_frozen"): frozen_accounts_modifier = dataent.db.get_single_value( 'Accounts Settings', 'frozen_accounts_modifier') if not frozen_accounts_modifier in dataent.get_roles(): dataent.throw( _("{0} {1} is frozen").format(party_type, party_name), PartyFrozen) elif party_type == "Employee": if dataent.db.get_value("Employee", party_name, "status") == "Left": dataent.msgprint(_("{0} {1} is not active").format( party_type, party_name), alert=True)
def validate_conversion_rate(args, meta): from epaas.controllers.accounts_controller import validate_conversion_rate if (not args.conversion_rate and args.currency==dataent.get_cached_value('Company', args.company, "default_currency")): args.conversion_rate = 1.0 # validate currency conversion rate validate_conversion_rate(args.currency, args.conversion_rate, meta.get_label("conversion_rate"), args.company) args.conversion_rate = flt(args.conversion_rate, get_field_precision(meta.get_field("conversion_rate"), dataent._dict({"fields": args}))) if args.price_list: if (not args.plc_conversion_rate and args.price_list_currency==dataent.db.get_value("Price List", args.price_list, "currency", cache=True)): args.plc_conversion_rate = 1.0 # validate price list currency conversion rate if not args.get("price_list_currency"): throw(_("Price List Currency not selected")) else: validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate, meta.get_label("plc_conversion_rate"), args.company) if meta.get_field("plc_conversion_rate"): args.plc_conversion_rate = flt(args.plc_conversion_rate, get_field_precision(meta.get_field("plc_conversion_rate"), dataent._dict({"fields": args})))
def get_amount_based_on_payment_days(self, row, joining_date, relieving_date): amount, additional_amount = row.amount, row.additional_amount if (self.salary_structure and cint(row.depends_on_payment_days) and cint(self.total_working_days) and (not self.salary_slip_based_on_timesheet or getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date)): additional_amount = flt( (flt(row.additional_amount) * flt(self.payment_days) / cint(self.total_working_days)), row.precision("additional_amount")) amount = flt((flt(row.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), row.precision("amount")) + additional_amount elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint( row.depends_on_payment_days): amount, additional_amount = 0, 0 elif not row.amount: amount = flt(row.default_amount) + flt(row.additional_amount) # apply rounding if dataent.get_cached_value("Salary Component", row.salary_component, "round_to_the_nearest_integer"): amount, additional_amount = rounded(amount), rounded( additional_amount) return amount, additional_amount
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0): actual_expense = amount or get_actual_expense(args) if actual_expense > budget_amount: diff = actual_expense - budget_amount currency = dataent.get_cached_value('Company', args.company, 'default_currency') msg = _( "{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}" ).format(_(action_for), dataent.bold(args.account), args.budget_against_field, dataent.bold(budget_against), dataent.bold(fmt_money(budget_amount, currency=currency)), dataent.bold(fmt_money(diff, currency=currency))) if (dataent.flags.exception_approver_role and dataent.flags.exception_approver_role in dataent.get_roles( dataent.session.user)): action = "Warn" if action == "Stop": dataent.throw(msg, BudgetError) else: dataent.msgprint(msg, indicator='orange')
def set_account_currency(filters): if filters.get("account") or (filters.get('party') and len(filters.party) == 1): filters["company_currency"] = dataent.get_cached_value( 'Company', filters.company, "default_currency") account_currency = None if filters.get("account"): account_currency = get_account_currency(filters.account) elif filters.get("party"): gle_currency = dataent.db.get_value( "GL Entry", { "party_type": filters.party_type, "party": filters.party[0], "company": filters.company }, "account_currency") if gle_currency: account_currency = gle_currency else: account_currency = (None if filters.party_type in [ "Employee", "Student", "Shareholder", "Member" ] else dataent.db.get_value( filters.party_type, filters.party[0], "default_currency")) filters[ "account_currency"] = account_currency or filters.company_currency if filters.account_currency != filters.company_currency and not filters.presentation_currency: filters.presentation_currency = filters.account_currency return filters