Merge branch 'develop' into usregional

This commit is contained in:
Nabin Hait 2019-01-29 12:14:11 +05:30 committed by GitHub
commit 82421e24f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 14596 additions and 12989 deletions

View File

@ -34,7 +34,6 @@ before_script:
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench use test_site
- bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- bench build
- bench scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json
- bench start &

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '10.1.77'
__version__ = '10.1.80'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -31,3 +31,13 @@ def make_bank_account(doctype, docname):
doc.is_default = 1
return doc
@frappe.whitelist()
def get_party_bank_account(party_type, party):
return frappe.db.get_value(party_type,
party, 'default_bank_account')
@frappe.whitelist()
def get_bank_account_details(bank_account):
return frappe.db.get_value("Bank Account",
bank_account, ['account', 'bank', 'bank_account_no'], as_dict=1)

View File

@ -284,7 +284,12 @@ frappe.ui.form.on('Payment Entry', {
() => frm.events.get_outstanding_documents(frm),
() => frm.events.hide_unhide_fields(frm),
() => frm.events.set_dynamic_labels(frm),
() => { frm.set_party_account_based_on_party = false; }
() => {
frm.set_party_account_based_on_party = false;
if (r.message.bank_account) {
frm.set_value("bank_account", r.message.bank_account);
}
}
]);
}
}
@ -833,6 +838,25 @@ frappe.ui.form.on('Payment Entry', {
}
})
}
},
bank_account: function(frm) {
const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to";
if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) {
frappe.call({
method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account_details",
args: {
bank_account: frm.doc.bank_account
},
callback: function(r) {
if (r.message) {
frm.set_value(field, r.message.account);
frm.set_value('bank', r.message.bank);
frm.set_value('bank_account_no', r.message.bank_account_no);
}
}
});
}
}
});

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@ -379,24 +380,24 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "party",
"fieldname": "contact_person",
"fieldtype": "Link",
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type",
"description": "",
"fieldname": "party_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Contact",
"label": "Party Name",
"length": 0,
"no_copy": 0,
"options": "Contact",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -444,24 +445,24 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type",
"description": "",
"fieldname": "party_name",
"fieldtype": "Data",
"depends_on": "party",
"fieldname": "bank_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Party Name",
"label": "Bank Account",
"length": 0,
"no_copy": 0,
"options": "Bank Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -509,6 +510,40 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "party",
"fieldname": "contact_person",
"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": "Contact",
"length": 0,
"no_copy": 0,
"options": "Contact",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1867,6 +1902,72 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "bank_account.bank",
"fieldname": "bank",
"fieldtype": "Read Only",
"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",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "bank_account.bank_account_no",
"fieldname": "bank_account_no",
"fieldtype": "Read Only",
"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 No",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -2040,7 +2141,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-09-25 14:38:48.312629",
"modified": "2019-01-15 15:58:40.742601",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@ -12,6 +12,7 @@ from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_ban
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details
from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status
from six import string_types, iteritems
@ -88,6 +89,16 @@ class PaymentEntry(AccountsController):
.format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name))
def set_bank_account_data(self):
if self.bank_account:
bank_data = get_bank_account_details(self.bank_account)
field = "paid_from" if self.payment_type == "Pay" else "paid_to"
self.bank = bank_data.bank
self.bank_account_no = bank_data.bank_account_no
self.set(field, bank_data.account)
def validate_allocated_amount(self):
for d in self.get("references"):
if (flt(d.allocated_amount))> 0:
@ -670,6 +681,7 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac
@frappe.whitelist()
def get_party_details(company, party_type, party, date, cost_center=None):
bank_account = ''
if not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
@ -680,13 +692,16 @@ def get_party_details(company, party_type, party, date, cost_center=None):
_party_name = "title" if party_type == "Student" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
if party_type in ["Customer", "Supplier"]:
bank_account = get_party_bank_account(party_type, party)
return {
"party_account": party_account,
"party_name": party_name,
"party_account_currency": account_currency,
"party_balance": party_balance,
"account_balance": account_balance
"account_balance": account_balance,
"bank_account": bank_account
}
@ -890,6 +905,11 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.allocate_payment_amount = 1
pe.letter_head = doc.get("letter_head")
if pe.party_type in ["Customer", "Supplier"]:
bank_account = get_party_bank_account(pe.party_type, pe.party)
pe.set("bank_account", bank_account)
pe.set_bank_account_data()
# only Purchase Invoice can be blocked individually
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
frappe.msgprint(_('{0} is on hold till {1}'.format(doc.name, doc.release_date)))

View File

