Merge branch 'develop' of https://github.com/frappe/erpnext into leave-management

This commit is contained in:
Mangesh-Khairnar 2019-07-22 13:57:04 +05:30
commit cbc22e6369
308 changed files with 21840 additions and 19598 deletions

View File

@ -121,7 +121,7 @@ frappe.treeview_settings["Account"] = {
},
onrender: function(node) {
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
var dr_or_cr = in_list(["Liability", "Income", "Equity"], node.data.root_type) ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?

View File

@ -9,25 +9,44 @@ frappe.ui.form.on('Accounting Dimension', {
frappe.set_route("List", frm.doc.document_type);
});
}
frm.set_query('document_type', () => {
return {
filters: {
name: ['not in', ['Accounting Dimension', 'Project', 'Cost Center']]
}
};
});
let button = frm.doc.disabled ? "Enable" : "Disable";
frm.add_custom_button(__(button), function() {
frm.set_value('disabled', 1 - frm.doc.disabled);
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
args: {
doc: frm.doc
},
freeze: true,
callback: function(r) {
let message = frm.doc.disabled ? "Dimension Disabled" : "Dimension Enabled";
frm.save();
frappe.show_alert({message:__(message), indicator:'green'});
}
});
});
},
document_type: function(frm) {
frm.set_value('label', frm.doc.document_type);
frm.set_value('fieldname', frappe.scrub(frm.doc.document_type));
frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type));
frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => {
if (r.document_type) {
if (r && r.document_type) {
frm.set_df_property('document_type', 'description', "Document type is already set as dimension");
}
});
},
disabled: function(frm) {
frappe.call({
method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.disable_dimension",
args: {
doc: frm.doc
}
});
}
});

View File

@ -38,7 +38,9 @@
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disable"
"hidden": 1,
"label": "Disable",
"read_only": 1
},
{
"default": "0",
@ -53,7 +55,7 @@
"label": "Mandatory For Profit and Loss Account"
}
],
"modified": "2019-05-27 18:18:17.792726",
"modified": "2019-07-14 17:25:01.307948",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting Dimension",

View File

@ -121,11 +121,11 @@ def delete_accounting_dimension(doc):
@frappe.whitelist()
def disable_dimension(doc):
if frappe.flags.in_test:
frappe.enqueue(start_dimension_disabling, doc=doc)
toggle_disabling(doc=doc)
else:
start_dimension_disabling(doc=doc)
frappe.enqueue(toggle_disabling, doc=doc)
def start_dimension_disabling(doc):
def toggle_disabling(doc):
doc = json.loads(doc)
if doc.get('disabled'):
@ -155,7 +155,7 @@ def get_doctypes_with_dimensions():
return doclist
def get_accounting_dimensions(as_list=True):
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "mandatory_for_pl", "mandatory_for_bs", "disabled"])
accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "mandatory_for_pl", "mandatory_for_bs", "disabled"], filters={"disabled": 0})
if as_list:
return [d.fieldname for d in accounting_dimensions]

View File