@ -1,23 +1,34 @@
{
"allow_copy": 1,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2014-07-09 12:04:51.681583",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 0,
"engine": "InnoDB",
"fields": [
{
"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": 0,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
@ -26,22 +37,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "party_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": "Party Type",
"length": 0,
"no_copy": 0,
@ -50,23 +69,31 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "party",
"fieldtype": "Dynamic 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": "Party",
"length": 0,
"no_copy": 0,
@ -75,22 +102,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "receivable_payable_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": "Receivable / Payable Account",
"length": 0,
"no_copy": 0,
@ -100,22 +135,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bank_cash_account",
"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": "Bank / Cash Account",
"length": 0,
"no_copy": 0,
@ -124,22 +167,30 @@
"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
},
{
"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,
@ -147,22 +198,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "from_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": "From Invoice Date",
"length": 0,
"no_copy": 0,
@ -170,22 +229,30 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"search_index": 0,
"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,
"fieldname": "to_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": "To Invoice Date",
"length": 0,
"no_copy": 0,
@ -193,22 +260,30 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"search_index": 0,
"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,
"fieldname": "minimum_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": "Minimum Invoice Amount",
"length": 0,
"no_copy": 0,
@ -216,22 +291,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maximum_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": "Maximum Invoice Amount",
"length": 0,
"no_copy": 0,
@ -239,22 +322,63 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "System will fetch all the entries if limit value is zero.",
"fieldname": "limit",
"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": "Limit",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "get_unreconciled_entries",
"fieldtype": "Button",
"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": "Get Unreconciled Entries",
"length": 0,
"no_copy": 0,
@ -262,22 +386,30 @@
"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
},
{
"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": "Unreconciled Payment Details",
"length": 0,
"no_copy": 0,
@ -285,22 +417,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "payments",
"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": "Payments",
"length": 0,
"no_copy": 0,
@ -309,22 +449,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reconcile",
"fieldtype": "Button",
"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": "Reconcile",
"length": 0,
"no_copy": 0,
@ -332,22 +480,30 @@
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sec_break2",
"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": "Invoice/Journal Entry Details",
"length": 0,
"no_copy": 0,
@ -355,22 +511,30 @@
"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
},
{
"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,
@ -379,25 +543,28 @@
"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
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 1,
"icon": "fa fa-resize-horizontal",
"icon": "icon-resize-horizontal",
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-01-04 02:26:58.807921",
"modified": "2019-01-15 17:42:21.135214",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",
@ -406,7 +573,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -426,7 +592,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -445,8 +610,13 @@
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}

View File

@ -24,9 +24,10 @@ class PaymentReconciliation(Document):
def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order"
payment_entries = get_advance_payment_entries(self.party_type, self.party,
self.receivable_payable_account, order_doctype, against_all_orders=True)
payment_entries = get_advance_payment_entries(self.party_type, self.party,
self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit)
return payment_entries
def get_jv_entries(self):
@ -36,6 +37,8 @@ class PaymentReconciliation(Document):
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
if self.bank_cash_account else "1=1"
limit_cond = "limit %s" % (self.limit or 1000)
journal_entries = frappe.db.sql("""
select
"Journal Entry" as reference_type, t1.name as reference_name,
@ -55,10 +58,11 @@ class PaymentReconciliation(Document):
THEN 1=1
ELSE {bank_account_condition}
END)
order by t1.posting_date
order by t1.posting_date {limit_cond}
""".format(**{
"dr_or_cr": dr_or_cr,
"bank_account_condition": bank_account_condition,
"limit_cond": limit_cond
}), {
"party_type": self.party_type,
"party": self.party,
@ -80,7 +84,7 @@ class PaymentReconciliation(Document):
condition = self.check_condition()
non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party,
self.receivable_payable_account, condition=condition)
self.receivable_payable_account, condition=condition, limit=self.limit)
self.add_invoice_entries(non_reconciled_invoices)

View File

@ -1,7 +1,8 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate
from frappe import _, throw

View File

@ -250,10 +250,12 @@ def get_serial_no_data(pos_profile, company):
cond = "1=1"
if pos_profile.get('update_stock') and pos_profile.get('warehouse'):
cond = "warehouse = '{0}'".format(pos_profile.get('warehouse'))
cond = "warehouse = %(warehouse)s"
serial_nos = frappe.db.sql("""select name, warehouse, item_code from `tabSerial No` where {0}
and company = %(company)s """.format(cond), {'company': company}, as_dict=1)
serial_nos = frappe.db.sql("""select name, warehouse, item_code
from `tabSerial No` where {0} and company = %(company)s """.format(cond),{
'company': company, 'warehouse': frappe.db.escape(pos_profile.get('warehouse'))
}, as_dict=1)
itemwise_serial_no = {}
for sn in serial_nos:

View File

@ -1135,18 +1135,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
apply_category: function() {
frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
category = this.selected_item_group || r.name;
if(category == r.name) {
return this.item_data
} else {
return this.item_data.filter(function(element, index, array){
return element.item_group == category;
});
}
})
var me = this;
category = this.selected_item_group || "All Item Groups";
if(category == 'All Item Groups') {
return this.item_data
} else {
return this.item_data.filter(function(element, index, array){
return element.item_group == category;
});
}
},
bind_items_event: function() {

View File

@ -14,7 +14,7 @@ from frappe.contacts.doctype.address.address import (get_address_display,
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_default_currency, get_company_currency
from erpnext import get_company_currency
from six import iteritems
@ -562,3 +562,12 @@ def get_party_shipping_address(doctype, name):
return out[0][0]
else:
return ''
def get_partywise_advanced_payment_amount(party_type="Customer"):
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
FROM `tabGL Entry`
WHERE party_type = %s and against_voucher is null GROUP BY party"""
.format(("credit - debit") if party_type == "Customer" else "debit") , party_type)
if data:
return frappe._dict(data)

View File

@ -0,0 +1,64 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Account Balance"] = {
"filters": [
{
fieldname:"company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company")
},
{
fieldname:"report_date",
label: __("Date"),
fieldtype: "Date",
default: frappe.datetime.get_today(),
reqd: 1
},
{
fieldname: "root_type",
label: __("Root Type"),
fieldtype: "Select",
options: [
{ "value": "Asset", "label": __("Asset") },
{ "value": "Liability", "label": __("Liability") },
{ "value": "Income", "label": __("Income") },
{ "value": "Expense", "label": __("Expense") },
{ "value": "Equity", "label": __("Equity") }
],
},
{
fieldname: "account_type",
label: __("Account Type"),
fieldtype: "Select",
options: [
{ "value": "Accumulated Depreciation", "label": __("Accumulated Depreciation") },
{ "value": "Asset Received But Not Billed", "label": __("Asset Received But Not Billed") },
{ "value": "Bank", "label": __("Bank") },
{ "value": "Cash", "label": __("Cash") },
{ "value": "Chargeble", "label": __("Chargeble") },
{ "value": "Capital Work in Progress", "label": __("Capital Work in Progress") },
{ "value": "Cost of Goods Sold", "label": __("Cost of Goods Sold") },
{ "value": "Depreciation", "label": __("Depreciation") },
{ "value": "Equity", "label": __("Equity") },
{ "value": "Expense Account", "label": __("Expense Account") },
{ "value": "Expenses Included In Asset Valuation", "label": __("Expenses Included In Asset Valuation") },
{ "value": "Expenses Included In Valuation", "label": __("Expenses Included In Valuation") },
{ "value": "Fixed Asset", "label": __("Fixed Asset") },
{ "value": "Income Account", "label": __("Income Account") },
{ "value": "Payable", "label": __("Payable") },
{ "value": "Receivable", "label": __("Receivable") },
{ "value": "Round Off", "label": __("Round Off") },
{ "value": "Stock", "label": __("Stock") },
{ "value": "Stock Adjustment", "label": __("Stock Adjustment") },
{ "value": "Stock Received But Not Billed", "label": __("Stock Received But Not Billed") },
{ "value": "Tax", "label": __("Tax") },
{ "value": "Temporary", "label": __("Temporary") },
],
},
]
}

View File

@ -0,0 +1,19 @@
{
"add_total_row": 0,
"creation": "2019-01-02 18:01:46.691685",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-01-02 18:01:46.691685",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account Balance",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Bank Account",
"report_name": "Account Balance",
"report_type": "Script Report",
"roles": []
}

View File

@ -0,0 +1,73 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from erpnext.accounts.utils import get_balance_on
def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns(filters)
data = get_data(filters)
return columns, data
def get_columns(filters):
columns = [
{
"label": _("Account"),
"fieldtype": "Link",
"fieldname": "account",
"options": "Account",
"width": 100
},
{
"label": _("Currency"),
"fieldtype": "Link",
"fieldname": "currency",
"options": "Currency",
"hidden": 1,
"width": 50
},
{
"label": _("Balance"),
"fieldtype": "Currency",
"fieldname": "balance",
"options": "currency",
"width": 100
}
]
return columns
def get_conditions(filters):
conditions = {}
if filters.account_type:
conditions["account_type"] = filters.account_type
return conditions
if filters.company:
conditions["company"] = filters.company
if filters.root_type:
conditions["root_type"] = filters.root_type
return conditions
def get_data(filters):
data = []
conditions = get_conditions(filters)
accounts = frappe.db.get_all("Account", fields=["name", "account_currency"],
filters=conditions)
for d in accounts:
balance = get_balance_on(d.name, date=filters.report_date)
row = {"account": d.name, "balance": balance, "currency": d.account_currency}
data.append(row)
return data

View File

@ -0,0 +1,69 @@
from __future__ import unicode_literals
import frappe
import unittest
from frappe.utils import getdate
from erpnext.accounts.report.account_balance.account_balance import execute
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
class TestAccountBalance(unittest.TestCase):
def test_account_balance(self):
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'")
frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'")
filters = {
'company': '_Test Company 2',
'report_date': getdate(),
'root_type': 'Income',
}
make_sales_invoice()
report = execute(filters)
expected_data = [
{
"account": 'Sales - _TC2',
"currency": 'EUR',
"balance": -100.0,
},
{
"account": 'Income - _TC2',
"currency": 'EUR',
"balance": -100.0,
},
{
"account": 'Service - _TC2',
"currency": 'EUR',
"balance": 0.0,
},
{
"account": 'Direct Income - _TC2',
"currency": 'EUR',
"balance": -100.0,
},
{
"account": 'Indirect Income - _TC2',
"currency": 'EUR',
"balance": 0.0,
},
]
self.assertEqual(expected_data, report[1])
def make_sales_invoice():
frappe.set_user("Administrator")
create_sales_invoice(company="_Test Company 2",
customer = '_Test Customer 2',
currency = 'EUR',
warehouse = 'Finished Goods - _TC2',
debit_to = 'Debtors - _TC2',
income_account = 'Sales - _TC2',
expense_account = 'Cost of Goods Sold - _TC2',
cost_center = '_Test Company 2 - _TC2')

View File

@ -190,7 +190,7 @@ class ReceivablePayableReport(object):
dn_details = get_dn_details(args.get("party_type"), voucher_nos)
self.voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details)
if self.filters.based_on_payment_terms:
if self.filters.based_on_payment_terms and gl_entries_data:
self.payment_term_map = self.get_payment_term_detail(voucher_nos)
for gle in gl_entries_data:

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _, scrub
from frappe.utils import flt
from erpnext.accounts.party import get_partywise_advanced_payment_amount
from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport
from six import iteritems
@ -24,6 +25,12 @@ class AccountsReceivableSummary(ReceivablePayableReport):
credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt"
columns += [{
"label": _("Advance Amount"),
"fieldname": "advance_amount",
"fieldtype": "Currency",
"options": "currency",
"width": 100
},{
"label": _("Total Invoiced Amt"),
"fieldname": "total_invoiced_amt",
"fieldtype": "Currency",
@ -129,12 +136,15 @@ class AccountsReceivableSummary(ReceivablePayableReport):
partywise_total = self.get_partywise_total(party_naming_by, args)
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {}
for party, party_dict in iteritems(partywise_total):
row = [party]
if party_naming_by == "Naming Series":
row += [self.get_party_name(args.get("party_type"), party)]
row += [partywise_advance_amount.get(party, 0)]
row += [
party_dict.invoiced_amt, party_dict.paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4,
@ -180,11 +190,14 @@ class AccountsReceivableSummary(ReceivablePayableReport):
def get_voucherwise_data(self, party_naming_by, args):
voucherwise_data = ReceivablePayableReport(self.filters).run(args)[1]
cols = ["posting_date", "party"]
cols = ["posting_date", "party", "customer-contact"]
if party_naming_by == "Naming Series":
cols += ["party_name"]
if args.get("party_type") == 'Customer':
cols += ["contact"]
cols += ["voucher_type", "voucher_no", "due_date"]
if args.get("party_type") == "Supplier":

View File

@ -8,7 +8,9 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category
def execute(filters=None):
validate_filters(filters)
columns = get_columns()
filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
columns = get_columns(filters)
res = get_result(filters)
return columns, res
@ -29,7 +31,8 @@ def get_result(filters):
# if no supplier selected, fetch data for all tds applicable supplier
# else fetch relevant data for selected supplier
pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type"]
fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type", "supplier_name"]
if filters.supplier:
filters.supplier = frappe.db.get_list('Supplier',
{"name": filters.supplier}, fields)
@ -49,8 +52,13 @@ def get_result(filters):
filters.company, filters.from_date, filters.to_date)
if total_invoiced_amount or tds_deducted:
out.append([supplier.pan, supplier.name, tds.name, supplier.supplier_type,
rate, total_invoiced_amount, tds_deducted])
row = [supplier.pan, supplier.name]
if filters.naming_series == 'Naming Series':
row.append(supplier.supplier_name)
row.extend([tds.name, supplier.supplier_type, rate, total_invoiced_amount, tds_deducted])
out.append(row)
return out
@ -86,7 +94,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
return total_invoiced_amount, tds_deducted
def get_columns():
def get_columns(filters):
columns = [
{
"label": _("PAN"),
@ -100,7 +108,17 @@ def get_columns():
"fieldname": "supplier",
"fieldtype": "Link",
"width": 180
},
}]
if filters.naming_series == 'Naming Series':
columns.append({
"label": _("Supplier Name"),
"fieldname": "supplier_name",
"fieldtype": "Data",
"width": 180
})
columns.extend([
{
"label": _("Section Code"),
"options": "Tax Withholding Category",
@ -132,6 +150,6 @@ def get_columns():
"fieldtype": "Float",
"width": 90
}
]
])
return columns

View File

@ -11,7 +11,7 @@ def execute(filters=None):
validate_filters(filters)
set_filters(filters)
columns = get_columns()
columns = get_columns(filters)
if not filters["invoices"]:
return columns, []
@ -43,6 +43,7 @@ def set_filters(filters):
invoices.append(d)
filters["invoices"] = invoices if invoices else filters["invoices"]
filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
def get_result(filters):
supplier_map, tds_docs = get_supplier_map(filters)
@ -71,9 +72,14 @@ def get_result(filters):
if getdate(filters.from_date) <= gle_map[d][0].posting_date \
and getdate(filters.to_date) >= gle_map[d][0].posting_date:
out.append([supplier.pan, supplier.name, tds_doc.name,
supplier.supplier_type, rate, total_amount_credited, tds_deducted,
gle_map[d][0].posting_date, "Purchase Invoice", d])
row = [supplier.pan, supplier.name]
if filters.naming_series == 'Naming Series':
row.append(supplier.supplier_name)
row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited,
tds_deducted, gle_map[d][0].posting_date, "Purchase Invoice", d])
out.append(row)
return out
@ -84,7 +90,7 @@ def get_supplier_map(filters):
pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
supplier_detail = frappe.db.get_all('Supplier',
{"name": ["in", [d.supplier for d in filters["invoices"]]]},
["tax_withholding_category", "name", pan+" as pan", "supplier_type"])
["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"])
for d in filters["invoices"]:
supplier_map[d.get("name")] = [k for k in supplier_detail
@ -113,7 +119,7 @@ def get_gle_map(filters):
return gle_map
def get_columns():
def get_columns(filters):
pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
columns = [
{
@ -128,7 +134,17 @@ def get_columns():
"fieldname": "supplier",
"fieldtype": "Link",
"width": 180
},
}]
if filters.naming_series == 'Naming Series':
columns.append({
"label": _("Supplier Name"),
"fieldname": "supplier_name",
"fieldtype": "Data",
"width": 180
})
columns.extend([
{
"label": _("Section Code"),
"options": "Tax Withholding Category",
@ -178,7 +194,7 @@ def get_columns():
"options": "transaction_type",
"width": 90
}
]
])
return columns

View File

@ -12,21 +12,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center",
"get_query": function() {
var company = frappe.query_report.get_filter_value('company');
return {
"doctype": "Cost Center",
"filters": {
"company": company,
}
}
}
},
{
"fieldname": "fiscal_year",
"label": __("Fiscal Year"),
@ -60,6 +45,27 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date"),
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center",
"get_query": function() {
var company = frappe.query_report.get_filter_value('company');
return {
"doctype": "Cost Center",
"filters": {
"company": company,
}
}
}
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book",
},
{
"fieldname": "with_period_closing_entry",
"label": __("Period Closing Entry"),
@ -75,6 +81,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"fieldname": "show_unclosed_fy_pl_balances",
"label": __("Show unclosed fiscal year's P&L balances"),
"fieldtype": "Check"
},
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check"
}
],
"formatter": erpnext.financial_statements.formatter,

View File

@ -67,11 +67,10 @@ def get_data(filters):
gl_entries_by_account = {}
opening_balances = get_opening_balances(filters)
set_gl_entries_by_account(filters.company, filters.from_date,
filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry))
opening_balances = get_opening_balances(filters)
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters, company_currency)
accumulate_values_into_parents(accounts, accounts_by_name)
@ -98,6 +97,18 @@ def get_rootwise_opening_balances(filters, report_type):
if not flt(filters.with_period_closing_entry):
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
if filters.cost_center:
lft, rgt = frappe.db.get_value('Cost Center', filters.cost_center, ['lft', 'rgt'])
additional_conditions += """ and cost_center in (select name from `tabCost Center`
where lft >= %s and rgt <= %s)""" % (lft, rgt)
if filters.finance_book:
fb_conditions = " and finance_book = %(finance_book)s"
if filters.include_default_book_entries:
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s) or finance_book is null)"
additional_conditions += fb_conditions
gle = frappe.db.sql("""
select
account, sum(debit) as opening_debit, sum(credit) as opening_credit
@ -112,7 +123,9 @@ def get_rootwise_opening_balances(filters, report_type):
"company": filters.company,
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date
"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)

View File

@ -6,13 +6,13 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2018-11-22 17:40:11.317567",
"modified": "2019-01-17 17:20:42.374958",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Trial Balance (Simple)",
"owner": "Administrator",
"prepared_report": 0,
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
"ref_doctype": "GL Entry",
"report_name": "Trial Balance (Simple)",
"report_type": "Query Report",

View File

@ -615,7 +615,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, limit=1000):
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
@ -628,6 +628,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
held_invoices = get_held_invoices(party_type, party)
limit_cond = "limit %s" % (limit or 1000)
invoice_list = frappe.db.sql("""
select
@ -655,11 +656,12 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
group by voucher_type, voucher_no
having (invoice_amount - payment_amount) > 0.005
order by posting_date, creation""".format(
order by posting_date, name {limit_cond}""".format(
dr_or_cr=dr_or_cr,
invoice = invoice,
payment_dr_or_cr=payment_dr_or_cr,
condition=condition or ""
condition=condition or "",
limit_cond = limit_cond
), {
"party_type": party_type,
"party": party,

File diff suppressed because it is too large Load Diff

View File

@ -149,6 +149,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_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": "Default Bank Account",
"length": 0,
"no_copy": 0,
"options": "Bank 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": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1463,7 +1496,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-07 16:52:04.660271",
"modified": "2019-01-17 13:58:08.597792",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",

View File

@ -135,13 +135,6 @@ def get_data():
"link": "leaderboard",
"label": _("Leaderboard")
},
{
"module_name": "Projects",
"color": "#8e44ad",
"icon": "octicon octicon-rocket",
"type": "module",
"hidden": 1
},
{
"module_name": "Support",
"color": "#2c3e50",

View File

@ -249,7 +249,6 @@ class AccountsController(TransactionBase):
if self.get("is_subcontracted"):
args["is_subcontracted"] = self.is_subcontracted
ret = get_item_details(args)
for fieldname, value in ret.items():
if item.meta.get_field(fieldname) and value is not None:
if (item.get(fieldname) is None or fieldname in force_item_fields):
@ -268,9 +267,10 @@ class AccountsController(TransactionBase):
if ret.get("pricing_rule"):
# if user changed the discount percentage then set user's discount percentage ?
item.set("pricing_rule", ret.get("pricing_rule"))
item.set("discount_percentage", ret.get("discount_percentage"))
if ret.get("pricing_rule_for") == "Price":
item.set("pricing_list_rate", ret.get("pricing_list_rate"))
if ret.get("pricing_rule_for") == "Rate":
item.set("price_list_rate", ret.get("price_list_rate"))
if item.price_list_rate:
item.rate = flt(item.price_list_rate *
@ -954,11 +954,12 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field,
return list(journal_entries)
def get_advance_payment_entries(party_type, party, party_account,
order_doctype, order_list=None, include_unallocated=True, against_all_orders=False):
def get_advance_payment_entries(party_type, party, party_account, order_doctype,
order_list=None, include_unallocated=True, against_all_orders=False, limit=1000):
party_account_field = "paid_from" if party_type == "Customer" else "paid_to"
payment_type = "Receive" if party_type == "Customer" else "Pay"
payment_entries_against_order, unallocated_payment_entries = [], []
limit_cond = "limit %s" % (limit or 1000)
if order_list or against_all_orders:
if order_list:
@ -978,8 +979,8 @@ def get_advance_payment_entries(party_type, party, party_account,
t1.name = t2.parent and t1.{0} = %s and t1.payment_type = %s
and t1.party_type = %s and t1.party = %s and t1.docstatus = 1
and t2.reference_doctype = %s {1}
order by t1.posting_date
""".format(party_account_field, reference_condition),
order by t1.posting_date {2}
""".format(party_account_field, reference_condition, limit_cond),
[party_account, payment_type, party_type, party,
order_doctype] + order_list, as_dict=1)
@ -991,8 +992,8 @@ def get_advance_payment_entries(party_type, party, party_account,
where
{0} = %s and party_type = %s and party = %s and payment_type = %s
and docstatus = 1 and unallocated_amount > 0
order by posting_date
""".format(party_account_field), (party_account, party_type, party, payment_type), as_dict=1)
order by posting_date {1}
""".format(party_account_field, limit_cond), (party_account, party_type, party, payment_type), as_dict=1)
return list(payment_entries_against_order) + list(unallocated_payment_entries)

View File

@ -260,8 +260,6 @@ def generate_keyed_value_combinations(args):
return results
def copy_attributes_to_variant(item, variant):
from frappe.model import no_value_fields
# copy non no-copy fields
exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",

View File

@ -8,7 +8,7 @@ from frappe import _, throw
from erpnext.stock.get_item_details import get_bin_details
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.doctype.item.item import get_item_defaults, set_item_default
from erpnext.stock.doctype.item.item import set_item_default
from frappe.contacts.doctype.address.address import get_address_display
from erpnext.controllers.stock_controller import StockController

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import cint, flt, cstr
from frappe import msgprint, _
from frappe import _
import frappe.defaults
from erpnext.accounts.utils import get_fiscal_year
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
@ -14,6 +14,7 @@ from erpnext.stock import get_warehouse_account_map
class QualityInspectionRequiredError(frappe.ValidationError): pass
class QualityInspectionRejectedError(frappe.ValidationError): pass
class QualityInspectionNotSubmittedError(frappe.ValidationError): pass
class StockController(AccountsController):
def validate(self):
@ -338,18 +339,20 @@ class StockController(AccountsController):
qa_required = True
elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
qa_required = True
if self.docstatus == 1 and d.quality_inspection:
qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
if qa_doc.docstatus == 0:
link = frappe.utils.get_link_to_form('Quality Inspection', d.quality_inspection)
frappe.throw(_("Quality Inspection: {0} is not submitted for the item: {1} in row {2}").format(link, d.item_code, d.idx), QualityInspectionNotSubmittedError)
if qa_required:
qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
if qa_failed:
frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
.format(d.idx, d.item_code), QualityInspectionRejectedError)
elif qa_required :
frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
if self.docstatus==1:
raise QualityInspectionRequiredError
elif self.docstatus == 1:
if d.quality_inspection:
qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
if qa_failed:
frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
.format(d.idx, d.item_code), QualityInspectionRejectedError)
def update_blanket_order(self):
@ -428,4 +431,4 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
return gl_entries
return gl_entries

View File

@ -1,9 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class Lead(Document):
pass

View File

@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
develop_version = '12.x.x-develop'
staging_version = '11.0.3-beta.34'
staging_version = '11.0.3-beta.37'
error_report_email = "support@erpnext.com"
@ -232,12 +232,16 @@ doc_events = {
}
scheduler_events = {
"all": [
"erpnext.projects.doctype.project.project.project_status_update_reminder"
],
"hourly": [
'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails',
"erpnext.accounts.doctype.subscription.subscription.process_all",
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
"erpnext.projects.doctype.project.project.hourly_reminder",
"erpnext.projects.doctype.project.project.collect_project_status"
],
"daily": [
"erpnext.stock.reorder_item.reorder_item",
@ -257,6 +261,7 @@ scheduler_events = {
"erpnext.assets.doctype.asset.asset.make_post_gl_entry",
"erpnext.crm.doctype.contract.contract.update_status_for_contracts",
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review"
],
"daily_long": [

View File

@ -112,6 +112,10 @@ def get_user_emails_from_group(group):
if isinstance(group_doc, string_types):
group_doc = frappe.get_doc('Daily Work Summary Group', group)
emails = [d.email for d in group_doc.users if frappe.db.get_value("User", d.user, "enabled")]
emails = get_users_email(group_doc)
return emails
def get_users_email(doc):
return [d.email for d in doc.users
if frappe.db.get_value("User", d.user, "enabled")]

View File

@ -2,10 +2,6 @@ from __future__ import unicode_literals
import frappe
import json
import io
import base64
import os
import requests
from frappe import _
from frappe.frappeclient import FrappeClient

View File

@ -1,8 +0,0 @@
import frappe
def set_required_items(production_order):
pass
def reserve_for_production(production_order):
'''Reserve pending raw materials for production'''
pass

View File

@ -350,7 +350,8 @@ frappe.ui.form.on("Work Order", {
before_submit: function(frm) {
frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
frm.toggle_reqd("transfer_material_against", frm.doc.operations);
frm.toggle_reqd("transfer_material_against",
frm.doc.operations && frm.doc.operations.length > 0);
frm.fields_dict.operations.grid.toggle_reqd("workstation", frm.doc.operations);
},

View File

@ -1,5 +1,6 @@
execute:import unidecode # new requirement
erpnext.patches.v8_0.move_perpetual_inventory_setting
erpnext.patches.v8_9.set_print_zero_amount_taxes
erpnext.patches.v11_0.rename_production_order_to_work_order
erpnext.patches.v11_0.refactor_naming_series
erpnext.patches.v11_0.refactor_autoname_naming
@ -442,7 +443,6 @@ erpnext.patches.v8_9.add_setup_progress_actions #08-09-2017 #26-09-2017 #22-11-2
erpnext.patches.v8_9.rename_company_sales_target_field
erpnext.patches.v8_8.set_bom_rate_as_per_uom
erpnext.patches.v8_8.add_new_fields_in_accounts_settings
erpnext.patches.v8_9.set_print_zero_amount_taxes
erpnext.patches.v8_9.set_default_customer_group
erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts
erpnext.patches.v8_9.set_default_fields_in_variant_settings
@ -572,7 +572,7 @@ execute:frappe.delete_doc_if_exists("Page", "sales-analytics")
execute:frappe.delete_doc_if_exists("Page", "purchase-analytics")
execute:frappe.delete_doc_if_exists("Page", "stock-analytics")
execute:frappe.delete_doc_if_exists("Page", "production-analytics")
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09
erpnext.patches.v11_0.drop_column_max_days_allowed
erpnext.patches.v11_0.change_healthcare_desktop_icons
erpnext.patches.v10_0.update_user_image_in_employee
@ -580,8 +580,10 @@ erpnext.patches.v11_0.update_delivery_trip_status
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
erpnext.patches.v11_0.set_missing_gst_hsn_code
erpnext.patches.v11_0.rename_bom_wo_fields
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
erpnext.patches.v11_0.renamed_from_to_fields_in_project
erpnext.patches.v12_0.change_qms_icon
erpnext.patches.v12_0.rename_learn_to_help
erpnext.patches.v12_0.rename_accounts_desktop_icon_to_accounting
erpnext.patches.v12_0.replace_project_list_desktop_icon_with_projects_module_desktop_icon
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
erpnext.patches.v12_0.replace_project_list_desktop_icon_with_projects_module_desktop_icon # 09-01-2019
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary

View File

@ -0,0 +1,13 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
frappe.reload_doc('projects', 'doctype', 'project')
if frappe.db.has_column('Project', 'from'):
rename_field('Project', 'from', 'from_time')
rename_field('Project', 'to', 'to_time')

View File

@ -1,24 +1,23 @@
import frappe
def execute():
frappe.db.sql("""DELETE
FROM `tabDesktop Icon`
WHERE
`module_name` in ('Project', 'Projects') AND
`standard`=1 AND
`app`='erpnext'
""")
projects_icons = frappe.get_all('Desktop Icon', filters={
'module_name': ['in', ('Project', 'Projects')],
})
desktop_icon = frappe.get_doc({
'doctype': 'Desktop Icon',
'idx': 5,
'standard': 1,
'app': 'erpnext',
'owner': 'Administrator',
fields_to_update = {
'module_name': 'Projects',
'color': '#8e44ad',
'icon': 'octicon octicon-rocket',
'type': 'module'
})
'type': 'module',
'link': ''
}
desktop_icon.save()
for icon in projects_icons:
icon_doc = frappe.get_doc('Desktop Icon', icon.name)
icon_doc.update(fields_to_update)
try:
icon_doc.save()
except frappe.exceptions.UniqueValidationError:
# delete duplicate icon
icon_doc.delete()

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,16 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, getdate, get_url, now
from frappe import _
from frappe.model.document import Document
from six import iteritems
from email_reply_parser import EmailReplyParser
from frappe.utils import (flt, getdate, get_url, now,
nowtime, get_time, today, get_datetime, add_days)
from erpnext.controllers.queries import get_filters_cond
from frappe.desk.reportview import get_match_cond
import datetime
from six import iteritems
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
from erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group import is_holiday_today
from frappe.model.document import Document
class Project(Document):
def get_feed(self):
@ -162,7 +162,7 @@ class Project(Document):
def is_row_updated(self, row, existing_task_data, fields):
if self.get("__islocal") or not existing_task_data: return True
d = existing_task_data.get(row.task_id)
d = existing_task_data.get(row.task_id, {})
for field in fields:
if row.get(field) != d.get(field):
@ -406,56 +406,137 @@ def get_users_for_project(doctype, txt, searchfield, start, page_len, filters):
def get_cost_center_name(project):
return frappe.db.get_value("Project", project, "cost_center")
@frappe.whitelist()
def hourly_reminder():
project = frappe.db.sql("""SELECT `tabProject`.name FROM `tabProject` WHERE `tabProject`.frequency = "Hourly" and (CURTIME() BETWEEN `tabProject`.from and `tabProject`.to) AND `tabProject`.collect_progress = 1 ORDER BY `tabProject`.name;""")
create_project_update(project)
fields = ["from_time", "to_time"]
projects = get_projects_for_collect_progress("Hourly", fields)
@frappe.whitelist()
def twice_daily_reminder():
project = frappe.db.sql("""SELECT `tabProject User`.user FROM `tabProject User` INNER JOIN `tabProject` ON `tabProject`.project_name = `tabProject User`.parent WHERE (`tabProject`.frequency = "Twice Daily") AND ((`tabProject`.first_email BETWEEN DATE_ADD(curtime(), INTERVAL -15 MINUTE) AND DATE_ADD(curtime(), INTERVAL 15 MINUTE)) OR (`tabProject`.second_email BETWEEN DATE_ADD(curtime(), INTERVAL -15 MINUTE) AND DATE_ADD(curtime(), INTERVAL 15 MINUTE))) AND `tabProject`.collect_progress = 1;""")
create_project_update(project)
for project in projects:
if (get_time(nowtime()) >= get_time(project.from_time) or
get_time(nowtime()) <= get_time(project.to_time)):
send_project_update_email_to_users(project.name)
def project_status_update_reminder():
daily_reminder()
twice_daily_reminder()
weekly_reminder()
@frappe.whitelist()
def daily_reminder():
project = frappe.db.sql("""SELECT `tabProject User`.user FROM `tabProject User` INNER JOIN `tabProject` ON `tabProject`.project_name = `tabProject User`.parent WHERE (`tabProject`.frequency = "Daily") AND (`tabProject`.daily_time_to_send BETWEEN DATE_ADD(curtime(), INTERVAL -15 MINUTE) AND DATE_ADD(curtime(), INTERVAL 15 MINUTE)) AND `tabProject`.collect_progress = 1;""")
create_project_update(project)
fields = ["daily_time_to_send"]
projects = get_projects_for_collect_progress("Daily", fields)
@frappe.whitelist()
def weekly():
today = datetime.datetime.now().strftime("%A")
project = frappe.db.sql("""SELECT `tabProject User`.user FROM `tabProject User` INNER JOIN `tabProject` ON `tabProject`.project_name = `tabProject User`.parent WHERE (`tabProject`.frequency = "Weekly") AND (`tabProject`.day_to_send = %s) AND (`tabProject`.weekly_time_to_send BETWEEN DATE_ADD(curtime(), INTERVAL -15 MINUTE) AND DATE_ADD(curtime(), INTERVAL 15 MINUTE)) AND `tabProject`.collect_progress = 1""", today)
create_project_update(project)
for project in projects:
if not check_project_update_exists(project.name, project.get("daily_time_to_send")):
send_project_update_email_to_users(project.name)
#Call this function in order to generate the Project Update for a specific project
def create_project_update(project):
data = []
date_today = datetime.date.today()
time_now = frappe.utils.now_datetime().strftime('%H:%M:%S')
for projects in project:
project_update_dict = {
"doctype" : "Project Update",
"project" : projects[0],
"date": date_today,
"time": time_now,
"naming_series": "UPDATE-.project.-.YY.MM.DD.-"
def twice_daily_reminder():
fields = ["first_email", "second_email"]
projects = get_projects_for_collect_progress("Twice Daily", fields)
for project in projects:
for d in fields:
if not check_project_update_exists(project.name, project.get(d)):
send_project_update_email_to_users(project.name)
def weekly_reminder():
fields = ["day_to_send", "weekly_time_to_send"]
projects = get_projects_for_collect_progress("Weekly", fields)
current_day = get_datetime().strftime("%A")
for project in projects:
if current_day != project.day_to_send:
continue
if not check_project_update_exists(project.name, project.get("weekly_time_to_send")):
send_project_update_email_to_users(project.name)
def check_project_update_exists(project, time):
data = frappe.db.sql(""" SELECT name from `tabProject Update`
WHERE project = %s and date = %s and time >= %s """, (project, today(), time))
return True if data and data[0][0] else False
def get_projects_for_collect_progress(frequency, fields):
fields.extend(["name"])
return frappe.get_all("Project", fields = fields,
filters = {'collect_progress': 1, 'frequency': frequency})
def send_project_update_email_to_users(project):
doc = frappe.get_doc('Project', project)
if is_holiday_today(doc.holiday_list) or not doc.users: return
project_update = frappe.get_doc({
"doctype" : "Project Update",
"project" : project,
"sent": 0,
"date": today(),
"time": nowtime(),
"naming_series": "UPDATE-.project.-.YY.MM.DD.-",
}).insert()
subject = "For project %s, update your status" % (project)
incoming_email_account = frappe.db.get_value('Email Account',
dict(enable_incoming=1, default_incoming=1), 'email_id')
frappe.sendmail(recipients=get_users_email(doc),
message=doc.message,
subject=_(subject),
reference_doctype=project_update.doctype,
reference_name=project_update.name,
reply_to=incoming_email_account
)
def collect_project_status():
for data in frappe.get_all("Project Update",
{'date': today(), 'sent': 0}):
replies = frappe.get_all('Communication',
fields=['content', 'text_content', 'sender'],
filters=dict(reference_doctype="Project Update",
reference_name=data.name,
communication_type='Communication',
sent_or_received='Received'),
order_by='creation asc')
for d in replies:
doc = frappe.get_doc("Project Update", data.name)
user_data = frappe.db.get_values("User", {"email": d.sender},
["full_name", "user_image", "name"], as_dict=True)[0]
doc.append("users", {
'user': user_data.name,
'full_name': user_data.full_name,
'image': user_data.user_image,
'project_status': frappe.utils.md_to_html(
EmailReplyParser.parse_reply(d.text_content) or d.content
)
})
doc.save(ignore_permissions=True)
def send_project_status_email_to_users():
yesterday = add_days(today(), -1)
for d in frappe.get_all("Project Update",
{'date': yesterday, 'sent': 0}):
doc = frappe.get_doc("Project Update", d.name)
project_doc = frappe.get_doc('Project', doc.project)
args = {
"users": doc.users,
"title": _("Project Summary for {0}").format(yesterday)
}
project_update = frappe.get_doc(project_update_dict)
project_update.insert()
#you can edit your local_host
local_host = "http://localhost:8003"
project_update_url = "<a class = 'btn btn-primary' href=%s target='_blank'>" % (local_host +"/desk#Form/Project%20Update/" + (project_update.name)) + ("CREATE PROJECT UPDATE" + "</a>")
data.append(project_update_url)
email = frappe.db.sql("""SELECT user from `tabProject User` WHERE parent = %s;""", project[0])
for emails in email:
frappe.sendmail(
recipients=emails,
subject=frappe._(projects[0]),
header=[frappe._("Please Update your Project Status"), 'blue'],
message= project_update_url
)
return data
frappe.sendmail(recipients=get_users_email(project_doc),
template='daily_project_summary',
args=args,
subject=_("Daily Project Summary for {0}").format(d.name),
reference_doctype="Project Update",
reference_name=d.name)
doc.db_set('sent', 1)
def update_project_sales_billing():
sales_update_frequency = frappe.db.get_single_value("Selling Settings", "sales_update_frequency")

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -13,6 +14,40 @@
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "naming_series",
"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": "Series",
"length": 0,
"no_copy": 0,
"options": "PROJ-UPD-.YYYY.-",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -46,6 +81,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "sent",
"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": "Sent",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -172,39 +240,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "progress",
"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": "How is the Project Progressing Right Now?",
"length": 0,
"no_copy": 0,
"options": "Not Updated\nGreat/Quickly\nGood/Steady\nChallenging/Slow\nProblematic/Stuck",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -238,38 +273,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "progress_details",
"fieldtype": "Text Editor",
"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": "Progress Details",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -301,40 +304,6 @@
"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,
"default": "",
"fieldname": "naming_series",
"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": "Series",
"length": 0,
"no_copy": 0,
"options": "PROJ-UPD-.YYYY.-",
"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,
@ -347,7 +316,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-21 14:44:21.287709",
"modified": "2019-01-16 19:31:05.210656",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Update",

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -44,6 +45,136 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "user.email",
"fieldname": "email",
"fieldtype": "Read Only",
"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": "Email",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "user.user_image",
"fieldname": "image",
"fieldtype": "Read Only",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image",
"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
},
{
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "user.full_name",
"fieldname": "full_name",
"fieldtype": "Read Only",
"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": "Full Name",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -107,6 +238,70 @@
"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,
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:parent.doctype == 'Project Update'",
"fieldname": "project_status",
"fieldtype": "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": "Project Status",
"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,
@ -119,7 +314,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-09-09 12:39:38.376816",
"modified": "2019-01-17 17:10:05.339735",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project User",

View File

@ -28,7 +28,10 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
if (this.frm.doc.__islocal
&& frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) {
this.frm.set_value("disable_rounded_total", cint(frappe.sys_defaults.disable_rounded_total));
var df = frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total");
var disable = df.default || cint(frappe.sys_defaults.disable_rounded_total);
this.frm.set_value("disable_rounded_total", disable);
}
/* eslint-disable */
@ -126,7 +129,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
if (doc.doctype == "Purchase Order" && item.blanket_order_rate) {
item_rate = item.blanket_order_rate;
}
item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100;
item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100;
item.rate = flt((item.price_list_rate) - (item.discount_amount), precision('rate', item));
this.calculate_taxes_and_totals();
@ -273,26 +276,26 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
d.qty = d.qty - my_qty;
cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
cur_frm.doc.items[i].qty = my_qty;
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
if (qty > 0)
{
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
item_length++;
for (var key in cur_frm.doc.items[i])
{
newrow[key] = cur_frm.doc.items[i][key];
}
newrow.idx = item_length;
newrow["stock_qty"] = newrow.conversion_factor*qty;
newrow["qty"] = qty;
newrow["material_request"] = "";
newrow["material_request_item"] = "";
}
}
});
@ -309,7 +312,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
if (doc.auto_repeat) {
frappe.call({
method:"frappe.desk.doctype.auto_repeat.auto_repeat.update_reference",
args:{
args:{
docname: doc.auto_repeat,
reference:doc.name
},
@ -434,4 +437,3 @@ erpnext.buying.get_items_from_product_bundle = function(frm) {
});
dialog.show();
}

View File

@ -7,5 +7,5 @@ from erpnext import get_region
def check_deletion_permission(doc, method):
region = get_region(doc.company)
if region in ["Nepal", "France"]:
if region in ["Nepal", "France"] and doc.docstatus != 0:
frappe.throw(_("Deletion is not permitted for country {0}".format(region)))

View File

@ -126,6 +126,9 @@ def make_custom_fields(update=True):
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='shipping_address',
print_hide=1, read_only=0),
]
purchase_invoice_itc_fields = [
dict(fieldname='eligibility_for_itc', label='Eligibility For ITC',
fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1,
options='input\ninput service\ncapital goods\nineligible', default="ineligible"),
@ -152,6 +155,9 @@ def make_custom_fields(update=True):
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
fetch_from='company_address.gstin', print_hide=1),
]
sales_invoice_shipping_fields = [
dict(fieldname='port_code', label='Port Code',
fieldtype='Data', insert_after='reason_for_issuing_document', print_hide=1,
depends_on="eval:doc.invoice_type=='Export' "),
@ -214,9 +220,12 @@ def make_custom_fields(update=True):
dict(fieldname='gst_state_number', label='GST State Number',
fieldtype='Data', insert_after='gst_state', read_only=1),
],
'Purchase Invoice': invoice_gst_fields + purchase_invoice_gst_fields,
'Sales Invoice': invoice_gst_fields + sales_invoice_gst_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields,
'Purchase Invoice': invoice_gst_fields + purchase_invoice_gst_fields + purchase_invoice_itc_fields,
'Purchase Order': purchase_invoice_gst_fields,
'Purchase Receipt': purchase_invoice_gst_fields,
'Sales Invoice': invoice_gst_fields + sales_invoice_gst_fields + sales_invoice_shipping_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields,
'Sales Order': sales_invoice_gst_fields,
'Sales Taxes and Charges Template': inter_state_gst_field,
'Purchase Taxes and Charges Template': inter_state_gst_field,
'Item': [

View File

@ -8,10 +8,10 @@ from erpnext.hr.utils import get_salary_assignment
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
def validate_gstin_for_india(doc, method):
if not hasattr(doc, 'gstin'):
if not hasattr(doc, 'gstin') or not doc.gstin:
return
doc.gstin = doc.gstin.upper().strip() if doc.gstin else ""
doc.gstin = doc.gstin.upper().strip()
if not doc.gstin or doc.gstin == 'NA':
return

View File

@ -217,6 +217,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_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": "Default Bank Account",
"length": 0,
"no_copy": 0,
"options": "Bank 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": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1873,7 +1906,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-01 10:07:34.510264",
"modified": "2019-01-17 13:10:24.360875",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,26 @@ class TestQuotation(unittest.TestCase):
self.assertFalse(sales_order.get('payment_schedule'))
def test_make_sales_order_with_different_currency(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
quotation = frappe.copy_doc(test_records[0])
quotation.transaction_date = nowdate()
quotation.valid_till = add_months(quotation.transaction_date, 1)
quotation.insert()
quotation.submit()
sales_order = make_sales_order(quotation.name)
sales_order.currency = "USD"
sales_order.conversion_rate = 20.0
sales_order.delivery_date = "2019-01-01"
sales_order.naming_series = "_T-Quotation-"
sales_order.transaction_date = nowdate()
sales_order.insert()
self.assertEquals(sales_order.currency, "USD")
self.assertNotEqual(sales_order.currency, quotation.currency)
def test_make_sales_order(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order

View File

@ -17,6 +17,20 @@ frappe.ui.form.on("Sales Order", {
// formatter for material request item
frm.set_indicator_formatter('item_code',
function(doc) { return (doc.stock_qty<=doc.delivered_qty) ? "green" : "orange" })
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
link_doctype: 'Company',
link_name: doc.company
}
};
})
},
refresh: function(frm) {
if(frm.doc.docstatus == 1 && frm.doc.status == 'To Deliver and Bill') {

File diff suppressed because it is too large Load Diff

View File

@ -147,7 +147,7 @@ class SalesOrder(SellingController):
super(SalesOrder, self).validate_with_previous_doc({
"Quotation": {
"ref_dn_field": "prevdoc_docname",
"compare_fields": [["company", "="], ["currency", "="]]
"compare_fields": [["company", "="]]
}
})

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@ -352,7 +353,7 @@
"fieldname": "to_emp",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
@ -618,7 +619,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-21 16:15:42.627233",
"modified": "2019-01-21 17:10:39.822125",
"modified_by": "Administrator",
"module": "Setup",
"name": "Authorization Rule",

View File

@ -1,5 +1,7 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "Prompt",
@ -13,6 +15,8 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -23,6 +27,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Email Digest Settings",
@ -37,9 +42,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -50,6 +58,7 @@
"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,
@ -63,9 +72,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -76,6 +88,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Enabled",
@ -90,9 +103,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -103,6 +119,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "For Company",
@ -118,9 +135,12 @@
"reqd": 1,
"search_index": 0,
"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,
@ -131,6 +151,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "How frequently?",
@ -146,9 +167,12 @@
"reqd": 1,
"search_index": 0,
"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,
@ -160,6 +184,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next email will be sent on:",
@ -174,9 +199,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -187,6 +215,7 @@
"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,
@ -200,9 +229,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -214,6 +246,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Recipients",
@ -229,9 +262,12 @@
"reqd": 1,
"search_index": 0,
"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,
@ -242,6 +278,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Add/Remove Recipients",
@ -256,9 +293,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -269,6 +309,7 @@
"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",
@ -283,9 +324,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -296,6 +340,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Profit & Loss",
@ -310,9 +355,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -324,6 +372,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "New Income",
@ -338,9 +387,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -352,6 +404,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "New Expenses",
@ -366,9 +419,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -379,6 +435,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Annual Income",
@ -393,9 +450,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -406,6 +466,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Annual Expenses",
@ -421,9 +482,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -435,6 +499,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Balance Sheet",
@ -449,9 +514,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -463,6 +531,7 @@
"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 Balance",
@ -477,9 +546,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -490,9 +562,10 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Credit Balance",
"label": "Bank Credit Balance",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -505,9 +578,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -519,6 +595,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Receivables",
@ -533,9 +610,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -547,6 +627,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Payables",
@ -561,9 +642,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -574,8 +658,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Work in Progress",
"length": 0,
"no_copy": 0,
@ -589,9 +674,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -602,8 +690,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Sales Orders to Bill",
"length": 0,
"no_copy": 0,
@ -617,9 +706,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -630,8 +722,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Purchase Orders to Bill",
"length": 0,
"no_copy": 0,
@ -645,9 +738,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -658,6 +754,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Operations",
@ -673,9 +770,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -686,6 +786,7 @@
"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,
@ -700,9 +801,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -713,6 +817,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "New Sales Orders",
@ -728,9 +833,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -741,8 +849,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "New Purchase Orders",
"length": 0,
"no_copy": 0,
@ -756,9 +865,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -769,8 +881,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Sales Orders to Deliver",
"length": 0,
"no_copy": 0,
@ -784,9 +897,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -797,8 +913,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Purchase Orders to Receive",
"length": 0,
"no_copy": 0,
@ -812,9 +929,76 @@
"reqd": 0,
"search_index": 0,
"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,
"fieldname": "sales_invoice",
"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": "New Sales Invoice",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "purchase_invoice",
"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": "New Purchase Invoice",
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -825,6 +1009,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
@ -840,9 +1025,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -853,6 +1041,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "New Quotations",
@ -868,9 +1057,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -881,8 +1073,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Open Quotations",
"length": 0,
"no_copy": 0,
@ -896,9 +1089,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -909,6 +1105,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Open Issues",
@ -924,9 +1121,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -937,6 +1137,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Open Projects",
@ -952,9 +1153,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -965,8 +1169,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"in_standard_filter": 0,
"label": "Purchase Orders Items Overdue",
"length": 0,
"no_copy": 0,
@ -980,9 +1185,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -993,6 +1201,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Other",
@ -1008,9 +1217,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1021,6 +1233,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Tools",
@ -1036,9 +1249,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1049,6 +1265,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Upcoming Calendar Events",
@ -1064,9 +1281,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1077,6 +1297,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Open To Do",
@ -1092,9 +1313,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1105,6 +1329,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Open Notifications",
@ -1120,9 +1345,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1133,6 +1361,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": " ",
@ -1148,9 +1377,12 @@
"reqd": 0,
"search_index": 0,
"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,
@ -1161,6 +1393,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Add Quote",
@ -1176,22 +1409,23 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-envelope",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-09-16 22:00:00.000000",
"modified": "2019-01-16 09:52:15.149908",
"modified_by": "Administrator",
"module": "Setup",
"name": "Email Digest",
@ -1199,7 +1433,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -1207,7 +1440,6 @@
"export": 0,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@ -1220,7 +1452,6 @@
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@ -1228,7 +1459,6 @@
"export": 0,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 1,
"print": 0,
"read": 1,
@ -1243,7 +1473,10 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import fmt_money, formatdate, format_time, now_datetime, \
get_url_to_form, get_url_to_list, flt, getdate
get_url_to_form, get_url_to_list, flt, get_link_to_report
from datetime import timedelta
from dateutil.relativedelta import relativedelta
from frappe.core.doctype.user.user import STANDARD_USERS
@ -239,7 +239,9 @@ class EmailDigest(Document):
for key in ("income", "expenses_booked", "income_year_to_date", "expense_year_to_date",
"bank_balance", "credit_balance", "invoiced_amount", "payables",
"sales_orders_to_bill", "purchase_orders_to_bill", "sales_order", "purchase_order",
"sales_orders_to_deliver", "purchase_orders_to_receive", "new_quotations", "pending_quotations"):
"sales_orders_to_deliver", "purchase_orders_to_receive", "sales_invoice", "purchase_invoice",
"new_quotations", "pending_quotations"):
if self.get(key):
cache_key = "email_digest:card:{0}:{1}:{2}:{3}".format(self.company, self.frequency, key, self.from_date)
card = cache.get(cache_key)
@ -288,8 +290,24 @@ class EmailDigest(Document):
"""Get income for given period"""
income, past_income, count = self.get_period_amounts(self.get_roots("income"),'income')
income_account = frappe.db.get_all('Account',
fields=["name"],
filters={
"root_type":"Income",
"parent_account":'',
"company": self.company
})
label = get_link_to_report("General Ledger",self.meta.get_label("income"),
filters={
"from_date": self.future_from_date,
"to_date": self.future_to_date,
"account": income_account[0].name,
"company": self.company
}
)
return {
"label": self.meta.get_label("income"),
"label": label,
"value": income,
"last_value": past_income,
"count": count
@ -312,8 +330,20 @@ class EmailDigest(Document):
balance += get_balance_on(account, date = self.future_to_date)
count += get_count_on(account, fieldname, date = self.future_to_date)
if fieldname == 'income':
filters = {
"currency": self.currency
}
label = get_link_to_report('Profit and Loss Statement', label=self.meta.get_label(root_type + "_year_to_date"), filters=filters)
elif fieldname == 'expenses_booked':
filters = {
"currency": self.currency
}
label = get_link_to_report('Profit and Loss Statement', label=self.meta.get_label(root_type + "_year_to_date"), filters=filters)
return {
"label": self.meta.get_label(root_type + "_year_to_date"),
"label": label,
"value": balance,
"count": count
}
@ -335,8 +365,25 @@ class EmailDigest(Document):
def get_expenses_booked(self):
expenses, past_expenses, count = self.get_period_amounts(self.get_roots("expense"), 'expenses_booked')
expense_account = frappe.db.get_all('Account',
fields=["name"],
filters={
"root_type": "Expense",
"parent_account": '',
"company": self.company
}
)
label = get_link_to_report("General Ledger",self.meta.get_label("expenses_booked"),
filters={
"company":self.company,
"from_date":self.future_from_date,
"to_date":self.future_to_date,
"account": expense_account[0].name
}
)
return {
"label": self.meta.get_label("expenses_booked"),
"label": label,
"value": expenses,
"last_value": past_expenses,
"count": count
@ -361,8 +408,19 @@ class EmailDigest(Document):
where (transaction_date <= %(to_date)s) and billing_status != "Fully Billed"
and status not in ('Closed','Cancelled', 'Completed') """, {"to_date": self.future_to_date})[0]
label = get_link_to_report('Sales Order', label=self.meta.get_label("sales_orders_to_bill"),
report_type="Report Builder",
doctype="Sales Order",
filters = {
"status": [['!=', "Closed"], ['!=', "Cancelled"]],
"per_billed": [['<', 100]],
"transaction_date": [['<=', self.future_to_date]],
"company": self.company
}
)
return {
"label": self.meta.get_label("sales_orders_to_bill"),
"label": label,
"value": value,
"count": count
}
@ -370,13 +428,24 @@ class EmailDigest(Document):
def get_sales_orders_to_deliver(self):
"""Get value not delivered"""
value, count = frappe.db.sql("""select ifnull((sum(grand_total)) - (sum(grand_total*per_delivered/100)),0),
value, count = frappe.db.sql("""select ifnull((sum(grand_total)) - (sum(grand_total*per_delivered/100)),0),
count(*) from `tabSales Order`
where (transaction_date <= %(to_date)s) and delivery_status != "Fully Delivered"
and status not in ('Closed','Cancelled', 'Completed') """, {"to_date": self.future_to_date})[0]
label = get_link_to_report('Sales Order', label=self.meta.get_label("sales_orders_to_deliver"),
report_type="Report Builder",
doctype="Sales Order",
filters = {
"status": [['!=', "Closed"], ['!=', "Cancelled"], ['!=', "Completed"]],
"delivery_status": [['!=', "Fully Delivered"]],
"transaction_date": [['<=', self.future_to_date]],
"company": self.company
}
)
return {
"label": self.meta.get_label("sales_orders_to_deliver"),
"label": label,
"value": value,
"count": count
}
@ -389,8 +458,19 @@ class EmailDigest(Document):
where (transaction_date <= %(to_date)s) and per_received < 100
and status not in ('Closed','Cancelled', 'Completed') """, {"to_date": self.future_to_date})[0]
label = get_link_to_report('Purchase Order', label=self.meta.get_label("purchase_orders_to_receive"),
report_type="Report Builder",
doctype="Purchase Order",
filters = {
"status": [['!=', "Closed"], ['!=', "Cancelled"], ['!=', "Completed"]],
"per_received": [['<', 100]],
"transaction_date": [['<=', self.future_to_date]],
"company": self.company
}
)
return {
"label": self.meta.get_label("purchase_orders_to_receive"),
"label": label,
"value": value,
"count": count
}
@ -403,8 +483,19 @@ class EmailDigest(Document):
where (transaction_date <= %(to_date)s) and per_billed < 100
and status not in ('Closed','Cancelled', 'Completed') """, {"to_date": self.future_to_date})[0]
label = get_link_to_report('Purchase Order', label=self.meta.get_label("purchase_orders_to_bill"),
report_type="Report Builder",
doctype="Purchase Order",
filters = {
"status": [['!=', "Closed"], ['!=', "Cancelled"], ['!=', "Completed"]],
"per_received": [['<', 100]],
"transaction_date": [['<=', self.future_to_date]],
"company": self.company
}
)
return {
"label": self.meta.get_label("purchase_orders_to_bill"),
"label": label,
"value": value,
"count": count
}
@ -428,13 +519,47 @@ class EmailDigest(Document):
prev_balance += get_balance_on(account, date=self.past_to_date, in_account_currency=False)
if fieldname in ("bank_balance","credit_balance"):
label = ""
if fieldname == "bank_balance":
filters = {
"root_type": "Asset",
"account_type": "Bank",
"report_date": self.future_to_date,
"company": self.company
}
label = get_link_to_report('Account Balance', label=self.meta.get_label(fieldname), filters=filters)
else:
filters = {
"root_type": "Liability",
"account_type": "Bank",
"report_date": self.future_to_date,
"company": self.company
}
label = get_link_to_report('Account Balance', label=self.meta.get_label(fieldname), filters=filters)
return {
'label': self.meta.get_label(fieldname),
'label': label,
'value': balance,
'last_value': prev_balance }
'last_value': prev_balance
}
else:
if account_type == 'Payable':
label = get_link_to_report('Accounts Payable', label=self.meta.get_label(fieldname),
filters={
"report_date": self.future_to_date,
"company": self.company
} )
elif account_type == 'Receivable':
label = get_link_to_report('Accounts Receivable', label=self.meta.get_label(fieldname),
filters={
"report_date": self.future_to_date,
"company": self.company
})
else:
label = self.meta.get_label(fieldname)
return {
'label': self.meta.get_label(fieldname),
'label': label,
'value': balance,
'last_value': prev_balance,
'count': count
@ -468,6 +593,14 @@ class EmailDigest(Document):
return self.get_summary_of_pending("Sales Order","pending_sales_orders","per_delivered")
def get_sales_invoice(self):
return self.get_summary_of_doc("Sales Invoice","sales_invoice")
def get_purchase_invoice(self):
return self.get_summary_of_doc("Purchase Invoice","purchase_invoice")
def get_new_quotations(self):
return self.get_summary_of_doc("Quotation","new_quotations")
@ -487,10 +620,10 @@ class EmailDigest(Document):
return {
"label": self.meta.get_label(fieldname),
"value": value,
"value": value,
"billed_value": billed_value,
"delivered_value": delivered_value,
"count": count
"count": count
}
def get_summary_of_pending_quotations(self, fieldname):
@ -505,33 +638,62 @@ class EmailDigest(Document):
and company = %(company)s
and status not in ('Ordered','Cancelled', 'Lost') """,{"to_date": self.past_to_date, "company": self.company})[0][0]
label = get_link_to_report('Quotation', label=self.meta.get_label(fieldname),
report_type="Report Builder",
doctype="Quotation",
filters = {
"status": [['!=', "Ordered"], ['!=', "Cancelled"], ['!=', "Lost"]],
"per_received": [['<', 100]],
"transaction_date": [['<=', self.future_to_date]],
"company": self.company
}
)
return {
"label": self.meta.get_label(fieldname),
"value": value,
"label": label,
"value": value,
"last_value": last_value,
"count": count
"count": count
}
def get_summary_of_doc(self, doc_type, fieldname):
value = self.get_total_on(doc_type, self.future_from_date, self.future_to_date)[0]
count = self.get_total_on(doc_type, self.future_from_date, self.future_to_date)[1]
date_field = 'posting_date' if doc_type in ['Sales Invoice', 'Purchase Invoice'] \
else 'transaction_date'
last_value =self.get_total_on(doc_type, self.past_from_date, self.past_to_date)[0]
value = flt(self.get_total_on(doc_type, self.future_from_date, self.future_to_date)[0].grand_total)
count = self.get_total_on(doc_type, self.future_from_date, self.future_to_date)[0].count
last_value = flt(self.get_total_on(doc_type, self.past_from_date, self.past_to_date)[0].grand_total)
filters = {
date_field: [['>=', self.future_from_date], ['<=', self.future_to_date]],
"status": [['!=','Cancelled']],
"company": self.company
}
label = get_link_to_report(doc_type,label=self.meta.get_label(fieldname),
report_type="Report Builder", filters=filters, doctype=doc_type)
return {
"label": self.meta.get_label(fieldname),
"value": value,
"last_value": last_value,
"label": label,
"value": value,
"last_value": last_value,
"count": count
}
def get_total_on(self, doc_type, from_date, to_date):
return frappe.db.sql("""select ifnull(sum(grand_total),0), count(*) from `tab{0}`
where (transaction_date between %(from_date)s and %(to_date)s) and company=%(company)s
and status not in ('Cancelled')""".format(doc_type),
{"from_date": from_date, "to_date": to_date, "company": self.company})[0]
date_field = 'posting_date' if doc_type in ['Sales Invoice', 'Purchase Invoice'] \
else 'transaction_date'
return frappe.get_all(doc_type,
filters={
date_field: ['between', (from_date, to_date)],
'status': ['not in', ('Cancelled')],
'company': self.company
},
fields=['count(*) as count', 'sum(grand_total) as grand_total'])
def get_from_to_date(self):
today = now_datetime().date()
@ -597,13 +759,13 @@ class EmailDigest(Document):
fields_poi = "`tabPurchase Order Item`.parent, `tabPurchase Order Item`.schedule_date, item_code," \
"received_qty, qty - received_qty as missing_qty, rate, amount"
sql_po = """select {fields} from `tabPurchase Order Item`
sql_po = """select {fields} from `tabPurchase Order Item`
left join `tabPurchase Order` on `tabPurchase Order`.name = `tabPurchase Order Item`.parent
where status<>'Closed' and `tabPurchase Order Item`.docstatus=1 and curdate() > `tabPurchase Order Item`.schedule_date
and received_qty < qty order by `tabPurchase Order Item`.parent DESC,
`tabPurchase Order Item`.schedule_date DESC""".format(fields=fields_po)
sql_poi = """select {fields} from `tabPurchase Order Item`
sql_poi = """select {fields} from `tabPurchase Order Item`
left join `tabPurchase Order` on `tabPurchase Order`.name = `tabPurchase Order Item`.parent
where status<>'Closed' and `tabPurchase Order Item`.docstatus=1 and curdate() > `tabPurchase Order Item`.schedule_date
and received_qty < qty order by `tabPurchase Order Item`.idx""".format(fields=fields_poi)
@ -631,11 +793,11 @@ def get_digest_msg(name):
def get_incomes_expenses_for_period(account, from_date, to_date):
"""Get amounts for current and past periods"""
val = 0.0
balance_on_to_date = get_balance_on(account, date = to_date)
balance_before_from_date = get_balance_on(account, date = from_date - timedelta(days=1))
fy_start_date = get_fiscal_year(to_date)[1]
if from_date == fy_start_date:

View File

@ -150,7 +150,7 @@ def adjust_qty_for_expired_items(data):
if item.get('has_batch_no') and item.get('website_warehouse'):
stock_qty_dict = get_qty_in_stock(
item.get('name'), 'website_warehouse', item.get('website_warehouse'))
qty = stock_qty_dict.stock_qty[0][0]
qty = stock_qty_dict.stock_qty[0][0] if stock_qty_dict.stock_qty else 0
item['in_stock'] = 1 if qty else 0
adjusted_data.append(item)

View File

@ -66,7 +66,7 @@ def place_order():
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
for item in sales_order.get("items"):
item.reserved_warehouse, is_stock_item = frappe.db.get_value("Item",
item.item_code, ["website_warehouse", "is_stock_item"]) or None, None
item.item_code, ["website_warehouse", "is_stock_item"])
if is_stock_item:
item_stock = get_qty_in_stock(item.item_code, "website_warehouse")

View File

@ -5,6 +5,7 @@ $.extend(cur_frm.cscript, {
onload: function() {
if(cur_frm.doc.__onload && cur_frm.doc.__onload.quotation_series) {
cur_frm.fields_dict.quotation_series.df.options = cur_frm.doc.__onload.quotation_series;
cur_frm.refresh_field("quotation_series");
}
},
refresh: function(){

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from erpnext.shopping_cart.cart import _get_cart_quotation
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings \
import is_cart_enabled, get_shopping_cart_settings, show_quantity_in_website
import get_shopping_cart_settings, show_quantity_in_website
from erpnext.utilities.product import get_price, get_qty_in_stock
@frappe.whitelist(allow_guest=True)

View File

@ -19,7 +19,6 @@
# default settings that can be made for a user.
from __future__ import unicode_literals
import frappe
product_name = "ERPNext"
user_defaults = {

View File

@ -6,7 +6,7 @@ import unittest
from frappe.utils import nowdate
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError
from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError, QualityInspectionNotSubmittedError
# test_records = frappe.get_test_records('Quality Inspection')
@ -19,7 +19,7 @@ class TestQualityInspection(unittest.TestCase):
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
self.assertRaises(QualityInspectionRequiredError, dn.submit)
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected", submit=True)
dn.reload()
self.assertRaises(QualityInspectionRejectedError, dn.submit)
@ -27,6 +27,12 @@ class TestQualityInspection(unittest.TestCase):
dn.reload()
dn.submit()
def test_qa_not_submit(self):
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, submit = False)
dn.items[0].quality_inspection = qa.name
self.assertRaises(QualityInspectionNotSubmittedError, dn.submit)
def create_quality_inspection(**args):
args = frappe._dict(args)
qa = frappe.new_doc("Quality Inspection")
@ -42,6 +48,7 @@ def create_quality_inspection(**args):
"status": args.status
})
qa.save()
qa.submit()
if args.submit:
qa.submit()
return qa

View File

@ -302,6 +302,9 @@ def has_duplicate_serial_no(sn, sle):
if sn.warehouse:
return True
if sn.company != sle.company:
return False
status = False
if sn.purchase_document_no:
if sle.voucher_type in ['Purchase Receipt', 'Stock Entry', "Purchase Invoice"] and \
@ -357,6 +360,7 @@ def auto_make_serial_nos(args):
sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None
sr.batch_no = args.get('batch_no')
sr.location = args.get('location')
sr.company = args.get('company')
if sr.sales_order and args.get('voucher_type') == "Stock Entry" \
and not args.get('actual_qty', 0) > 0:
sr.sales_order = None

View File

@ -7,6 +7,12 @@
from __future__ import unicode_literals
import frappe, unittest
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No')
@ -29,3 +35,21 @@ class TestSerialNo(unittest.TestCase):
sr.warehouse = "_Test Warehouse - _TC"
self.assertTrue(SerialNoCannotCannotChangeError, sr.save)
def test_inter_company_transfer(self):
se = make_serialized_item(target_warehouse="_Test Warehouse - _TC")
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
create_delivery_note(item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0])
wh = create_warehouse("_Test Warehouse", company="_Test Company 1")
make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1, serial_no=serial_nos[0],
company="_Test Company 1", warehouse=wh)
serial_no = frappe.db.get_value("Serial No", serial_nos[0], ["warehouse", "company"], as_dict=1)
self.assertEqual(serial_no.warehouse, wh)
self.assertEqual(serial_no.company, "_Test Company 1")
def tearDown(self):
frappe.db.rollback()