@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
class AccountingPeriod(Document):
def validate(self):
@ -16,7 +17,7 @@ class AccountingPeriod(Document):
def autoname(self):
company_abbr = frappe.get_cached_value('Company', self.company, "abbr")
self.name = " - ".join([self.period_name, company_abbr])
def validate_overlap(self):
existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period`
where (
@ -33,7 +34,7 @@ class AccountingPeriod(Document):
}, as_dict=True)
if len(existing_accounting_period) > 0:
frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))
frappe.throw(_("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))))
def get_doctypes_for_closing(self):
docs_for_closing = []

View File

@ -10,6 +10,7 @@
"acc_frozen_upto",
"frozen_accounts_modifier",
"determine_address_tax_category_from",
"over_billing_allowance",
"column_break_4",
"credit_controller",
"check_supplier_invoice_uniqueness",
@ -168,12 +169,18 @@
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms"
},
{
"description": "Percentage you are allowed to bill more against the amount ordered. For example: If the order value is $100 for an item and tolerance is set as 10% then you are allowed to bill for $110.",
"fieldname": "over_billing_allowance",
"fieldtype": "Currency",
"label": "Over Billing Allowance (%)"
}
],
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"modified": "2019-04-28 18:20:55.789946",
"modified": "2019-07-04 18:20:55.789946",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@ -200,4 +207,4 @@
"quick_entry": 1,
"sort_order": "ASC",
"track_changes": 1
}
}

View File

@ -48,7 +48,10 @@ class BankAccount(Document):
# Encode characters as numbers
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
to_check = int(''.join(encoded))
try:
to_check = int(''.join(encoded))
except ValueError:
frappe.throw(_('IBAN is not valid'))
if to_check % 97 != 1:
frappe.throw(_('IBAN is not valid'))

View File

@ -103,7 +103,7 @@ class BankReconciliation(Document):
for d in self.get('payment_entries'):
if d.clearance_date:
if not d.payment_document:
frappe.throw(_("Row #{0}: Payment document is required to complete the trasaction"))
frappe.throw(_("Row #{0}: Payment document is required to complete the transaction"))
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw(_("Row #{0}: Clearance date {1} cannot be before Cheque Date {2}")
@ -113,10 +113,8 @@ class BankReconciliation(Document):
if not d.clearance_date:
d.clearance_date = None
frappe.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date)
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
where name=%s""".format(d.payment_document),
(d.clearance_date, nowdate(), d.payment_entry))
payment_entry = frappe.get_doc(d.payment_document, d.payment_entry)
payment_entry.db_set('clearance_date', d.clearance_date)
clearance_date_updated = True

View File

@ -48,7 +48,7 @@ class BankStatementTransactionEntry(Document):
def get_statement_headers(self):
if not self.bank_settings:
frappe.throw("Bank Data mapper doesn't exist")
frappe.throw(_("Bank Data mapper doesn't exist"))
mapper_doc = frappe.get_doc("Bank Statement Settings", self.bank_settings)
headers = {entry.mapped_header:entry.stmt_header for entry in mapper_doc.header_items}
return headers
@ -57,7 +57,7 @@ class BankStatementTransactionEntry(Document):
if self.bank_statement is None: return
filename = self.bank_statement.split("/")[-1]
if (len(self.new_transaction_items + self.reconciled_transaction_items) > 0):
frappe.throw("Transactions already retreived from the statement")
frappe.throw(_("Transactions already retreived from the statement"))
date_format = frappe.get_value("Bank Statement Settings", self.bank_settings, "date_format")
if (date_format is None):
@ -314,7 +314,7 @@ class BankStatementTransactionEntry(Document):
try:
reconcile_against_document(lst)
except:
frappe.throw("Exception occurred while reconciling {0}".format(payment.reference_name))
frappe.throw(_("Exception occurred while reconciling {0}".format(payment.reference_name)))
def submit_payment_entries(self):
for payment in self.new_transaction_items:
@ -414,7 +414,7 @@ def get_transaction_entries(filename, headers):
elif (filename.lower().endswith("xls")):
rows = get_rows_from_xls_file(filename)
else:
frappe.throw("Only .csv and .xlsx files are supported currently")
frappe.throw(_("Only .csv and .xlsx files are supported currently"))
stmt_headers = headers.values()
for row in rows:

View File

@ -78,7 +78,6 @@ var validate_csv_data = function(frm) {
var create_import_button = function(frm) {
frm.page.set_primary_action(__("Start Import"), function () {
setup_progress_bar(frm);
frappe.call({
method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
args: {
@ -86,11 +85,11 @@ var create_import_button = function(frm) {
company: frm.doc.company
},
freeze: true,
freeze_message: __("Creating Accounts..."),
callback: function(r) {
if(!r.exc) {
clearInterval(frm.page["interval"]);
frm.page.set_indicator(__('Import Successfull'), 'blue');
frappe.hide_progress();
create_reset_button(frm);
}
}
@ -126,13 +125,3 @@ var generate_tree_preview = function(frm) {
}
});
};
var setup_progress_bar = function(frm) {
frm.page["seconds_elapsed"] = 0;
frm.page["execution_time"] = (frm.page["total_accounts"] > 100) ? 100 : frm.page["total_accounts"];
frm.page["interval"] = setInterval(function() {
frm.page["seconds_elapsed"] += 1;
frappe.show_progress(__('Creating Accounts'), frm.page["seconds_elapsed"], frm.page["execution_time"]);
}, 250);
};

View File

@ -33,6 +33,9 @@ def import_coa(file_name, company):
def generate_data_from_csv(file_name, as_dict=False):
''' read csv file and return the generated nested tree '''
if not file_name.endswith('.csv'):
frappe.throw("Only CSV files can be used to for importing data. Please check the file format you are trying to upload")
file_doc = frappe.get_doc('File', {"file_url": file_name})
file_path = file_doc.get_full_path()
@ -96,15 +99,27 @@ def build_forest(data):
return [child] + return_parent(data, parent_account)
charts_map, paths = {}, []
line_no = 3
error_messages = []
for i in data:
account_name, _, account_number, is_group, account_type, root_type = i
if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
charts_map[account_name] = {}
if is_group: charts_map[account_name]["is_group"] = is_group
if is_group == 1: charts_map[account_name]["is_group"] = is_group
if account_type: charts_map[account_name]["account_type"] = account_type
if root_type: charts_map[account_name]["root_type"] = root_type
if account_number: charts_map[account_name]["account_number"] = account_number
path = return_parent(data, account_name)[::-1]
paths.append(path) # List of path is created
line_no += 1
if error_messages:
frappe.throw("<br>".join(error_messages))
out = {}
for path in paths:
@ -150,22 +165,27 @@ def validate_root(accounts):
if len(roots) < 4:
return _("Number of root accounts cannot be less than 4")
error_messages = []
for account in roots:
if not account.get("root_type"):
return _("Please enter Root Type for - {0}").format(account.get("account_name"))
elif account.get("root_type") not in ("Asset", "Liability", "Expense", "Income", "Equity"):
return _('Root Type for "{0}" must be one of the Asset, Liability, Income, Expense and Equity').format(account.get("account_name"))
if not account.get("root_type") and account.get("account_name"):
error_messages.append("Please enter Root Type for account- {0}".format(account.get("account_name")))
elif account.get("root_type") not in ("Asset", "Liability", "Expense", "Income", "Equity") and account.get("account_name"):
error_messages.append("Root Type for {0} must be one of the Asset, Liability, Income, Expense and Equity".format(account.get("account_name")))
if error_messages:
return "<br>".join(error_messages)
def validate_account_types(accounts):
account_types_for_ledger = ["Cost of Goods Sold", "Depreciation", "Fixed Asset", "Payable", "Receivable", "Stock Adjustment"]
account_types = [accounts[d]["account_type"] for d in accounts if not accounts[d]['is_group']]
account_types = [accounts[d]["account_type"] for d in accounts if not accounts[d]['is_group'] == 1]
missing = list(set(account_types_for_ledger) - set(account_types))
if missing:
return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))
account_types_for_group = ["Bank", "Cash", "Stock"]
account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group']]
account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group'] not in ('', 1)]
missing = list(set(account_types_for_group) - set(account_groups))
if missing:

View File

@ -1,177 +1,64 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2019-03-07 12:07:09.416101",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"sales_invoice",
"customer",
"column_break_3",
"posting_date",
"outstanding_amount"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_invoice",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Invoice",
"length": 0,
"no_copy": 0,
"options": "Sales Invoice",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "sales_invoice.customer",
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Customer",
"length": 0,
"no_copy": 0,
"options": "Customer",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "sales_invoice.posting_date",
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "sales_invoice.grand_total",
"fieldname": "outstanding_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Outstanding Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2019-03-07 16:38:03.622666",
"modified": "2019-05-30 19:27:29.436153",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Discounted Invoice",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
"track_changes": 1
}

View File

@ -21,9 +21,29 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
refresh: function(frm) {
if(frm.doc.docstatus==1) {
frm.add_custom_button(__('Create Journal Entry'), function() {
return frm.events.make_jv(frm);
});
frappe.db.get_value("Journal Entry Account", {
'reference_type': 'Exchange Rate Revaluation',
'reference_name': frm.doc.name,
'docstatus': 1
}, "sum(debit) as sum", (r) =>{
let total_amt = 0;
frm.doc.accounts.forEach(d=> {
total_amt = total_amt + d['new_balance_in_base_currency'];
});
if(total_amt === r.sum) {
frm.add_custom_button(__("Journal Entry"), function(){
frappe.route_options = {
'reference_type': 'Exchange Rate Revaluation',
'reference_name': frm.doc.name
};
frappe.set_route("List", "Journal Entry");
}, __("View"));
} else {
frm.add_custom_button(__('Create Journal Entry'), function() {
return frm.events.make_jv(frm);
});
}
}, 'Journal Entry');
}
},

View File

@ -848,6 +848,39 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "due_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Due Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -861,7 +894,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-07 07:05:00.366399",
"modified": "2019-05-01 07:05:00.366399",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",

View File

@ -91,13 +91,13 @@ class GLEntry(Document):
if account_type == "Profit and Loss" \
and dimension.mandatory_for_pl and not dimension.disabled:
if not self.get(dimension.fieldname):
frappe.throw(_("{0} is required for 'Profit and Loss' account {1}.")
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Profit and Loss' account {1}.")
.format(dimension.label, self.account))
if account_type == "Balance Sheet" \
and dimension.mandatory_for_bs and not dimension.disabled:
if not self.get(dimension.fieldname):
frappe.throw(_("{0} is required for 'Balance Sheet' account {1}.")
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
.format(dimension.label, self.account))

View File

@ -1,744 +1,177 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "ACC-INV-DISC-.YYYY.-.#####",
"beta": 0,
"creation": "2019-03-07 12:01:56.296952",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"posting_date",
"loan_start_date",
"loan_period",
"loan_end_date",
"column_break_3",
"status",
"company",
"section_break_5",
"invoices",
"section_break_7",
"total_amount",
"column_break_9",
"bank_charges",
"section_break_6",
"short_term_loan",
"bank_account",
"bank_charges_account",
"column_break_15",
"accounts_receivable_credit",
"accounts_receivable_discounted",
"accounts_receivable_unpaid",
"amended_from"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Posting Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "loan_start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Loan Start Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Loan Start Date"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "loan_period",
"fieldtype": "Int",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Loan Period",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Loan Period (Days)"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "loan_end_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Loan End Date",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 1,
"options": "Draft\nSanctioned\nDisbursed\nSettled\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "invoices",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Invoices",
"length": 0,
"no_copy": 0,
"options": "Discounted Invoice",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Amount",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_charges",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Charges",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Company:company:default_currency"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "short_term_loan",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Short Term Loan Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_charges_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Charges Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_15",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts_receivable_credit",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounts Receivable Credit Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts_receivable_discounted",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounts Receivable Discounted Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts_receivable_unpaid",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounts Receivable Unpaid Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Invoice Discounting",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-08 14:24:31.222027",
"modified": "2019-05-30 19:08:21.199759",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Invoice Discounting",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
@ -748,26 +181,17 @@
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
"track_changes": 1
}

View File

@ -28,18 +28,39 @@ class InvoiceDiscounting(AccountsController):
self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
def on_submit(self):
self.update_sales_invoice()
self.make_gl_entries()
def on_cancel(self):
self.set_status()
self.update_sales_invoice()
self.make_gl_entries()
def set_status(self):
self.status = "Draft"
if self.docstatus == 1:
self.status = "Sanctioned"
elif self.docstatus == 2:
self.status = "Cancelled"
def set_status(self, status=None):
if status:
self.status = status
self.db_set("status", status)
for d in self.invoices:
frappe.get_doc("Sales Invoice", d.sales_invoice).set_status(update=True, update_modified=False)
else:
self.status = "Draft"
if self.docstatus == 1:
self.status = "Sanctioned"
elif self.docstatus == 2:
self.status = "Cancelled"
def update_sales_invoice(self):
for d in self.invoices:
if self.docstatus == 1:
is_discounted = 1
else:
discounted_invoice = frappe.db.exists({
"doctype": "Discounted Invoice",
"sales_invoice": d.sales_invoice,
"docstatus": 1
})
is_discounted = 1 if discounted_invoice else 0
frappe.db.set_value("Sales Invoice", d.sales_invoice, "is_discounted", is_discounted)
def make_gl_entries(self):
company_currency = frappe.get_cached_value('Company', self.company, "default_currency")

View File

@ -223,11 +223,18 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
if(in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
// Filter by cost center
if(jvd.cost_center) {
out.filters.push([jvd.reference_type, "cost_center", "in", ["", jvd.cost_center]]);
}
// account filter
frappe.model.validate_missing(jvd, "account");
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
if (in_list(['Debit Note', 'Credit Note'], doc.voucher_type)) {
out.filters.push([jvd.reference_type, "is_return", "=", 1]);
}
}
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {

View File

@ -105,24 +105,28 @@ class JournalEntry(AccountsController):
invoice_discounting_list = list(set([d.reference_name for d in self.accounts if d.reference_type=="Invoice Discounting"]))
for inv_disc in invoice_discounting_list:
short_term_loan_account, id_status = frappe.db.get_value("Invoice Discounting", inv_disc, ["short_term_loan", "status"])
inv_disc_doc = frappe.get_doc("Invoice Discounting", inv_disc)
status = None
for d in self.accounts:
if d.account == short_term_loan_account and d.reference_name == inv_disc:
if d.account == inv_disc_doc.short_term_loan and d.reference_name == inv_disc:
if self.docstatus == 1:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, id_status, "Sanctioned", d.idx)
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Sanctioned", d.idx)
status = "Disbursed"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, id_status, "Disbursed", d.idx)
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
status = "Settled"
else:
if d.credit > 0:
_validate_invoice_discounting_status(inv_disc, id_status, "Disbursed", d.idx)
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Disbursed", d.idx)
status = "Sanctioned"
elif d.debit > 0:
_validate_invoice_discounting_status(inv_disc, id_status, "Settled", d.idx)
_validate_invoice_discounting_status(inv_disc, inv_disc_doc.status, "Settled", d.idx)
status = "Disbursed"
frappe.db.set_value("Invoice Discounting", inv_disc, "status", status)
break
if status:
inv_disc_doc.set_status(status=status)
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
@ -331,7 +335,8 @@ class JournalEntry(AccountsController):
for reference_name, total in iteritems(self.reference_totals):
reference_type = self.reference_types[reference_name]
if reference_type in ("Sales Invoice", "Purchase Invoice"):
if (reference_type in ("Sales Invoice", "Purchase Invoice") and
self.voucher_type not in ['Debit Note', 'Credit Note']):
invoice = frappe.db.get_value(reference_type, reference_name,
["docstatus", "outstanding_amount"], as_dict=1)
@ -497,6 +502,7 @@ class JournalEntry(AccountsController):
self.get_gl_dict({
"account": d.account,
"party_type": d.party_type,
"due_date": self.due_date,
"party": d.party,
"against": d.against_account,
"debit": flt(d.debit, d.precision("debit")),

View File

@ -302,7 +302,7 @@ frappe.ui.form.on('Payment Entry', {
},
() => frm.set_value("party_balance", r.message.party_balance),
() => frm.set_value("party_name", r.message.party_name),
() => frm.events.get_outstanding_documents(frm),
() => frm.clear_table("references"),
() => frm.events.hide_unhide_fields(frm),
() => frm.events.set_dynamic_labels(frm),
() => {
@ -323,9 +323,7 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_account_currency_and_balance(frm, frm.doc.paid_from,
"paid_from_account_currency", "paid_from_account_balance", function(frm) {
if (frm.doc.payment_type == "Receive") {
frm.events.get_outstanding_documents(frm);
} else if (frm.doc.payment_type == "Pay") {
if (frm.doc.payment_type == "Pay") {
frm.events.paid_amount(frm);
}
}
@ -337,9 +335,7 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_account_currency_and_balance(frm, frm.doc.paid_to,
"paid_to_account_currency", "paid_to_account_balance", function(frm) {
if(frm.doc.payment_type == "Pay") {
frm.events.get_outstanding_documents(frm);
} else if (frm.doc.payment_type == "Receive") {
if (frm.doc.payment_type == "Receive") {
if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
if(frm.doc.source_exchange_rate) {
frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
@ -533,26 +529,87 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_unallocated_amount(frm);
},
get_outstanding_documents: function(frm) {
get_outstanding_invoice: function(frm) {
const today = frappe.datetime.get_today();
const fields = [
{fieldtype:"Section Break", label: __("Posting Date")},
{fieldtype:"Date", label: __("From Date"),
fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)},
{fieldtype:"Column Break"},
{fieldtype:"Date", label: __("To Date"), fieldname:"to_posting_date", default:today},
{fieldtype:"Section Break", label: __("Due Date")},
{fieldtype:"Date", label: __("From Date"), fieldname:"from_due_date"},
{fieldtype:"Column Break"},
{fieldtype:"Date", label: __("To Date"), fieldname:"to_due_date"},
{fieldtype:"Section Break", label: __("Outstanding Amount")},
{fieldtype:"Float", label: __("Greater Than Amount"),
fieldname:"outstanding_amt_greater_than", default: 0},
{fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
{fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
];
frappe.prompt(fields, function(filters){
frappe.flags.allocate_payment_amount = true;
frm.events.validate_filters_data(frm, filters);
frm.events.get_outstanding_documents(frm, filters);
}, __("Filters"), __("Get Outstanding Invoices"));
},
validate_filters_data: function(frm, filters) {
const fields = {
'Posting Date': ['from_posting_date', 'to_posting_date'],
'Due Date': ['from_posting_date', 'to_posting_date'],
'Advance Amount': ['from_posting_date', 'to_posting_date'],
};
for (let key in fields) {
let from_field = fields[key][0];
let to_field = fields[key][1];
if (filters[from_field] && !filters[to_field]) {
frappe.throw(__("Error: {0} is mandatory field",
[to_field.replace(/_/g, " ")]
));
} else if (filters[from_field] && filters[from_field] > filters[to_field]) {
frappe.throw(__("{0}: {1} must be less than {2}",
[key, from_field.replace(/_/g, " "), to_field.replace(/_/g, " ")]
));
}
}
},
get_outstanding_documents: function(frm, filters) {
frm.clear_table("references");
if(!frm.doc.party) return;
if(!frm.doc.party) {
return;
}
frm.events.check_mandatory_to_fetch(frm);
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var args = {
"posting_date": frm.doc.posting_date,
"company": frm.doc.company,
"party_type": frm.doc.party_type,
"payment_type": frm.doc.payment_type,
"party": frm.doc.party,
"party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to,
"cost_center": frm.doc.cost_center
}
for (let key in filters) {
args[key] = filters[key];
}
frappe.flags.allocate_payment_amount = filters['allocate_payment_amount'];
return frappe.call({
method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_outstanding_reference_documents',
args: {
args: {
"posting_date": frm.doc.posting_date,
"company": frm.doc.company,
"party_type": frm.doc.party_type,
"payment_type": frm.doc.payment_type,
"party": frm.doc.party,
"party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to,
"cost_center": frm.doc.cost_center
}
args:args
},
callback: function(r, rt) {
if(r.message) {
@ -608,25 +665,11 @@ frappe.ui.form.on('Payment Entry', {
frm.events.allocate_party_amount_against_ref_docs(frm,
(frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount));
}
});
},
allocate_payment_amount: function(frm) {
if(frm.doc.payment_type == 'Internal Transfer'){
return
}
if(frm.doc.references.length == 0){
frm.events.get_outstanding_documents(frm);
}
if(frm.doc.payment_type == 'Internal Transfer') {
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.paid_amount);
} else {
frm.events.allocate_party_amount_against_ref_docs(frm, frm.doc.received_amount);
}
},
allocate_party_amount_against_ref_docs: function(frm, paid_amount) {
var total_positive_outstanding_including_order = 0;
var total_negative_outstanding = 0;
@ -677,7 +720,7 @@ frappe.ui.form.on('Payment Entry', {
$.each(frm.doc.references || [], function(i, row) {
row.allocated_amount = 0 //If allocate payment amount checkbox is unchecked, set zero to allocate amount
if(frm.doc.allocate_payment_amount){
if(frappe.flags.allocate_payment_amount){
if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
if(row.outstanding_amount >= allocated_positive_outstanding) {
row.allocated_amount = allocated_positive_outstanding;
@ -958,7 +1001,7 @@ frappe.ui.form.on('Payment Entry', {
},
() => {
if(frm.doc.payment_type != "Internal") {
frm.events.get_outstanding_documents(frm);
frm.clear_table("references");
}
}
]);

View File

@ -40,7 +40,7 @@
"target_exchange_rate",
"base_received_amount",
"section_break_14",
"allocate_payment_amount",
"get_outstanding_invoice",
"references",
"section_break_34",
"total_allocated_amount",
@ -325,19 +325,15 @@
"reqd": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "references",
"depends_on": "eval:(doc.party && doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"label": "Reference"
},
{
"default": "1",
"depends_on": "eval:in_list(['Pay', 'Receive'], doc.payment_type)",
"fieldname": "allocate_payment_amount",
"fieldtype": "Check",
"label": "Allocate Payment Amount"
"fieldname": "get_outstanding_invoice",
"fieldtype": "Button",
"label": "Get Outstanding Invoice"
},
{
"fieldname": "references",
@ -570,7 +566,7 @@
}
],
"is_submittable": 1,
"modified": "2019-05-25 22:02:40.575822",
"modified": "2019-05-27 15:53:21.108857",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@ -535,6 +535,20 @@ class PaymentEntry(AccountsController):
"amount": self.total_allocated_amount * (tax_details['tax']['rate'] / 100)
}
def set_gain_or_loss(self, account_details=None):
if not self.difference_amount:
self.set_difference_amount()
row = {
'amount': self.difference_amount
}
if account_details:
row.update(account_details)
self.append('deductions', row)
self.set_unallocated_amount()
@frappe.whitelist()
def get_outstanding_reference_documents(args):
@ -560,8 +574,8 @@ def get_outstanding_reference_documents(args):
# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), party_account_currency, company_currency)
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), args.get("company"), party_account_currency, company_currency)
# Get positive outstanding sales /purchase invoices/ Fees
condition = ""
@ -571,10 +585,23 @@ def get_outstanding_reference_documents(args):
# Add cost center condition
if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account():
condition += " and cost_center='%s'" % args.get("cost_center")
condition += " and cost_center='%s'" % args.get("cost_center")
date_fields_dict = {
'posting_date': ['from_posting_date', 'to_posting_date'],
'due_date': ['from_due_date', 'to_due_date']
}
for fieldname, date_fields in date_fields_dict.items():
if args.get(date_fields[0]) and args.get(date_fields[1]):
condition += " and {0} between '{1}' and '{2}'".format(fieldname,
args.get(date_fields[0]), args.get(date_fields[1]))
if args.get("company"):
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), condition=condition)
args.get("party_account"), filters=args, condition=condition)
for d in outstanding_invoices:
d["exchange_rate"] = 1
@ -592,12 +619,19 @@ def get_outstanding_reference_documents(args):
orders_to_be_billed = []
if (args.get("party_type") != "Student"):
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
args.get("party"), party_account_currency, company_currency)
args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
if not data:
frappe.msgprint(_("No outstanding invoices found for the {0} <b>{1}</b>.")
.format(args.get("party_type").lower(), args.get("party")))
return data
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency, cost_center=None):
def get_orders_to_be_billed(posting_date, party_type, party,
company, party_account_currency, company_currency, cost_center=None, filters=None):
if party_type == "Customer":
voucher_type = 'Sales Order'
elif party_type == "Supplier":
@ -627,6 +661,7 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
where
{party_type} = %s
and docstatus = 1
and company = %s
and ifnull(status, "") != "Closed"
and {ref_field} > advance_paid
and abs(100 - per_billed) > 0.01
@ -638,10 +673,14 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
"voucher_type": voucher_type,
"party_type": scrub(party_type),
"condition": condition
}), party, as_dict=True)
}), (party, company), as_dict=True)
order_list = []
for d in orders:
if not (d.outstanding_amount >= filters.get("outstanding_amt_greater_than")
and d.outstanding_amount <= filters.get("outstanding_amt_less_than")):
continue
d["voucher_type"] = voucher_type
# This assumes that the exchange rate required is the one in the SO
d["exchange_rate"] = get_exchange_rate(party_account_currency, company_currency, posting_date)
@ -649,7 +688,8 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
return order_list
def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency, cost_center=None):
def get_negative_outstanding_invoices(party_type, party, party_account,
company, party_account_currency, company_currency, cost_center=None):
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
supplier_condition = ""
if voucher_type == "Purchase Invoice":
@ -670,7 +710,8 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac
from
`tab{voucher_type}`
where
{party_type} = %s and {party_account} = %s and docstatus = 1 and outstanding_amount < 0
{party_type} = %s and {party_account} = %s and docstatus = 1 and
company = %s and outstanding_amount < 0
{supplier_condition}
order by
posting_date, name
@ -682,7 +723,7 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac
"party_type": scrub(party_type),
"party_account": "debit_to" if party_type == "Customer" else "credit_to",
"cost_center": cost_center
}), (party, party_account), as_dict=True)
}), (party, party_account, company), as_dict=True)
@frappe.whitelist()
@ -910,7 +951,6 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.paid_to_account_currency = party_account_currency if payment_type=="Pay" else bank.account_currency
pe.paid_amount = paid_amount
pe.received_amount = received_amount
pe.allocate_payment_amount = 1
pe.letter_head = doc.get("letter_head")
if pe.party_type in ["Customer", "Supplier"]:

View File

@ -16,6 +16,20 @@ frappe.ui.form.on("Payment Reconciliation Payment", {
})[0].outstanding_amount;
frappe.model.set_value(cdt, cdn, "allocated_amount", Math.min(invoice_amount, row.amount));
frm.call({
doc: frm.doc,
method: 'get_difference_amount',
args: {
child_row: row
},
callback: function(r, rt) {
if(r.message) {
frappe.model.set_value(cdt, cdn,
"difference_amount", r.message);
}
}
});
}
}
});
@ -104,6 +118,91 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
reconcile: function() {
var me = this;
var show_dialog = me.frm.doc.payments.filter(d => d.difference_amount && !d.difference_account);
if (show_dialog && show_dialog.length) {
this.data = [];
const dialog = new frappe.ui.Dialog({
title: __("Select Difference Account"),
fields: [
{
fieldname: "payments", fieldtype: "Table", label: __("Payments"),
data: this.data, in_place_edit: true,
get_data: () => {
return this.data;
},
fields: [{
fieldtype:'Data',
fieldname:"docname",
in_list_view: 1,
hidden: 1
}, {
fieldtype:'Data',
fieldname:"reference_name",
label: __("Voucher No"),
in_list_view: 1,
read_only: 1
}, {
fieldtype:'Link',
options: 'Account',
in_list_view: 1,
label: __("Difference Account"),
fieldname: 'difference_account',
reqd: 1,
get_query: function() {
return {
filters: {
company: me.frm.doc.company,
is_group: 0
}
}
}
}, {
fieldtype:'Currency',
in_list_view: 1,
label: __("Difference Amount"),
fieldname: 'difference_amount',
read_only: 1
}]
},
],
primary_action: function() {
const args = dialog.get_values()["payments"];
args.forEach(d => {
frappe.model.set_value("Payment Reconciliation Payment", d.docname,
"difference_account", d.difference_account);
});
me.reconcile_payment_entries();
dialog.hide();
},
primary_action_label: __('Reconcile Entries')
});
this.frm.doc.payments.forEach(d => {
if (d.difference_amount && !d.difference_account) {
dialog.fields_dict.payments.df.data.push({
'docname': d.name,
'reference_name': d.reference_name,
'difference_amount': d.difference_amount,
'difference_account': d.difference_account,
});
}
});
this.data = dialog.fields_dict.payments.df.data;
dialog.fields_dict.payments.grid.refresh();
dialog.show();
} else {
this.reconcile_payment_entries();
}
},
reconcile_payment_entries: function() {
var me = this;
return this.frm.call({
doc: me.frm.doc,
method: 'reconcile',

View File

@ -3,10 +3,11 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import flt
from frappe.utils import flt, today
from frappe import msgprint, _
from frappe.model.document import Document
from erpnext.accounts.utils import get_outstanding_invoices
from erpnext.accounts.utils import (get_outstanding_invoices,
update_reference_in_payment_entry, reconcile_against_document)
from erpnext.controllers.accounts_controller import get_advance_payment_entries
class PaymentReconciliation(Document):
@ -20,7 +21,10 @@ class PaymentReconciliation(Document):
payment_entries = self.get_payment_entries()
journal_entries = self.get_jv_entries()
self.add_payment_entries(payment_entries + journal_entries)
if self.party_type in ["Customer", "Supplier"]:
dr_or_cr_notes = self.get_dr_or_cr_notes()
self.add_payment_entries(payment_entries + journal_entries + dr_or_cr_notes)
def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order"
@ -71,6 +75,34 @@ class PaymentReconciliation(Document):
return list(journal_entries)
def get_dr_or_cr_notes(self):
dr_or_cr = ("credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
reconciled_dr_or_cr = ("debit_in_account_currency"
if dr_or_cr == "credit_in_account_currency" else "credit_in_account_currency")
voucher_type = ('Sales Invoice'
if self.party_type == 'Customer' else "Purchase Invoice")
return frappe.db.sql(""" SELECT `tab{doc}`.name as reference_name, %(voucher_type)s as reference_type,
(sum(`tabGL Entry`.{dr_or_cr}) - sum(`tabGL Entry`.{reconciled_dr_or_cr})) as amount
FROM `tab{doc}`, `tabGL Entry`
WHERE
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
and `tab{doc}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)s
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
GROUP BY `tabSales Invoice`.name
Having
amount > 0
""".format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), {
'party': self.party,
'party_type': self.party_type,
'voucher_type': voucher_type,
'account': self.receivable_payable_account
}, as_dict=1)
def add_payment_entries(self, entries):
self.set('payments', [])
for e in entries:
@ -114,36 +146,67 @@ class PaymentReconciliation(Document):
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
lst = []
dr_or_cr_notes = []
for e in self.get('payments'):
reconciled_entry = []
if e.invoice_number and e.allocated_amount:
lst.append(frappe._dict({
'voucher_type': e.reference_type,
'voucher_no' : e.reference_name,
'voucher_detail_no' : e.reference_row,
'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_amount' : flt(e.amount),
'allocated_amount' : flt(e.allocated_amount)
}))
if e.reference_type in ['Sales Invoice', 'Purchase Invoice']:
reconciled_entry = dr_or_cr_notes
else:
reconciled_entry = lst
reconciled_entry.append(self.get_payment_details(e, dr_or_cr))
if lst:
from erpnext.accounts.utils import reconcile_against_document
reconcile_against_document(lst)
msgprint(_("Successfully Reconciled"))
self.get_unreconciled_entries()
if dr_or_cr_notes:
reconcile_dr_cr_note(dr_or_cr_notes)
msgprint(_("Successfully Reconciled"))
self.get_unreconciled_entries()
def get_payment_details(self, row, dr_or_cr):
return frappe._dict({
'voucher_type': row.reference_type,
'voucher_no' : row.reference_name,
'voucher_detail_no' : row.reference_row,
'against_voucher_type' : row.invoice_type,
'against_voucher' : row.invoice_number,
'account' : self.receivable_payable_account,
'party_type': self.party_type,
'party': self.party,
'is_advance' : row.is_advance,
'dr_or_cr' : dr_or_cr,
'unadjusted_amount' : flt(row.amount),
'allocated_amount' : flt(row.allocated_amount),
'difference_amount': row.difference_amount,
'difference_account': row.difference_account
})
def get_difference_amount(self, child_row):
if child_row.get("reference_type") != 'Payment Entry': return
child_row = frappe._dict(child_row)
if child_row.invoice_number and " | " in child_row.invoice_number:
child_row.invoice_type, child_row.invoice_number = child_row.invoice_number.split(" | ")
dr_or_cr = ("credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
row = self.get_payment_details(child_row, dr_or_cr)
doc = frappe.get_doc(row.voucher_type, row.voucher_no)
update_reference_in_payment_entry(row, doc, do_not_save=True)
return doc.difference_amount
def check_mandatory_to_fetch(self):
for fieldname in ["company", "party_type", "party", "receivable_payable_account"]:
if not self.get(fieldname):
frappe.throw(_("Please select {0} first").format(self.meta.get_label(fieldname)))
def validate_invoice(self):
if not self.get("invoices"):
frappe.throw(_("No records found in the Invoice table"))
@ -188,3 +251,41 @@ class PaymentReconciliation(Document):
cond += " and `{0}` <= {1}".format(dr_or_cr, flt(self.maximum_amount))
return cond
def reconcile_dr_cr_note(dr_cr_notes):
for d in dr_cr_notes:
voucher_type = ('Credit Note'
if d.voucher_type == 'Sales Invoice' else 'Debit Note')
dr_or_cr = ('credit_in_account_currency'
if d.reference_type == 'Sales Invoice' else 'debit_in_account_currency')
reconcile_dr_or_cr = ('debit_in_account_currency'
if dr_or_cr == 'credit_in_account_currency' else 'credit_in_account_currency')
jv = frappe.get_doc({
"doctype": "Journal Entry",
"voucher_type": voucher_type,
"posting_date": today(),
"accounts": [
{
'account': d.account,
'party': d.party,
'party_type': d.party_type,
reconcile_dr_or_cr: (abs(d.allocated_amount)
if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
'reference_type': d.against_voucher_type,
'reference_name': d.against_voucher
},
{
'account': d.account,
'party': d.party,
'party_type': d.party_type,
dr_or_cr: abs(d.allocated_amount),
'reference_type': d.voucher_type,
'reference_name': d.voucher_no
}
]
})
jv.submit()

View File

@ -1,389 +1,127 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2014-07-09 16:13:35.452759",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"creation": "2014-07-09 16:13:35.452759",
"doctype": "DocType",
"editable_grid": 1,
"field_order": [
"reference_type",
"reference_name",
"posting_date",
"is_advance",
"reference_row",
"col_break1",
"invoice_number",
"amount",
"allocated_amount",
"section_break_10",
"difference_account",
"difference_amount",
"sec_break1",
"remark"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Type",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "reference_type",
"fieldtype": "Link",
"label": "Reference Type",
"options": "DocType",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 0,
"options": "reference_type",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
"options": "reference_type",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Posting Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "posting_date",
"fieldtype": "Date",
"label": "Posting Date",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_advance",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Advance",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "is_advance",
"fieldtype": "Data",
"hidden": 1,
"label": "Is Advance",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Row",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Row",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "col_break1",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "invoice_number",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Invoice Number",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "invoice_number",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Invoice Number",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Allocated amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Allocated amount",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sec_break1",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "sec_break1",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "remark",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Remark",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "remark",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Remark",
"read_only": 1
},
{
"columns": 2,
"fieldname": "difference_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Difference Account",
"options": "Account"
},
{
"fieldname": "difference_amount",
"fieldtype": "Currency",
"label": "Difference Amount",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "section_break_10",
"fieldtype": "Section Break"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
"modified": "2019-01-07 16:52:07.567027",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Payment",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
],
"istable": 1,
"modified": "2019-06-24 00:08:11.150796",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Payment",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -8,6 +8,10 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
return { filters: { selling: 1 } };
});
frm.set_query("tc_name", function() {
return { filters: { selling: 1 } };
});
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});

View File

@ -1,751 +1,166 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2019-03-24 14:48:59.649168",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"disable",
"column_break_2",
"rule_description",
"section_break_1",
"min_qty",
"max_qty",
"column_break_3",
"min_amount",
"max_amount",
"section_break_6",
"same_item",
"free_item",
"free_qty",
"column_break_9",
"free_item_uom",
"free_item_rate",
"section_break_12",
"warehouse",
"threshold_percentage",
"column_break_15",
"priority",
"apply_multiple_pricing_rules"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "disable",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Disable",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Check",
"label": "Disable"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rule_description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rule Description",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_1",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "min_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Min Qty",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Min Qty"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "max_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Max Qty",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Max Qty"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "min_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Min Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Min Amount"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "max_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Max Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Max Amount"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Free Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Free Item"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"depends_on": "eval:!parent.mixed_conditions",
"fieldname": "same_item",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Same Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Same Item"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.same_item || parent.mixed_conditions",
"fieldname": "free_item",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
"options": "Item",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Item"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "free_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Qty",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Qty"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "free_item_uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UOM",
"length": 0,
"no_copy": 0,
"options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "UOM"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "free_item_rate",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Rate"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_12",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Warehouse"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "threshold_percentage",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Threshold for Suggestion",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Threshold for Suggestion"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_15",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "priority",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Priority",
"length": 0,
"no_copy": 0,
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "apply_multiple_pricing_rules",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Apply Multiple Pricing Rules",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Apply Multiple Pricing Rules"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2019-03-24 14:48:59.649168",
"modified": "2019-07-21 00:00:56.674284",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme Product Discount",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
"sort_order": "DESC"
}

View File

@ -157,7 +157,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
can_change_release_date: function(date) {
const diff = frappe.datetime.get_diff(date, frappe.datetime.nowdate());
if (diff < 0) {
frappe.throw('New release date should be in the future');
frappe.throw(__('New release date should be in the future'));
return false;
} else {
return true;

View File

@ -105,7 +105,7 @@ class PurchaseInvoice(BuyingController):
def validate_release_date(self):
if self.release_date and getdate(nowdate()) >= getdate(self.release_date):
frappe.msgprint('Release date must be in the future', raise_exception=True)
frappe.throw(_('Release date must be in the future'))
def validate_cash(self):
if not self.cash_bank_account and flt(self.paid_amount):
@ -336,8 +336,10 @@ class PurchaseInvoice(BuyingController):
if not self.is_return:
self.update_against_document_in_jv()
self.update_billing_status_for_zero_amount_refdoc("Purchase Receipt")
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.update_billing_status_in_pr()
self.update_billing_status_in_pr()
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty in bin depends upon updated ordered qty in PO
@ -416,6 +418,7 @@ class PurchaseInvoice(BuyingController):
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"due_date": self.due_date,
"against": self.against_expense_account,
"credit": grand_total_in_company_currency,
"credit_in_account_currency": grand_total_in_company_currency \
@ -484,9 +487,13 @@ class PurchaseInvoice(BuyingController):
"credit": flt(item.rm_supp_cost)
}, warehouse_account[self.supplier_warehouse]["account_currency"], item=item))
elif not item.is_fixed_asset or (item.is_fixed_asset and is_cwip_accounting_disabled()):
expense_account = (item.expense_account
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account if not item.enable_deferred_expense else item.deferred_expense_account,
"account": expense_account,
"against": self.supplier,
"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
"debit_in_account_currency": (flt(item.base_net_amount,
@ -768,8 +775,10 @@ class PurchaseInvoice(BuyingController):
self.update_prevdoc_status()
if not self.is_return:
self.update_billing_status_for_zero_amount_refdoc("Purchase Receipt")
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.update_billing_status_in_pr()
self.update_billing_status_in_pr()
# Updating stock ledger should always be called after updating prevdoc status,
# because updating ordered qty in bin depends upon updated ordered qty in PO

View File

@ -451,6 +451,10 @@ def make_customer_and_address(customers):
def add_customer(data):
customer = data.get('full_name') or data.get('customer')
if frappe.db.exists("Customer", customer.strip()):
return customer.strip()
customer_doc = frappe.new_doc('Customer')
customer_doc.customer_name = data.get('full_name') or data.get('customer')
customer_doc.customer_pos_id = data.get('customer_pos_id')

View File

@ -83,10 +83,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}
}
if (doc.outstanding_amount>0 && !cint(doc.is_return)) {
if (doc.outstanding_amount>0) {
cur_frm.add_custom_button(__('Payment Request'), function() {
me.make_payment_request();
}, __('Create'));
cur_frm.add_custom_button(__('Invoice Discounting'), function() {
cur_frm.events.create_invoice_discounting(cur_frm);
}, __('Create'));
}
if (doc.docstatus === 1) {
@ -187,9 +191,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
method: "erpnext.selling.doctype.quotation.quotation.make_sales_invoice",
source_doctype: "Quotation",
target: me.frm,
setters: {
customer: me.frm.doc.customer || undefined,
},
setters: [{
fieldtype: 'Link',
label: __('Customer'),
options: 'Customer',
fieldname: 'party_name',
default: me.frm.doc.customer,
}],
get_query_filters: {
docstatus: 1,
status: ["!=", "Lost"],
@ -804,6 +812,13 @@ frappe.ui.form.on('Sales Invoice', {
frm.set_df_property("patient_name", "hidden", 1);
frm.set_df_property("ref_practitioner", "hidden", 1);
}
},
create_invoice_discounting: function(frm) {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_invoice_discounting",
frm: frm
});
}
})

View File

@ -155,6 +155,7 @@
"inter_company_invoice_reference",
"customer_group",
"campaign",
"is_discounted",
"col_break23",
"status",
"source",
@ -1324,6 +1325,13 @@
"options": "Campaign",
"print_hide": 1
},
{
"fieldname": "is_discounted",
"fieldtype": "Check",
"label": "Is Discounted",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "col_break23",
"fieldtype": "Column Break",
@ -1336,7 +1344,7 @@
"in_standard_filter": 1,
"label": "Status",
"no_copy": 1,
"options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled",
"options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nOverdue\nCancelled",
"print_hide": 1,
"read_only": 1
},
@ -1558,7 +1566,7 @@
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
"modified": "2019-05-25 22:05:03.474745",
"modified": "2019-07-04 22:05:03.474745",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@ -1612,4 +1620,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@ -166,6 +166,7 @@ class SalesInvoice(SellingController):
self.make_gl_entries()
if not self.is_return:
self.update_billing_status_for_zero_amount_refdoc("Delivery Note")
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.check_credit_limit()
@ -220,6 +221,7 @@ class SalesInvoice(SellingController):
self.update_billing_status_in_dn()
if not self.is_return:
self.update_billing_status_for_zero_amount_refdoc("Delivery Note")
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.update_serial_no(in_cancel=True)
@ -395,14 +397,17 @@ class SalesInvoice(SellingController):
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
'company', 'select_print_heading', 'cash_bank_account', 'company_address',
'write_off_account', 'write_off_cost_center', 'apply_discount_on', 'cost_center'):
for fieldname in ('territory', 'naming_series', 'currency', 'letter_head', 'tc_name',
'company', 'select_print_heading', 'cash_bank_account', 'write_off_account', 'taxes_and_charges',
'write_off_cost_center', 'apply_discount_on', 'cost_center'):
if (not for_validate) or (for_validate and not self.get(fieldname)):
self.set(fieldname, pos.get(fieldname))
customer_price_list = frappe.get_value("Customer", self.customer, 'default_price_list')
if pos.get("company_address"):
self.company_address = pos.get("company_address")
if not customer_price_list:
self.set('selling_price_list', pos.get('selling_price_list'))
@ -734,6 +739,7 @@ class SalesInvoice(SellingController):
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"due_date": self.due_date,
"against": self.against_income_account,
"debit": grand_total_in_company_currency,
"debit_in_account_currency": grand_total_in_company_currency \
@ -783,10 +789,13 @@ class SalesInvoice(SellingController):
asset.db_set("disposal_date", self.posting_date)
asset.set_status("Sold" if self.docstatus==1 else None)
else:
account_currency = get_account_currency(item.income_account)
income_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict({
"account": item.income_account if not item.enable_deferred_revenue else item.deferred_revenue_account,
"account": income_account,
"against": self.customer,
"credit": flt(item.base_net_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
@ -1173,6 +1182,56 @@ class SalesInvoice(SellingController):
self.set_missing_values(for_validate = True)
def get_discounting_status(self):
status = None
if self.is_discounted:
invoice_discounting_list = frappe.db.sql("""
select status
from `tabInvoice Discounting` id, `tabDiscounted Invoice` d
where
id.name = d.parent
and d.sales_invoice=%s
and id.docstatus=1
and status in ('Disbursed', 'Settled')
""", self.name)
for d in invoice_discounting_list:
status = d[0]
if status == "Disbursed":
break
return status
def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
if self.get('amended_from'):
self.status = 'Draft'
return
if not status:
if self.docstatus == 2:
status = "Cancelled"
elif self.docstatus == 1:
if flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
self.status = "Overdue and Discounted"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) < getdate(nowdate()):
self.status = "Overdue"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed':
self.status = "Unpaid and Discounted"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()):
self.status = "Unpaid"
elif flt(self.outstanding_amount) < 0 and self.is_return==0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
self.status = "Credit Note Issued"
elif self.is_return == 1:
self.status = "Return"
elif flt(self.outstanding_amount)<=0:
self.status = "Paid"
else:
self.status = "Submitted"
else:
self.status = "Draft"
if update:
self.db_set('status', self.status, update_modified = update_modified)
def validate_inter_company_party(doctype, party, company, inter_company_reference):
if not party:
return
@ -1201,9 +1260,8 @@ def validate_inter_company_party(doctype, party, company, inter_company_referenc
frappe.throw(_("Invalid Company for Inter Company Transaction."))
elif frappe.db.get_value(partytype, {"name": party, internal: 1}, "name") == party:
companies = frappe.db.sql("""select company from `tabAllowed To Transact With`
where parenttype = '{0}' and parent = '{1}'""".format(partytype, party), as_list = 1)
companies = [d[0] for d in companies]
companies = frappe.get_all("Allowed To Transact With", fields=["company"], filters={"parenttype": partytype, "parent": party})
companies = [d.company for d in companies]
if not company in companies:
frappe.throw(_("{0} not allowed to transact with {1}. Please change the Company.").format(partytype, company))
@ -1427,4 +1485,18 @@ def get_loyalty_programs(customer):
frappe.db.set(customer, 'loyalty_program', lp_details[0])
return []
else:
return lp_details
return lp_details
@frappe.whitelist()
def create_invoice_discounting(source_name, target_doc=None):
invoice = frappe.get_doc("Sales Invoice", source_name)
invoice_discounting = frappe.new_doc("Invoice Discounting")
invoice_discounting.company = invoice.company
invoice_discounting.append("invoices", {
"sales_invoice": source_name,
"customer": invoice.customer,
"posting_date": invoice.posting_date,
"outstanding_amount": invoice.outstanding_amount
})
return invoice_discounting

View File

@ -6,17 +6,18 @@ frappe.listview_settings['Sales Invoice'] = {
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
"currency", "is_return"],
get_indicator: function(doc) {
if(flt(doc.outstanding_amount) < 0) {
return [__("Credit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date >= frappe.datetime.get_today()) {
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"]
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date < frappe.datetime.get_today()) {
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<=,Today"]
} else if(cint(doc.is_return)) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if(flt(doc.outstanding_amount)==0) {
return [__("Paid"), "green", "outstanding_amount,=,0"]
}
var status_color = {
"Draft": "grey",
"Unpaid": "orange",
"Paid": "green",
"Return": "darkgrey",
"Credit Note Issued": "darkgrey",
"Unpaid and Discounted": "orange",
"Overdue and Discounted": "red",
"Overdue": "red"
};
return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
},
right_column: "grand_total"
};

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from erpnext.utilities.product import get_price
@ -13,7 +14,7 @@ class SubscriptionPlan(Document):
def validate_interval_count(self):
if self.billing_interval_count < 1:
frappe.throw('Billing Interval Count cannot be less than 1')
frappe.throw(_('Billing Interval Count cannot be less than 1'))
@frappe.whitelist()
def get_plan_rate(plan, quantity=1, customer=None):
@ -26,7 +27,7 @@ def get_plan_rate(plan, quantity=1, customer=None):
customer_group = frappe.db.get_value("Customer", customer, "customer_group")
else:
customer_group = None
price = get_price(item_code=plan.item, price_list=plan.price_list, customer_group=customer_group, company=None, qty=quantity)
if not price:
return 0

View File

@ -88,6 +88,12 @@ frappe.query_reports["Accounts Payable"] = {
}
}
},
{
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldname":"supplier_group",
"label": __("Supplier Group"),
@ -108,3 +114,14 @@ frappe.query_reports["Accounts Payable"] = {
});
}
}
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -77,6 +77,12 @@ frappe.query_reports["Accounts Payable Summary"] = {
"fieldtype": "Link",
"options": "Supplier"
},
{
"fieldname":"payment_terms_template",
"label": __("Payment Terms Template"),
"fieldtype": "Link",
"options": "Payment Terms Template"
},
{
"fieldname":"supplier_group",
"label": __("Supplier Group"),
@ -92,3 +98,14 @@ frappe.query_reports["Accounts Payable Summary"] = {
});
}
}
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -172,3 +172,14 @@ frappe.query_reports["Accounts Receivable"] = {
});
}
}
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext
from frappe import _, scrub
from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
class ReceivablePayableReport(object):
def __init__(self, filters=None):
@ -540,6 +541,10 @@ class ReceivablePayableReport(object):
where supplier_group=%s)""")
values.append(self.filters.get("supplier_group"))
if self.filters.get("payment_terms_template"):
conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
values.append(self.filters.get("payment_terms_template"))
if self.filters.get("cost_center"):
lft, rgt = frappe.get_cached_value("Cost Center",
self.filters.get("cost_center"), ['lft', 'rgt'])
@ -553,6 +558,14 @@ class ReceivablePayableReport(object):
conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
values += accounts
accounting_dimensions = get_accounting_dimensions()
if accounting_dimensions:
for dimension in accounting_dimensions:
if self.filters.get(dimension):
conditions.append("{0} = %s".format(dimension))
values.append(self.filters.get(dimension))
return " and ".join(conditions), values
def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
@ -599,9 +612,12 @@ class ReceivablePayableReport(object):
rows = []
for d in data:
values = d[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
precision = cint(frappe.db.get_default("float_precision")) or 2
formatted_values = [frappe.utils.rounded(val, precision) for val in values]
rows.append(
{
'values': d[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
'values': formatted_values
}
)

View File

@ -116,3 +116,14 @@ frappe.query_reports["Accounts Receivable Summary"] = {
});
}
}
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -12,11 +12,11 @@ def execute(filters=None):
columns = get_columns()
if not filters.get("account"): return columns, []
account_currency = frappe.db.get_value("Account", filters.account, "account_currency")
data = get_entries(filters)
from erpnext.accounts.utils import get_balance_on
balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
@ -24,7 +24,7 @@ def execute(filters=None):
for d in data:
total_debit += flt(d.debit)
total_credit += flt(d.credit)
amounts_not_reflected_in_system = get_amounts_not_reflected_in_system(filters)
bank_bal = flt(balance_as_per_system) - flt(total_debit) + flt(total_credit) \
@ -39,7 +39,7 @@ def execute(filters=None):
"credit": total_credit,
"account_currency": account_currency
},
get_balance_row(_("Cheques and Deposits incorrectly cleared"), amounts_not_reflected_in_system,
get_balance_row(_("Cheques and Deposits incorrectly cleared"), amounts_not_reflected_in_system,
account_currency),
{},
get_balance_row(_("Calculated Bank Statement balance"), bank_bal, account_currency)
@ -55,9 +55,16 @@ def get_columns():
"fieldtype": "Date",
"width": 90
},
{
"fieldname": "payment_document",
"label": _("Payment Document Type"),
"fieldtype": "Link",
"options": "DocType",
"width": 220
},
{
"fieldname": "payment_entry",
"label": _("Payment Entry"),
"label": _("Payment Document"),
"fieldtype": "Dynamic Link",
"options": "payment_document",
"width": 220
@ -100,7 +107,7 @@ def get_columns():
"label": _("Clearance Date"),
"fieldtype": "Date",
"width": 110
},
},
{
"fieldname": "account_currency",
"label": _("Currency"),
@ -112,9 +119,9 @@ def get_columns():
def get_entries(filters):
journal_entries = frappe.db.sql("""
select "Journal Entry" as payment_document, jv.posting_date,
jv.name as payment_entry, jvd.debit_in_account_currency as debit,
jvd.credit_in_account_currency as credit, jvd.against_account,
select "Journal Entry" as payment_document, jv.posting_date,
jv.name as payment_entry, jvd.debit_in_account_currency as debit,
jvd.credit_in_account_currency as credit, jvd.against_account,
jv.cheque_no as reference_no, jv.cheque_date as ref_date, jv.clearance_date, jvd.account_currency
from
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
@ -122,13 +129,13 @@ def get_entries(filters):
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'""", filters, as_dict=1)
payment_entries = frappe.db.sql("""
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date as ref_date,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(account)s, paid_amount, 0) as credit,
select
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date as ref_date,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(account)s, paid_amount, 0) as credit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
from `tabPayment Entry`
@ -156,25 +163,25 @@ def get_entries(filters):
return sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
key=lambda k: k['posting_date'] or getdate(nowdate()))
def get_amounts_not_reflected_in_system(filters):
je_amount = frappe.db.sql("""
select sum(jvd.debit_in_account_currency - jvd.credit_in_account_currency)
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%(account)s
and jv.posting_date > %(report_date)s and jv.clearance_date <= %(report_date)s
and jv.posting_date > %(report_date)s and jv.clearance_date <= %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No' """, filters)
je_amount = flt(je_amount[0][0]) if je_amount else 0.0
pe_amount = frappe.db.sql("""
select sum(if(paid_from=%(account)s, paid_amount, received_amount))
from `tabPayment Entry`
where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date > %(report_date)s and clearance_date <= %(report_date)s""", filters)
pe_amount = flt(pe_amount[0][0]) if pe_amount else 0.0
return je_amount + pe_amount
def get_balance_row(label, amount, account_currency):

View File

@ -63,9 +63,7 @@ frappe.query_reports["Budget Variance Report"] = {
]
}
let dimension_filters = erpnext.get_dimension_filters();
dimension_filters.then((dimensions) => {
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
});

View File

@ -8,17 +8,19 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
// The last item in the array is the definition for Presentation Currency
// filter. It won't be used in cash flow for now so we pop it. Please take
// of this if you are working here.
frappe.query_reports["Cash Flow"]["filters"].pop();
frappe.query_reports["Cash Flow"]["filters"].push({
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check"
});
frappe.query_reports["Cash Flow"]["filters"].splice(5, 1);
frappe.query_reports["Cash Flow"]["filters"].push({
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
});
frappe.query_reports["Cash Flow"]["filters"].push(
{
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check"
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
}
);
});