View File

@ -8,6 +8,7 @@ from erpnext import set_perpetual_inventory
from frappe.test_runner import make_test_records
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
import erpnext
import frappe
import unittest
test_records = frappe.get_test_records('Warehouse')
@ -90,17 +91,24 @@ class TestWarehouse(unittest.TestCase):
self.assertTrue(frappe.db.get_value("Warehouse",
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
def create_warehouse(warehouse_name, properties=None):
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
def create_warehouse(warehouse_name, properties=None, company=None):
if not company:
company = "_Test Company"
warehouse_id = erpnext.encode_company_abbr(warehouse_name, company)
if not frappe.db.exists("Warehouse", warehouse_id):
w = frappe.new_doc("Warehouse")
w.warehouse_name = warehouse_name
w.parent_warehouse = "_Test Warehouse Group - _TC"
w.company = "_Test Company"
w.company = company
make_account_for_warehouse(warehouse_name, w)
w.account = warehouse_name + " - _TC"
w.account = warehouse_id
if properties:
w.update(properties)
w.save()
return w.name
else:
return warehouse_id
def make_account_for_warehouse(warehouse_name, warehouse_obj):
if not frappe.db.exists("Account", warehouse_name + " - _TC"):

View File

@ -257,7 +257,7 @@ def repost_all_stock_vouchers():
doc.update_stock_ledger()
doc.make_gl_entries(repost_future_gle=False)
frappe.db.commit()
except Exception as e:
except Exception:
print(frappe.get_traceback())
rejected.append([voucher_type, voucher_no])
frappe.db.rollback()

View File

@ -0,0 +1,46 @@
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<h3>{{ title }}</h3>
</tr>
</table>
{% for user in users %}
<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr height="10"></tr>
<tr>
<td width="15"></td>
<td valign="top" width="24">
{% if user.image %}
<img class="sender-avatar" width="24" height="24" embed="{{ user.image }}"/>
{% else %}
<div class="sender-avatar-placeholder">
{{ user.full_name[0] }}
</div>
{% endif %}
</td>
<td width="10"></td>
<td>
<div class="text-medium text-muted">
<span>{{ user.full_name }}</span>
</div>
</td>
<td width="15"></td>
</tr>
<tr height="10"></tr>
</table>
<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr height="10"></tr>
<tr>
<td width="15"></td>
<td>
<div>
{{ user.project_status }}
</div>
</td>
<td width="15"></td>
</tr>
<tr height="10"></tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr height="20"></tr>
</table>
{% endfor %}

View File

@ -3,9 +3,8 @@
from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.utils import cint, formatdate
import frappe
@frappe.whitelist(allow_guest=True)
def send_message(subject="Website Query", message="", sender="", status="Open"):

View File

@ -1,4 +1,4 @@
import unittest, frappe, requests, os, time, erpnext
import unittest, frappe, requests, os, time
from erpnext.erpnext_integrations.connectors.woocommerce_connection import order
class TestWoocommerce(unittest.TestCase):

View File

@ -1,5 +1,4 @@
import frappe
import foundation
no_cache = 1