View File

@ -69,7 +69,9 @@ def execute(filters=None):
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
return columns, data
chart = get_chart_data(columns, data)
return columns, data, None, chart
def get_cash_flow_accounts():
operation_accounts = {
@ -123,8 +125,9 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data["total"] = total
return data
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters):
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters={}):
cond = ""
filters = frappe._dict(filters)
if filters.finance_book:
cond = " and finance_book = %s" %(frappe.db.escape(filters.finance_book))
@ -171,4 +174,21 @@ def add_total_row_account(out, data, label, period_list, currency, consolidated
total_row["total"] += row["total"]
out.append(total_row)
out.append({})
out.append({})
def get_chart_data(columns, data):
labels = [d.get("label") for d in columns[2:]]
datasets = [{'name':account.get('account').replace("'", ""), 'values': [account.get('total')]} for account in data if account.get('parent_account') == None and account.get('currency')]
datasets = datasets[:-1]
chart = {
"data": {
'labels': labels,
'datasets': datasets
},
"type": "bar"
}
chart["fieldtype"] = "Currency"
return chart

View File

@ -130,7 +130,7 @@ def get_cash_flow_data(fiscal_year, companies, filters):
section_data.append(net_profit_loss)
for account in cash_flow_account['account_types']:
account_data = get_account_type_based_data(account['account_type'], companies, fiscal_year)
account_data = get_account_type_based_data(account['account_type'], companies, fiscal_year, filters)
account_data.update({
"account_name": account['label'],
"account": account['label'],
@ -148,12 +148,12 @@ def get_cash_flow_data(fiscal_year, companies, filters):
return data
def get_account_type_based_data(account_type, companies, fiscal_year):
def get_account_type_based_data(account_type, companies, fiscal_year, filters):
data = {}
total = 0
for company in companies:
amount = get_account_type_based_gl_data(company,
fiscal_year.year_start_date, fiscal_year.year_end_date, account_type)
fiscal_year.year_start_date, fiscal_year.year_end_date, account_type, filters)
if amount and account_type == "Depreciation":
amount *= -1

View File

@ -159,9 +159,7 @@ frappe.query_reports["General Ledger"] = {
]
}
let dimension_filters = erpnext.get_dimension_filters();
dimension_filters.then((dimensions) => {
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
"fieldname": dimension["fieldname"],

View File

@ -11,6 +11,7 @@ from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.report.financial_statements import get_cost_centers_with_children
from six import iteritems
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
from collections import OrderedDict
def execute(filters=None):
if not filters:
@ -274,7 +275,7 @@ def group_by_field(group_by):
return 'voucher_no'
def initialize_gle_map(gl_entries, filters):
gle_map = frappe._dict()
gle_map = OrderedDict()
group_by = group_by_field(filters.get('group_by'))
for gle in gl_entries:

View File

@ -93,4 +93,6 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss):
else:
chart["type"] = "line"
chart["fieldtype"] = "Currency"
return chart

View File

@ -16,7 +16,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldname": "based_on",
"label": __("Based On"),
"fieldtype": "Select",
"options": "Cost Center\nProject",
"options": ["Cost Center", "Project"],
"default": "Cost Center",
"reqd": 1
},
@ -104,5 +104,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"parent_field": "parent_account",
"initial_depth": 3
}
});
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Profitability Analysis"].filters[1].options.push(dimension["document_type"]);
});
});
});

View File

@ -24,8 +24,17 @@ def get_accounts_data(based_on, company):
if based_on == 'cost_center':
return frappe.db.sql("""select name, parent_cost_center as parent_account, cost_center_name as account_name, lft, rgt
from `tabCost Center` where company=%s order by name""", company, as_dict=True)
else:
elif based_on == 'project':
return frappe.get_all('Project', fields = ["name"], filters = {'company': company}, order_by = 'name')
else:
filters = {}
doctype = frappe.unscrub(based_on)
has_company = frappe.db.has_column(doctype, 'company')
if has_company:
filters.update({'company': company})
return frappe.get_all(doctype, fields = ["name"], filters = filters, order_by = 'name')
def get_data(accounts, filters, based_on):
if not accounts:
@ -42,7 +51,7 @@ def get_data(accounts, filters, based_on):
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row, parent_children_map, based_on)
data = filter_out_zero_value_rows(data, parent_children_map,
data = filter_out_zero_value_rows(data, parent_children_map,
show_zero_values=filters.get("show_zero_values"))
return data
@ -112,14 +121,14 @@ def prepare_data(accounts, filters, total_row, parent_children_map, 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
@ -174,7 +183,7 @@ def set_gl_entries_by_account(company, from_date, to_date, based_on, gl_entries_
if from_date:
additional_conditions.append("and posting_date >= %(from_date)s")
gl_entries = frappe.db.sql("""select posting_date, {based_on} as based_on, debit, credit,
gl_entries = frappe.db.sql("""select posting_date, {based_on} as based_on, debit, credit,
is_opening, (select root_type from `tabAccount` where name = account) as type
from `tabGL Entry` where company=%(company)s
{additional_conditions}

View File

@ -67,3 +67,14 @@ frappe.query_reports["Sales Register"] = {
}
]
}
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import msgprint, _
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
def execute(filters=None):
return _execute(filters)
@ -163,6 +164,16 @@ def get_conditions(filters):
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)"""
accounting_dimensions = get_accounting_dimensions()
if accounting_dimensions:
for dimension in accounting_dimensions:
if filters.get(dimension):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.{0}, '') = %({0})s)""".format(dimension)
return conditions
def get_invoices(filters, additional_query_columns):

View File

@ -96,3 +96,14 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
}
});
erpnext.dimension_filters.then((dimensions) => {
dimensions.forEach((dimension) => {
frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
});

View File

@ -7,6 +7,7 @@ from frappe import _
from frappe.utils import flt, getdate, formatdate, cstr
from erpnext.accounts.report.financial_statements \
import filter_accounts, set_gl_entries_by_account, filter_out_zero_value_rows
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
@ -109,6 +110,25 @@ def get_rootwise_opening_balances(filters, report_type):
additional_conditions += fb_conditions
accounting_dimensions = get_accounting_dimensions()
query_filters = {
"company": filters.company,
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date,
"finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book')
}
if accounting_dimensions:
for dimension in accounting_dimensions:
additional_conditions += """ and {0} in (%({0})s) """.format(dimension)
query_filters.update({
dimension: filters.get(dimension)
})
gle = frappe.db.sql("""
select
account, sum(debit) as opening_debit, sum(credit) as opening_credit
@ -118,16 +138,7 @@ def get_rootwise_opening_balances(filters, report_type):
{additional_conditions}
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
and account in (select name from `tabAccount` where report_type=%(report_type)s)
group by account""".format(additional_conditions=additional_conditions),
{
"company": filters.company,
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date,
"finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book')
},
as_dict=True)
group by account""".format(additional_conditions=additional_conditions), query_filters , as_dict=True)
opening = frappe._dict()
for d in gle:

View File

@ -104,6 +104,9 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
# get balance of all entries that exist
date = nowdate()
if account:
acc = frappe.get_doc("Account", account)
try:
year_start_date = get_fiscal_year(date, verbose=0)[1]
except FiscalYearError:
@ -118,7 +121,12 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account()
if cost_center and allow_cost_center_in_entry_of_bs_account:
if account:
report_type = acc.report_type
else:
report_type = ""
if cost_center and (allow_cost_center_in_entry_of_bs_account or report_type =='Profit and Loss'):
cc = frappe.get_doc("Cost Center", cost_center)
if cc.is_group:
cond.append(""" exists (
@ -132,20 +140,13 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
if account:
acc = frappe.get_doc("Account", account)
if not frappe.flags.ignore_account_permission:
acc.check_permission("read")
if not allow_cost_center_in_entry_of_bs_account and acc.report_type == 'Profit and Loss':
if report_type == 'Profit and Loss':
# for pl accounts, get balance within a fiscal year
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
% year_start_date)
elif allow_cost_center_in_entry_of_bs_account:
# for all accounts, get balance within a fiscal year if maintain cost center in balance account is checked
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
% year_start_date)
# different filter for group and ledger - improved performance
if acc.is_group:
cond.append("""exists (
@ -435,7 +436,7 @@ def update_reference_in_journal_entry(d, jv_obj):
jv_obj.flags.ignore_validate_update_after_submit = True
jv_obj.save(ignore_permissions=True)
def update_reference_in_payment_entry(d, payment_entry):
def update_reference_in_payment_entry(d, payment_entry, do_not_save=False):
reference_details = {
"reference_doctype": d.against_voucher_type,
"reference_name": d.against_voucher,
@ -466,7 +467,17 @@ def update_reference_in_payment_entry(d, payment_entry):
payment_entry.setup_party_account_field()
payment_entry.set_missing_values()
payment_entry.set_amounts()
payment_entry.save(ignore_permissions=True)
if d.difference_amount and d.difference_account:
payment_entry.set_gain_or_loss(account_details={
'account': d.difference_account,
'cost_center': payment_entry.cost_center or frappe.get_cached_value('Company',
payment_entry.company, "cost_center"),
'amount': d.difference_amount
})
if not do_not_save:
payment_entry.save(ignore_permissions=True)
def unlink_ref_doc_from_payment_entries(ref_doc):
remove_ref_doc_link_from_jv(ref_doc.doctype, ref_doc.name)
@ -618,7 +629,7 @@ def get_held_invoices(party_type, party):
return held_invoices
def get_outstanding_invoices(party_type, party, account, condition=None):
def get_outstanding_invoices(party_type, party, account, condition=None, filters=None):
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
@ -634,7 +645,8 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
invoice_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount
voucher_no, voucher_type, posting_date, due_date,
ifnull(sum({dr_or_cr}), 0) as invoice_amount
from
`tabGL Entry`
where
@ -667,7 +679,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
""".format(payment_dr_or_cr=payment_dr_or_cr), {
"party_type": party_type,
"party": party,
"account": account,
"account": account
}, as_dict=True)
pe_map = frappe._dict()
@ -678,10 +690,12 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
payment_amount = pe_map.get((d.voucher_type, d.voucher_no), 0)
outstanding_amount = flt(d.invoice_amount - payment_amount, precision)
if outstanding_amount > 0.5 / (10**precision):
if not d.voucher_type == "Purchase Invoice" or d.voucher_no not in held_invoices:
due_date = frappe.db.get_value(
d.voucher_type, d.voucher_no, "posting_date" if party_type == "Employee" else "due_date")
if (filters and filters.get("outstanding_amt_greater_than") and
not (outstanding_amount >= filters.get("outstanding_amt_greater_than") and
outstanding_amount <= filters.get("outstanding_amt_less_than"))):
continue
if not d.voucher_type == "Purchase Invoice" or d.voucher_no not in held_invoices:
outstanding_invoices.append(
frappe._dict({
'voucher_no': d.voucher_no,
@ -690,7 +704,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
'invoice_amount': flt(d.invoice_amount),
'payment_amount': payment_amount,
'outstanding_amount': outstanding_amount,
'due_date': due_date
'due_date': d.due_date
})
)
@ -732,7 +746,7 @@ def get_children(doctype, parent, company, is_root=False):
filters.append(['company', '=', company])
else:
fields += ['account_currency'] if doctype == 'Account' else []
fields += ['root_type', 'account_currency'] if doctype == 'Account' else []
fields += [parent_fieldname + ' as parent']
acc = frappe.get_list(doctype, fields=fields, filters=filters)

View File

@ -388,7 +388,8 @@ class Asset(AccountsController):
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"credit": self.purchase_receipt_amount,
"credit_in_account_currency": self.purchase_receipt_amount
"credit_in_account_currency": self.purchase_receipt_amount,
"cost_center": self.cost_center
}))
gl_entries.append(self.get_gl_dict({
@ -397,7 +398,8 @@ class Asset(AccountsController):
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"debit": self.purchase_receipt_amount,
"debit_in_account_currency": self.purchase_receipt_amount
"debit_in_account_currency": self.purchase_receipt_amount,
"cost_center": self.cost_center
}))
if gl_entries:

View File

@ -66,10 +66,11 @@
"net_total",
"total_net_weight",
"taxes_section",
"taxes_and_charges",
"tax_category",
"column_break_50",
"shipping_rule",
"section_break_52",
"taxes_and_charges",
"taxes",
"sec_tax_breakup",
"other_charges_calculation",
@ -569,7 +570,7 @@
{
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"label": "Taxes and Charges",
"label": "Purchase Taxes and Charges Template",
"oldfieldname": "purchase_other_charges",
"oldfieldtype": "Link",
"options": "Purchase Taxes and Charges Template",
@ -1032,12 +1033,18 @@
"fieldname": "update_auto_repeat_reference",
"fieldtype": "Button",
"label": "Update Auto Repeat Reference"
},
{
"fieldname": "tax_category",
"fieldtype": "Link",
"label": "Tax Category",
"options": "Tax Category"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"modified": "2019-06-24 21:22:05.483429",
"modified": "2019-07-11 18:25:49.509343",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import unittest
import frappe
import json
import frappe.defaults
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from frappe.utils import flt, add_days, nowdate, getdate
@ -15,7 +16,7 @@ from erpnext.stock.doctype.material_request.test_material_request import make_ma
from erpnext.stock.doctype.material_request.material_request import make_purchase_order
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.controllers.accounts_controller import update_child_qty_rate
import json
from erpnext.controllers.status_updater import OverAllowanceError
class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_receipt(self):
@ -41,7 +42,7 @@ class TestPurchaseOrder(unittest.TestCase):
po.load_from_db()
self.assertEqual(po.get("items")[0].received_qty, 4)
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
frappe.db.set_value('Item', '_Test Item', 'over_delivery_receipt_allowance', 50)
pr = create_pr_against_po(po.name, received_qty=8)
self.assertEqual(get_ordered_qty(), existing_ordered_qty)
@ -57,12 +58,12 @@ class TestPurchaseOrder(unittest.TestCase):
def test_ordered_qty_against_pi_with_update_stock(self):
existing_ordered_qty = get_ordered_qty()
po = create_purchase_order()
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 10)
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
frappe.db.set_value('Item', '_Test Item', 'over_delivery_receipt_allowance', 50)
frappe.db.set_value('Item', '_Test Item', 'over_billing_allowance', 20)
pi = make_pi_from_po(po.name)
pi.update_stock = 1
@ -81,6 +82,11 @@ class TestPurchaseOrder(unittest.TestCase):
po.load_from_db()
self.assertEqual(po.get("items")[0].received_qty, 0)
frappe.db.set_value('Item', '_Test Item', 'over_delivery_receipt_allowance', 0)
frappe.db.set_value('Item', '_Test Item', 'over_billing_allowance', 0)
frappe.db.set_value("Accounts Settings", None, "over_billing_allowance", 0)
def test_update_child_qty_rate(self):
mr = make_material_request(qty=10)
po = make_purchase_order(mr.name)

View File

@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-03-29 17:18:06.678728",
"modified": "2019-07-21 23:24:21.094269",
"modified_by": "Administrator",
"module": "Buying",
"name": "Procurement Tracker",
@ -16,5 +16,12 @@
"ref_doctype": "Purchase Order",
"report_name": "Procurement Tracker",
"report_type": "Script Report",
"roles": []
"roles": [
{
"role": "Purchase Manager"
},
{
"role": "Purchase User"
}
]
}

View File

@ -150,10 +150,10 @@ def get_conditions(filters):
"""% (filters.get('cost_center'), filters.get('project'))
if filters.get("from_date"):
conditions += "AND transaction_date>=%s"% filters.get('from_date')
conditions += " AND transaction_date>=%s"% filters.get('from_date')
if filters.get("to_date"):
conditions += "AND transaction_date<=%s"% filters.get('to_date')
conditions += " AND transaction_date<=%s"% filters.get('to_date')
return conditions
def get_data(filters):

View File

@ -6,11 +6,12 @@ import frappe
def get_data():
config = [
{
"label": _("Masters and Accounts"),
"label": _("Accounts Receivable"),
"items": [
{
"type": "doctype",
"name": "Item",
"name": "Sales Invoice",
"description": _("Bills raised to Customers."),
"onboard": 1,
},
{
@ -19,12 +20,115 @@ def get_data():
"description": _("Customer database."),
"onboard": 1,
},
{
"type": "doctype",
"name": "Payment Entry",
"description": _("Bank/Cash transactions against party or for internal transfer")
},
{
"type": "doctype",
"name": "Payment Request",
"description": _("Payment Request"),
},
{
"type": "report",
"name": "Accounts Receivable",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Accounts Receivable Summary",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Sales Register",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Item-wise Sales Register",
"is_query_report": True,
"doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Ordered Items To Be Billed",
"is_query_report": True,
"doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Delivered Items To Be Billed",
"is_query_report": True,
"doctype": "Sales Invoice"
},
]
},
{
"label": _("Accounts Payable"),
"items": [
{
"type": "doctype",
"name": "Purchase Invoice",
"description": _("Bills raised by Suppliers."),
"onboard": 1
},
{
"type": "doctype",
"name": "Supplier",
"description": _("Supplier database."),
"onboard": 1,
},
{
"type": "doctype",
"name": "Payment Entry",
"description": _("Bank/Cash transactions against party or for internal transfer")
},
{
"type": "report",
"name": "Accounts Payable",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Accounts Payable Summary",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Purchase Register",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Item-wise Purchase Register",
"is_query_report": True,
"doctype": "Purchase Invoice"
},
{
"type": "report",
"name": "Purchase Order Items To Be Billed",
"is_query_report": True,
"doctype": "Purchase Invoice"
},
{
"type": "report",
"name": "Received Items To Be Billed",
"is_query_report": True,
"doctype": "Purchase Invoice"
},
]
},
{
"label": _("Accounting Masters"),
"items": [
{
"type": "doctype",
"name": "Company",
@ -40,201 +144,31 @@ def get_data():
"description": _("Tree of financial accounts."),
"onboard": 1,
},
]
},
{
"label": _("Billing"),
"items": [
{
"type": "doctype",
"name": "Sales Invoice",
"description": _("Bills raised to Customers."),
"onboard": 1,
},
{
"type": "doctype",
"name": "Purchase Invoice",
"description": _("Bills raised by Suppliers."),
"onboard": 1
},
{
"type": "doctype",
"name": "Payment Request",
"description": _("Payment Request"),
},
{
"type": "doctype",
"name": "Payment Term",
"description": _("Payment Terms based on conditions")
},
# Reports
{
"type": "report",
"name": "Ordered Items To Be Billed",
"is_query_report": True,
"reference_doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Delivered Items To Be Billed",
"is_query_report": True,
"reference_doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Purchase Order Items To Be Billed",
"is_query_report": True,
"reference_doctype": "Purchase Invoice"
},
{
"type": "report",
"name": "Received Items To Be Billed",
"is_query_report": True,
"reference_doctype": "Purchase Invoice"
},
]
},
{
"label": _("Settings"),
"icon": "fa fa-cog",
"items": [
{
"type": "doctype",
"name": "Accounts Settings",
"description": _("Default settings for accounting transactions.")
},
{
"type": "doctype",
"name": "Fiscal Year",
"description": _("Financial / accounting year.")
},
{
"type": "doctype",
"name": "Currency",
"description": _("Enable / disable currencies.")
},
{
"type": "doctype",
"name": "Currency Exchange",
"description": _("Currency exchange rate master.")
},
{
"type": "doctype",
"name": "Exchange Rate Revaluation",
"description": _("Exchange Rate Revaluation master.")
},
{
"type": "doctype",
"name": "Payment Gateway Account",
"description": _("Setup Gateway accounts.")
},
{
"type": "doctype",
"name": "Terms and Conditions",
"label": _("Terms and Conditions Template"),
"description": _("Template of terms or contract.")
},
{
"type": "doctype",
"name": "Mode of Payment",
"description": _("e.g. Bank, Cash, Credit Card")
},
{
"type": "doctype",
"name": "Auto Repeat",
"label": _("Auto Repeat"),
"description": _("To make recurring documents")
},
{
"type": "doctype",
"name": "C-Form",
"description": _("C-Form records"),
"country": "India"
},
{
"type": "doctype",
"name": "Cheque Print Template",
"description": _("Setup cheque dimensions for printing")
},
{
"type": "doctype",
"name": "Accounting Dimension",
"description": _("Setup custom dimensions for accounting")
},
{
"type": "doctype",
"name": "Opening Invoice Creation Tool",
"description": _("Create Opening Sales and Purchase Invoices")
}
]
},
{
"label": _("Accounting Entries"),
"items": [
{
"type": "doctype",
"name": "Payment Entry",
"description": _("Bank/Cash transactions against party or for internal transfer")
"name": "Finance Book",
},
{
"type": "doctype",
"name": "Journal Entry",
"description": _("Accounting journal entries.")
}
]
},
{
"label": _("Financial Statements"),
"items": [
{
"type": "report",
"name": "General Ledger",
"doctype": "GL Entry",
"is_query_report": True,
"name": "Accounting Period",
},
{
"type": "report",
"name": "Accounts Receivable",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Accounts Payable",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Trial Balance",
"doctype": "GL Entry",
"is_query_report": True,
},
{
"type": "report",
"name": "Balance Sheet",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Cash Flow",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Profit and Loss Statement",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Consolidated Financial Statement",
"doctype": "GL Entry",
"is_query_report": True
"type": "doctype",
"name": "Payment Term",
"description": _("Payment Terms based on conditions")
},
]
},
@ -243,43 +177,10 @@ def get_data():
"items": [
{
"type": "doctype",
"label": _("Bank"),
"name": "Bank",
"label": _("Match Payments with Invoices"),
"name": "Payment Reconciliation",
"description": _("Match non-linked Invoices and Payments.")
},
{
"type": "page",
"label": _("Reconcile payments and bank transactions"),
"name": "bank-reconciliation",
"description": _("Link bank transactions with payments.")
},
{
"type": "doctype",
"label": _("Bank Account"),
"name": "Bank Account",
},
{
"type": "doctype",
"label": _("Invoice Discounting"),
"name": "Invoice Discounting",
},
{
"type": "doctype",
"label": _("Bank Statement Transaction Entry List"),
"name": "Bank Statement Transaction Entry",
"route": "#List/Bank Statement Transaction Entry",
},
{
"type": "doctype",
"label": _("Bank Statement Transaction Entry Report"),
"name": "Bank Statement Transaction Entry",
"route": "#Report/Bank Statement Transaction Entry",
},
{
"type": "doctype",
"label": _("Bank Statement Settings"),
"name": "Bank Statement Settings",
},
{
"type": "doctype",
"label": _("Update Bank Transaction Dates"),
@ -288,9 +189,8 @@ def get_data():
},
{
"type": "doctype",
"label": _("Match Payments with Invoices"),
"name": "Payment Reconciliation",
"description": _("Match non-linked Invoices and Payments.")
"label": _("Invoice Discounting"),
"name": "Invoice Discounting",
},
{
"type": "report",
@ -306,8 +206,75 @@ def get_data():
},
{
"type": "doctype",
"name": "Bank Guarantee",
"doctype": "Bank Guarantee"
"name": "Bank Guarantee"
},
{
"type": "doctype",
"name": "Cheque Print Template",
"description": _("Setup cheque dimensions for printing")
},
]
},
{
"label": _("General Ledger"),
"items": [
{
"type": "doctype",
"name": "Journal Entry",
"description": _("Accounting journal entries.")
},
{
"type": "report",
"name": "General Ledger",
"doctype": "GL Entry",
"is_query_report": True,
},
{
"type": "report",
"name": "Customer Ledger Summary",
"doctype": "Sales Invoice",
"is_query_report": True,
},
{
"type": "report",
"name": "Supplier Ledger Summary",
"doctype": "Sales Invoice",
"is_query_report": True,
}
]
},
{
"label": _("Taxes"),
"items": [
{
"type": "doctype",
"name": "Sales Taxes and Charges Template",
"description": _("Tax template for selling transactions.")
},
{
"type": "doctype",
"name": "Purchase Taxes and Charges Template",
"description": _("Tax template for buying transactions.")
},
{
"type": "doctype",
"name": "Item Tax Template",
"description": _("Tax template for item tax rates.")
},
{
"type": "doctype",
"name": "Tax Category",
"description": _("Tax Category for overriding tax rates.")
},
{
"type": "doctype",
"name": "Tax Rule",
"description": _("Tax Rule for transactions.")
},
{
"type": "doctype",
"name": "Tax Withholding Category",
"description": _("Tax Withholding rates to be applied on transactions.")
},
]
},
@ -327,6 +294,10 @@ def get_data():
"name": "Budget",
"description": _("Define budget for a financial year.")
},
{
"type": "doctype",
"name": "Accounting Dimension",
},
{
"type": "report",
"name": "Budget Variance Report",
@ -338,51 +309,106 @@ def get_data():
"name": "Monthly Distribution",
"description": _("Seasonality for setting budgets, targets etc.")
},
]
},
{
"label": _("Financial Statements"),
"items": [
{
"type": "report",
"name": "Trial Balance",
"doctype": "GL Entry",
"is_query_report": True,
},
{
"type": "report",
"name": "Profit and Loss Statement",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Balance Sheet",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Cash Flow",
"doctype": "GL Entry",
"is_query_report": True
},
{
"type": "report",
"name": "Consolidated Financial Statement",
"doctype": "GL Entry",
"is_query_report": True
},
]
},
{
"label": _("Opening and Closing"),
"items": [
{
"type": "doctype",
"name": "Opening Invoice Creation Tool",
},
{
"type": "doctype",
"name": "Chart of Accounts Importer",
},
{
"type": "doctype",
"name": "Period Closing Voucher",
"description": _("Close Balance Sheet and book Profit or Loss.")
},
]
},
{
"label": _("Taxes"),
"label": _("Multi Currency"),
"items": [
{
"type": "doctype",
"name": "Tax Category",
"description": _("Tax Category for overriding tax rates.")
"name": "Currency",
"description": _("Enable / disable currencies.")
},
{
"type": "doctype",
"name": "Sales Taxes and Charges Template",
"description": _("Tax template for selling transactions.")
"name": "Currency Exchange",
"description": _("Currency exchange rate master.")
},
{
"type": "doctype",
"name": "Purchase Taxes and Charges Template",
"description": _("Tax template for buying transactions.")
"name": "Exchange Rate Revaluation",
"description": _("Exchange Rate Revaluation master.")
},
]
},
{
"label": _("Settings"),
"icon": "fa fa-cog",
"items": [
{
"type": "doctype",
"name": "Payment Gateway Account",
"description": _("Setup Gateway accounts.")
},
{
"type": "doctype",
"name": "Item Tax Template",
"description": _("Tax template for item tax rates.")
"name": "Terms and Conditions",
"label": _("Terms and Conditions Template"),
"description": _("Template of terms or contract.")
},
{
"type": "doctype",
"name": "Tax Rule",
"description": _("Tax Rule for transactions.")
},
{
"type": "doctype",
"name": "Tax Withholding Category",
"description": _("Tax Withholding rates to be applied on transactions.")
"name": "Mode of Payment",
"description": _("e.g. Bank, Cash, Credit Card")
},
]
},
{
"label": _("Subscription Management"),
"icon": "fa fa-microchip ",
"items": [
{
"type": "doctype",
@ -403,7 +429,31 @@ def get_data():
]
},
{
"label": _("Key Reports"),
"label": _("Bank Statement"),
"items": [
{
"type": "doctype",
"label": _("Bank"),
"name": "Bank",
},
{
"type": "doctype",
"label": _("Bank Account"),
"name": "Bank Account",
},
{
"type": "doctype",
"name": "Bank Statement Transaction Entry",
},
{
"type": "doctype",
"label": _("Bank Statement Settings"),
"name": "Bank Statement Settings",
},
]
},
{
"label": _("Profitability"),
"items": [
{
"type": "report",
@ -413,21 +463,9 @@ def get_data():
},
{
"type": "report",
"name": "Sales Register",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Purchase Register",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Purchase Invoice Trends",
"name": "Profitability Analysis",
"doctype": "GL Entry",
"is_query_report": True,
"doctype": "Purchase Invoice"
},
{
"type": "report",
@ -437,38 +475,14 @@ def get_data():
},
{
"type": "report",
"name": "Item-wise Sales Register",
"is_query_report": True,
"doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Item-wise Purchase Register",
"name": "Purchase Invoice Trends",
"is_query_report": True,
"doctype": "Purchase Invoice"
},
{
"type": "report",
"name": "Profitability Analysis",
"doctype": "GL Entry",
"is_query_report": True,
},
{
"type": "report",
"name": "Customer Ledger Summary",
"doctype": "Sales Invoice",
"is_query_report": True,
},
{
"type": "report",
"name": "Supplier Ledger Summary",
"doctype": "Sales Invoice",
"is_query_report": True,
}
]
},
{
"label": _("Other Reports"),
"label": _("Reports"),
"icon": "fa fa-table",
"items": [
{
@ -489,18 +503,6 @@ def get_data():
"is_query_report": True,
"doctype": "Sales Invoice"
},
{
"type": "report",
"name": "Accounts Receivable Summary",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
"type": "report",
"name": "Accounts Payable Summary",
"doctype": "Purchase Invoice",
"is_query_report": True
},
{
"type": "report",
"is_query_report": True,
@ -549,27 +551,7 @@ def get_data():
}
]
},
{
"label": _("Help"),
"icon": "fa fa-facetime-video",
"items": [
{
"type": "help",
"label": _("Chart of Accounts"),
"youtube_id": "DyR-DST-PyA"
},
{
"type": "help",
"label": _("Opening Accounting Balance"),
"youtube_id": "kdgM20Q-q68"
},
{
"type": "help",
"label": _("Setting up Taxes"),
"youtube_id": "nQ1zZdPgdaQ"
}
]
}
]
gst = {
@ -617,6 +599,12 @@ def get_data():
"name": "GST Itemised Purchase Register",
"is_query_report": True
},
{
"type": "doctype",
"name": "C-Form",
"description": _("C-Form records"),
"country": "India"
},
]
}
@ -624,6 +612,6 @@ def get_data():
countries = frappe.get_all("Company", fields="country")
countries = [country["country"] for country in countries]
if "India" in countries:
config.insert(7, gst)
config.insert(9, gst)
domains = frappe.get_active_domains()
return config

View File

@ -157,6 +157,13 @@ def get_data():
"reference_doctype": "Purchase Order",
"onboard": 1,
},
{
"type": "report",
"is_query_report": True,
"name": "Procurement Tracker",
"reference_doctype": "Purchase Order",
"onboard": 1,
},
{
"type": "report",
"is_query_report": True,
@ -228,29 +235,5 @@ def get_data():
}
]
},
{
"label": _("Help"),
"items": [
{
"type": "help",
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Material Request to Purchase Order"),
"youtube_id": "4TN9kPyfIqM"
},
{
"type": "help",
"label": _("Purchase Order to Payment"),
"youtube_id": "EK65tLdVUDk"
},
{
"type": "help",
"label": _("Managing Subcontracting"),
"youtube_id": "ThiMCC2DtKo"
},
]
},
]

View File

@ -26,8 +26,8 @@ def get_data():
},
{
"type": "page",
"name": "medical_record",
"label": _("Patient Medical Record"),
"name": "patient_history",
"label": _("Patient History"),
},
{
"type": "page",

View File

@ -4,127 +4,13 @@ from frappe import _
def get_data():
return [
{
"label": _("Employee and Attendance"),
"label": _("Employee"),
"items": [
{
"type": "doctype",
"name": "Employee",
"onboard": 1,
},
{
"type": "doctype",
"name": "Employee Attendance Tool",
"hide_count": True,
"onboard": 1,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Group",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Attendance",
"onboard": 1,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Attendance Request",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Upload Attendance",
"hide_count": True,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Checkin",
"hide_count": True,
"onboard": 1,
"dependencies": ["Employee"]
},
]
},
{
"label": _("Payroll"),
"items": [
{
"type": "doctype",
"name": "Salary Structure",
"onboard": 1,
},
{
"type": "doctype",
"name": "Salary Structure Assignment",
"onboard": 1,
"dependencies": ["Salary Structure", "Employee"],
},
{
"type": "doctype",
"name": "Salary Slip",
"onboard": 1,
},
{
"type": "doctype",
"name": "Payroll Entry",
"onboard": 1,
},
{
"type": "doctype",
"name": "Employee Benefit Application",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Benefit Claim",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Additional Salary",
},
{
"type": "doctype",
"name": "Employee Tax Exemption Declaration",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Tax Exemption Proof Submission",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Incentive",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Retention Bonus",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Payroll Period",
},
{
"type": "doctype",
"name": "Salary Component",
},
]
},
{
"label": _("Settings"),
"icon": "fa fa-cog",
"items": [
{
"type": "doctype",
"name": "HR Settings",
},
{
"type": "doctype",
"name": "Employment Type",
@ -147,19 +33,56 @@ def get_data():
},
{
"type": "doctype",
"name": "Daily Work Summary Group"
"name": "Employee Group",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Health Insurance"
},
{
"type": "doctype",
"name": "Staffing Plan",
}
]
},
{
"label": _("Attendance"),
"items": [
{
"type": "doctype",
"name": "Employee Attendance Tool",
"hide_count": True,
"onboard": 1,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Attendance",
"onboard": 1,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Attendance Request",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Upload Attendance",
"hide_count": True,
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Checkin",
"hide_count": True,
"dependencies": ["Employee"]
},
{
"type": "report",
"is_query_report": True,
"name": "Monthly Attendance Sheet",
"doctype": "Attendance"
},
]
},
{
"label": _("Leaves"),
"items": [
@ -175,13 +98,8 @@ def get_data():
},
{
"type": "doctype",
"name": "Compensatory Leave Request",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Leave Encashment",
"dependencies": ["Employee"]
"name": "Leave Policy",
"dependencies": ["Leave Type"]
},
{
"type": "doctype",
@ -194,37 +112,172 @@ def get_data():
},
{
"type": "doctype",
"name": "Leave Policy",
"dependencies": ["Leave Type"]
"name": "Holiday List",
},
{
"type": "doctype",
"name": "Holiday List",
"name": "Compensatory Leave Request",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Leave Encashment",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Leave Block List",
},
{
"type": "report",
"is_query_report": True,
"name": "Employee Leave Balance",
"doctype": "Leave Application"
},
]
},
{
"label": _("Recruitment and Training"),
"label": _("Payroll"),
"items": [
{
"type": "doctype",
"name": "Job Applicant",
"name": "Salary Structure",
"onboard": 1,
},
{
"type": "doctype",
"name": "Salary Structure Assignment",
"onboard": 1,
"dependencies": ["Salary Structure", "Employee"],
},
{
"type": "doctype",
"name": "Payroll Entry",
"onboard": 1,
},
{
"type": "doctype",
"name": "Salary Slip",
"onboard": 1,
},
{
"type": "doctype",
"name": "Salary Component",
},
{
"type": "doctype",
"name": "Additional Salary",
},
{
"type": "doctype",
"name": "Retention Bonus",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Incentive",
"dependencies": ["Employee"]
},
{
"type": "report",
"is_query_report": True,
"name": "Salary Register",
"doctype": "Salary Slip"
},
]
},
{
"label": _("Employee Tax and Benefits"),
"items": [
{
"type": "doctype",
"name": "Employee Tax Exemption Declaration",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Tax Exemption Proof Submission",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Benefit Application",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Benefit Claim",
"dependencies": ["Employee"]
},
]
},
{
"label": _("Employee Lifecycle"),
"items": [
{
"type": "doctype",
"name": "Employee Onboarding",
"dependencies": ["Job Applicant"],
},
{
"type": "doctype",
"name": "Employee Skill Map",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Promotion",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Transfer",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Separation",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Onboarding Template",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Separation Template",
"dependencies": ["Employee"]
},
]
},
{
"label": _("Recruitment"),
"items": [
{
"type": "doctype",
"name": "Job Opening",
"onboard": 1,
},
{
"type": "doctype",
"name": "Job Applicant",
"onboard": 1,
},
{
"type": "doctype",
"name": "Job Offer",
"onboard": 1,
},
{
"type": "doctype",
"name": "Staffing Plan",
},
]
},
{
"label": _("Training"),
"items": [
{
"type": "doctype",
"name": "Training Program"
@ -244,42 +297,7 @@ def get_data():
]
},
{
"label": _("Employee Lifecycle"),
"items": [
{
"type": "doctype",
"name": "Employee Transfer",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Promotion",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Separation",
"dependencies": ["Employee"],
},
{
"type": "doctype",
"name": "Employee Onboarding",
"dependencies": ["Job Applicant"],
},
{
"type": "doctype",
"name": "Employee Separation Template",
"dependencies": ["Employee"]
},
{
"type": "doctype",
"name": "Employee Onboarding Template",
"dependencies": ["Employee"]
}
]
},
{
"label": _("Appraisals, Expense Claims and Loans"),
"label": _("Performance"),
"items": [
{
"type": "doctype",
@ -290,15 +308,24 @@ def get_data():
"name": "Appraisal Template",
},
{
"type": "page",
"name": "team-updates",
"label": _("Team Updates")
"type": "doctype",
"name": "Energy Point Rule",
},
{
"type": "doctype",
"name": "Employee Advance",
"dependencies": ["Employee"]
"name": "Energy Point Log",
},
{
"type": "link",
"doctype": "Energy Point Log",
"label": _("Energy Point Leaderboard"),
"route": "#social/users"
},
]
},
{
"label": _("Expense Claims"),
"items": [
{
"type": "doctype",
"name": "Expense Claim",
@ -306,8 +333,14 @@ def get_data():
},
{
"type": "doctype",
"name": "Loan Type",
"name": "Employee Advance",
"dependencies": ["Employee"]
},
]
},
{
"label": _("Loans"),
"items": [
{
"type": "doctype",
"name": "Loan Application",
@ -316,19 +349,72 @@ def get_data():
{
"type": "doctype",
"name": "Loan"
}
},
{
"type": "doctype",
"name": "Loan Type",
},
]
},
{
"label": _("Shift Management"),
"items": [
{
"type": "doctype",
"name": "Shift Type",
},
{
"type": "doctype",
"name": "Shift Request",
},
{
"type": "doctype",
"name": "Shift Assignment",
},
]
},
{
"label": _("Fleet Management"),
"items": [
{
"type": "doctype",
"name": "Vehicle"
},
{
"type": "doctype",
"name": "Vehicle Log"
},
{
"type": "report",
"is_query_report": True,
"name": "Vehicle Expenses",
"doctype": "Vehicle"
},
]
},
{
"label": _("Settings"),
"icon": "fa fa-cog",
"items": [
{
"type": "doctype",
"name": "HR Settings",
},
{
"type": "doctype",
"name": "Daily Work Summary Group"
},
{
"type": "page",
"name": "team-updates",
"label": _("Team Updates")
},
]
},
{
"label": _("Reports"),
"icon": "fa fa-list",
"items": [
{
"type": "report",
"is_query_report": True,
"name": "Employee Leave Balance",
"doctype": "Leave Application"
},
{
"type": "report",
"is_query_report": True,
@ -341,29 +427,6 @@ def get_data():
"name": "Employees working on a holiday",
"doctype": "Employee"
},
{
"type": "report",
"name": "Employee Information",
"doctype": "Employee"
},
{
"type": "report",
"is_query_report": True,
"name": "Salary Register",
"doctype": "Salary Slip"
},
{
"type": "report",
"is_query_report": True,
"name": "Monthly Attendance Sheet",
"doctype": "Attendance"
},
{
"type": "report",
"is_query_report": True,
"name": "Vehicle Expenses",
"doctype": "Vehicle"
},
{
"type": "report",
"is_query_report": True,
@ -372,50 +435,4 @@ def get_data():
},
]
},
{
"label": _("Shifts and Fleet Management"),
"items": [
{
"type": "doctype",
"name": "Shift Type",
},
{
"type": "doctype",
"name": "Shift Request",
},
{
"type": "doctype",
"name": "Shift Assignment",
},
{
"type": "doctype",
"name": "Vehicle"
},
{
"type": "doctype",
"name": "Vehicle Log"
},
]
},
# {
# "label": _("Help"),
# "icon": "fa fa-facetime-video",
# "items": [
# {
# "type": "help",
# "label": _("Setting up Employees"),
# "youtube_id": "USfIUdZlUhw"
# },
# {
# "type": "help",
# "label": _("Leave Management"),
# "youtube_id": "fc0p_AXebc8"
# },
# {
# "type": "help",
# "label": _("Expense Claims"),
# "youtube_id": "5SZHJF--ZFY"
# }
# ]
# },
]

View File

@ -3,43 +3,6 @@ from frappe import _
def get_data():
return [
{
"label": _("Production"),
"icon": "fa fa-star",
"items": [
{
"type": "doctype",
"name": "Work Order",
"description": _("Orders released for production."),
"onboard": 1,
"dependencies": ["Item", "BOM"]
},
{
"type": "doctype",
"name": "Production Plan",
"description": _("Generate Material Requests (MRP) and Work Orders."),
"onboard": 1,
"dependencies": ["Item", "BOM"]
},
{
"type": "doctype",
"name": "Stock Entry",
"onboard": 1,
"dependencies": ["Item"]
},
{
"type": "doctype",
"name": "Timesheet",
"description": _("Time Sheet for manufacturing."),
"onboard": 1,
"dependencies": ["Activity Type"]
},
{
"type": "doctype",
"name": "Job Card"
}
]
},
{
"label": _("Bill of Materials"),
"items": [
@ -85,6 +48,43 @@ def get_data():
]
},
{
"label": _("Production"),
"icon": "fa fa-star",
"items": [
{
"type": "doctype",
"name": "Work Order",
"description": _("Orders released for production."),
"onboard": 1,
"dependencies": ["Item", "BOM"]
},
{
"type": "doctype",
"name": "Production Plan",
"description": _("Generate Material Requests (MRP) and Work Orders."),
"onboard": 1,
"dependencies": ["Item", "BOM"]
},
{
"type": "doctype",
"name": "Stock Entry",
"onboard": 1,
"dependencies": ["Item"]
},
{
"type": "doctype",
"name": "Timesheet",
"description": _("Time Sheet for manufacturing."),
"onboard": 1,
"dependencies": ["Activity Type"]
},
{
"type": "doctype",
"name": "Job Card"
}
]
},
{
"label": _("Tools"),
"icon": "fa fa-wrench",

View File

@ -88,17 +88,14 @@ def get_data():
"doctype": "Project",
"dependencies": ["Project"],
},
]
},
{
"label": _("Help"),
"icon": "fa fa-facetime-video",
"items": [
{
"type": "help",
"label": _("Managing Projects"),
"youtube_id": "egxIGwtoKI4"
"type": "report",
"is_query_report": True,
"name": "Project Billing Summary",
"doctype": "Project",
"dependencies": ["Project"],
},
]
},
]

View File

@ -318,41 +318,5 @@ def get_data():
}
]
},
{
"label": _("SMS"),
"icon": "fa fa-wrench",
"items": [
{
"type": "doctype",
"name": "SMS Center",
"description":_("Send mass SMS to your contacts"),
},
{
"type": "doctype",
"name": "SMS Log",
"description":_("Logs for maintaining sms delivery status"),
},
]
},
{
"label": _("Help"),
"items": [
{
"type": "help",
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Sales Order to Payment"),
"youtube_id": "1eP90MWoDQM"
},
{
"type": "help",
"label": _("Point-of-Sale"),
"youtube_id": "4WkelWkbP_c"
},
]
},
]

View File

@ -281,9 +281,9 @@ def get_data():
},
{
"type": "report",
"is_query_report": True,
"name": "Item Shortage Report",
"route": "#Report/Bin/Item Shortage Report",
"doctype": "Purchase Receipt"
"doctype": "Bin"
},
{
"type": "report",
@ -329,45 +329,5 @@ def get_data():
}
]
},
{
"label": _("Help"),
"icon": "fa fa-facetime-video",
"items": [
{
"type": "help",
"label": _("Items and Pricing"),
"youtube_id": "qXaEwld4_Ps"
},
{
"type": "help",
"label": _("Item Variants"),
"youtube_id": "OGBETlCzU5o"
},
{
"type": "help",
"label": _("Opening Stock Balance"),
"youtube_id": "0yPgrtfeCTs"
},
{
"type": "help",
"label": _("Making Stock Entries"),
"youtube_id": "Njt107hlY3I"
},
{
"type": "help",
"label": _("Serialized Inventory"),
"youtube_id": "gvOVlEwFDAk"
},
{
"type": "help",
"label": _("Batch Inventory"),
"youtube_id": "J0QKl7ABPKM"
},
{
"type": "help",
"label": _("Managing Subcontracting"),
"youtube_id": "ThiMCC2DtKo"
},
]
}
]

View File

@ -21,13 +21,7 @@ def get_data():
"type": "doctype",
"name": "Issue Priority",
"description": _("Issue Priority."),
},
{
"type": "doctype",
"name": "Communication",
"description": _("Communication log."),
"onboard": 1,
},
}
]
},
{
@ -97,4 +91,15 @@ def get_data():
},
]
},
{
"label": _("Settings"),
"icon": "fa fa-list",
"items": [
{
"type": "doctype",
"name": "Support Settings",
"label": _("Support Settings"),
},
]
},
]

View File

@ -475,21 +475,20 @@ class AccountsController(TransactionBase):
order_doctype = "Purchase Order"
order_list = list(set([d.get(order_field)
for d in self.get("items") if d.get(order_field)]))
for d in self.get("items") if d.get(order_field)]))
journal_entries = get_advance_journal_entries(party_type, party, party_account,
amount_field, order_doctype, order_list, include_unallocated)
amount_field, order_doctype, order_list, include_unallocated)
payment_entries = get_advance_payment_entries(party_type, party, party_account,
order_doctype, order_list, include_unallocated)
order_doctype, order_list, include_unallocated)
res = journal_entries + payment_entries
return res
def is_inclusive_tax(self):
is_inclusive = cint(frappe.db.get_single_value("Accounts Settings",
"show_inclusive_tax_in_print"))
is_inclusive = cint(frappe.db.get_single_value("Accounts Settings", "show_inclusive_tax_in_print"))
if is_inclusive:
is_inclusive = 0
@ -501,7 +500,7 @@ class AccountsController(TransactionBase):
def validate_advance_entries(self):
order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order"
order_list = list(set([d.get(order_field)
for d in self.get("items") if d.get(order_field)]))
for d in self.get("items") if d.get(order_field)]))
if not order_list: return
@ -513,7 +512,7 @@ class AccountsController(TransactionBase):
if not advance_entries_against_si or d.reference_name not in advance_entries_against_si:
frappe.msgprint(_(
"Payment Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.")
.format(d.reference_name, d.against_order))
.format(d.reference_name, d.against_order))
def update_against_document_in_jv(self):
"""
@ -551,9 +550,9 @@ class AccountsController(TransactionBase):
'unadjusted_amount': flt(d.advance_amount),
'allocated_amount': flt(d.allocated_amount),
'exchange_rate': (self.conversion_rate
if self.party_account_currency != self.company_currency else 1),
if self.party_account_currency != self.company_currency else 1),
'grand_total': (self.base_grand_total
if self.party_account_currency == self.company_currency else self.grand_total),
if self.party_account_currency == self.company_currency else self.grand_total),
'outstanding_amount': self.outstanding_amount
})
lst.append(args)
@ -576,36 +575,37 @@ class AccountsController(TransactionBase):
unlink_ref_doc_from_payment_entries(self)
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
from erpnext.controllers.status_updater import get_allowance_for
item_allowance = {}
global_qty_allowance, global_amount_allowance = None, 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))
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))
_("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]
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))
self.precision(based_on, item))
tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code,
item_tolerance, global_tolerance)
allowance, item_allowance, global_qty_allowance, global_amount_allowance = \
get_allowance_for(item.item_code, item_allowance, global_qty_allowance, global_amount_allowance, "amount")
max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100)
max_allowed_amt = flt(ref_amt * (100 + allowance) / 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 over-billing, please set in Stock Settings").format(
item.item_code, item.idx, max_allowed_amt))
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set in Stock Settings")
.format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
from erpnext.accounts.utils import get_company_default
@ -615,9 +615,10 @@ class AccountsController(TransactionBase):
stock_items = []
item_codes = list(set(item.item_code for item in self.get("items")))
if item_codes:
stock_items = [r[0] for r in frappe.db.sql("""select name
from `tabItem` where name in (%s) and is_stock_item=1""" % \
(", ".join((["%s"] * len(item_codes))),), item_codes)]
stock_items = [r[0] for r in frappe.db.sql("""
select name from `tabItem`
where name in (%s) and is_stock_item=1
""" % (", ".join((["%s"] * len(item_codes))),), item_codes)]
return stock_items
@ -860,7 +861,7 @@ class AccountsController(TransactionBase):
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
grand_total = grand_total - flt(self.write_off_amount)
if total != grand_total:
if total != flt(grand_total, self.precision("grand_total")):
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
def is_rounded_total_disabled(self):

View File

@ -636,7 +636,8 @@ class BuyingController(StockController):
asset.set_missing_values()
asset.insert()
frappe.msgprint(_("Asset {0} created").format(asset.name))
asset_link = frappe.utils.get_link_to_form('Asset', asset.name)
frappe.msgprint(_("Asset {0} created").format(asset_link))
return asset.name
def make_asset_movement(self, row):

View File

@ -98,8 +98,8 @@ def validate_item_attribute_value(attributes_list, attribute, attribute_value, i
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'))
frappe.throw(_("The value {0} is already assigned to an exisiting Item {2}.").format(
attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Rename Not Allowed'))
def get_attribute_values(item):
if not frappe.flags.attribute_values:
@ -176,7 +176,7 @@ def enqueue_multiple_variant_creation(item, args):
for key in variants:
total_variants *= len(variants[key])
if total_variants >= 600:
frappe.msgprint("Please do not create more than 500 items at a time", raise_exception=1)
frappe.throw(_("Please do not create more than 500 items at a time"))
return
if total_variants < 10:
return create_multiple_variants(item, args)

View File

@ -206,9 +206,10 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
idx desc, name
limit %(start)s, %(page_len)s """.format(
fcond=get_filters_cond(doctype, filters, conditions),
mcond=get_match_cond(doctype),
key=searchfield), {
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
mcond=get_match_cond(doctype).replace('%', '%%'),
key=searchfield),
{
'txt': '%' + txt + '%',
'_txt': txt.replace("%", ""),
'start': start or 0,

View File

@ -75,7 +75,7 @@ def validate_returned_items(doc):
items_returned = False
for d in doc.get("items"):
if flt(d.qty) < 0 or d.get('received_qty') < 0:
if d.item_code and (flt(d.qty) < 0 or d.get('received_qty') < 0):
if d.item_code not in valid_items:
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
.format(d.idx, d.item_code, doc.doctype, doc.return_against))
@ -107,6 +107,9 @@ def validate_returned_items(doc):
items_returned = True
elif d.item_name:
items_returned = True
if not items_returned:
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))

View File

@ -7,6 +7,8 @@ from frappe.utils import flt, comma_or, nowdate, getdate
from frappe import _
from frappe.model.document import Document
class OverAllowanceError(frappe.ValidationError): pass
def validate_status(status, options):
if status not in options:
frappe.throw(_("Status must be one of {0}").format(comma_or(options)))
@ -43,16 +45,6 @@ status_map = {
["Closed", "eval:self.status=='Closed'"],
["On Hold", "eval:self.status=='On Hold'"],
],
"Sales Invoice": [
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
],
"Purchase Invoice": [
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
@ -98,7 +90,8 @@ status_map = {
["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"],
["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"],
["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"]
["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
["Manufactured", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Manufacture'"]
],
"Bank Transaction": [
["Unreconciled", "eval:self.docstatus == 1 and self.unallocated_amount>0"],
@ -154,8 +147,9 @@ class StatusUpdater(Document):
def validate_qty(self):
"""Validates qty at row level"""
self.tolerance = {}
self.global_tolerance = None
self.item_allowance = {}
self.global_qty_allowance = None
self.global_amount_allowance = None
for args in self.status_updater:
if "target_ref_field" not in args:
@ -186,32 +180,41 @@ class StatusUpdater(Document):
# if not item[args['target_ref_field']]:
# msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code))
if args.get('no_tolerance'):
if args.get('no_allowance'):
item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']]
if item['reduce_by'] > .01:
self.limits_crossed_error(args, item)
elif item[args['target_ref_field']]:
self.check_overflow_with_tolerance(item, args)
self.check_overflow_with_allowance(item, args)
def check_overflow_with_tolerance(self, item, args):
def check_overflow_with_allowance(self, item, args):
"""
Checks if there is overflow condering a relaxation tolerance
Checks if there is overflow condering a relaxation allowance
"""
# check if overflow is within tolerance
tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'],
self.tolerance, self.global_tolerance)
qty_or_amount = "qty" if "qty" in args['target_ref_field'] else "amount"
# check if overflow is within allowance
allowance, self.item_allowance, self.global_qty_allowance, self.global_amount_allowance = \
get_allowance_for(item['item_code'], self.item_allowance,
self.global_qty_allowance, self.global_amount_allowance, qty_or_amount)
overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
item[args['target_ref_field']]) * 100
if overflow_percent - tolerance > 0.01:
item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
if overflow_percent - allowance > 0.01:
item['max_allowed'] = flt(item[args['target_ref_field']] * (100+allowance)/100)
item['reduce_by'] = item[args['target_field']] - item['max_allowed']
self.limits_crossed_error(args, item)
self.limits_crossed_error(args, item, qty_or_amount)
def limits_crossed_error(self, args, item):
def limits_crossed_error(self, args, item, qty_or_amount):
'''Raise exception for limits crossed'''
if qty_or_amount == "qty":
action_msg = _('To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.')
else:
action_msg = _('To allow over billing, update "Over Billing Allowance" in Accounts Settings or the Item.')
frappe.throw(_('This document is over limit by {0} {1} for item {4}. Are you making another {3} against the same {2}?')
.format(
frappe.bold(_(item["target_ref_field"].title())),
@ -219,9 +222,7 @@ class StatusUpdater(Document):
frappe.bold(_(args.get('target_dt'))),
frappe.bold(_(self.doctype)),
frappe.bold(item.get('item_code'))
) + '<br><br>' +
_('To allow over-billing or over-ordering, update "Allowance" in Stock Settings or the Item.'),
title = _('Limit Crossed'))
) + '<br><br>' + action_msg, OverAllowanceError, title = _('Limit Crossed'))
def update_qty(self, update_modified=True):
"""Updates qty or amount at row level
@ -294,7 +295,7 @@ class StatusUpdater(Document):
frappe.db.sql("""update `tab%(target_parent_dt)s`
set %(target_parent_field)s = round(
ifnull((select
ifnull(sum(if(%(target_ref_field)s > %(target_field)s, abs(%(target_field)s), abs(%(target_ref_field)s))), 0)
ifnull(sum(if(abs(%(target_ref_field)s) > abs(%(target_field)s), abs(%(target_field)s), abs(%(target_ref_field)s))), 0)
/ sum(abs(%(target_ref_field)s)) * 100
from `tab%(target_dt)s` where parent="%(name)s" having sum(abs(%(target_ref_field)s)) > 0), 0), 6)
%(update_modified)s
@ -358,19 +359,34 @@ class StatusUpdater(Document):
ref_doc.db_set("per_billed", per_billed)
ref_doc.set_status(update=True)
def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None):
def get_allowance_for(item_code, item_allowance={}, global_qty_allowance=None, global_amount_allowance=None, qty_or_amount="qty"):
"""
Returns the tolerance for the item, if not set, returns global tolerance
Returns the allowance for the item, if not set, returns global allowance
"""
if item_tolerance.get(item_code):
return item_tolerance[item_code], item_tolerance, global_tolerance
if qty_or_amount == "qty":
if item_allowance.get(item_code, frappe._dict()).get("qty"):
return item_allowance[item_code].qty, item_allowance, global_qty_allowance, global_amount_allowance
else:
if item_allowance.get(item_code, frappe._dict()).get("amount"):
return item_allowance[item_code].amount, item_allowance, global_qty_allowance, global_amount_allowance
tolerance = flt(frappe.db.get_value('Item',item_code,'tolerance') or 0)
qty_allowance, over_billing_allowance = \
frappe.db.get_value('Item', item_code, ['over_delivery_receipt_allowance', 'over_billing_allowance'])
if not tolerance:
if global_tolerance == None:
global_tolerance = flt(frappe.db.get_value('Stock Settings', None, 'tolerance'))
tolerance = global_tolerance
if qty_or_amount == "qty" and not qty_allowance:
if global_qty_allowance == None:
global_qty_allowance = flt(frappe.db.get_single_value('Stock Settings', 'over_delivery_receipt_allowance'))
qty_allowance = global_qty_allowance
elif qty_or_amount == "amount" and not over_billing_allowance:
if global_amount_allowance == None:
global_amount_allowance = flt(frappe.db.get_single_value('Accounts Settings', 'over_billing_allowance'))
over_billing_allowance = global_amount_allowance
item_tolerance[item_code] = tolerance
return tolerance, item_tolerance, global_tolerance
if qty_or_amount == "qty":
allowance = qty_allowance
item_allowance.setdefault(item_code, frappe._dict()).setdefault("qty", qty_allowance)
else:
allowance = over_billing_allowance
item_allowance.setdefault(item_code, frappe._dict()).setdefault("amount", over_billing_allowance)
return allowance, item_allowance, global_qty_allowance, global_amount_allowance

View File

@ -15,6 +15,9 @@ class calculate_taxes_and_totals(object):
self.calculate()
def calculate(self):
if not len(self.doc.get("items")):
return
self.discount_amount_applied = False
self._calculate()
@ -320,7 +323,7 @@ class calculate_taxes_and_totals(object):
self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
if self.doc.doctype in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]:
self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate) \
self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate, self.doc.precision("base_grand_total")) \
if self.doc.total_taxes_and_charges else self.doc.base_net_total
else:
self.doc.taxes_and_charges_added = self.doc.taxes_and_charges_deducted = 0.0

View File

@ -7,14 +7,8 @@ cur_frm.email_field = "email_id";
erpnext.LeadController = frappe.ui.form.Controller.extend({
setup: function () {
this.frm.make_methods = {
'Quotation': () => erpnext.utils.create_new_doc('Quotation', {
'quotation_to': this.frm.doc.doctype,
'party_name': this.frm.doc.name
}),
'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', {
'opportunity_from': this.frm.doc.doctype,
'party_name': this.frm.doc.name
})
'Quotation': this.make_quotation,
'Opportunity': this.create_opportunity
}
this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) {

View File

@ -19,6 +19,10 @@ frappe.ui.form.on("Opportunity", {
}
}
});
if (frm.doc.opportunity_from && frm.doc.party_name){
frm.trigger('set_contact_link');
}
},
onload_post_render: function(frm) {

View File

@ -87,7 +87,7 @@ def get_employee_emails_for_popup(communication_medium):
'parent': communication_medium,
'from_time': ['<=', now_time],
'to_time': ['>=', now_time],
}, fields=['employee_group'], debug=1)
}, fields=['employee_group'])
available_employee_groups = tuple([emp.employee_group for emp in available_employee_groups])

View File

@ -38,7 +38,7 @@ class Question(Document):
options = self.options
answers = [item.name for item in options if item.is_correct == True]
if len(answers) == 0:
frappe.throw("No correct answer is set for {0}".format(self.name))
frappe.throw(_("No correct answer is set for {0}".format(self.name)))
return None
elif len(answers) == 1:
return answers[0]

View File

@ -4,12 +4,13 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
class Quiz(Document):
def validate(self):
if self.passing_score > 100:
frappe.throw("Passing Score value should be between 0 and 100")
frappe.throw(_("Passing Score value should be between 0 and 100"))
def allowed_attempt(self, enrollment, quiz_name):
if self.max_attempts == 0:
@ -17,7 +18,7 @@ class Quiz(Document):
try:
if len(frappe.get_all("Quiz Activity", {'enrollment': enrollment.name, 'quiz': quiz_name})) >= self.max_attempts:
frappe.msgprint("Maximum attempts for this quiz reached!")
frappe.msgprint(_("Maximum attempts for this quiz reached!"))
return False
else:
return True
@ -56,5 +57,5 @@ def compare_list_elementwise(*args):
else:
return False
except TypeError:
frappe.throw("Compare List function takes on list arguments")
frappe.throw(_("Compare List function takes on list arguments"))

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.model.document import Document
from erpnext.education.api import get_grade
from frappe.utils.pdf import get_pdf
@ -79,7 +80,7 @@ def get_attendance_count(student, academic_year, academic_term=None):
from_date, to_date = frappe.db.get_value("Academic Term", academic_term, ["term_start_date", "term_end_date"])
if from_date and to_date:
attendance = dict(frappe.db.sql('''select status, count(student) as no_of_days
from `tabStudent Attendance` where student = %s
from `tabStudent Attendance` where student = %s
and date between %s and %s group by status''',
(student, from_date, to_date)))
if "Absent" not in attendance.keys():
@ -88,4 +89,4 @@ def get_attendance_count(student, academic_year, academic_term=None):
attendance["Present"] = 0
return attendance
else:
frappe.throw("Provide the academic year and set the starting and ending date.")
frappe.throw(_("Provide the academic year and set the starting and ending date."))

View File

@ -148,7 +148,7 @@ def enroll_in_program(program_name, student=None):
# Check if self enrollment in allowed
program = frappe.get_doc('Program', program_name)
if not program.allow_self_enroll:
return frappe.throw("You are not allowed to enroll for this course")
return frappe.throw(_("You are not allowed to enroll for this course"))
student = get_current_student()
if not student:
@ -162,7 +162,7 @@ def enroll_in_program(program_name, student=None):
# Check if self enrollment in allowed
program = frappe.get_doc('Program', program_name)
if not program.allow_self_enroll:
return frappe.throw("You are not allowed to enroll for this course")
return frappe.throw(_("You are not allowed to enroll for this course"))
# Enroll in program
program_enrollment = student.enroll_in_program(program_name)
@ -185,7 +185,7 @@ def add_activity(course, content_type, content, program):
student = get_current_student()
if not student:
return frappe.throw("Student with email {0} does not exist".format(frappe.session.user), frappe.DoesNotExistError)
return frappe.throw(_("Student with email {0} does not exist".format(frappe.session.user)), frappe.DoesNotExistError)
enrollment = get_or_create_course_enrollment(course, program)
if content_type == 'Quiz':
@ -220,7 +220,7 @@ def get_quiz(quiz_name, course):
quiz = frappe.get_doc("Quiz", quiz_name)
questions = quiz.get_questions()
except:
frappe.throw("Quiz {0} does not exist".format(quiz_name))
frappe.throw(_("Quiz {0} does not exist".format(quiz_name)))
return None
questions = [{
@ -347,7 +347,7 @@ def get_or_create_course_enrollment(course, program):
if not course_enrollment:
program_enrollment = get_enrollment('program', program, student.name)
if not program_enrollment:
frappe.throw("You are not enrolled in program {0}".format(program))
frappe.throw(_("You are not enrolled in program {0}".format(program)))
return
return student.enroll_in_course(course_name=course, program_enrollment=get_enrollment('program', program, student.name))
else:

View File

@ -124,7 +124,7 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
else:
so = frappe.get_doc("Sales Order", so)
frappe.db.commit()
return so
@ -252,6 +252,6 @@ def get_tax_account_head(tax):
{"parent": "Shopify Settings", "shopify_tax": tax_title}, "tax_account")
if not tax_account:
frappe.throw("Tax Account not specified for Shopify Tax {0}".format(tax.get("title")))
frappe.throw(_("Tax Account not specified for Shopify Tax {0}".format(tax.get("title"))))
return tax_account

View File

@ -7,7 +7,9 @@ import frappe
from frappe import _
from frappe.model.document import Document
from requests_oauthlib import OAuth2Session
import json, requests
import json
import requests
import traceback
from erpnext import encode_company_abbr
# QuickBooks requires a redirect URL, User will be redirect to this URL
@ -32,7 +34,6 @@ def callback(*args, **kwargs):
class QuickBooksMigrator(Document):
def __init__(self, *args, **kwargs):
super(QuickBooksMigrator, self).__init__(*args, **kwargs)
from pprint import pprint
self.oauth = OAuth2Session(
client_id=self.client_id,
redirect_uri=self.redirect_url,
@ -46,7 +47,9 @@ class QuickBooksMigrator(Document):
if self.company:
# We need a Cost Center corresponding to the selected erpnext Company
self.default_cost_center = frappe.db.get_value('Company', self.company, 'cost_center')
self.default_warehouse = frappe.get_all('Warehouse', filters={"company": self.company, "is_group": 0})[0]["name"]
company_warehouses = frappe.get_all('Warehouse', filters={"company": self.company, "is_group": 0})
if company_warehouses:
self.default_warehouse = company_warehouses[0].name
if self.authorization_endpoint:
self.authorization_url = self.oauth.authorization_url(self.authorization_endpoint)[0]
@ -218,7 +221,7 @@ class QuickBooksMigrator(Document):
def _fetch_general_ledger(self):
try:
query_uri = "{}/company/{}/reports/GeneralLedger".format(self.api_endpoint ,self.quickbooks_company_id)
query_uri = "{}/company/{}/reports/GeneralLedger".format(self.api_endpoint, self.quickbooks_company_id)
response = self._get(query_uri,
params={
"columns": ",".join(["tx_date", "txn_type", "credit_amt", "debt_amt"]),
@ -493,17 +496,17 @@ class QuickBooksMigrator(Document):
"account_currency": customer["CurrencyRef"]["value"],
"company": self.company,
})[0]["name"]
except Exception as e:
except Exception:
receivable_account = None
erpcustomer = frappe.get_doc({
"doctype": "Customer",
"quickbooks_id": customer["Id"],
"customer_name" : encode_company_abbr(customer["DisplayName"], self.company),
"customer_type" : "Individual",
"customer_group" : "Commercial",
"customer_name": encode_company_abbr(customer["DisplayName"], self.company),
"customer_type": "Individual",
"customer_group": "Commercial",
"default_currency": customer["CurrencyRef"]["value"],
"accounts": [{"company": self.company, "account": receivable_account}],
"territory" : "All Territories",
"territory": "All Territories",
"company": self.company,
}).insert()
if "BillAddr" in customer:
@ -521,7 +524,7 @@ class QuickBooksMigrator(Document):
item_dict = {
"doctype": "Item",
"quickbooks_id": item["Id"],
"item_code" : encode_company_abbr(item["Name"], self.company),
"item_code": encode_company_abbr(item["Name"], self.company),
"stock_uom": "Unit",
"is_stock_item": 0,
"item_group": "All Item Groups",
@ -549,14 +552,14 @@ class QuickBooksMigrator(Document):
erpsupplier = frappe.get_doc({
"doctype": "Supplier",
"quickbooks_id": vendor["Id"],
"supplier_name" : encode_company_abbr(vendor["DisplayName"], self.company),
"supplier_group" : "All Supplier Groups",
"supplier_name": encode_company_abbr(vendor["DisplayName"], self.company),
"supplier_group": "All Supplier Groups",
"company": self.company,
}).insert()
if "BillAddr" in vendor:
self._create_address(erpsupplier, "Supplier", vendor["BillAddr"], "Billing")
if "ShipAddr" in vendor:
self._create_address(erpsupplier, "Supplier",vendor["ShipAddr"], "Shipping")
self._create_address(erpsupplier, "Supplier", vendor["ShipAddr"], "Shipping")
except Exception as e:
self._log_error(e)
@ -829,7 +832,7 @@ class QuickBooksMigrator(Document):
"currency": invoice["CurrencyRef"]["value"],
"conversion_rate": invoice.get("ExchangeRate", 1),
"posting_date": invoice["TxnDate"],
"due_date": invoice.get("DueDate", invoice["TxnDate"]),
"due_date": invoice.get("DueDate", invoice["TxnDate"]),
"credit_to": credit_to_account,
"supplier": frappe.get_all("Supplier",
filters={
@ -1200,7 +1203,7 @@ class QuickBooksMigrator(Document):
def _create_address(self, entity, doctype, address, address_type):
try :
try:
if not frappe.db.exists({"doctype": "Address", "quickbooks_id": address["Id"]}):
frappe.get_doc({
"doctype": "Address",
@ -1252,8 +1255,6 @@ class QuickBooksMigrator(Document):
def _log_error(self, execption, data=""):
import json, traceback
traceback.print_exc()
frappe.log_error(title="QuickBooks Migration Error",
message="\n".join([
"Data",

View File

@ -296,7 +296,9 @@ class TallyMigration(Document):
else:
function = voucher_to_journal_entry
try:
vouchers.append(function(voucher))
processed_voucher = function(voucher)
if processed_voucher:
vouchers.append(processed_voucher)
except:
self.log(voucher)
return vouchers
@ -342,6 +344,10 @@ class TallyMigration(Document):
account_field = "credit_to"
account_name = encode_company_abbr(self.tally_creditors_account, self.erpnext_company)
price_list_field = "buying_price_list"
else:
# Do not handle vouchers other than "Purchase", "Debit Note", "Sales" and "Credit Note"
# Do not handle Custom Vouchers either
return
invoice = {
"doctype": doctype,

View File

@ -30,7 +30,7 @@ class ClinicalProcedureTemplate(Document):
try:
frappe.delete_doc("Item",self.item)
except Exception:
frappe.throw("""Not permitted. Please disable the Procedure Template""")
frappe.throw(_("""Not permitted. Please disable the Procedure Template"""))
def get_item_details(self, args=None):
item = frappe.db.sql("""select stock_uom, item_name

View File

@ -21,9 +21,9 @@ frappe.ui.form.on('Patient', {
});
}
if (frm.doc.patient_name && frappe.user.has_role("Physician")) {
frm.add_custom_button(__('Medical Record'), function () {
frm.add_custom_button(__('Patient History'), function () {
frappe.route_options = { "patient": frm.doc.name };
frappe.set_route("medical_record");
frappe.set_route("patient_history");
},"View");
}
if (!frm.doc.__islocal && (frappe.user.has_role("Nursing User") || frappe.user.has_role("Physician"))) {

View File

@ -30,9 +30,9 @@ frappe.ui.form.on('Patient Appointment', {
};
});
if(frm.doc.patient){
frm.add_custom_button(__('Medical Record'), function() {
frm.add_custom_button(__('Patient History'), function() {
frappe.route_options = {"patient": frm.doc.patient};
frappe.set_route("medical_record");
frappe.set_route("patient_history");
},__("View"));
}
if(frm.doc.status == "Open"){
@ -298,7 +298,7 @@ var get_procedure_prescribed = function(frm){
});
}
else{
frappe.msgprint("Please select Patient to get prescribed procedure");
frappe.msgprint(__("Please select Patient to get prescribed procedure"));
}
};

View File

@ -41,10 +41,10 @@ frappe.ui.form.on('Patient Encounter', {
}
});
}
frm.add_custom_button(__('Medical Record'), function() {
frm.add_custom_button(__('Patient History'), function() {
if (frm.doc.patient) {
frappe.route_options = {"patient": frm.doc.patient};
frappe.set_route("medical_record");
frappe.set_route("patient_history");
} else {
frappe.msgprint(__("Please select Patient"));
}
@ -160,7 +160,7 @@ var btn_create_vital_signs = function (frm) {
var btn_create_procedure = function (frm) {
if(!frm.doc.patient){
frappe.throw("Please select patient");
frappe.throw(__("Please select patient"));
}
frappe.route_options = {
"patient": frm.doc.patient,

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,182 +0,0 @@
frappe.provide("frappe.medical_record");
frappe.pages['medical_record'].on_page_load = function(wrapper) {
var me = this;
var page = frappe.ui.make_app_page({
parent: wrapper,
title: 'Medical Record',
});
frappe.breadcrumbs.add("Medical");
page.main.html(frappe.render_template("patient_select", {}));
var patient = frappe.ui.form.make_control({
parent: page.main.find(".patient"),
df: {
fieldtype: "Link",
options: "Patient",
fieldname: "patient",
change: function(){
page.main.find(".frappe-list").html("");
draw_page(patient.get_value(), me);
}
},
only_input: true,
});
patient.refresh();
this.page.main.on("click", ".medical_record-message", function() {
var doctype = $(this).attr("data-doctype"),
docname = $(this).attr("data-docname");
if (doctype && docname) {
frappe.route_options = {
scroll_to: { "doctype": doctype, "name": docname }
};
frappe.set_route(["Form", doctype, docname]);
}
});
this.page.sidebar.on("click", ".edit-details", function() {
patient = patient.get_value();
if (patient) {
frappe.set_route(["Form", "Patient", patient]);
}
});
};
frappe.pages['medical_record'].refresh = function() {
var me = this;
if(frappe.route_options) {
if(frappe.route_options.patient){
me.page.main.find(".frappe-list").html("");
var patient = frappe.route_options.patient;
draw_page(patient,me);
me.page.main.find("[data-fieldname='patient']").val(patient);
frappe.route_options = null;
}
}
};
var show_patient_info = function(patient, me){
frappe.call({
"method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail",
args: {
patient: patient
},
callback: function (r) {
var data = r.message;
var details = "";
if(data.email) details += "<br><b>Email :</b> " + data.email;
if(data.mobile) details += "<br><b>Mobile :</b> " + data.mobile;
if(data.occupation) details += "<br><b>Occupation :</b> " + data.occupation;
if(data.blood_group) details += "<br><b>Blood group : </b> " + data.blood_group;
if(data.allergies) details += "<br><br><b>Allergies : </b> "+ data.allergies;
if(data.medication) details += "<br><b>Medication : </b> "+ data.medication;
if(data.alcohol_current_use) details += "<br><br><b>Alcohol use : </b> "+ data.alcohol_current_use;
if(data.alcohol_past_use) details += "<br><b>Alcohol past use : </b> "+ data.alcohol_past_use;
if(data.tobacco_current_use) details += "<br><b>Tobacco use : </b> "+ data.tobacco_current_use;
if(data.tobacco_past_use) details += "<br><b>Tobacco past use : </b> "+ data.tobacco_past_use;
if(data.medical_history) details += "<br><br><b>Medical history : </b> "+ data.medical_history;
if(data.surgical_history) details += "<br><b>Surgical history : </b> "+ data.surgical_history;
if(data.surrounding_factors) details += "<br><br><b>Occupational hazards : </b> "+ data.surrounding_factors;
if(data.other_risk_factors) details += "<br><b>Other risk factors : </b> " + data.other_risk_factors;
if(data.patient_details) details += "<br><br><b>More info : </b> " + data.patient_details;
if(details){
details = "<div style='padding-left:10px; font-size:13px;' align='center'></br><b class='text-muted'>Patient Details</b>" + details + "</div>";
}
var vitals = "";
if(data.temperature) vitals += "<br><b>Temperature :</b> " + data.temperature;
if(data.pulse) vitals += "<br><b>Pulse :</b> " + data.pulse;
if(data.respiratory_rate) vitals += "<br><b>Respiratory Rate :</b> " + data.respiratory_rate;
if(data.bp) vitals += "<br><b>BP :</b> " + data.bp;
if(data.bmi) vitals += "<br><b>BMI :</b> " + data.bmi;
if(data.height) vitals += "<br><b>Height :</b> " + data.height;
if(data.weight) vitals += "<br><b>Weight :</b> " + data.weight;
if(data.signs_date) vitals += "<br><b>Date :</b> " + data.signs_date;
if(vitals){
vitals = "<div style='padding-left:10px; font-size:13px;' align='center'></br><b class='text-muted'>Vital Signs</b>" + vitals + "<br></div>";
details = vitals + details;
}
if(details) details += "<div align='center'><br><a class='btn btn-default btn-sm edit-details'>Edit Details</a></b> </div>";
me.page.sidebar.addClass("col-sm-3");
me.page.sidebar.html(details);
me.page.wrapper.find(".layout-main-section-wrapper").addClass("col-sm-9");
}
});
};
var draw_page = function(patient, me){
frappe.model.with_doctype("Patient Medical Record", function() {
me.page.list = new frappe.ui.BaseList({
hide_refresh: true,
page: me.page,
method: 'erpnext.healthcare.page.medical_record.medical_record.get_feed',
args: {name: patient},
parent: $("<div></div>").appendTo(me.page.main),
render_view: function(values) {
var me = this;
var wrapper = me.page.main.find(".result-list").get(0);
values.map(function (value) {
var row = $('<div class="list-row">').data("data", value).appendTo($(wrapper)).get(0);
new frappe.medical_record.Feed(row, value);
});
},
show_filters: true,
doctype: "Patient Medical Record",
});
show_patient_info(patient, me);
me.page.list.run();
});
};
frappe.medical_record.last_feed_date = false;
frappe.medical_record.Feed = Class.extend({
init: function(row, data) {
this.scrub_data(data);
this.add_date_separator(row, data);
if(!data.add_class)
data.add_class = "label-default";
data.link = "";
if (data.reference_doctype && data.reference_name) {
data.link = frappe.format(data.reference_name, {fieldtype: "Link", options: data.reference_doctype},
{label: __(data.reference_doctype)});
}
$(row)
.append(frappe.render_template("medical_record_row", data))
.find("a").addClass("grey");
},
scrub_data: function(data) {
data.by = frappe.user.full_name(data.owner);
data.imgsrc = frappe.utils.get_file_link(frappe.user_info(data.owner).image);
data.icon = "icon-flag";
},
add_date_separator: function(row, data) {
var date = frappe.datetime.str_to_obj(data.creation);
var last = frappe.medical_record.last_feed_date;
if((last && frappe.datetime.obj_to_str(last) != frappe.datetime.obj_to_str(date)) || (!last)) {
var diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
if(diff < 1) {
var pdate = 'Today';
} else if(diff < 2) {
pdate = 'Yesterday';
} else {
pdate = frappe.datetime.global_date_format(date);
}
data.date_sep = pdate;
data.date_class = pdate=='Today' ? "date-indicator blue" : "date-indicator";
} else {
data.date_sep = null;
data.date_class = "";
}
frappe.medical_record.last_feed_date = date;
}
});

View File

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, ESS LLP and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import cint
@frappe.whitelist()
def get_feed(start, page_length, name):
"""get feed"""
result = frappe.db.sql("""select name, owner, modified, creation,
reference_doctype, reference_name, subject
from `tabPatient Medical Record`
where patient=%(patient)s
order by creation desc
limit %(start)s, %(page_length)s""",
{
"start": cint(start),
"page_length": cint(page_length),
"patient": name
}, as_dict=True)
return result

View File

@ -1,21 +0,0 @@
<div class="row medical_record-row" data-creation="{%= creation.split(" ")[0] + " 00:00:00" %}">
<div class="col-xs-3 text-right medical_record-date"><span class="{%= date_class %}">
{%= date_sep || "" %}</span>
</div>
<div class="col-xs-9 medical_record-message"
data-doctype="{%= reference_doctype %}"
data-docname="{%= reference_name %}"
title="{%= by %} / {%= frappe.datetime.str_to_user(creation) %}">
<span class="avatar avatar-small">
<div class="avatar-frame" style="background-image: url({{ imgsrc }});"></div>
<!-- <img src="{%= imgsrc %}"> -->
</span>
<span class="small">
{% if (reference_doctype && reference_name) { %}
{%= __("{0}: {1}", [link, "<strong>" + subject + "</strong>"]) %}
{% } else { %}
{%= subject %}
{% } %}
</span>
</div>
</div>

View File

@ -1,5 +0,0 @@
<div class="text-center col-sm-9" style="padding: 40px;">
<p>{%= __("Select Patient") %}</p>
<p class="patient" style="margin: auto; max-width: 300px; margin-bottom: 20px;"></p>
</div>

View File

@ -14,6 +14,10 @@
margin-bottom: -4px;
}
.medical_record-row > * {
z-index: -999;
}
.date-indicator {
background:none;
font-size:12px;
@ -35,6 +39,61 @@
color: #5e64ff;
}
.div-bg-color {
background: #fafbfc;
}
.bg-color-white {
background: #FFFFFF;
}
.d-flex {
display: flex;
}
.width-full {
width: 100%;
}
.p-3 {
padding: 16px;
}
.mt-2 {
margin-top: 8px;
}
.mr-3 {
margin-right: 16px;
}
.Box {
background-color: #fff;
border: 1px solid #d1d5da;
border-radius: 3px;
}
.flex-column {
flex-direction: column;
}
.avatar {
display: inline-block;
overflow: hidden;
line-height: 1;
vertical-align: middle;
border-radius: 3px;
}
.py-3 {
padding-top: 16px;
padding-bottom: 16px;
}
.border-bottom {
border-bottom: 1px #e1e4e8 solid;
}
.date-indicator.blue::after {
background: #5e64ff;
}
@ -65,8 +124,3 @@
#page-medical_record .list-filters {
display: none ;
}
#page-medical_record .octicon-heart {
color: #ff5858;
margin: 0px 5px;
}

View File

@ -0,0 +1,20 @@
<div class="col-sm-12">
<div class="col-sm-3">
<p class="text-center">{%= __("Select Patient") %}</p>
<p class="patient" style="margin: auto; max-width: 300px; margin-bottom: 20px;"></p>
<div class="patient_details" style="z-index=0"></div>
</div>
<div class="col-sm-9 patient_documents">
<div class="col-sm-12">
<div class="col-sm-12 show_chart_btns" align="center">
</div>
<div id="chart" class="col-sm-12 patient_vital_charts">
</div>
</div>
<div class="col-sm-12 patient_documents_list">
</div>
<div class="col-sm-12 text-center py-3">
<a class="btn btn-sm btn-default btn-get-records" style="display:none">More..</a>
</div>
</div>
</div>

View File

@ -0,0 +1,300 @@
frappe.provide("frappe.patient_history");
frappe.pages['patient_history'].on_page_load = function(wrapper) {
var me = this;
var page = frappe.ui.make_app_page({
parent: wrapper,
title: 'Patient History',
single_column: true
});
frappe.breadcrumbs.add("Healthcare");
let pid = '';
page.main.html(frappe.render_template("patient_history", {}));
var patient = frappe.ui.form.make_control({
parent: page.main.find(".patient"),
df: {
fieldtype: "Link",
options: "Patient",
fieldname: "patient",
change: function(){
if(pid != patient.get_value() && patient.get_value()){
me.start = 0;
me.page.main.find(".patient_documents_list").html("");
get_documents(patient.get_value(), me);
show_patient_info(patient.get_value(), me);
show_patient_vital_charts(patient.get_value(), me, "bp", "mmHg", "Blood Pressure");
}
pid = patient.get_value();
}
},
only_input: true,
});
patient.refresh();
if (frappe.route_options){
patient.set_value(frappe.route_options.patient);
}
this.page.main.on("click", ".btn-show-chart", function() {
var btn_show_id = $(this).attr("data-show-chart-id"), pts = $(this).attr("data-pts");
var title = $(this).attr("data-title");
show_patient_vital_charts(patient.get_value(), me, btn_show_id, pts, title);
});
this.page.main.on("click", ".btn-more", function() {
var doctype = $(this).attr("data-doctype"), docname = $(this).attr("data-docname");
if(me.page.main.find("."+docname).parent().find('.document-html').attr('data-fetched') == "1"){
me.page.main.find("."+docname).hide();
me.page.main.find("."+docname).parent().find('.document-html').show();
}else{
if(doctype && docname){
let exclude = ["patient", "patient_name", 'patient_sex', "encounter_date"];
frappe.call({
method: "erpnext.healthcare.utils.render_doc_as_html",
args:{
doctype: doctype,
docname: docname,
exclude_fields: exclude
},
callback: function(r) {
if (r.message){
me.page.main.find("."+docname).hide();
me.page.main.find("."+docname).parent().find('.document-html').html(r.message.html+"\
<div align='center'><a class='btn octicon octicon-chevron-up btn-default btn-xs\
btn-less' data-doctype='"+doctype+"' data-docname='"+docname+"'></a></div>");
me.page.main.find("."+docname).parent().find('.document-html').show();
me.page.main.find("."+docname).parent().find('.document-html').attr('data-fetched', "1");
}
},
freeze: true
});
}
}
});
this.page.main.on("click", ".btn-less", function() {
var docname = $(this).attr("data-docname");
me.page.main.find("."+docname).parent().find('.document-id').show();
me.page.main.find("."+docname).parent().find('.document-html').hide();
});
me.start = 0;
me.page.main.on("click", ".btn-get-records", function(){
get_documents(patient.get_value(), me);
});
};
var get_documents = function(patient, me){
frappe.call({
"method": "erpnext.healthcare.page.patient_history.patient_history.get_feed",
args: {
name: patient,
start: me.start,
page_length: 20
},
callback: function (r) {
var data = r.message;
if(data.length){
add_to_records(me, data);
}else{
me.page.main.find(".patient_documents_list").append("<div class='text-muted' align='center'><br><br>No more records..<br><br></div>");
me.page.main.find(".btn-get-records").hide();
}
}
});
};
var add_to_records = function(me, data){
var details = "<ul class='nav nav-pills nav-stacked'>";
var i;
for(i=0; i<data.length; i++){
if(data[i].reference_doctype){
let label = '';
if(data[i].subject){
label += "<br/>"+data[i].subject;
}
data[i] = add_date_separator(data[i]);
if(frappe.user_info(data[i].owner).image){
data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
}
else{
data[i].imgsrc = false;
}
var time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
time_line_heading += data[i].reference_doctype + " - "+ data[i].reference_name;
details += `<li data-toggle='pill' class='patient_doc_menu'
data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
<div class='col-sm-12 d-flex border-bottom py-3'>`;
if (data[i].imgsrc){
details += `<span class='mr-3'>
<img class='avtar' src='${data[i].imgsrc}' width='32' height='32'>
</img>
</span>`;
}else{
details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'><div align='center' class='standard-image'
style='background-color: #fafbfc;'>${data[i].practitioner ? data[i].practitioner.charAt(0) : "U"}</div></span>`;
}
details += `<div class='d-flex flex-column width-full'>
<div>
`+time_line_heading+` on
<span>
${data[i].date_sep}
</span>
</div>
<div class='Box p-3 mt-2'>
<span class='${data[i].reference_name} document-id'>${label}
<div align='center'>
<a class='btn octicon octicon-chevron-down btn-default btn-xs btn-more'
data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
</a>
</div>
</span>
<span class='document-html' hidden data-fetched="0">
</span>
</div>
</div>
</div>
</li>`;
}
}
details += "</ul>";
me.page.main.find(".patient_documents_list").append(details);
me.start += data.length;
if(data.length===20){
me.page.main.find(".btn-get-records").show();
}else{
me.page.main.find(".btn-get-records").hide();
me.page.main.find(".patient_documents_list").append("<div class='text-muted' align='center'><br><br>No more records..<br><br></div>");
}
};
var add_date_separator = function(data) {
var date = frappe.datetime.str_to_obj(data.creation);
var diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
if(diff < 1) {
var pdate = 'Today';
} else if(diff < 2) {
pdate = 'Yesterday';
} else {
pdate = frappe.datetime.global_date_format(date);
}
data.date_sep = pdate;
return data;
};
var show_patient_info = function(patient, me){
frappe.call({
"method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail",
args: {
patient: patient
},
callback: function (r) {
var data = r.message;
var details = "";
if(data.image){
details += "<div><img class='thumbnail' width=75% src='"+data.image+"'></div>";
}
details += "<b>" + data.patient_name +"</b><br>" + data.sex;
if(data.email) details += "<br>" + data.email;
if(data.mobile) details += "<br>" + data.mobile;
if(data.occupation) details += "<br><br><b>Occupation :</b> " + data.occupation;
if(data.blood_group) details += "<br><b>Blood group : </b> " + data.blood_group;
if(data.allergies) details += "<br><br><b>Allergies : </b> "+ data.allergies.replace("\n", "<br>");
if(data.medication) details += "<br><b>Medication : </b> "+ data.medication.replace("\n", "<br>");
if(data.alcohol_current_use) details += "<br><br><b>Alcohol use : </b> "+ data.alcohol_current_use;
if(data.alcohol_past_use) details += "<br><b>Alcohol past use : </b> "+ data.alcohol_past_use;
if(data.tobacco_current_use) details += "<br><b>Tobacco use : </b> "+ data.tobacco_current_use;
if(data.tobacco_past_use) details += "<br><b>Tobacco past use : </b> "+ data.tobacco_past_use;
if(data.medical_history) details += "<br><br><b>Medical history : </b> "+ data.medical_history.replace("\n", "<br>");
if(data.surgical_history) details += "<br><b>Surgical history : </b> "+ data.surgical_history.replace("\n", "<br>");
if(data.surrounding_factors) details += "<br><br><b>Occupational hazards : </b> "+ data.surrounding_factors.replace("\n", "<br>");
if(data.other_risk_factors) details += "<br><b>Other risk factors : </b> " + data.other_risk_factors.replace("\n", "<br>");
if(data.patient_details) details += "<br><br><b>More info : </b> " + data.patient_details.replace("\n", "<br>");
if(details){
details = "<div style='padding-left:10px; font-size:13px;' align='center'>" + details + "</div>";
}
me.page.main.find(".patient_details").html(details);
}
});
};
var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
frappe.call({
method: "erpnext.healthcare.utils.get_patient_vitals",
args:{
patient: patient
},
callback: function(r) {
if (r.message){
var show_chart_btns_html = "<div style='padding-top:5px;'><a class='btn btn-default btn-xs btn-show-chart' \
data-show-chart-id='bp' data-pts='mmHg' data-title='Blood Pressure'>Blood Pressure</a>\
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='pulse_rate' \
data-pts='per Minutes' data-title='Respiratory/Pulse Rate'>Respiratory/Pulse Rate</a>\
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' \
data-pts='°C or °F' data-title='Temperature'>Temperature</a>\
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' \
data-pts='bmi' data-title='BMI'>BMI</a></div>";
me.page.main.find(".show_chart_btns").html(show_chart_btns_html);
var data = r.message;
let labels = [], datasets = [];
let bp_systolic = [], bp_diastolic = [], temperature = [];
let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = [];
for(var i=0; i<data.length; i++){
labels.push(data[i].signs_date+"||"+data[i].signs_time);
if(btn_show_id=="bp"){
bp_systolic.push(data[i].bp_systolic);
bp_diastolic.push(data[i].bp_diastolic);
}
if(btn_show_id=="temperature"){
temperature.push(data[i].temperature);
}
if(btn_show_id=="pulse_rate"){
pulse.push(data[i].pulse);
respiratory_rate.push(data[i].respiratory_rate);
}
if(btn_show_id=="bmi"){
bmi.push(data[i].bmi);
height.push(data[i].height);
weight.push(data[i].weight);
}
}
if(btn_show_id=="temperature"){
datasets.push({name: "Temperature", values: temperature, chartType:'line'});
}
if(btn_show_id=="bmi"){
datasets.push({name: "BMI", values: bmi, chartType:'line'});
datasets.push({name: "Height", values: height, chartType:'line'});
datasets.push({name: "Weight", values: weight, chartType:'line'});
}
if(btn_show_id=="bp"){
datasets.push({name: "BP Systolic", values: bp_systolic, chartType:'line'});
datasets.push({name: "BP Diastolic", values: bp_diastolic, chartType:'line'});
}
if(btn_show_id=="pulse_rate"){
datasets.push({name: "Heart Rate / Pulse", values: pulse, chartType:'line'});
datasets.push({name: "Respiratory Rate", values: respiratory_rate, chartType:'line'});
}
new Chart( ".patient_vital_charts", {
data: {
labels: labels,
datasets: datasets
},
title: title,
type: 'axis-mixed', // 'axis-mixed', 'bar', 'line', 'pie', 'percentage'
height: 150,
colors: ['purple', '#ffa3ef', 'light-blue'],
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' ' + pts,
}
});
}else{
me.page.main.find(".patient_vital_charts").html("");
me.page.main.find(".show_chart_btns").html("");
}
}
});
};

View File

@ -1,18 +1,21 @@
{
"content": null,
"creation": "2016-06-09 11:33:14.025787",
"creation": "2018-08-08 17:09:13.816199",
"docstatus": 0,
"doctype": "Page",
"icon": "icon-play",
"icon": "",
"idx": 0,
"modified": "2018-08-06 11:40:39.705660",
"modified": "2018-08-08 17:09:55.969424",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "medical_record",
"name": "patient_history",
"owner": "Administrator",
"page_name": "medical_record",
"page_name": "patient_history",
"restrict_to_domain": "Healthcare",
"roles": [
{
"role": "Healthcare Administrator"
},
{
"role": "Physician"
}
@ -21,5 +24,5 @@
"standard": "Yes",
"style": null,
"system_page": 0,
"title": "Medical Record"
"title": "Patient History"
}

Some files were not shown because too many files have changed in this diff Show More